Skip to content

Commit

Permalink
fix: server side i18n function
Browse files Browse the repository at this point in the history
  • Loading branch information
pahaz committed Jun 9, 2024
1 parent 0869f4d commit 75e6277
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 24 deletions.
9 changes: 5 additions & 4 deletions apps/web/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
'use server'

import { Show } from '@repo/ui/refine/antd'
import React from 'react'

import { Layout } from 'web/components/Layout'
import { getTranslate } from 'web/providers/i18n/server'

export default async function DashboardPage(): Promise<React.JSX.Element> {
const translate = await getTranslate()
const titleMessage = translate('dashboard.title', 'Dashboard')
return (
<Layout>
<Show headerButtons={[]}>
<h1>Dashboard!</h1>
<p>Content of your show page...</p>
<Show headerButtons={[]} title={titleMessage}>
<h1>{titleMessage}</h1>
</Show>
</Layout>
)
Expand Down
7 changes: 3 additions & 4 deletions apps/web/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use server'

import { getLocale, getServerTranslate } from '@repo/i18n/server'
import { Layout } from '@repo/ui/general'
import Image from 'next/image'
import React from 'react'

import { BrandTitle, Logo } from '../components/BrandTitle'
import { FormExample } from '../components/FormExample'
import { getTranslate } from '../providers/i18n/server'
import styles from './page.module.css'

const LINKS = [
Expand Down Expand Up @@ -34,12 +34,11 @@ const LINKS = [
]

async function Head(): Promise<React.JSX.Element> {
const locale = await getLocale()
const translate = await getServerTranslate(locale)
const translate = await getTranslate()

return (
<div className={styles.description}>
<p>{translate('dashboard.title', 'Dashboard')}</p>
<p>{translate('dashboard.title', 'Dash')}</p>
<div>
<BrandTitle collapsed={false} />
</div>
Expand Down
5 changes: 5 additions & 0 deletions apps/web/providers/i18n/importer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// we should define this function inside the app!
const IMPORTER = (language: string, namespace: string) =>
import(`web/public/locales/${language}/${namespace}.json`)

export { IMPORTER }
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ import {
LOCALES,
} from '@repo/i18n'

import { IMPORTER } from './importer'

const runsOnServerSide = typeof window === 'undefined'

i18next
.use(initReactI18next)
.use(LanguageDetector)
.use(
resourcesToBackend(
(language: string, namespace: string) =>
import(`../public/locales/${language}/${namespace}.json`),
),
)
.use(resourcesToBackend(IMPORTER))
.init({
// debug: true,
lng: undefined, // let detect the language on client side
Expand Down
7 changes: 7 additions & 0 deletions apps/web/providers/i18n/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getLocale, getServerTranslate } from '@repo/i18n/server'
import { IMPORTER } from './importer'

export async function getTranslate() {
const locale = await getLocale()
return await getServerTranslate(IMPORTER, locale)
}
35 changes: 25 additions & 10 deletions packages/i18n/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,37 @@ import { cookies, headers } from 'next/headers'
import { initReactI18next } from 'react-i18next/initReactI18next'
import acceptLanguage from 'accept-language'

import { DEFAULT_LOCALE, LOCALE_COOKIE_NAME, LOCALES } from './config'
import {
DEFAULT_LOCALE,
DEFAULT_NAMESPACE,
LOCALE_COOKIE_NAME,
LOCALES,
} from './config'

type Importer = (
language: string,
namespace: string,
) => Promise<string | boolean | null | undefined>

acceptLanguage.languages(LOCALES)
const IMPORTER = (language: string, namespace: string) =>
import(`${process.cwd()}/public/locales/${language}/${namespace}.json`)

// based on: https://github.com/i18next/next-app-dir-i18next-example/blob/main/app/i18n/index.js#L6
const initI18next = async (locale: string, options = {}) => {
const initI18next = async (
importer: Importer,
locale: string,
options = {},
) => {
// on server side we create a new instance for each render, because during compilation everything seems to be executed in parallel
const i18nInstance = createInstance()
await i18nInstance
.use(initReactI18next)
.use(resourcesToBackend(IMPORTER))
.use(resourcesToBackend(importer))
.init({
// debug: true,
debug: true,
fallbackLng: DEFAULT_LOCALE,
defaultNS: 'common',
fallbackNS: DEFAULT_NAMESPACE,
defaultNS: DEFAULT_NAMESPACE,
ns: [DEFAULT_NAMESPACE],
lng: locale,
...options,
})
Expand All @@ -40,14 +54,15 @@ export async function getLocale(): Promise<string> {

// Accept-Language header
const headerLocale = acceptLanguage.get(headersStore.get('accept-language'))
if (typeof headerLocale === 'string' && LOCALES.includes(headerLocale))
if (typeof headerLocale === 'string' && LOCALES.includes(headerLocale)) {
return headerLocale
}

return DEFAULT_LOCALE
}

export async function getServerTranslate(locale: string) {
const i18nextInstance = await initI18next(locale)
export async function getServerTranslate(importer: Importer, locale: string) {
const i18nextInstance = await initI18next(importer, locale)
return i18nextInstance.getFixedT(locale)
}

Expand Down

0 comments on commit 75e6277

Please sign in to comment.