I have a relatively simple vite-plugin-ssr project that I am trying to add internationalization support to using react-i18next. I have set up my i18n
instance:
// i18n.ts
i18n.use(initReactI18next) // passes i18n down to react-i18next
.use(LanguageDetector)
.use(resourcesToBackend((language, ns) => import(`../locales/${language}/${ns}.json`)))
.init({
fallbackLng: "en",
debug: true,
interpolation: {
escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
}
})
export default i18n
And I've imported and provided it with a I18nextProvider
in my client and server rendered code:
// _default.page.server.tsx
import i18n from "./i18n";
async function render(pageContext: PageContextServer) {
[...]
const pageHtml = ReactDOMServer.renderToString(
<PageShell pageContext={pageContext}>
<I18nextProvider i18n={i18n}>
<Page {...pageProps} />
</I18nextProvider>
</PageShell>
)
[...]
}
// _default.page.client.tsx
import i18n from "./i18n";
async function render(pageContext: PageContextClient) {
const { Page, pageProps } = pageContext
hydrateRoot(
document.getElementById('page-view')!,
<PageShell pageContext={pageContext}>
<I18nextProvider i18n={i18n}>
<Page {...pageProps} />
</I18nextProvider>
</PageShell>
)
}
However, when I load my page that uses a <Trans>
component, I get the following errors:
i18next: hasLoadedNamespace: i18next was not initialized ['en']
i18next::translator: key "hello" for languages "en" won't get resolved as namespace "translation" was not yet loaded This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!
How should I ensure i18next is loaded? I could imagine checking it in a useEffect
and rendering nothing until the promise resolves, but I don't think useEffects
are rendered in SSR (?). Ideally during build time I would look up all my translations and bake them in so no waiting or flickering occurred.
Here is a repo demonstrating the issue: https://github.com/crummy/vite-ssr-i18n
Seems like the <Trans>
component does not use the provided i18n
automatically. I resolved the issue by modifying my page from this:
function Page() {
return <h1><Trans>hello</Trans></h1>
}
To this:
function Page() {
const { t } = useTranslation();
return <h1><Trans t={t}>hello</Trans></h1>
}