From 732ce397790191f46fe4ccfb449e01e30fdfe92a Mon Sep 17 00:00:00 2001 From: Yaros Date: Fri, 18 Sep 2026 23:03:05 +0200 Subject: [PATCH 1/6] feat: multi-language site --- site/astro.config.mjs | 37 +++- site/pnpm-lock.yaml | 50 +++--- site/src/components/BaseHead.astro | 21 ++- site/src/components/CameraMatrix.astro | 57 ++++--- site/src/components/HeaderLink.astro | 7 +- site/src/components/LanguageSelector.svelte | 84 +++++++++ site/src/components/Navbar.astro | 20 ++- site/src/components/docs/Admonition.astro | 19 ++- site/src/components/docs/LedStatus.astro | 45 ++--- site/src/components/home/Compatibility.astro | 8 +- site/src/components/home/Gallery.astro | 31 ++-- site/src/components/home/Hero.astro | 26 +-- site/src/components/home/Requirements.astro | 13 +- site/src/consts.ts | 118 +++---------- .../content/docs/{ => en}/compatibility.mdx | 6 +- site/src/content/docs/{ => en}/flashing.mdx | 2 +- site/src/content/docs/{ => en}/hardware.mdx | 2 +- site/src/content/docs/{ => en}/overview.mdx | 2 +- site/src/content/docs/{ => en}/setup.mdx | 2 +- site/src/content/docs/{ => en}/status-led.mdx | 2 +- .../content/docs/{ => en}/troubleshooting.mdx | 4 +- site/src/content/docs/{ => en}/web-ui.mdx | 4 +- site/src/content/docs/{ => en}/wiring.mdx | 2 +- site/src/content/docs/es/compatibility.mdx | 46 +++++ site/src/content/docs/es/flashing.mdx | 32 ++++ site/src/content/docs/es/hardware.mdx | 23 +++ site/src/content/docs/es/overview.mdx | 41 +++++ site/src/content/docs/es/setup.mdx | 95 +++++++++++ site/src/content/docs/es/status-led.mdx | 15 ++ site/src/content/docs/es/troubleshooting.mdx | 98 +++++++++++ site/src/content/docs/es/web-ui.mdx | 159 ++++++++++++++++++ site/src/content/docs/es/wiring.mdx | 53 ++++++ site/src/content/docs/uk/compatibility.mdx | 45 +++++ site/src/content/docs/uk/flashing.mdx | 32 ++++ site/src/content/docs/uk/hardware.mdx | 23 +++ site/src/content/docs/uk/overview.mdx | 40 +++++ site/src/content/docs/uk/setup.mdx | 95 +++++++++++ site/src/content/docs/uk/status-led.mdx | 15 ++ site/src/content/docs/uk/troubleshooting.mdx | 98 +++++++++++ site/src/content/docs/uk/web-ui.mdx | 159 ++++++++++++++++++ site/src/content/docs/uk/wiring.mdx | 53 ++++++ site/src/i18n/getLangPaths.ts | 7 + site/src/i18n/index.ts | 88 ++++++++++ site/src/i18n/locales/en.json | 145 ++++++++++++++++ site/src/i18n/locales/es.json | 145 ++++++++++++++++ site/src/i18n/locales/uk.json | 145 ++++++++++++++++ site/src/layouts/DocsLayout.astro | 23 +-- site/src/layouts/MainLayout.astro | 11 +- site/src/lib/docs.ts | 19 ++- site/src/lib/remark-localize-doc-links.mjs | 20 +++ site/src/middleware.ts | 71 ++++++++ site/src/pages/404.astro | 25 ++- site/src/pages/[...lang]/docs/[...slug].astro | 32 ++++ site/src/pages/[...lang]/docs/index.astro | 31 ++++ site/src/pages/[...lang]/flash.astro | 45 +++++ site/src/pages/[...lang]/index.astro | 22 +++ site/src/pages/docs/[...slug].astro | 24 --- site/src/pages/docs/index.astro | 17 -- site/src/pages/flash.astro | 38 ----- site/src/pages/index.astro | 38 +++-- site/wrangler.jsonc | 2 +- 61 files changed, 2277 insertions(+), 355 deletions(-) create mode 100644 site/src/components/LanguageSelector.svelte rename site/src/content/docs/{ => en}/compatibility.mdx (90%) rename site/src/content/docs/{ => en}/flashing.mdx (93%) rename site/src/content/docs/{ => en}/hardware.mdx (94%) rename site/src/content/docs/{ => en}/overview.mdx (95%) rename site/src/content/docs/{ => en}/setup.mdx (98%) rename site/src/content/docs/{ => en}/status-led.mdx (86%) rename site/src/content/docs/{ => en}/troubleshooting.mdx (97%) rename site/src/content/docs/{ => en}/web-ui.mdx (97%) rename site/src/content/docs/{ => en}/wiring.mdx (95%) create mode 100644 site/src/content/docs/es/compatibility.mdx create mode 100644 site/src/content/docs/es/flashing.mdx create mode 100644 site/src/content/docs/es/hardware.mdx create mode 100644 site/src/content/docs/es/overview.mdx create mode 100644 site/src/content/docs/es/setup.mdx create mode 100644 site/src/content/docs/es/status-led.mdx create mode 100644 site/src/content/docs/es/troubleshooting.mdx create mode 100644 site/src/content/docs/es/web-ui.mdx create mode 100644 site/src/content/docs/es/wiring.mdx create mode 100644 site/src/content/docs/uk/compatibility.mdx create mode 100644 site/src/content/docs/uk/flashing.mdx create mode 100644 site/src/content/docs/uk/hardware.mdx create mode 100644 site/src/content/docs/uk/overview.mdx create mode 100644 site/src/content/docs/uk/setup.mdx create mode 100644 site/src/content/docs/uk/status-led.mdx create mode 100644 site/src/content/docs/uk/troubleshooting.mdx create mode 100644 site/src/content/docs/uk/web-ui.mdx create mode 100644 site/src/content/docs/uk/wiring.mdx create mode 100644 site/src/i18n/getLangPaths.ts create mode 100644 site/src/i18n/index.ts create mode 100644 site/src/i18n/locales/en.json create mode 100644 site/src/i18n/locales/es.json create mode 100644 site/src/i18n/locales/uk.json create mode 100644 site/src/lib/remark-localize-doc-links.mjs create mode 100644 site/src/middleware.ts create mode 100644 site/src/pages/[...lang]/docs/[...slug].astro create mode 100644 site/src/pages/[...lang]/docs/index.astro create mode 100644 site/src/pages/[...lang]/flash.astro create mode 100644 site/src/pages/[...lang]/index.astro delete mode 100644 site/src/pages/docs/[...slug].astro delete mode 100644 site/src/pages/docs/index.astro delete mode 100644 site/src/pages/flash.astro diff --git a/site/astro.config.mjs b/site/astro.config.mjs index 628e3a5..8d25120 100644 --- a/site/astro.config.mjs +++ b/site/astro.config.mjs @@ -7,15 +7,48 @@ import sitemap from '@astrojs/sitemap'; import mdx from '@astrojs/mdx'; import cloudflare from '@astrojs/cloudflare'; +import remarkLocalizeDocLinks from './src/lib/remark-localize-doc-links.mjs'; export default defineConfig({ site: 'https://shutterbridge.yarosfpv.com', compressHTML: true, - integrations: [svelte(), icon(), sitemap(), mdx()], + + markdown: { + remarkPlugins: [remarkLocalizeDocLinks], + }, + integrations: [ + svelte(), + icon(), + sitemap({ + i18n: { + defaultLocale: 'en', + locales: { en: 'en', es: 'es', uk: 'uk' }, + }, + }), + mdx(), + ], + + i18n: { + defaultLocale: 'en', + locales: ['en', 'es', 'uk'], + routing: { + prefixDefaultLocale: true, + }, + }, vite: { plugins: [tailwindcss()], - optimizeDeps: { include: ['esptool-js'] }, + // Pre-bundle the deps that would otherwise be discovered mid-session and + // trigger a full optimizer reload, which the Cloudflare workerd dev runner + // can't survive (crash: ".vite/deps_ssr/handler-*.js does not exist"). + optimizeDeps: { + include: [ + 'esptool-js', + '@astrojs/svelte/server.js', + 'astro-icon/components', + 'astro/logger/console', + ], + }, }, adapter: cloudflare(), diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml index 51acaa2..88c28c1 100644 --- a/site/pnpm-lock.yaml +++ b/site/pnpm-lock.yaml @@ -10,16 +10,16 @@ importers: dependencies: '@astrojs/cloudflare': specifier: ^14.3.0 - version: 14.3.0(@types/node@24.13.3)(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(wrangler@4.129.0) + version: 14.3.0(@types/node@24.13.3)(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(wrangler@4.129.0) '@astrojs/mdx': specifier: ^7.0.5 - version: 7.0.8(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0)) + version: 7.0.8(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0)) '@astrojs/sitemap': specifier: ^3.7.4 version: 3.7.4 '@astrojs/svelte': specifier: ^9.0.1 - version: 9.0.1(@types/node@24.13.3)(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(svelte@5.57.0)(typescript@6.0.3) + version: 9.0.1(@types/node@24.13.3)(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(svelte@5.57.0)(typescript@6.0.3) '@iconify-json/fa6-brands': specifier: ^1.2.6 version: 1.2.6 @@ -34,7 +34,7 @@ importers: version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)) astro: specifier: ^7.3.1 - version: 7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) + version: 7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) astro-icon: specifier: ^1.2.0 version: 1.2.0 @@ -140,8 +140,8 @@ packages: '@astrojs/markdown-remark@7.2.4': resolution: {integrity: sha512-MvspGMynWKAjTe4/lTUdmBPHIFKNVLTCF6UlyWGogTGzNrTvjD+D4n48k7h8swxsEPKHK2TwxkZO7uoaCv1Pow==} - '@astrojs/markdown-satteri@0.4.0': - resolution: {integrity: sha512-wykOOW9KsUVcZweOpY/CeXpdKcCKZy6fQbdcteWFuI75+sQCiqxYM7VKsGa5b+aGl3cYQscFY37rsbbyal5MRw==} + '@astrojs/markdown-satteri@0.4.1': + resolution: {integrity: sha512-EniHbFNa6SQHDih7JnpPos3NWXO6hdt4raBcOosfGmlfc3gP9CI/sESA3VOf1PgJZ7SFfewlZW9Livn0JugEZg==} '@astrojs/mdx@7.0.8': resolution: {integrity: sha512-RNuwq2ccTSi7NX9YqlR0noaWoVdOrZuJvdfWXotAzdhMVB0b0zEMLnNU+xar7le0GwTMlTObD/QAu8jeHA/3nA==} @@ -1349,8 +1349,8 @@ packages: resolution: {integrity: sha512-0848V2WZuTPhqGSqLeZimLJZ5wmamMtWYzvA2kvg8s2DrUPZ3/nrTcHJWN0eJHt62jy7uvNxgTNiUJGIr7JNxg==} engines: {node: '>=22.12.0'} - astro@7.3.1: - resolution: {integrity: sha512-A/bJYHtc6n0UAdROY9W948fW6lX0pnUA+JWKW+IGCXRyDIGN2MsXC0OlS8onZGJjr+sv8htemwOc9W5PBRXCkw==} + astro@7.3.3: + resolution: {integrity: sha512-NF08hk3edFkVmr9avf9HW/rQyf6NrpbVDyYj2cVN3JfijDhfJYh1ivWVTY5PUd5+rRZn/Vtu4iaeyNlP0Iv6mg==} engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true peerDependencies: @@ -1609,8 +1609,8 @@ packages: fflate@0.8.3: resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} - find-proc@0.1.0: - resolution: {integrity: sha512-OaOpEYv2PiQ7SQ5LIrl+deA1XaWcxEjnpM6VuWXTUvn+teIXxeFTLDmu18/zDQpFmHN4o3oDBX+BT0AGwEhemg==} + find-proc@0.2.0: + resolution: {integrity: sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==} engines: {node: ^20.19.0 || >=22.12.0} flattie@1.1.1: @@ -2507,6 +2507,10 @@ packages: uploadthing: optional: true + verkit@0.4.0: + resolution: {integrity: sha512-sXMwN6DMHeouPfCxkxWkKAmxphWKEenHYY5H1nIBzU3PmDsmJp6kBXJdshjVdpMZuWCmL9SH7KFRx29AylpP6g==} + engines: {node: '>=18.12.0'} + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -2630,12 +2634,12 @@ snapshots: package-manager-detector: 1.8.0 tinyexec: 1.3.1 - '@astrojs/cloudflare@14.3.0(@types/node@24.13.3)(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(wrangler@4.129.0)': + '@astrojs/cloudflare@14.3.0(@types/node@24.13.3)(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(wrangler@4.129.0)': dependencies: '@astrojs/internal-helpers': 0.11.0 '@astrojs/underscore-redirects': 1.0.4 '@cloudflare/vite-plugin': 1.54.4(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0))(wrangler@4.129.0) - astro: 7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) + astro: 7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) piccolore: 0.1.3 vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0) wrangler: 4.129.0 @@ -2753,20 +2757,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/markdown-satteri@0.4.0': + '@astrojs/markdown-satteri@0.4.1': dependencies: '@astrojs/internal-helpers': 0.11.0 '@astrojs/prism': 4.0.2 github-slugger: 2.0.0 satteri: 0.10.5 - '@astrojs/mdx@7.0.8(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))': + '@astrojs/mdx@7.0.8(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))': dependencies: '@astrojs/internal-helpers': 0.10.4 '@astrojs/markdown-remark': 7.2.4 '@mdx-js/mdx': 3.1.1 acorn: 8.18.0 - astro: 7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) + astro: 7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) es-module-lexer: 2.3.2 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -2789,10 +2793,10 @@ snapshots: sitemap: 9.0.1 zod: 4.5.4 - '@astrojs/svelte@9.0.1(@types/node@24.13.3)(astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(svelte@5.57.0)(typescript@6.0.3)': + '@astrojs/svelte@9.0.1(@types/node@24.13.3)(astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0))(esbuild@0.28.2)(jiti@2.7.0)(svelte@5.57.0)(typescript@6.0.3)': dependencies: '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.57.0)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)) - astro: 7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) + astro: 7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0) svelte: 5.57.0 svelte2tsx: 0.7.61(svelte@5.57.0)(typescript@6.0.3) typescript: 6.0.3 @@ -3678,11 +3682,11 @@ snapshots: '@iconify/types': 2.0.0 '@iconify/utils': 3.1.5 - astro@7.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0): + astro@7.3.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0): dependencies: '@astrojs/compiler-rs': 0.4.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3) '@astrojs/internal-helpers': 0.11.0 - '@astrojs/markdown-satteri': 0.4.0 + '@astrojs/markdown-satteri': 0.4.1 '@astrojs/telemetry': 3.3.3 '@capsizecss/unpack': 4.0.1 '@clack/prompts': 1.7.0 @@ -3699,7 +3703,7 @@ snapshots: dset: 3.1.4 es-module-lexer: 2.3.2 esbuild: 0.28.2 - find-proc: 0.1.0 + find-proc: 0.2.0 flattie: 1.1.1 fontace: 0.4.1 get-tsconfig: 5.0.0-beta.4 @@ -3718,7 +3722,6 @@ snapshots: package-manager-detector: 1.8.0 piccolore: 0.1.3 picomatch: 4.0.7 - semver: 7.8.5 shiki: 4.4.3 smol-toml: 1.8.0 svgo: 4.1.0 @@ -3728,6 +3731,7 @@ snapshots: ultrahtml: 1.7.0 unifont: 0.7.5 unstorage: 1.17.5 + verkit: 0.4.0 vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0) vitefu: 1.1.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)) xxhash-wasm: 1.1.0 @@ -4039,7 +4043,7 @@ snapshots: fflate@0.8.3: {} - find-proc@0.1.0: {} + find-proc@0.2.0: {} flattie@1.1.1: {} @@ -5358,6 +5362,8 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.4 + verkit@0.4.0: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 diff --git a/site/src/components/BaseHead.astro b/site/src/components/BaseHead.astro index 447bb86..604d5b3 100644 --- a/site/src/components/BaseHead.astro +++ b/site/src/components/BaseHead.astro @@ -11,10 +11,17 @@ interface Props { title: string; description: string; image?: string; + lang?: string; } const canonicalURL = new URL(Astro.url.pathname, Astro.site); -const { title, description, image = "/og.webp" } = Astro.props; +const { title, description, image = "/og.webp", lang = "en" } = Astro.props; + +const normalizedPath = Astro.url.pathname.replace(/^\/(en|es|uk)(?=\/|$)/, ""); +const locales = ["en", "es", "uk"]; +const altHref = (code: string) => + new URL(`/${code}${normalizedPath === "" ? "/" : normalizedPath}`, Astro.site) + .href; const siteURL = new URL("/", Astro.site).href; const publisher = { @@ -106,6 +113,13 @@ const jsonLd = { +{ + locales.map((code) => ( + + )) +} + + {title} @@ -116,7 +130,10 @@ const jsonLd = { - + diff --git a/site/src/components/CameraMatrix.astro b/site/src/components/CameraMatrix.astro index 4c3a3eb..d71f0a3 100644 --- a/site/src/components/CameraMatrix.astro +++ b/site/src/components/CameraMatrix.astro @@ -1,6 +1,20 @@ --- import { Icon } from "astro-icon/components"; -import { CAMERAS, FEATURES, type Feature, type Support } from "../consts"; +import { + CAMERAS, + FEATURE_SUPPORT, + type FeatureSupport, + type Support, +} from "../consts"; +import { getLangFromUrl, useTranslations, useData } from "../i18n"; + +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); +const d = useData(lang); + +const cameraNotes = d("compat.cameraNotes"); +const featureLabels = d("compat.featureLabels"); +const columnLabels = d("compat.columns"); const cell = (s: Support) => s === "yes" @@ -9,16 +23,21 @@ const cell = (s: Support) => ? { icon: "mdi:circle-slice-5", cls: "text-[rgb(var(--color-accent))]" } : { icon: "mdi:close-circle", cls: "text-[rgb(var(--color-danger))]" }; -const columns: { label: string; key: keyof Omit }[] = [ - { label: "Osmo (Nano)", key: "osmoNano" }, - { label: "Action / 360", key: "action" }, - { label: "GoPro", key: "gopro" }, +const columns: { label: string; key: keyof FeatureSupport }[] = [ + { label: columnLabels[0], key: "osmoNano" }, + { label: columnLabels[1], key: "action" }, + { label: columnLabels[2], key: "gopro" }, ]; + +const features = FEATURE_SUPPORT.map((support, i) => ({ + label: featureLabels[i], + support, +})); ---
{ - CAMERAS.map((cam) => ( + CAMERAS.map((cam, i) => (
@@ -26,16 +45,16 @@ const columns: { label: string; key: keyof Omit }[] = [ {cam.tested ? ( - Tested + {t("compat.tested")} ) : ( - Untested + {t("compat.untested")} )}

{cam.name}

-

{cam.notes}

+

{cameraNotes[i]}

)) } @@ -47,7 +66,7 @@ const columns: { label: string; key: keyof Omit }[] = [ - + { columns.map((c) => ( @@ -57,14 +76,14 @@ const columns: { label: string; key: keyof Omit }[] = [ { - FEATURES.map((f, i) => ( + features.map((f, i) => ( {columns.map((c) => ( ))} @@ -77,15 +96,15 @@ const columns: { label: string; key: keyof Omit }[] = [
{ - FEATURES.map((f) => ( + features.map((f) => (

{f.label}

{columns.map((c) => (
{c.label} @@ -102,18 +121,18 @@ const columns: { label: string; key: keyof Omit }[] = [ class="mt-4 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-xs text-[rgb(var(--color-text-muted))]" > Supported {t("compat.legendSupported")} Partial / conditional {t("compat.legendPartial")} Unsupported {t("compat.legendUnsupported")}
diff --git a/site/src/components/HeaderLink.astro b/site/src/components/HeaderLink.astro index 47453c1..19c64c2 100644 --- a/site/src/components/HeaderLink.astro +++ b/site/src/components/HeaderLink.astro @@ -1,5 +1,6 @@ --- import type { HTMLAttributes } from "astro/types"; +import { getRouteFromUrl } from "../i18n"; type Props = HTMLAttributes<"a">; @@ -10,8 +11,10 @@ const normalize = (route: string) => { return route.replace(/\/$/, ""); }; -const current = normalize(Astro.url.pathname); -const target = normalize(new URL(href || "/", Astro.url.origin).pathname); +const current = normalize(getRouteFromUrl(Astro.url)); +const target = normalize( + getRouteFromUrl(new URL(href || "/", Astro.url.origin)), +); const isActive = current === target || (target !== "/" && current.startsWith(target + "/")); diff --git a/site/src/components/LanguageSelector.svelte b/site/src/components/LanguageSelector.svelte new file mode 100644 index 0000000..647d4e8 --- /dev/null +++ b/site/src/components/LanguageSelector.svelte @@ -0,0 +1,84 @@ + + +
+ + + {#if showDropdown} + + +
(showDropdown = false)} + > + {#each Object.entries(languages) as [langCode, langName]} + + {/each} +
+ {/if} +
+ + { + const target = e.target as Element; + if (!target.closest(".relative")) showDropdown = false; + }} +/> diff --git a/site/src/components/Navbar.astro b/site/src/components/Navbar.astro index 0585f47..6620256 100644 --- a/site/src/components/Navbar.astro +++ b/site/src/components/Navbar.astro @@ -1,13 +1,19 @@ --- import HeaderLink from "./HeaderLink.astro"; import ThemeToggle from "./ThemeToggle.svelte"; +import LanguageSelector from "./LanguageSelector.svelte"; import Socials from "./Socials.astro"; import { Icon } from "astro-icon/components"; +import { getLangFromUrl, useTranslations, getLocalizedUrl } from "../i18n"; + +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); +const homeUrl = getLocalizedUrl(lang, "/"); const links = [ - { href: "/", label: "Home", icon: "mdi:home-variant" }, - { href: "/flash", label: "Flasher", icon: "mdi:flash" }, - { href: "/docs", label: "Documentation", icon: "mdi:book-open-variant" }, + { href: getLocalizedUrl(lang, "/"), label: t("nav.home"), icon: "mdi:home-variant" }, + { href: getLocalizedUrl(lang, "/flash"), label: t("nav.flasher"), icon: "mdi:flash" }, + { href: getLocalizedUrl(lang, "/docs"), label: t("nav.docs"), icon: "mdi:book-open-variant" }, ]; --- @@ -17,7 +23,7 @@ const links = [
Feature{t("compat.featureHeader")}{c.label}
{f.label}