From 3129822c49b9e9dde41fcf51f79506e37dbc8ce3 Mon Sep 17 00:00:00 2001
From: Kalle <38327916+Sendouc@users.noreply.github.com>
Date: Sun, 25 Sep 2022 15:55:22 +0300
Subject: [PATCH] Remember selected language
Closes #921
---
app/components/layout/LanguageChanger.tsx | 8 ++---
app/modules/i18n/i18next.server.ts | 10 ++++++
app/modules/i18n/index.ts | 2 +-
app/root.tsx | 40 ++++++++++++++---------
4 files changed, 40 insertions(+), 20 deletions(-)
diff --git a/app/components/layout/LanguageChanger.tsx b/app/components/layout/LanguageChanger.tsx
index 360def10c..7afa3c3ed 100644
--- a/app/components/layout/LanguageChanger.tsx
+++ b/app/components/layout/LanguageChanger.tsx
@@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { languages } from "~/modules/i18n";
-import { Button } from "../Button";
+import { LinkButton } from "../Button";
import { GlobeIcon } from "../icons/Globe";
import { Popover } from "../Popover";
@@ -14,17 +14,17 @@ export function LanguageChanger() {
>
{languages.map((lang) => (
-
+
))}
diff --git a/app/modules/i18n/i18next.server.ts b/app/modules/i18n/i18next.server.ts
index aa04d710f..b591e1d3b 100644
--- a/app/modules/i18n/i18next.server.ts
+++ b/app/modules/i18n/i18next.server.ts
@@ -1,10 +1,20 @@
+import { createCookie } from "@remix-run/node";
import Backend from "i18next-fs-backend";
import { resolve } from "node:path";
import { RemixI18Next } from "remix-i18next";
import { config } from "./config";
+const TEN_YEARS_IN_SECONDS = 31_536_000 * 10;
+
+export const i18nCookie = createCookie("i18n", {
+ sameSite: "lax",
+ path: "/",
+ maxAge: TEN_YEARS_IN_SECONDS,
+});
+
export const i18next = new RemixI18Next({
detection: {
+ cookie: i18nCookie,
supportedLanguages: config.supportedLngs,
fallbackLanguage: config.fallbackLng,
},
diff --git a/app/modules/i18n/index.ts b/app/modules/i18n/index.ts
index 49426891f..d46768a1f 100644
--- a/app/modules/i18n/index.ts
+++ b/app/modules/i18n/index.ts
@@ -1,4 +1,4 @@
export { i18nLoader } from "./loader";
export { i18Instance } from "./loader.server";
-export { i18next } from "./i18next.server";
+export { i18next, i18nCookie } from "./i18next.server";
export { DEFAULT_LANGUAGE, languages } from "./config";
diff --git a/app/root.tsx b/app/root.tsx
index e3cf27bd1..a68a4e44c 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -25,7 +25,7 @@ import { db } from "./db";
import type { FindAllPatrons } from "./db/models/users/queries.server";
import type { UserWithPlusTier } from "./db/types";
import { getUser } from "./modules/auth";
-import { DEFAULT_LANGUAGE, i18next } from "./modules/i18n";
+import { DEFAULT_LANGUAGE, i18nCookie, i18next } from "./modules/i18n";
import { useChangeLanguage } from "remix-i18next";
import { useTranslation } from "react-i18next";
import { Theme, ThemeHead, useTheme, ThemeProvider } from "./modules/theme";
@@ -33,7 +33,12 @@ import { getThemeSession } from "./modules/theme/session.server";
import { COMMON_PREVIEW_IMAGE } from "./utils/urls";
import { ConditionalScrollRestoration } from "./components/ConditionalScrollRestoration";
-export const unstable_shouldReload: ShouldReloadFunction = () => false;
+export const unstable_shouldReload: ShouldReloadFunction = ({ url }) => {
+ // reload on language change so the selected language gets set into the cookie
+ const lang = url.searchParams.get("lng");
+
+ return Boolean(lang);
+};
export const links: LinksFunction = () => {
return [
@@ -68,19 +73,24 @@ export const loader: LoaderFunction = async ({ request }) => {
const locale = await i18next.getLocale(request);
const themeSession = await getThemeSession(request);
- return json({
- locale,
- theme: themeSession.getTheme(),
- patrons: db.users.findAllPatrons(),
- user: user
- ? {
- discordAvatar: user.discordAvatar,
- discordId: user.discordId,
- id: user.id,
- plusTier: user.plusTier,
- }
- : undefined,
- });
+ return json(
+ {
+ locale,
+ theme: themeSession.getTheme(),
+ patrons: db.users.findAllPatrons(),
+ user: user
+ ? {
+ discordAvatar: user.discordAvatar,
+ discordId: user.discordId,
+ id: user.id,
+ plusTier: user.plusTier,
+ }
+ : undefined,
+ },
+ {
+ headers: { "Set-Cookie": await i18nCookie.serialize(locale) },
+ }
+ );
};
export const handle = {