UNPKG

@inlang/paraglide-js

Version:

[![NPM Downloads](https://img.shields.io/npm/dw/%40inlang%2Fparaglide-js?logo=npm&logoColor=red&label=npm%20downloads)](https://www.npmjs.com/package/@inlang/paraglide-js) [![GitHub Issues](https://img.shields.io/github/issues-closed/opral/paraglide-js?lo

600 lines 22.2 kB
import { newProject } from "@inlang/sdk"; import { expect, test, vi } from "vitest"; import { createParaglide } from "../create-paraglide.js"; test("sets the cookie to a different locale", async () => { // @ts-expect-error - global variable definition globalThis.document = {}; // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = { hostname: "example.com" }; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", }); globalThis.document.cookie = "PARAGLIDE_LOCALE=en"; runtime.setLocale("de"); // set the locale expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=de; path=/; max-age=34560000"); // reloads the site if window is available expect(globalThis.window.location.reload).toBeCalled(); }); test("sets the cookie with explicit domain to a different locale navigating subdomain", async () => { // @ts-expect-error - global variable definition globalThis.document = {}; // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = { hostname: "web.example.com" }; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", cookieDomain: "example.com", }); globalThis.document.cookie = "PARAGLIDE_LOCALE=en"; runtime.setLocale("de"); // set the locale expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=de; path=/; max-age=34560000; domain=example.com"); // reloads the site if window is available expect(globalThis.window.location.reload).toBeCalled(); }); test("sets the cookie with explicit domain to a different locale navigating domain", async () => { // @ts-expect-error - global variable definition globalThis.document = {}; // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = { hostname: "example.com" }; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", cookieDomain: "example.com", }); globalThis.document.cookie = "PARAGLIDE_LOCALE=en"; runtime.setLocale("de"); // set the locale expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=de; path=/; max-age=34560000; domain=example.com"); // reloads the site if window is available expect(globalThis.window.location.reload).toBeCalled(); }); test("url pattern strategy sets the window location", async () => { // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = {}; globalThis.window.location.hostname = "example.com"; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"] }, }), strategy: ["url"], urlPatterns: [ { pattern: "https://example.:tld/:path*", localized: [ ["en", "https://example.com/:path*"], ["de", "https://example.de/:path*"], ], }, ], }); globalThis.window.location.href = "https://example.com/page"; runtime.setLocale("de"); expect(globalThis.window.location.href).toBe("https://example.de/page"); // setting window.location.hostname automatically reloads the page expect(globalThis.window.location.reload).not.toBeCalled(); }); test("url strategy setLocale normalizes mixed-case explicit locales", async () => { // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = {}; globalThis.window.location.hostname = "example.com"; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"] }, }), strategy: ["url"], urlPatterns: [ { pattern: "https://example.:tld/:path*", localized: [ ["en", "https://example.com/:path*"], ["de", "https://example.de/:path*"], ], }, ], }); globalThis.window.location.href = "https://example.com/page"; runtime.setLocale("DE"); expect(globalThis.window.location.href).toBe("https://example.de/page"); // setting window.location.hostname automatically reloads the page expect(globalThis.window.location.reload).not.toBeCalled(); }); test("routeStrategies can disable url navigation on matching routes", async () => { // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.document = {}; // @ts-expect-error - global variable definition globalThis.window.location = { href: "https://example.com/dashboard", hostname: "example.com", reload: vi.fn(), }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr"] }, }), strategy: ["url", "cookie", "baseLocale"], cookieName: "PARAGLIDE_LOCALE", routeStrategies: [ { match: "/dashboard/:path(.*)?", strategy: ["cookie", "baseLocale"], }, ], }); globalThis.document.cookie = "PARAGLIDE_LOCALE=en"; runtime.setLocale("fr"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=fr; path=/; max-age=34560000"); expect(globalThis.window.location.href).toBe("https://example.com/dashboard"); expect(globalThis.window.location.reload).toBeCalled(); }); // `!document.cookie` was used which returned false for an empty string test("sets the cookie when it's an empty string", async () => { const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", }); /** @ts-expect-error - client side api */ globalThis.document = { cookie: "" }; runtime.setLocale("en"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=en; path=/; max-age=34560000"); }); test("when strategy precedes URL, it should set the locale and re-direct to the URL", async () => { const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr"], }, }), strategy: ["cookie", "url", "baseLocale"], cookieName: "PARAGLIDE_LOCALE", isServer: "false", urlPatterns: [ { pattern: "https://example.com/en/:path(.*)?", localized: [ ["en", "https://example.com/en/:path(.*)?"], ["fr", "https://example.com/fr/:path(.*)?"], ], }, ], }); /** @ts-expect-error - client side api */ globalThis.document = { cookie: "PARAGLIDE_LOCALE=fr" }; globalThis.window = { location: new URL("https://example.com/fr/some-path"), }; // Cookie strategy should determine locale as French expect(runtime.getLocale()).toBe("fr"); runtime.setLocale("en"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=en; path=/; max-age=34560000"); expect(globalThis.window.location.href).toBe("https://example.com/en/some-path"); }); test("overwriteSetLocale receives the options object", async () => { const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", }); // Provide minimal browser globals to avoid strategy branches failing. /** @ts-expect-error - browser shim for tests */ globalThis.document = { cookie: "" }; globalThis.window = { location: { href: "https://example.com/en", reload: vi.fn(), }, }; const spy = vi.fn(); runtime.overwriteSetLocale(spy); runtime.setLocale("fr", { reload: false }); expect(spy).toHaveBeenCalledWith("fr", { reload: false }); }); // https://github.com/opral/inlang-paraglide-js/issues/430 test("should not reload when setting locale to current locale", async () => { // @ts-expect-error - global variable definition globalThis.document = {}; // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = { hostname: "example.com" }; globalThis.window.location.reload = vi.fn(); const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"], }, }), strategy: ["cookie"], cookieName: "PARAGLIDE_LOCALE", }); globalThis.document.cookie = "PARAGLIDE_LOCALE=en; path=/"; // Setting to the current locale (en) runtime.setLocale("en"); // Cookie should remain unchanged expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=en; path=/; max-age=34560000"); // Should not trigger a reload expect(globalThis.window.location.reload).not.toBeCalled(); // Setting to a different locale should still work runtime.setLocale("de"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=de; path=/; max-age=34560000"); expect(globalThis.window.location.reload).toBeCalled(); }); test("sets the locale to localStorage", async () => { // @ts-expect-error - global variable definition globalThis.localStorage = { setItem: vi.fn(), getItem: () => "en", }; // @ts-expect-error - global variable definition globalThis.window = {}; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de"], }, }), strategy: ["localStorage"], }); runtime.setLocale("de"); expect(globalThis.localStorage.setItem).toHaveBeenCalledWith("PARAGLIDE_LOCALE", "de"); }); // Test that all strategies set their respective storage mechanisms test("should set locale in all configured storage mechanisms regardless of which strategy resolved the locale", async () => { // Setup global objects // @ts-expect-error - global variable definition globalThis.document = { cookie: "" }; // @ts-expect-error - global variable definition globalThis.localStorage = { setItem: vi.fn(), getItem: () => null, }; // @ts-expect-error - global variable definition globalThis.window = {}; // @ts-expect-error - global variable definition globalThis.window.location = {}; globalThis.window.location.hostname = "example.com"; globalThis.window.location.href = "https://example.com/en/page"; globalThis.window.location.reload = vi.fn(); // Create runtime with multiple strategies const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "de", "fr"], }, }), strategy: ["url", "localStorage", "cookie", "baseLocale"], cookieName: "PARAGLIDE_LOCALE", urlPatterns: [ { pattern: "https://example.com/:locale/:path*", localized: [ ["en", "https://example.com/en/:path*"], ["de", "https://example.com/de/:path*"], ["fr", "https://example.com/fr/:path*"], ], }, ], }); // Call setLocale runtime.setLocale("fr"); // Verify that all storage mechanisms are updated expect(globalThis.window.location.href).toBe("https://example.com/fr/page"); expect(globalThis.localStorage.setItem).toHaveBeenCalledWith("PARAGLIDE_LOCALE", "fr"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=fr; path=/; max-age=34560000"); }); test("calls setLocale on custom strategy", async () => { let customLocale = "en"; let setLocaleCalled = false; globalThis.window = { location: { reload: vi.fn() }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-setter", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-setter", { getLocale: () => customLocale, setLocale: (locale) => { customLocale = locale; setLocaleCalled = true; }, }); runtime.setLocale("fr"); expect(setLocaleCalled).toBe(true); expect(customLocale).toBe("fr"); expect(globalThis.window.location.reload).toHaveBeenCalled(); }); test("calls setLocale on multiple custom strategies", async () => { let customLocale1 = "en"; let customLocale2 = "en"; let setLocaleCalled1 = false; let setLocaleCalled2 = false; globalThis.window = { location: { reload: vi.fn() }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-multi1", "custom-multi2", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-multi1", { getLocale: () => customLocale1, setLocale: (locale) => { customLocale1 = locale; setLocaleCalled1 = true; }, }); runtime.defineCustomClientStrategy("custom-multi2", { getLocale: () => customLocale2, setLocale: (locale) => { customLocale2 = locale; setLocaleCalled2 = true; }, }); runtime.setLocale("de"); expect(setLocaleCalled1).toBe(true); expect(setLocaleCalled2).toBe(true); expect(customLocale1).toBe("de"); expect(customLocale2).toBe("de"); }); test("setLocale should return a promise if any custom setLocale function is async", async () => { let customLocale1 = "en"; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-async", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-async", { getLocale: () => customLocale1, setLocale: async (locale) => { customLocale1 = locale; }, }); const setLocalePromise = runtime.setLocale("de"); const setLocalePromiseWithoutReload = runtime.setLocale("de", { reload: false, }); expect(setLocalePromise).toBeInstanceOf(Promise); expect(setLocalePromiseWithoutReload).toBeInstanceOf(Promise); }); test("awaits async setLocale functions to resolve in custom strategy", async () => { let customLocale1 = "en"; globalThis.window = { location: { reload: vi.fn(), }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-async", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-async", { getLocale: () => customLocale1, setLocale: async (locale) => { customLocale1 = locale; }, }); const setLocalePromise = runtime.setLocale("de"); expect(window.location.reload).not.toHaveBeenCalled(); await setLocalePromise; // Verify that setLocale resolved before reload was called expect(window.location.reload).toHaveBeenCalledTimes(1); expect(customLocale1).toBe("de"); }); test("awaits async setLocale functions to resolve in multiple custom strategies", async () => { let customLocale1 = "en"; let customLocale2 = "en"; globalThis.window = { location: { reload: vi.fn(), }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-async1", "custom-async2", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-async1", { getLocale: () => customLocale1, setLocale: async (locale) => { customLocale1 = locale; }, }); runtime.defineCustomClientStrategy("custom-async2", { getLocale: () => customLocale2, setLocale: async (locale) => { customLocale2 = locale; }, }); const setLocalePromise = runtime.setLocale("de"); expect(window.location.reload).not.toHaveBeenCalled(); await setLocalePromise; // Verify that setLocale resolved before reload was called expect(window.location.reload).toHaveBeenCalledTimes(1); expect(customLocale1).toBe("de"); expect(customLocale2).toBe("de"); }); test("reload should not run if async setLocale function rejects in custom strategy", async () => { const customLocale1 = "en"; globalThis.window = { location: { reload: vi.fn(), }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-async", "baseLocale"], isServer: "false", }); runtime.defineCustomClientStrategy("custom-async", { getLocale: () => customLocale1, setLocale: async () => { throw new Error("fetch error"); }, }); const error = expect(() => runtime.setLocale("de")).rejects; await error.toThrowError(`Custom strategy "custom-async" setLocale failed.`); await error.toMatchObject({ cause: { message: "fetch error" } }); // Verify that reload was never called expect(window.location.reload).toHaveBeenCalledTimes(0); expect(customLocale1).toBe("en"); }); test("custom strategy setLocale works with cookie and localStorage", async () => { let customData = "en"; globalThis.document = { cookie: "" }; globalThis.localStorage = { setItem: vi.fn(), getItem: () => null, }; globalThis.window = { location: { hostname: "example.com", reload: vi.fn(), }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["custom-api", "localStorage", "cookie", "baseLocale"], cookieName: "PARAGLIDE_LOCALE", isServer: "false", }); runtime.defineCustomClientStrategy("custom-api", { getLocale: () => customData, setLocale: (locale) => { customData = locale; }, }); runtime.setLocale("fr"); expect(customData).toBe("fr"); expect(globalThis.localStorage.setItem).toHaveBeenCalledWith("PARAGLIDE_LOCALE", "fr"); expect(globalThis.document.cookie).toBe("PARAGLIDE_LOCALE=fr; path=/; max-age=34560000"); }); test("custom strategy setLocale integrates with URL strategy", async () => { let customStoredLocale = "en"; globalThis.window = { location: { hostname: "example.com", href: "https://example.com/en/page", reload: vi.fn(), }, }; const runtime = await createParaglide({ blob: await newProject({ settings: { baseLocale: "en", locales: ["en", "fr", "de"], }, }), strategy: ["url", "custom-urlIntegration", "baseLocale"], urlPatterns: [ { pattern: "https://example.com/:locale/:path*", localized: [ ["en", "https://example.com/en/:path*"], ["fr", "https://example.com/fr/:path*"], ["de", "https://example.com/de/:path*"], ], }, ], isServer: "false", }); runtime.defineCustomClientStrategy("custom-urlIntegration", { getLocale: () => customStoredLocale, setLocale: (locale) => { customStoredLocale = locale; }, }); runtime.setLocale("de"); expect(globalThis.window.location.href).toBe("https://example.com/de/page"); expect(customStoredLocale).toBe("de"); }); //# sourceMappingURL=set-locale.test.js.map