diff --git a/press.config.tsx b/press.config.tsx index 2c0e47da..85628b3d 100644 --- a/press.config.tsx +++ b/press.config.tsx @@ -181,6 +181,7 @@ export default defineConfig({ href="/favicon-16x16.png" /> + + + +
+

Choose your language:

+ +
+ + diff --git a/public/language-redirect.js b/public/language-redirect.js new file mode 100644 index 00000000..cf6fb32c --- /dev/null +++ b/public/language-redirect.js @@ -0,0 +1,65 @@ +(() => { + const supportedLanguages = new Set(["en", "zh", "de", "fr", "ja"]); + const storageKey = "rustfs-docs-language"; + const getPathLanguage = () => + window.location.pathname.match(/^\/(en|zh|de|fr|ja)(?:\/|$)/)?.[1]; + const savePathLanguage = () => { + const language = getPathLanguage(); + if (!language) return; + + try { + window.localStorage.setItem(storageKey, language); + } catch { + // Language detection still works when storage is unavailable. + } + }; + + if (getPathLanguage()) { + savePathLanguage(); + + if (window.history) { + const pushState = window.history.pushState; + window.history.pushState = function (...args) { + const result = pushState.apply(this, args); + window.queueMicrotask(savePathLanguage); + return result; + }; + + const replaceState = window.history.replaceState; + window.history.replaceState = function (...args) { + const result = replaceState.apply(this, args); + window.queueMicrotask(savePathLanguage); + return result; + }; + window.addEventListener("popstate", savePathLanguage); + } + + return; + } + + if (window.location.pathname !== "/" && window.location.pathname !== "/index.html") { + return; + } + + let savedLanguage; + try { + savedLanguage = window.localStorage.getItem(storageKey); + } catch { + // Fall back to the browser language when storage is unavailable. + } + + const browserLanguages = navigator.languages?.length + ? navigator.languages + : [navigator.language]; + const detectedLanguage = browserLanguages + .map((language) => language?.toLowerCase().split("-")[0]) + .find((language) => language && supportedLanguages.has(language)); + const language = + savedLanguage && supportedLanguages.has(savedLanguage) + ? savedLanguage + : (detectedLanguage ?? "en"); + + window.location.replace( + `/${language}${window.location.search}${window.location.hash}`, + ); +})(); diff --git a/scripts/add-language-redirects.mjs b/scripts/add-language-redirects.mjs index ec459221..3144f166 100644 --- a/scripts/add-language-redirects.mjs +++ b/scripts/add-language-redirects.mjs @@ -6,9 +6,12 @@ import { fileURLToPath } from 'node:url'; import { collectLanguageRedirects } from './language-redirects.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const SOURCE_INDEX = path.join(ROOT, 'public', 'index.html'); +const OUTPUT_INDEX = path.join(ROOT, 'dist', 'public', 'index.html'); const OUTPUT_REDIRECTS = path.join(ROOT, 'dist', 'public', '_redirects'); const rules = collectLanguageRedirects(); const output = [...rules].map(([source, target]) => `${source} ${target}`).join('\n'); +fs.copyFileSync(SOURCE_INDEX, OUTPUT_INDEX); fs.writeFileSync(OUTPUT_REDIRECTS, `${output}\n`); -console.log(`language redirects: wrote ${rules.size} Cloudflare rules`); +console.log(`language redirects: wrote the language entry page and ${rules.size} Cloudflare rules`); diff --git a/scripts/language-redirects.mjs b/scripts/language-redirects.mjs index 00ca6841..8c47090f 100644 --- a/scripts/language-redirects.mjs +++ b/scripts/language-redirects.mjs @@ -16,7 +16,6 @@ function prefixEnglishTarget(target) { export function collectLanguageRedirects() { /** @type {Map} */ const rules = new Map(); - rules.set('/', '/en 302'); const existingRules = fs.readFileSync(SOURCE_REDIRECTS, 'utf8').split('\n'); for (const line of existingRules) {