Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-pots-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@opennextjs/aws": patch
---

Fix path localization for the middleware when using both `localeDetection:false` and domains
31 changes: 24 additions & 7 deletions packages/open-next/src/core/routing/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ function getLocaleFromCookie(cookies: Record<string, string>) {
}

// Inspired by https://github.com/vercel/next.js/blob/6d93d652e0e7ba72d9a3b66e78746dce2069db03/packages/next/src/shared/lib/i18n/detect-domain-locale.ts#L3-L25
/**
* @param arg an object containing the hostname and detectedLocale
* @returns The `DomainLocale` object if a domain is detected, `undefined` otherwise
*/
export function detectDomainLocale({
hostname,
detectedLocale,
Expand All @@ -31,11 +35,12 @@ export function detectDomainLocale({
detectedLocale?: string;
}): DomainLocale | undefined {
const i18n = NextConfig.i18n;
if (!i18n || i18n.localeDetection === false || !i18n.domains) {
const domains = i18n?.domains;
if (!domains) {
return;
}
const lowercasedLocale = detectedLocale?.toLowerCase();
for (const domain of i18n.domains) {
for (const domain of domains) {
// We remove the port if present
const domainHostname = domain.domain.split(":", 1)[0].toLowerCase();
if (
Expand All @@ -50,12 +55,21 @@ export function detectDomainLocale({
}
}

/**
*
* @param internalEvent
* @param i18n
* @returns The detected locale, if `localeDetection` is set to `false` it will return the default locale **or** the domain default locale if a domain is detected.
*/
export function detectLocale(
internalEvent: InternalEvent,
i18n: i18nConfig,
): string {
const domainLocale = detectDomainLocale({
hostname: internalEvent.headers.host,
});
if (i18n.localeDetection === false) {
return i18n.defaultLocale;
return domainLocale?.defaultLocale ?? i18n.defaultLocale;
}

const cookiesLocale = getLocaleFromCookie(internalEvent.cookies);
Expand All @@ -67,10 +81,7 @@ export function detectLocale(
cookiesLocale,
preferredLocale,
defaultLocale: i18n.defaultLocale,
});

const domainLocale = detectDomainLocale({
hostname: internalEvent.headers.host,
domainLocale,
});

return (
Expand All @@ -81,11 +92,17 @@ export function detectLocale(
);
}

/**
* This function is used for OpenNext internal routing to localize the path for next config rewrite/redirects/headers and the middleware
* @param internalEvent
* @returns The localized path
*/
export function localizePath(internalEvent: InternalEvent): string {
const i18n = NextConfig.i18n;
if (!i18n) {
return internalEvent.rawPath;
}
// When the path is already localized we don't need to do anything
if (isLocalizedPath(internalEvent.rawPath)) {
return internalEvent.rawPath;
}
Expand Down
49 changes: 49 additions & 0 deletions packages/tests-unit/tests/core/routing/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,55 @@ describe("localizePath", () => {

expect(result).toEqual("/en/foo");
});

it("should use default locale 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: "http://localhost/foo",
});

const result = localizePath(event);

expect(result).toEqual("/en/foo");

i18nSpy.mockRestore();
});

it("should use domain default locale if localeDetection is set to false but with a domain", () => {
const i18nSpy = vi.spyOn(NextConfig, "i18n", "get").mockReturnValue({
defaultLocale: "en",
locales: ["en", "fr"],
domains: [
{
domain: "mydomain.com",
defaultLocale: "en",
},
{
domain: "mydomain.fr",
defaultLocale: "fr",
},
],
localeDetection: false,
});

const event = createEvent({
url: "http://mydomain.fr/foo",
headers: {
host: "mydomain.fr",
},
});

const result = localizePath(event);

expect(result).toEqual("/fr/foo");

i18nSpy.mockRestore();
});
});

describe("handleLocaleRedirect", () => {
Expand Down
Loading