Skip to content

Commit

Permalink
feat: Rendering pages on browser when Instance i18n finished initiali…
Browse files Browse the repository at this point in the history
…zation completely

Rendering pages after loading resources of backend to resolve error `Text content does not match server-rendered HTML` on NEXT.
  • Loading branch information
zakudriver committed Dec 5, 2024
1 parent 8d9c11f commit 3f483ff
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
28 changes: 22 additions & 6 deletions src/appWithTranslation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useRef } from 'react'
import React, { useMemo, useState, useRef } from 'react'
import hoistNonReactStatics from 'hoist-non-react-statics'
import { I18nextProvider } from 'react-i18next'
import type { AppProps as NextJsAppProps } from 'next/app'
Expand All @@ -18,11 +18,18 @@ export {

export let globalI18n: I18NextClient | null = null

const addResourcesToI18next = (instance: I18NextClient, resources: Resource) => {
const addResourcesToI18next = (
instance: I18NextClient,
resources: Resource
) => {
if (resources && instance.isInitialized) {
for (const locale of Object.keys(resources)) {
for (const ns of Object.keys(resources[locale])) {
if (!instance?.store?.data || !instance.store.data[locale] || !instance.store.data[locale][ns]) {
if (
!instance?.store?.data ||
!instance.store.data[locale] ||
!instance.store.data[locale][ns]
) {
instance.addResourceBundle(
locale,
ns,
Expand All @@ -49,6 +56,9 @@ export const appWithTranslation = <Props extends NextJsAppProps>(
const ns = _nextI18Next?.ns

const instanceRef = useRef<I18NextClient | null>(null)
const [ready, setReady] = useState<boolean>(
!configOverride?.clientAwaitInit
)

/**
* Memoize i18n instance and reuse it rather than creating new instance.
Expand Down Expand Up @@ -89,15 +99,21 @@ export const appWithTranslation = <Props extends NextJsAppProps>(
if (instance) {
addResourcesToI18next(instance, resources)
} else {
instance = createClient({
const { i18n: ins, initPromise } = createClient({
...createConfig({
...userConfig,
lng: locale,
}),
lng: locale,
...(ns && { ns }),
resources,
}).i18n
})

instance = ins

if (configOverride?.clientAwaitInit) {
initPromise.then(() => setReady(true))
}

addResourcesToI18next(instance, resources)

Expand All @@ -117,7 +133,7 @@ export const appWithTranslation = <Props extends NextJsAppProps>(
i18n.changeLanguage(locale)
}, [i18n, locale])

return i18n !== null ? (
return i18n !== null && ready ? (
<I18nextProvider i18n={i18n}>
<WrappedComponent {...props} />
</I18nextProvider>
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type UserConfig = {
reloadOnPrerender?: boolean
serializeConfig?: boolean
use?: any[]
clientAwaitInit?: boolean

Check failure on line 52 in src/types.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Expected interface keys to be in ascending order. 'clientAwaitInit' should be before 'use'
} & InitOptions

export type InternalConfig = Omit<UserConfig, 'i18n'> &
Expand Down

0 comments on commit 3f483ff

Please sign in to comment.