diff --git a/packages/web/package.json b/packages/web/package.json index 280a52e6..f47fec44 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -9,7 +9,8 @@ "start": "astro dev", "build": "astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "test": "bun test" }, "dependencies": { "@astrojs/cloudflare": "12.6.3", @@ -41,4 +42,4 @@ "@astrojs/check": "0.9.6", "typescript": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/web/src/i18n/locales.ts b/packages/web/src/i18n/locales.ts index d1b3e74d..eb957cee 100644 --- a/packages/web/src/i18n/locales.ts +++ b/packages/web/src/i18n/locales.ts @@ -99,19 +99,20 @@ export function matchLocale(input: string) { const value = parse(input) if (!value) return null - if (value.startsWith("zh")) { - if (value.includes("hant") || value.includes("-tw") || value.includes("-hk") || value.includes("-mo")) { - return "zh-tw" - } - return "zh-cn" - } + let match: Locale | null = starts.find((item) => value.startsWith(item[0]))?.[1] ?? null - if (value in localeAlias) { - return localeAlias[value as keyof typeof localeAlias] + if (value.startsWith("zh")) { + match = + value.includes("hant") || value.includes("-tw") || value.includes("-hk") || value.includes("-mo") + ? "zh-tw" + : "zh-cn" + } else if (value in localeAlias) { + match = localeAlias[value as keyof typeof localeAlias] + } else if (value.startsWith("pt")) { + match = "pt-br" + } else if (value.startsWith("no") || value.startsWith("nb") || value.startsWith("nn")) { + match = "nb" } - if (value.startsWith("pt")) return "pt-br" - if (value.startsWith("no") || value.startsWith("nb") || value.startsWith("nn")) return "nb" - - return starts.find((item) => value.startsWith(item[0]))?.[1] ?? null + return match } diff --git a/packages/web/test/locales.test.ts b/packages/web/test/locales.test.ts new file mode 100644 index 00000000..6e5f8508 --- /dev/null +++ b/packages/web/test/locales.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from "bun:test" +import { matchLocale } from "../src/i18n/locales" + +describe("matchLocale", () => { + test("matches exact and prefixed locales", () => { + expect(matchLocale("de")).toBe("de") + expect(matchLocale("fr-CA")).toBe("fr") + expect(matchLocale("pt-PT")).toBe("pt-br") + expect(matchLocale("nn-NO")).toBe("nb") + }) + + test("matches Chinese locale variants", () => { + expect(matchLocale("zh-Hant")).toBe("zh-tw") + expect(matchLocale("zh-TW")).toBe("zh-tw") + expect(matchLocale("zh-CN")).toBe("zh-cn") + }) + + test("returns null for invalid or unsupported locales", () => { + expect(matchLocale("")).toBeNull() + expect(matchLocale("%")).toBeNull() + expect(matchLocale("unsupported")).toBeNull() + }) +}) \ No newline at end of file