admin管理员组文章数量:1310254
I want to create an astro ponent taking into account a variable in localstorage to get each ponent text, but Astro shows null.
let locale = "en"; //default
const userLanguage = localStorage.getItem("language");
if (userLanguage ) {
locale = userLanguage;
} let menu;
import(`../locale/${locale}/menu.json`).then((lang) =\> {
menu = lang.default;
});
I need to find the way to have language based json or markup files and load each user's language. I was thinking about using svelte/react but I will have to create a lot of calls or maybe is there another way to make it?
I want to create an astro ponent taking into account a variable in localstorage to get each ponent text, but Astro shows null.
let locale = "en"; //default
const userLanguage = localStorage.getItem("language");
if (userLanguage ) {
locale = userLanguage;
} let menu;
import(`../locale/${locale}/menu.json`).then((lang) =\> {
menu = lang.default;
});
I need to find the way to have language based json or markup files and load each user's language. I was thinking about using svelte/react but I will have to create a lot of calls or maybe is there another way to make it?
Share Improve this question edited Mar 1, 2024 at 16:01 VLAZ 29.1k9 gold badges63 silver badges84 bronze badges asked Feb 21, 2023 at 15:31 Chris_xDChris_xD 311 silver badge3 bronze badges1 Answer
Reset to default 9Why it happens
As I understood you want to create *.astro
ponent and use localStorage
API within it. However, browser related API (such as document
and window
) is not accessible on the server i.e. in Astro and from MDN you can see that localStorage
is part of window
object.
The
localStorage
read-only property of thewindow
interface allows you to access aStorage
object for theDocument
's origin; the stored data is saved across browser sessions.
With that in mind the right usage of localStorage
will be window.localStorage
which will cause the following Astro error:
document
(orwindow
) is not defined
From Astro docs you can see what this actually means:
Astro ponents run on the server, so you can’t access these browser-specific objects within the frontmatter.
Potential solutions
So the potential solution will be to use Framework ponents with lifecycle hooks (e.g React's useEffect
, Vue's onMounted
and so on) or <script>
as mentioned in Astro docs as well:
If the code is in an Astro ponent, move it to a
<script>
tag outside of the frontmatter. This tells Astro to run this code on the client, wheredocument
andwindow
are available.
If the code is in a framework ponent, try to access these objects after rendering using lifecycle methods ... Tell the framework ponent to hydrate client-side by using a
client:
directive, likeclient:load
, to run these lifecycle methods.
How would I solve it
Hovewer, from my experience I would move the async loading of json
translation from the client to the server by just loading all the translations, i.e for each language.
Let's say you have the following folder structure for translations:
- locales
--- menu
----- en.json
----- ru.json
----- es.json
--- other_feature
----- en.json
----- ru.json
----- es.json
Then we can use glob import to import everything at once:
const translations = import.meta.glob('./locales/menu/*.json', { eager: true, import: 'default' })
Then you just pass this translations object (which is object with keys representing path to file and values representing the json
string) to your Framework ponent. You can learn more about glob import here.
Framework ponent itself should use lifecycle method to access the localStorage
to read user locale and conditionally take the correct translation from the input props. Below the Vue example:
<script setup>
import { onMounted, ref } from 'vue'
const props = defineProps(['translations'])
const translation = ref({})
onMounted(() => {
const userLocale = window.localeStorage.getItem("language")
// take the correct translation from all translations
translation.value = JSON.parse(
translations[Object.keys(translations).find(key => key.includes(userLocale))]
)
})
</script>
<template>
<p>This message displayed in your mother tongue: {{ translation.message }}</p>
</template>
So the final Astro file can look like this:
---
const translations = import.meta.glob('./locales/menu/*.json', { eager: true, import: 'default' })
---
<div>
<!-- Keep in mind that using `client:load` you might face hydration issues. They can be resolved by explicitly rendering the ponent on the client using `client:only` -->
<VueMessageComponent translations={ translations } client:load />
</div>
I hope it helps but keep in mind that I wrote that in JavaScript (not in TypeScript) which can cause some issues with null
/undefined
values. Also, I did not test this code so it might not work just out of the box :)
本文标签: javascriptMultilanguageAstro amp LocalStorageStack Overflow
版权声明:本文标题:javascript - Multilanguage + Astro & LocalStorage - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741842428a2400580.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论