From 79971ecf9673d536ce59a6163bde22d3edd5cbe9 Mon Sep 17 00:00:00 2001 From: Adrien Lacroix Date: Tue, 22 Oct 2024 10:54:35 +0200 Subject: [PATCH 1/3] feat: support localeDetection = false --- packages/open-next/src/core/routing/i18n/index.ts | 4 ++++ packages/open-next/src/types/next-types.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/packages/open-next/src/core/routing/i18n/index.ts b/packages/open-next/src/core/routing/i18n/index.ts index bbb07aeed..aff4cbed6 100644 --- a/packages/open-next/src/core/routing/i18n/index.ts +++ b/packages/open-next/src/core/routing/i18n/index.ts @@ -21,6 +21,10 @@ function getLocaleFromCookie(cookies: Record) { } function detectLocale(internalEvent: InternalEvent, i18n: i18nConfig): string { + if (i18n.localeDetection === false) { + return i18n.defaultLocale; + } + const cookiesLocale = getLocaleFromCookie(internalEvent.cookies); const preferredLocale = acceptLanguage( internalEvent.headers["accept-language"], diff --git a/packages/open-next/src/types/next-types.ts b/packages/open-next/src/types/next-types.ts index b9640528d..fd81f8f7d 100644 --- a/packages/open-next/src/types/next-types.ts +++ b/packages/open-next/src/types/next-types.ts @@ -64,6 +64,7 @@ export type Header = { export interface i18nConfig { locales: string[]; defaultLocale: string; + localeDetection?: false; } export interface NextConfig { basePath?: string; From ce24972fab9d7963a1d3bd6c5f711904ad7a2495 Mon Sep 17 00:00:00 2001 From: Adrien Lacroix Date: Fri, 25 Oct 2024 10:16:57 +0200 Subject: [PATCH 2/3] test: add unit tests for localizePath --- .../tests/core/routing/i18n.test.ts | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 packages/tests-unit/tests/core/routing/i18n.test.ts diff --git a/packages/tests-unit/tests/core/routing/i18n.test.ts b/packages/tests-unit/tests/core/routing/i18n.test.ts new file mode 100644 index 000000000..65292f040 --- /dev/null +++ b/packages/tests-unit/tests/core/routing/i18n.test.ts @@ -0,0 +1,144 @@ +import { NextConfig } from "@opennextjs/aws/adapters/config/index.js"; +import { localizePath } from "@opennextjs/aws/core/routing/i18n/index.js"; +import { convertFromQueryString } from "@opennextjs/aws/core/routing/util.js"; +import type { InternalEvent } from "@opennextjs/aws/types/open-next.js"; +import { vi } from "vitest"; + +vi.mock("@opennextjs/aws/adapters/config/index.js", () => { + return { + NextConfig: { + i18n: { + defaultLocale: "en", + locales: ["en", "fr"], + }, + }, + }; +}); + +vi.mock("@opennextjs/aws/core/routing/i18n/accept-header.js", () => ({ + acceptLanguage: (header: string, _?: string[]) => (header ? "fr" : undefined), +})); + +type PartialEvent = Partial< + Omit +> & { body?: string }; + +function createEvent(event: PartialEvent): InternalEvent { + const [rawPath, qs] = (event.url ?? "/").split("?", 2); + return { + type: "core", + method: event.method ?? "GET", + rawPath, + url: event.url ?? "/", + body: Buffer.from(event.body ?? ""), + headers: event.headers ?? {}, + query: convertFromQueryString(qs ?? ""), + cookies: event.cookies ?? {}, + remoteAddress: event.remoteAddress ?? "::1", + }; +} + +beforeEach(() => { + vi.resetAllMocks(); +}); + +describe("localizePath", () => { + it("should return raw path if no i18n config is set", () => { + const i18nSpy = vi + .spyOn(NextConfig, "i18n", "get") + .mockReturnValue(undefined); + + const event = createEvent({ + url: "/foo", + }); + + const result = localizePath(event); + + expect(result).toEqual("/foo"); + + i18nSpy.mockRestore(); + }); + + it("should return default locale localized if localeDetection is set to false", () => { + const i18nSpy = vi.spyOn(NextConfig, "i18n", "get").mockReturnValue({ + defaultLocale: "en", + locales: ["en", "fr"], + localeDetection: false, + }); + + const event = createEvent({ + url: "/foo", + headers: { + "accept-language": "fr", + }, + cookies: { + NEXT_LOCALE: "fr", + }, + }); + + const result = localizePath(event); + + expect(result).toEqual("/en/foo"); + + i18nSpy.mockRestore(); + }); + + it("should return the same path if the path is already localized", () => { + const event = createEvent({ + url: "/fr/foo", + }); + + const result = localizePath(event); + + expect(result).toEqual("/fr/foo"); + }); + + it("should get locale from cookies if NEXT_LOCALE cookie is set to a valid locale", () => { + const event = createEvent({ + url: "/foo", + cookies: { + NEXT_LOCALE: "fr", + }, + }); + + const result = localizePath(event); + + expect(result).toEqual("/fr/foo"); + }); + + it("should fallback on default locale if NEXT_LOCALE cookie is set to an invalid locale", () => { + const event = createEvent({ + url: "/foo", + cookies: { + NEXT_LOCALE: "pt", + }, + }); + + const result = localizePath(event); + + expect(result).toEqual("/en/foo"); + }); + + it("should use accept-language header if no cookie are present", () => { + const event = createEvent({ + url: "/foo", + headers: { + "accept-language": "fr", + }, + }); + + const result = localizePath(event); + + expect(result).toEqual("/fr/foo"); + }); + + it("should fallback to default locale if no cookie or header are set", () => { + const event = createEvent({ + url: "/foo", + }); + + const result = localizePath(event); + + expect(result).toEqual("/en/foo"); + }); +}); From 92ec92b5f892a4e5e5fe8221d74b01eb8f17eebf Mon Sep 17 00:00:00 2001 From: conico974 Date: Fri, 25 Oct 2024 11:37:55 +0200 Subject: [PATCH 3/3] Create giant-horses-sin.md --- .changeset/giant-horses-sin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/giant-horses-sin.md diff --git a/.changeset/giant-horses-sin.md b/.changeset/giant-horses-sin.md new file mode 100644 index 000000000..ab7fed6da --- /dev/null +++ b/.changeset/giant-horses-sin.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +Support i18n localeDetection with value false