2026-06-01 15:09:58 +08:00
|
|
|
import type { Lang } from "./i18n";
|
|
|
|
|
|
|
|
|
|
export const localizedHomeRoutes: ReadonlyArray<{ lang: Lang; path: string }> =
|
|
|
|
|
[
|
|
|
|
|
{ lang: "zh-CN", path: "/chinese" },
|
|
|
|
|
{ lang: "ja", path: "/japanese" },
|
|
|
|
|
{ lang: "ko", path: "/korean" },
|
|
|
|
|
{ lang: "vi", path: "/vietnamese" },
|
|
|
|
|
{ lang: "id", path: "/indonesian" },
|
|
|
|
|
{ lang: "ms", path: "/malay" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
function normalizePathname(pathname: string): string {
|
|
|
|
|
const normalized = pathname.replace(/\/+$/, "");
|
|
|
|
|
return normalized || "/";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function languageForHomePathname(pathname: string): Lang | null {
|
|
|
|
|
const normalized = normalizePathname(pathname);
|
|
|
|
|
return (
|
|
|
|
|
localizedHomeRoutes.find((route) => route.path === normalized)?.lang ?? null
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isHomePathname(pathname: string): boolean {
|
|
|
|
|
return (
|
|
|
|
|
normalizePathname(pathname) === "/" ||
|
|
|
|
|
languageForHomePathname(pathname) !== null
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function homePathForLang(lang: Lang): string {
|
|
|
|
|
if (lang === "en") return "/";
|
|
|
|
|
return localizedHomeRoutes.find((route) => route.lang === lang)?.path ?? "/";
|
|
|
|
|
}
|
2026-06-01 16:35:40 +08:00
|
|
|
|
|
|
|
|
/** Returns the URL prefix for a language (e.g. "/malay"), or "" for English. */
|
|
|
|
|
export function langPathPrefix(lang: Lang): string {
|
|
|
|
|
if (lang === "en") return "";
|
|
|
|
|
return localizedHomeRoutes.find((route) => route.lang === lang)?.path ?? "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Detects which language a URL belongs to by inspecting the path prefix. */
|
|
|
|
|
export function languageFromPathname(pathname: string): Lang {
|
|
|
|
|
const normalized = normalizePathname(pathname);
|
|
|
|
|
for (const route of localizedHomeRoutes) {
|
|
|
|
|
if (normalized === route.path || normalized.startsWith(route.path + "/")) {
|
|
|
|
|
return route.lang;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "en";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepends a language prefix to a path. Path may include `?query` or `#hash`;
|
|
|
|
|
* the prefix is inserted before the pathname only.
|
|
|
|
|
*
|
|
|
|
|
* localizePath("/browse", "ms") -> "/malay/browse"
|
|
|
|
|
* localizePath("/", "ms") -> "/malay"
|
|
|
|
|
* localizePath("/browse", "en") -> "/browse"
|
|
|
|
|
*/
|
|
|
|
|
export function localizePath(path: string, lang: Lang): string {
|
|
|
|
|
const prefix = langPathPrefix(lang);
|
|
|
|
|
if (!prefix) return path;
|
|
|
|
|
if (!path.startsWith("/")) path = "/" + path;
|
|
|
|
|
if (path === "/") return prefix;
|
|
|
|
|
return prefix + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes any known language prefix from a pathname. Useful when comparing
|
|
|
|
|
* the current route against canonical (unprefixed) paths.
|
|
|
|
|
*
|
|
|
|
|
* stripLangPrefix("/malay/browse") -> "/browse"
|
|
|
|
|
* stripLangPrefix("/malay") -> "/"
|
|
|
|
|
* stripLangPrefix("/browse") -> "/browse"
|
|
|
|
|
*/
|
|
|
|
|
export function stripLangPrefix(pathname: string): string {
|
|
|
|
|
const normalized = normalizePathname(pathname);
|
|
|
|
|
for (const route of localizedHomeRoutes) {
|
|
|
|
|
if (normalized === route.path) return "/";
|
|
|
|
|
if (normalized.startsWith(route.path + "/")) {
|
|
|
|
|
return normalized.slice(route.path.length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return normalized;
|
|
|
|
|
}
|