remix-i18next
Version:
The easiest way to translate your Full Stack React Router apps
431 lines (343 loc) • 11.4 kB
text/typescript
import { describe, expect, test } from "bun:test";
import type { BackendModule, FormatterModule } from "i18next";
import { createCookie, createMemorySessionStorage } from "react-router";
import { RemixI18Next } from "./server.js";
describe(RemixI18Next.name, () => {
describe("getLocale", () => {
test("should get the locale from the search param ?lng", async () => {
let request = new Request("https://example.com/dashboard?lng=es");
let i18n = new RemixI18Next({
detection: { supportedLanguages: ["es", "en"], fallbackLanguage: "en" },
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should get the locale from the cookie", async () => {
let cookie = createCookie("locale");
let request = new Request("https://example.com/dashboard", {
headers: { Cookie: await cookie.serialize("es") },
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
cookie,
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should get the locale from the Session", async () => {
let sessionStorage = createMemorySessionStorage({
cookie: { name: "session", secrets: ["s3cr3t"] },
});
let session = await sessionStorage.getSession();
session.set("lng", "es");
let request = new Request("https://example.com/dashboard", {
headers: { Cookie: await sessionStorage.commitSession(session) },
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
sessionStorage,
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should get the locale from the Session using a different key", async () => {
let sessionKey = "locale";
let sessionStorage = createMemorySessionStorage({
cookie: { name: "session", secrets: ["s3cr3t"] },
});
let session = await sessionStorage.getSession();
session.set(sessionKey, "es");
let request = new Request("https://example.com/dashboard", {
headers: { Cookie: await sessionStorage.commitSession(session) },
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
sessionStorage,
sessionKey,
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should get the locale from the request header", async () => {
let request = new Request("https://example.com/dashboard", {
headers: {
"Accept-Language": "es-AR,es;q=0.2,en-US;q=0.6,en;q=0.4,*;q=0.5",
},
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should get the locale using the findLocale method", async () => {
let request = new Request("https://example.com/dashboard", {
headers: {
"Accept-Language": "es-AR,es;q=0.2,en-US;q=0.6,en;q=0.4,*;q=0.5",
},
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
async findLocale(request) {
return "es";
},
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should use the fallback language if search param, cookie and request headers are not there", async () => {
let request = new Request("https://example.com/dashboard");
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
},
});
expect(await i18n.getLocale(request)).toBe("en");
});
test("should use the fallback language if the expected one is not supported", async () => {
let request = new Request("https://example.com/dashboard?lng=fr");
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en"],
fallbackLanguage: "en",
},
});
expect(await i18n.getLocale(request)).toBe("en");
});
test("should prefer search params over cookie, session and header", async () => {
let cookie = createCookie("locale");
let sessionStorage = createMemorySessionStorage({
cookie: { name: "session", secrets: ["s3cr3t"] },
});
let session = await sessionStorage.getSession();
session.set("lng", "en");
let headers = new Headers();
headers.set("Accept-Language", "fr");
headers.append("Cookie", await cookie.serialize("jp"));
headers.append("Cookie", await sessionStorage.commitSession(session));
let request = new Request("https://example.com/dashboard?lng=es", {
headers,
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "fr", "jp", "en"],
fallbackLanguage: "en",
sessionStorage,
cookie,
},
});
expect(await i18n.getLocale(request)).toBe("es");
});
test("should prefer cookie over session and header", async () => {
let cookie = createCookie("locale");
let request = new Request("https://example.com/dashboard", {
headers: {
"Accept-Language": "fr",
Cookie: await cookie.serialize("jp"),
},
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "fr", "jp", "en"],
fallbackLanguage: "en",
cookie,
},
});
expect(await i18n.getLocale(request)).toBe("jp");
});
test("should prefer session over header", async () => {
let sessionStorage = createMemorySessionStorage({
cookie: { name: "session", secrets: ["s3cr3t"] },
});
let session = await sessionStorage.getSession();
session.set("lng", "jp");
let request = new Request("https://example.com/dashboard", {
headers: {
"Accept-Language": "fr",
Cookie: await sessionStorage.commitSession(session),
},
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "fr", "jp", "en"],
fallbackLanguage: "en",
sessionStorage,
},
});
expect(await i18n.getLocale(request)).toBe("jp");
});
test("allow changing the order", async () => {
let cookie = createCookie("locale");
let sessionStorage = createMemorySessionStorage({
cookie: { name: "session", secrets: ["s3cr3t"] },
});
let session = await sessionStorage.getSession();
session.set("lng", "en");
let headers = new Headers();
headers.set("Accept-Language", "fr");
headers.append("Cookie", await sessionStorage.commitSession(session));
headers.append("Cookie", await cookie.serialize("jp"));
let request = new Request("https://example.com/dashboard?lng=es", {
headers,
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "fr", "jp", "en"],
fallbackLanguage: "en",
sessionStorage,
cookie,
order: ["session", "cookie", "header", "searchParams"],
},
});
expect(await i18n.getLocale(request)).toBe("en");
});
test("return the specific locale if there are multiple variants", async () => {
let request = new Request("https://example.com/dashboard?lng=es-MX");
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "en", "es-MX"],
fallbackLanguage: "en",
},
});
expect(await i18n.getLocale(request)).toBe("es-MX");
});
});
describe("getFixedT", () => {
let backendPlugin: BackendModule = {
type: "backend",
init: () => null,
read(_language, _namespace, callback) {
callback(null, {
hello: "Hello {{name, uppercase}}",
user: { age: "My age is {{number}}" },
});
},
};
let formatterPlugin: FormatterModule = {
type: "formatter",
init: () => null,
add: () => null,
addCached: () => null,
format(value, format) {
if (format === "uppercase") return value.toUpperCase();
},
};
test("get a fixed T function for server-side usage", async () => {
let headers = new Headers();
headers.set("Accept-Language", "fr");
let request = new Request("https://example.com/dashboard?lng=1", {
headers,
});
let i18n = new RemixI18Next({
detection: {
supportedLanguages: ["es", "fr", "jp", "en"],
fallbackLanguage: "en",
order: ["session", "cookie", "header", "searchParams"],
},
i18next: {
fallbackNS: "common",
defaultNS: "common",
resources: {
fr: {
common: {
"Hello {{name}}": "Bonjour {{name}}",
},
},
},
},
});
let t = await i18n.getFixedT(request, "common");
// @ts-expect-error - We're not using the typed resources here
expect(t("Hello {{name}}", { name: "Remix" })).toBe("Bonjour Remix");
});
test("get a fixed T function set with `backend`", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
backend: backendPlugin,
detection: {
supportedLanguages: ["en"],
fallbackLanguage: "en",
},
});
let t = await i18n.getFixedT(request, "common");
expect(t("hello", { name: "Remix" })).toBe("Hello Remix");
});
test("get a fixed T function set with single `plugins`", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
plugins: [backendPlugin],
detection: {
supportedLanguages: ["en"],
fallbackLanguage: "en",
},
});
let t = await i18n.getFixedT(request, "common");
expect(t("hello", { name: "Remix" })).toBe("Hello Remix");
});
test("get a fixed T function set with multiple `plugins`", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
plugins: [backendPlugin, formatterPlugin],
detection: {
supportedLanguages: ["en"],
fallbackLanguage: "en",
},
});
let t = await i18n.getFixedT(request, "common");
expect(t("hello", { name: "Remix" })).toBe("Hello REMIX");
});
test("get a fixed T function set with `backend` and `plugins`", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
backend: backendPlugin,
plugins: [formatterPlugin],
detection: {
supportedLanguages: ["en"],
fallbackLanguage: "en",
},
});
let t = await i18n.getFixedT(request, "common");
expect(t("hello", { name: "Remix" })).toBe("Hello REMIX");
});
test("get a fixed T with a key prefix", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
backend: backendPlugin,
plugins: [formatterPlugin],
detection: { supportedLanguages: ["en"], fallbackLanguage: "en" },
});
let t = await i18n.getFixedT(request, "common", { keyPrefix: "user" });
expect(t("age", { number: 25 })).toBe("My age is 25");
});
test("get a fixed T that uses instance fallback language", async () => {
let request = new Request("https://example.com/dashboard?lng=1");
let i18n = new RemixI18Next({
backend: backendPlugin,
plugins: [formatterPlugin],
detection: { supportedLanguages: ["es", "en"], fallbackLanguage: "en" },
});
let t = await i18n.getFixedT(request, "common");
expect(t("hello", { name: "Remix" })).toBe("Hello REMIX");
});
});
});
declare module "i18next" {
interface CustomTypeOptions {
resources: {
common: {
hello: string;
user: { age: string };
};
};
}
}