返回 CodeWhale
path.ts
根目录 / web / lib / i18n / path.ts
1 /**
2 * Locale path helpers for the website router.
3 *
4 * Middleware, the locale switcher, and the docs-only theme toggle all have
5 * to agree on what the first path segment means. `pt-BR` is one segment,
6 * not two; a bare `/install` is not yet localized. One implementation keeps
7 * those call sites from drifting into a regex that only matches `[a-z]{2}`.
8 */
9 import { locales } from "./config";
10
11 const ROUTED = locales as readonly string[];
12
13 /**
14 * The routed locale a first path segment names, in canonical casing.
15 *
16 * Matching ignores case so `/pt-br/install` resolves to the same route as
17 * `/pt-BR/install`. Only the regional tag has a case to get wrong, and an
18 * external link that lowercases it used to fall through to the bare-path
19 * branch and land on `/en/pt-br/install` — a 404.
20 */
21 function routedLocale(segment: string | undefined): string | null {
22 if (!segment) return null;
23 const lower = segment.toLowerCase();
24 return ROUTED.find((l) => l.toLowerCase() === lower) ?? null;
25 }
26
27 /** The routed locale already in `pathname`, or null if the path is bare. */
28 export function pathLocale(pathname: string): string | null {
29 return routedLocale(pathname.split("/")[1]);
30 }
31
32 /**
33 * Swap or insert the locale prefix. Used by the switcher so a click on
34 * `/pt-BR/docs/guide` lands on `/ja/docs/guide` rather than a nested
35 * `/ja/pt-BR/docs/guide` that the compact nav then treats as a miss, and by
36 * the middleware to fold a miscased prefix onto its canonical spelling.
37 */
38 export function replacePathLocale(pathname: string, locale: string): string {
39 const segments = pathname.split("/");
40 if (routedLocale(segments[1])) {
41 segments[1] = locale;
42 return segments.join("/");
43 }
44 // `"/"` splits to `["", ""]`, so splicing would join to `/<locale>/` — a
45 // URL Next.js only serves after a trailing-slash redirect. Every other
46 // path keeps whatever trailing slash it arrived with.
47 if (pathname === "" || pathname === "/") return `/${locale}`;
48 segments.splice(1, 0, locale);
49 return segments.join("/");
50 }
51
52 /** True when the path is a docs route, with or without a locale prefix. */
53 export function isDocsPath(pathname: string): boolean {
54 const segs = pathname.split("/").filter(Boolean);
55 if (routedLocale(segs[0])) {
56 return segs[1] === "docs";
57 }
58 return segs[0] === "docs";
59 }
60
60 lines TYPESCRIPT