| 1 | import { defaultLocale, locales } from "./config"; |
| 2 | import { hasComputerUseTranslation } from "./dictionaries"; |
| 3 | |
| 4 | /** |
| 5 | * Routes whose page-body translation coverage differs from English/Chinese. |
| 6 | * |
| 7 | * `/docs/guide` is not listed: its French/German/Catalan/Hindi/Turkish/ |
| 8 | * Italian/Polish/Arabic dictionaries translate only the overview and headings, |
| 9 | * while the getting-started steps that make up the body ship in English and |
| 10 | * Chinese, so those variants canonicalize to English like any other partial |
| 11 | * page. |
| 12 | */ |
| 13 | const ROUTE_CONTENT_LOCALES: Readonly<Record<string, readonly string[]>> = { |
| 14 | "/": locales, |
| 15 | "/install": ["en"], |
| 16 | "/computer-use": locales.filter(hasComputerUseTranslation), |
| 17 | }; |
| 18 | |
| 19 | /** Most first-party page bodies currently ship in English and Chinese. */ |
| 20 | const DEFAULT_CONTENT_LOCALES = ["en", "zh"] as const; |
| 21 | |
| 22 | function normalizedPath(path: string): string { |
| 23 | if (path === "" || path === "/") return "/"; |
| 24 | return `/${path.replace(/^\/+|\/+$/g, "")}`; |
| 25 | } |
| 26 | |
| 27 | /** Locales with a genuine page-body translation for an indexable route. */ |
| 28 | export function contentLocalesForPath(path: string): readonly string[] { |
| 29 | return ROUTE_CONTENT_LOCALES[normalizedPath(path)] ?? DEFAULT_CONTENT_LOCALES; |
| 30 | } |
| 31 | |
| 32 | /** |
| 33 | * Canonical locale for a rendered route. |
| 34 | * |
| 35 | * Partial locale routes stay accessible in the product, but an English-body |
| 36 | * fallback points crawlers at the English source instead of presenting a |
| 37 | * duplicate as a translated page. |
| 38 | */ |
| 39 | export function canonicalLocaleForPath(path: string, locale: string): string { |
| 40 | return contentLocalesForPath(path).includes(locale) ? locale : defaultLocale; |
| 41 | } |
| 42 |