11---
2- import context from ' virtual:starlight/project-context' ;
32import config from ' virtual:starlight/user-config' ;
43import Select from ' @astrojs/starlight/components/Select.astro' ;
54import { DOCS_LOCALE_SELECTOR_OPTIONS } from ' ../i18n/generated/docs-locale-resources.mjs' ;
5+ import { buildDocsRoutePath , stripDocsLocalePrefix , type DocsLocale } from ' @/lib/i18n' ;
66
7- function stripTrailingSlash(path : string ): string {
8- if (path === ' /' ) {
9- return ' ' ;
10- }
11-
12- return path .endsWith (' /' ) && path !== ' /' ? path .slice (0 , - 1 ) : path ;
13- }
14-
15- function localizedPathname(locale : string | undefined ): string {
16- const url = new URL (Astro .url );
17-
18- if (! config .locales ) {
19- return url .pathname ;
20- }
21-
22- const nextLocale = locale === ' root' ? ' ' : locale ;
23- const base = stripTrailingSlash (import .meta .env .BASE_URL );
24- const hasBase = url .pathname .startsWith (base );
25-
26- if (hasBase ) {
27- url .pathname = url .pathname .replace (base , ' ' );
28- }
29-
30- const [_leadingSlash, baseSegment] = url .pathname .split (' /' );
31- const htmlExt = ' .html' ;
32- const isRootHtml = baseSegment ?.endsWith (htmlExt );
33- const baseSlug = isRootHtml ? baseSegment ?.slice (0 , - 1 * htmlExt .length ) : baseSegment ;
34-
35- if (baseSlug && baseSlug in config .locales ) {
36- if (nextLocale ) {
37- url .pathname = url .pathname .replace (baseSlug , nextLocale );
38- } else if (isRootHtml ) {
39- url .pathname = ' /index.html' ;
40- } else {
41- url .pathname = url .pathname .replace (' /' + baseSlug , ' ' );
42- }
43- } else if (nextLocale ) {
44- if (baseSegment === ' index.html' ) {
45- url .pathname = ' /' + nextLocale + ' .html' ;
46- } else {
47- url .pathname = ' /' + nextLocale + url .pathname ;
48- }
49- }
50-
51- if (hasBase ) {
52- url .pathname = base + url .pathname ;
53- }
54-
55- if (context .trailingSlash === ' never' ) {
56- url .pathname = stripTrailingSlash (url .pathname );
57- }
58-
59- return url .pathname ;
7+ function buildLanguageSelectValue(locale : DocsLocale ): string {
8+ return JSON .stringify ({
9+ path: buildDocsRoutePath (locale , stripDocsLocalePrefix (Astro .url .pathname )),
10+ locale ,
11+ });
6012}
6113
6214const localeOptions = DOCS_LOCALE_SELECTOR_OPTIONS .filter (({ code }) => {
@@ -75,7 +27,7 @@ const localeOptions = DOCS_LOCALE_SELECTOR_OPTIONS.filter(({ code }) => {
7527 icon = " translate"
7628 label = { Astro .locals .t (' languageSelect.accessibleLabel' )}
7729 options = { localeOptions .map ((locale ) => ({
78- value: localizedPathname (locale .code ),
30+ value: buildLanguageSelectValue (locale .code ),
7931 selected: locale .code === Astro .locals .starlightRoute .locale ,
8032 label: locale .label ,
8133 }))}
@@ -88,23 +40,21 @@ const localeOptions = DOCS_LOCALE_SELECTOR_OPTIONS.filter(({ code }) => {
8840<script >
8941 const DOCS_LANGUAGE_STORAGE_KEY = 'starlight-route';
9042
91- function isEnglishDocsPath(pathname) {
92- return pathname === '/en' || pathname === '/en/' || pathname.startsWith('/en/');
93- }
43+ function parseSelectedLocaleTarget(value) {
44+ try {
45+ const parsed = JSON.parse(value);
46+ if (!parsed || typeof parsed !== 'object') {
47+ return null;
48+ }
9449
95- function detectDocsLocaleFromPath(pathname) {
96- const segments = pathname.split('/').filter(Boolean);
97- const firstSegment = segments[0];
98- if (firstSegment === 'en') {
99- return 'en';
100- }
50+ if (typeof parsed.path !== 'string' || typeof parsed.locale !== 'string') {
51+ return null;
52+ }
10153
102- const blogRouteLocales = ['zh-Hant', 'ja-JP', 'ko-KR', 'de-DE', 'fr-FR', 'es-ES', 'pt-BR', 'ru-RU'] ;
103- if (blogRouteLocales.includes(firstSegment) ) {
104- return firstSegment ;
54+ return parsed ;
55+ } catch (_error ) {
56+ return null ;
10557 }
106-
107- return isEnglishDocsPath(pathname) ? 'en' : 'root';
10858 }
10959
11060 function serializeStoredDocsLocale(storageValue, locale) {
@@ -122,9 +72,7 @@ const localeOptions = DOCS_LOCALE_SELECTOR_OPTIONS.filter(({ code }) => {
12272 return JSON.stringify(routeObj);
12373 }
12474
125- function persistSelectedDocsLocale(targetPath) {
126- const locale = detectDocsLocaleFromPath(targetPath);
127-
75+ function persistSelectedDocsLocale(locale) {
12876 try {
12977 const previousValue = localStorage.getItem(DOCS_LANGUAGE_STORAGE_KEY);
13078 localStorage.setItem(
@@ -143,8 +91,13 @@ const localeOptions = DOCS_LOCALE_SELECTOR_OPTIONS.filter(({ code }) => {
14391 if (select) {
14492 select.addEventListener('change', (e) => {
14593 if (e.currentTarget instanceof HTMLSelectElement) {
146- persistSelectedDocsLocale(e.currentTarget.value);
147- window.location.pathname = e.currentTarget.value;
94+ const target = parseSelectedLocaleTarget(e.currentTarget.value);
95+ if (!target) {
96+ return;
97+ }
98+
99+ persistSelectedDocsLocale(target.locale);
100+ window.location.pathname = target.path;
148101 }
149102 });
150103 window.addEventListener('pageshow', (event) => {
0 commit comments