Question about internationalization
Unanswered
PepeW posted this in #help-forum
PepeWOP
I'm trying to figure out something about internationalization in NextJS.
The official doc is the following: https://nextjs.org/docs/app/building-your-application/routing/internationalization
Because for now I've only one language, I've done the following:
The problem I have is that I can't really use this code on a client components because it will load all the
So instead of using
Both methods works the same on server components.
My method seems to work well also on client components because I get the translation directly in the html (inspecting the network tab).
Also when I add a lot of translations in my object, the bundle size remains the same (doing a
Because my solution works so well and is so simple I'm scared that I'm missing something. Any thoughts ?
The official doc is the following: https://nextjs.org/docs/app/building-your-application/routing/internationalization
Because for now I've only one language, I've done the following:
{
"hello": {
"world": "salut"
},
}// getTranslations.ts
const dictionaries = {
fr: () => import('./fr.json').then((module) => module.default),
}
export const getTranslations = async () => dictionaries["fr"]?.()// usage
export default async function Page() {
const translations = await getTranslations()
return (
<div>{translations.hello.world}</div>
)
}The problem I have is that I can't really use this code on a client components because it will load all the
json client side so it will increase the bundle size.So instead of using
.json file I switched to a .ts file containing a js object with all the translations:export const translations = {
hello: {
world: "salut"
},
}// getTranslationsFromObj.ts
import { translations } from "@/locales/fr/fileobj";
export function getTranslationsFromObj() {
return translations
}// usage
export default async function Page() {
const translations = getTranslationsFromObj()
return (
<div>{translations.hello.world}</div>
)
}Both methods works the same on server components.
My method seems to work well also on client components because I get the translation directly in the html (inspecting the network tab).
Also when I add a lot of translations in my object, the bundle size remains the same (doing a
next build).Because my solution works so well and is so simple I'm scared that I'm missing something. Any thoughts ?
6 Replies
Siberian Flycatcher
Hi 👋
You will load all translations to the JS bundle in both cases.
If you want to keep your bundle size minimal, try to load dictionaries on the server and pass a subset of a dictionary to a client component.
For example:
You will load all translations to the JS bundle in both cases.
If you want to keep your bundle size minimal, try to load dictionaries on the server and pass a subset of a dictionary to a client component.
For example:
"use client"
function SubscribeForm({dict}) {
return (
<form>
<label>{dict.username}</label>
...
</form>
)
}async function Page({params: {lang}}) {
const dict = await getDictionary(lang);
return (
...
<h1>{dict.hello}</h1>
<SubscribeForm dict={dict.subscribeForm} />
...
)
}PepeWOP
After further research you're right.
I guess I'll stick to what you said and what the doc said but passing translations as props for every client component is kind of annoying.
I guess I'll stick to what you said and what the doc said but passing translations as props for every client component is kind of annoying.
Siberian Flycatcher
Yep, it is a bit annoying right now.
RSC is a new paradigm. And currently, we have to rely on 3rd party libraries from the previous client-only paradigm, which is causing some friction.
I'd imagine with time, we will have more atomic client primitives directly from Next.js or from the community and less need to create complex, large client components ourselves. In this world, working with dictionaries will be much easier.
For example:
RSC is a new paradigm. And currently, we have to rely on 3rd party libraries from the previous client-only paradigm, which is causing some friction.
I'd imagine with time, we will have more atomic client primitives directly from Next.js or from the community and less need to create complex, large client components ourselves. In this world, working with dictionaries will be much easier.
For example:
// Client components handling interactivity (loading states, error handling, etc...)
import { Form, FormField, FormSubmit, FormError } from 'next/forms'
async function Page({params: {lang}}) {
const dict = await getDictionary(lang);
return (
...
<h1>{dict.hello}</h1>
<Form action={...}>
<FormField name="username">{dict.subscribeForm.username}</FormField>
<FormError name="username">{dict.subsrribeform.usernameError}</FormError>
...
<FormSubmit
loadingState={dict.subscribeForm.loading}>
{dict.subscribeForm.submit}
</FormSubmit>
</Form>
...
)
}PepeWOP
Mmmh I found something interesting.
I modified my
And when I compared with the result using my
I modified my
getTranslations() function to be exactly like the doc and then did a next build. Here's the result:And when I compared with the result using my
getTranslationsFromObj() I found that the builds are the same size.So I guess reading keys synchronously from an object in a client component doesn't increase the bundle size ðŸ§
PepeWOP
Ok I get it.
Basically my method reading from an object is valid and works inside client components without increasing the bundle size. BUT it only works because for now I only have one locale.
If I have multiple locales, I need to get the lang in the url so I need to use
So to be future proof I'll stick to the official NextJS doc.
Basically my method reading from an object is valid and works inside client components without increasing the bundle size. BUT it only works because for now I only have one locale.
If I have multiple locales, I need to get the lang in the url so I need to use
usePathname(). And if I do this, now, the bundle size is increased because my function getTranslationsFromObj() needs to wait for the usePathname() which is executed purely client side.So to be future proof I'll stick to the official NextJS doc.