From 868c38ab4f19b2d8f86bfd1b30d0fe164e81fed7 Mon Sep 17 00:00:00 2001 From: Simon Depelchin Date: Thu, 27 Mar 2025 15:16:39 +0100 Subject: [PATCH 1/2] Use different strategy for API i18n --- .prettierignore | 3 +- examples/tanstack-start/src/api.ts | 15 ++++- .../tanstack-start/src/locales/en/messages.po | 63 ++++++++++--------- .../tanstack-start/src/locales/fr/messages.po | 63 ++++++++++--------- .../src/modules/lingui/i18n.server.ts | 49 +++++++++++++++ .../src/routes/api/users.$id.ts | 3 +- .../src/routes/users.$userId.tsx | 10 ++- .../tanstack-start/src/routes/users.route.tsx | 9 ++- examples/tanstack-start/src/ssr.tsx | 51 +-------------- 9 files changed, 152 insertions(+), 114 deletions(-) create mode 100644 examples/tanstack-start/src/modules/lingui/i18n.server.ts diff --git a/.prettierignore b/.prettierignore index 9afd6010b..d7e8906d3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,5 +10,6 @@ coverage/ website/ .github -examples +/examples/* +!/examples/tanstack-start /.nx/workspace-data diff --git a/examples/tanstack-start/src/api.ts b/examples/tanstack-start/src/api.ts index 2de4eff99..824342f11 100644 --- a/examples/tanstack-start/src/api.ts +++ b/examples/tanstack-start/src/api.ts @@ -2,5 +2,18 @@ import { createStartAPIHandler, defaultAPIFileRouteHandler, } from "@tanstack/react-start/api" +import { + defaultLocale, + dynamicActivate, + isLocaleValid, +} from "./modules/lingui/i18n" + +export default createStartAPIHandler(async (ctx) => { + // Define the locale based on the Accept-Language header + const headerLocale = ctx.request.headers.get("Accept-Language") ?? "" + await dynamicActivate( + isLocaleValid(headerLocale) ? headerLocale : defaultLocale + ) -export default createStartAPIHandler(defaultAPIFileRouteHandler) + return defaultAPIFileRouteHandler(ctx) +}) diff --git a/examples/tanstack-start/src/locales/en/messages.po b/examples/tanstack-start/src/locales/en/messages.po index 31c01f2ef..8f310841c 100644 --- a/examples/tanstack-start/src/locales/en/messages.po +++ b/examples/tanstack-start/src/locales/en/messages.po @@ -13,15 +13,30 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +#. js-lingui-explicit-id +#: src/routes/users.$userId.tsx:18 +msgid "Failed to fetch user" +msgstr "Failed to fetch user" + +#. js-lingui-explicit-id +#: src/routes/users.route.tsx:18 +msgid "Failed to fetch users" +msgstr "Failed to fetch users" + +#. js-lingui-explicit-id +#: src/routes/api/users.$id.ts:22 +msgid "User not found" +msgstr "User not found" + #: src/routes/posts_.$postId.deep.tsx:24 msgid "← All Posts" msgstr "← All Posts" -#: src/routes/deferred.tsx:57 +#: src/routes/deferred.tsx:70 msgid "Count: {count}" msgstr "Count: {count}" -#: src/routes/posts.$postId.tsx:31 +#: src/routes/posts.$postId.tsx:35 msgid "Deep View" msgstr "Deep View" @@ -29,15 +44,7 @@ msgstr "Deep View" msgid "Deferred" msgstr "Deferred" -#: src/routes/users.$userId.tsx:16 -msgid "Failed to fetch user" -msgstr "Failed to fetch user" - -#: src/routes/users.route.tsx:14 -msgid "Failed to fetch users" -msgstr "Failed to fetch users" - -#: src/components/NotFound.tsx:15 +#: src/components/NotFound.tsx:19 msgid "Go back" msgstr "Go back" @@ -45,11 +52,11 @@ msgstr "Go back" msgid "Go Back" msgstr "Go Back" -#: src/routes/_pathlessLayout/_nested-layout.tsx:19 +#: src/routes/_pathlessLayout/_nested-layout.tsx:21 msgid "Go to route A" msgstr "Go to route A" -#: src/routes/_pathlessLayout/_nested-layout.tsx:27 +#: src/routes/_pathlessLayout/_nested-layout.tsx:29 msgid "Go to route B" msgstr "Go to route B" @@ -58,31 +65,31 @@ msgstr "Go to route B" msgid "Home" msgstr "Home" -#: src/routes/_pathlessLayout.tsx:11 +#: src/routes/_pathlessLayout.tsx:12 msgid "I'm a layout" msgstr "I'm a layout" -#: src/routes/_pathlessLayout/_nested-layout.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout.tsx:12 msgid "I'm a nested layout" msgstr "I'm a nested layout" -#: src/routes/_pathlessLayout/_nested-layout/route-a.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout/route-a.tsx:13 msgid "I'm A!" msgstr "I'm A!" -#: src/routes/_pathlessLayout/_nested-layout/route-b.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout/route-b.tsx:13 msgid "I'm B!" msgstr "I'm B!" -#: src/routes/deferred.tsx:59 +#: src/routes/deferred.tsx:74 msgid "Increment" msgstr "Increment" -#: src/routes/deferred.tsx:41 +#: src/routes/deferred.tsx:44 msgid "Loading person..." msgstr "Loading person..." -#: src/routes/deferred.tsx:51 +#: src/routes/deferred.tsx:60 msgid "Loading stuff..." msgstr "Loading stuff..." @@ -90,7 +97,7 @@ msgstr "Loading stuff..." msgid "Non-existent Post" msgstr "Non-existent Post" -#: src/routes/users.route.tsx:29 +#: src/routes/users.route.tsx:33 msgid "Non-existent User" msgstr "Non-existent User" @@ -98,7 +105,7 @@ msgstr "Non-existent User" msgid "Pathless Layout" msgstr "Pathless Layout" -#: src/routes/posts.$postId.tsx:12 +#: src/routes/posts.$postId.tsx:14 msgid "Post not found" msgstr "Post not found" @@ -106,19 +113,19 @@ msgstr "Post not found" msgid "Posts" msgstr "Posts" -#: src/routes/posts.index.tsx:9 +#: src/routes/posts.index.tsx:11 msgid "Select a post." msgstr "Select a post." -#: src/routes/users.index.tsx:9 +#: src/routes/users.index.tsx:11 msgid "Select a user." msgstr "Select a user." -#: src/components/NotFound.tsx:21 +#: src/components/NotFound.tsx:25 msgid "Start Over" msgstr "Start Over" -#: src/components/NotFound.tsx:8 +#: src/components/NotFound.tsx:10 msgid "The page you are looking for does not exist." msgstr "The page you are looking for does not exist." @@ -130,7 +137,7 @@ msgstr "This Route Does Not Exist" msgid "Try Again" msgstr "Try Again" -#: src/routes/users.$userId.tsx:22 +#: src/routes/users.$userId.tsx:26 msgid "User not found" msgstr "User not found" @@ -138,6 +145,6 @@ msgstr "User not found" msgid "Users" msgstr "Users" -#: src/routes/index.tsx:11 +#: src/routes/index.tsx:12 msgid "Welcome Home!!!" msgstr "Welcome Home!!!" diff --git a/examples/tanstack-start/src/locales/fr/messages.po b/examples/tanstack-start/src/locales/fr/messages.po index 7d0ed8a8e..1054880d1 100644 --- a/examples/tanstack-start/src/locales/fr/messages.po +++ b/examples/tanstack-start/src/locales/fr/messages.po @@ -13,15 +13,30 @@ msgstr "" "Plural-Forms: \n" "X-Generator: Poedit 3.5\n" +#. js-lingui-explicit-id +#: src/routes/users.$userId.tsx:18 +msgid "Failed to fetch user" +msgstr "Échec du chargement de l'utilisateur" + +#. js-lingui-explicit-id +#: src/routes/users.route.tsx:18 +msgid "Failed to fetch users" +msgstr "Échec du chargement des utilisateurs" + +#. js-lingui-explicit-id +#: src/routes/api/users.$id.ts:22 +msgid "User not found" +msgstr "Utilisateur non trouvé" + #: src/routes/posts_.$postId.deep.tsx:24 msgid "← All Posts" msgstr "← Tous les articles" -#: src/routes/deferred.tsx:57 +#: src/routes/deferred.tsx:70 msgid "Count: {count}" msgstr "Compte: {count}" -#: src/routes/posts.$postId.tsx:31 +#: src/routes/posts.$postId.tsx:35 msgid "Deep View" msgstr "Vue détaillée" @@ -29,15 +44,7 @@ msgstr "Vue détaillée" msgid "Deferred" msgstr "Différé" -#: src/routes/users.$userId.tsx:16 -msgid "Failed to fetch user" -msgstr "Échec du chargement de l'utilisateur" - -#: src/routes/users.route.tsx:14 -msgid "Failed to fetch users" -msgstr "Échec du chargement des utilisateurs" - -#: src/components/NotFound.tsx:15 +#: src/components/NotFound.tsx:19 msgid "Go back" msgstr "Retour" @@ -45,11 +52,11 @@ msgstr "Retour" msgid "Go Back" msgstr "Retour" -#: src/routes/_pathlessLayout/_nested-layout.tsx:19 +#: src/routes/_pathlessLayout/_nested-layout.tsx:21 msgid "Go to route A" msgstr "Aller à la route A" -#: src/routes/_pathlessLayout/_nested-layout.tsx:27 +#: src/routes/_pathlessLayout/_nested-layout.tsx:29 msgid "Go to route B" msgstr "Aller à la route B" @@ -58,31 +65,31 @@ msgstr "Aller à la route B" msgid "Home" msgstr "Accueil" -#: src/routes/_pathlessLayout.tsx:11 +#: src/routes/_pathlessLayout.tsx:12 msgid "I'm a layout" msgstr "Je suis un layout" -#: src/routes/_pathlessLayout/_nested-layout.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout.tsx:12 msgid "I'm a nested layout" msgstr "Je suis un layout imbriqué" -#: src/routes/_pathlessLayout/_nested-layout/route-a.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout/route-a.tsx:13 msgid "I'm A!" msgstr "Je suis A !" -#: src/routes/_pathlessLayout/_nested-layout/route-b.tsx:11 +#: src/routes/_pathlessLayout/_nested-layout/route-b.tsx:13 msgid "I'm B!" msgstr "Je suis B !" -#: src/routes/deferred.tsx:59 +#: src/routes/deferred.tsx:74 msgid "Increment" msgstr "Incrémenter" -#: src/routes/deferred.tsx:41 +#: src/routes/deferred.tsx:44 msgid "Loading person..." msgstr "Chargement de la personne..." -#: src/routes/deferred.tsx:51 +#: src/routes/deferred.tsx:60 msgid "Loading stuff..." msgstr "Chargement de choses..." @@ -90,7 +97,7 @@ msgstr "Chargement de choses..." msgid "Non-existent Post" msgstr "Article non-existant" -#: src/routes/users.route.tsx:29 +#: src/routes/users.route.tsx:33 msgid "Non-existent User" msgstr "Utilisateur non-existant" @@ -98,7 +105,7 @@ msgstr "Utilisateur non-existant" msgid "Pathless Layout" msgstr "Layout sans chemin" -#: src/routes/posts.$postId.tsx:12 +#: src/routes/posts.$postId.tsx:14 msgid "Post not found" msgstr "Article non trouvé" @@ -106,19 +113,19 @@ msgstr "Article non trouvé" msgid "Posts" msgstr "Articles" -#: src/routes/posts.index.tsx:9 +#: src/routes/posts.index.tsx:11 msgid "Select a post." msgstr "Sélectionnez un article." -#: src/routes/users.index.tsx:9 +#: src/routes/users.index.tsx:11 msgid "Select a user." msgstr "Sélectionnez un utilisateur." -#: src/components/NotFound.tsx:21 +#: src/components/NotFound.tsx:25 msgid "Start Over" msgstr "Recommencer" -#: src/components/NotFound.tsx:8 +#: src/components/NotFound.tsx:10 msgid "The page you are looking for does not exist." msgstr "La page que vous cherchez n'existe pas." @@ -130,7 +137,7 @@ msgstr "Cette route n'existe pas" msgid "Try Again" msgstr "Réessayer" -#: src/routes/users.$userId.tsx:22 +#: src/routes/users.$userId.tsx:26 msgid "User not found" msgstr "Utilisateur non trouvé" @@ -138,6 +145,6 @@ msgstr "Utilisateur non trouvé" msgid "Users" msgstr "Utilisateurs" -#: src/routes/index.tsx:11 +#: src/routes/index.tsx:12 msgid "Welcome Home!!!" msgstr "Bienvenue à la maison !!!" diff --git a/examples/tanstack-start/src/modules/lingui/i18n.server.ts b/examples/tanstack-start/src/modules/lingui/i18n.server.ts new file mode 100644 index 000000000..28f007c5e --- /dev/null +++ b/examples/tanstack-start/src/modules/lingui/i18n.server.ts @@ -0,0 +1,49 @@ +import { + getHeaders, + getWebRequest, + setHeader, +} from "@tanstack/react-start/server" +import { parse, serialize } from "cookie-es" + +import { defaultLocale, dynamicActivate, isLocaleValid } from "./i18n" + +function getLocaleFromRequest() { + const request = getWebRequest() + const headers = getHeaders() + const cookie = parse(headers.cookie ?? "") + + if (request) { + const url = new URL(request.url) + const queryLocale = url.searchParams.get("locale") ?? "" + + if (isLocaleValid(queryLocale)) { + setHeader( + "Set-Cookie", + serialize("locale", queryLocale, { + maxAge: 30 * 24 * 60 * 60, + path: "/", + }) + ) + + return queryLocale + } + } + + if (cookie.locale && isLocaleValid(cookie.locale)) { + return cookie.locale + } + + setHeader( + "Set-Cookie", + serialize("locale", defaultLocale, { + maxAge: 30 * 24 * 60 * 60, + path: "/", + }) + ) + + return defaultLocale +} + +export async function setupLocaleFromRequest() { + await dynamicActivate(getLocaleFromRequest()) +} diff --git a/examples/tanstack-start/src/routes/api/users.$id.ts b/examples/tanstack-start/src/routes/api/users.$id.ts index 5df73552e..a0a25b610 100644 --- a/examples/tanstack-start/src/routes/api/users.$id.ts +++ b/examples/tanstack-start/src/routes/api/users.$id.ts @@ -2,6 +2,7 @@ import { json } from "@tanstack/react-start" import { createAPIFileRoute } from "@tanstack/react-start/api" import axios from "redaxios" import type { User } from "../../utils/users" +import { i18n } from "@lingui/core" export const APIRoute = createAPIFileRoute("/api/users/$id")({ GET: async ({ request, params }) => { @@ -18,7 +19,7 @@ export const APIRoute = createAPIFileRoute("/api/users/$id")({ }) } catch (e) { console.error(e) - return json({ error: "User not found" }, { status: 404 }) + return json({ error: i18n._("User not found") }, { status: 404 }) } }, }) diff --git a/examples/tanstack-start/src/routes/users.$userId.tsx b/examples/tanstack-start/src/routes/users.$userId.tsx index b841947c0..a2faac112 100644 --- a/examples/tanstack-start/src/routes/users.$userId.tsx +++ b/examples/tanstack-start/src/routes/users.$userId.tsx @@ -1,4 +1,3 @@ -import { t } from "@lingui/core/macro" import { Trans } from "@lingui/react/macro" import { createFileRoute } from "@tanstack/react-router" import axios from "redaxios" @@ -6,14 +5,19 @@ import type { User } from "~/utils/users" import { DEPLOY_URL } from "~/utils/users" import { NotFound } from "~/components/NotFound" import { UserErrorComponent } from "~/components/UserError" +import { i18n } from "@lingui/core" export const Route = createFileRoute("/users/$userId")({ loader: async ({ params: { userId } }) => { return await axios - .get(DEPLOY_URL + "/api/users/" + userId) + .get(DEPLOY_URL + "/api/users/" + userId, { + headers: { + "Accept-Language": i18n.locale, + }, + }) .then((r) => r.data) .catch(() => { - throw new Error(t`Failed to fetch user`) + throw new Error(i18n._("Failed to fetch user")) }) }, errorComponent: UserErrorComponent, diff --git a/examples/tanstack-start/src/routes/users.route.tsx b/examples/tanstack-start/src/routes/users.route.tsx index b2cf0bf8f..afca4a43b 100644 --- a/examples/tanstack-start/src/routes/users.route.tsx +++ b/examples/tanstack-start/src/routes/users.route.tsx @@ -4,14 +4,19 @@ import { Link, Outlet, createFileRoute } from "@tanstack/react-router" import axios from "redaxios" import { DEPLOY_URL } from "../utils/users" import type { User } from "../utils/users" +import { i18n } from "@lingui/core" export const Route = createFileRoute("/users")({ loader: async () => { return await axios - .get>(DEPLOY_URL + "/api/users") + .get>(DEPLOY_URL + "/api/users", { + headers: { + "Accept-Language": i18n.locale, + }, + }) .then((r) => r.data) .catch(() => { - throw new Error(t`Failed to fetch users`) + throw new Error(i18n._("Failed to fetch users")) }) }, component: UsersLayoutComponent, diff --git a/examples/tanstack-start/src/ssr.tsx b/examples/tanstack-start/src/ssr.tsx index f3441e9bc..8f8b74b24 100644 --- a/examples/tanstack-start/src/ssr.tsx +++ b/examples/tanstack-start/src/ssr.tsx @@ -4,60 +4,11 @@ import { createStartHandler, defaultStreamHandler, defineEventHandler, - getHeaders, - getWebRequest, - setHeader, } from "@tanstack/react-start/server" import { getRouterManifest } from "@tanstack/react-start/router-manifest" -import { parse, serialize } from "cookie-es" -import { - defaultLocale, - dynamicActivate, - isLocaleValid, -} from "./modules/lingui/i18n" import { createRouter } from "./router" - -function getLocaleFromRequest() { - const request = getWebRequest() - const headers = getHeaders() - const cookie = parse(headers.cookie ?? "") - - if (request) { - const url = new URL(request.url) - const queryLocale = url.searchParams.get("locale") ?? "" - - if (isLocaleValid(queryLocale)) { - setHeader( - "Set-Cookie", - serialize("locale", queryLocale, { - maxAge: 30 * 24 * 60 * 60, - path: "/", - }) - ) - - return queryLocale - } - } - - if (cookie.locale && isLocaleValid(cookie.locale)) { - return cookie.locale - } - - setHeader( - "Set-Cookie", - serialize("locale", defaultLocale, { - maxAge: 30 * 24 * 60 * 60, - path: "/", - }) - ) - - return defaultLocale -} - -async function setupLocaleFromRequest() { - await dynamicActivate(getLocaleFromRequest()) -} +import { setupLocaleFromRequest } from "./modules/lingui/i18n.server" export default defineEventHandler(async (event) => { await setupLocaleFromRequest() From 8769d97c84eb4d1addae15f288f22143413c3e18 Mon Sep 17 00:00:00 2001 From: Simon Depelchin Date: Thu, 27 Mar 2025 15:17:24 +0100 Subject: [PATCH 2/2] Reset .prettierignore changes --- .prettierignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index d7e8906d3..9afd6010b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,6 +10,5 @@ coverage/ website/ .github -/examples/* -!/examples/tanstack-start +examples /.nx/workspace-data