Skip to content

Commit 0e2ea66

Browse files
committed
Improved i18n handling
1 parent 6fdf8a9 commit 0e2ea66

4 files changed

Lines changed: 38 additions & 2 deletions

File tree

app/localization/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ Due to the fact that the server does not care about loading in additional resour
1313
pass in `resources` to the `i18next` instance. This provides all the languages to your server which allows it to render
1414
the correct language on the server.
1515

16+
The server side also first checks the search param for the `lng` param and uses that as the language, otherwise it checks
17+
the cookie and if it has the users preferred language set. If the cookie is not set it defaults to the fallback language.
18+
19+
This is useful if the user navigates to a page without the query param set, the server will still be able to render the page in the correct language.
20+
1621
## Client-side
1722

1823
The client-side is a bit more complicated. We do not want to load in all the languages on the client side as it would

app/localization/cookie.server.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createCookie } from "react-router";
2+
import { getServerEnv } from "~/env.server";
3+
4+
const env = getServerEnv()
5+
6+
export const localeCookie = createCookie("lng", {
7+
path: "/",
8+
sameSite: "lax",
9+
secure: env.NODE_ENV === "production",
10+
httpOnly: true,
11+
});

app/localization/i18n.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { RemixI18Next } from "remix-i18next/server"
22
import i18n from "~/localization/i18n" // your i18n configuration file
3+
import { localeCookie } from "./cookie.server"
34
import { resources } from "./resource"
45

56
const i18next = new RemixI18Next({
67
detection: {
78
supportedLanguages: i18n.supportedLngs,
89
fallbackLanguage: i18n.fallbackLng,
10+
cookie: localeCookie,
11+
order: ["searchParams", "cookie"]
912
},
1013
// This is the configuration for i18next used
1114
// when translating messages server-side only

app/root.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
import { useTranslation } from "react-i18next"
2-
import { Links, Meta, Outlet, Scripts, ScrollRestoration, isRouteErrorResponse, useRouteError } from "react-router"
2+
import {
3+
Links,
4+
Meta,
5+
Outlet,
6+
Scripts,
7+
ScrollRestoration,
8+
data,
9+
isRouteErrorResponse,
10+
useRouteError,
11+
} from "react-router"
312
import type { LinksFunction } from "react-router"
413
import { useChangeLanguage } from "remix-i18next/react"
514
import type { Route } from "./+types/root"
615
import { LanguageSwitcher } from "./library/language-switcher"
16+
import { localeCookie } from "./localization/cookie.server"
717
import { ClientHintCheck, getHints } from "./services/client-hints"
818
import tailwindcss from "./tailwind.css?url"
919

1020
export async function loader({ context, request }: Route.LoaderArgs) {
1121
const { lang, clientEnv } = context
1222
const hints = getHints(request)
13-
return { lang, clientEnv, hints }
23+
return data(
24+
{ lang, clientEnv, hints },
25+
{
26+
headers: {
27+
"Set-Cookie": await localeCookie.serialize(lang),
28+
},
29+
}
30+
)
1431
}
1532

1633
export const links: LinksFunction = () => [{ rel: "stylesheet", href: tailwindcss }]

0 commit comments

Comments
 (0)