feat(i18n): localize the site into ru, es-ES and es-AR - #20
Merged
Conversation
Adds three locales alongside English, using Astro's own routing — no i18n dependency, so the devDependency footprint is unchanged. Routing: a single [...locale].astro renders all four pages via getStaticPaths, English at / and the rest prefixed (/ru/, /es-es/, /es-ar/). One template, no duplication. Copy: every UI string moves out of the markup into src/i18n/ui.ts, typed as Record<Locale, Strings>. A missing or misspelled key is a typecheck failure rather than a blank spot on the page — verified by deleting one key and watching astro check name it. Group ids are typed the same way, so a group in site.ts without matching copy will not compile. Repository-specific text — product summaries, details, bullets, code captions and archived-repo notes — stays English, matching the READMEs and code it describes. Rich text: strings mark their emphasized fragment with *asterisks* and <Emphasis> renders it as a span/em/b. Locale files stay free of markup and there is no set:html anywhere. This also keeps the hero wordplay intact — 'eco*system*' splits the same way in Одна *эко*/система and Un *eco*/sistema. es-AR is not a copy of es-ES: it uses voseo throughout (Explorá, Abrí, Mirá, entendé, seguí, Probá, Compartí, Unite, Necesitás, usás) and 'roadmap' over 'hoja de ruta', spreading the shared es-ES strings and overriding only what actually differs. Also: language switcher in the topbar (full language names as the accessible label), per-locale <html lang>, title, description, canonical and hreflang alternates including x-default, and localized labels for the theme toggle and copy button passed to the client scripts via data attributes. Topbar gains a fourth control, so at <=640px the switcher tightens and the GitHub button drops to its mark — checked at 390px, no overflow.
Four inline chips took 104px of topbar and still only showed opaque two-letter codes; AR in particular reads as a country, not a Spanish variant. A dropdown trims the trigger to ~45px on phones and gives the menu room to name each language in full — English / Русский / Español (España) / Español (Argentina) — with the code kept as a secondary column. Built on <details>/<summary>, so open/close and keyboard operation are native with no JS; the small component script only adds outside-click and Escape (returning focus to the trigger). The four options remain plain links, so navigation still works with JS disabled. The narrower trigger also lets the mobile rules relax: it keeps the globe and drops the code, since the open menu names the language anyway.
Extends localization to the repository prose that was deliberately left English: 12 summaries, 12 details and 44 bullets, plus the two archived -repo notes. site.ts keeps structure only — tag, name, code snippet, the lang caption naming the file a snippet belongs to, and URLs. Prose moves to the locale files keyed by product name, with ProductName and ArchivedName typed as unions of the actual entries, so a product added to site.ts without copy in all four locales fails astro check rather than rendering blank. The dictionary was outgrowing one file, so it splits per locale: types.ts holds the Strings shape, en/ru/es-es/es-ar hold the copy, ui.ts just assembles the Record<Locale, Strings>. Not translated, because they are identical in every language: repository names, code snippets, version lines (Gatling 3.13.5 · Scala 2.13.16 · Java 17+), API identifiers (query / queryP, matchByValue, insertInto, *PluginEnabled, --set), and the lang caption (scala · build.sbt). All 26 such identifiers verified present verbatim in each locale's built HTML. es-AR overrides six products where the copy genuinely differs — voseo (agregá, usá, necesitás, elegí) and LatAm vocabulary (archivo over fichero, notebook over portátil) — and inherits the rest from es-ES.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Three locales alongside English, on Astro's own routing — no i18n dependency, devDependency footprint unchanged.
<html lang>/en/ru/ru/es-es/es-ES/es-ar/es-ARScope
Per the call on scope: the interface is translated, repository-specific text is not. Product summaries, details, bullets, code captions and archived-repo notes stay English in
src/data/site.ts, matching the READMEs and code they describe. Everything else — nav, hero, section headings, group labels, community cards, Telegram panel, manifesto, priority block, footer, and the micro-labels (// About,Read the README,Copy,Archived) — is localized.How it works
src/pages/[...locale].astrorenders all four pages viagetStaticPaths; English at the root, the rest prefixed. Single template, no duplication.src/i18n/ui.ts, typed asRecord<Locale, Strings>. A missing or misspelled key is a typecheck failure, not a blank spot on the page — verified by deleting one key and watchingastro checkname it:site.tswithout matching copy won't compile. This is the same "types instead of tests" line as the validation PR.*asterisks*and a small<Emphasis>component renders it asspan/em/b. Locale files stay free of markup and there's noset:htmlanywhere. It also keeps the hero wordplay intact:eco|systemsplits the same way inОдна *эко*/системаandUn *eco*/sistema.roadmapoverhoja de ruta. It spreads the shared es-ES strings and overrides only what actually differs, so future edits to common copy stay in one place.hreflangalternates includingx-default; switcher links carry full language names as their accessible label rather than the two-letter chip.Copiar → CopiadoandСветлая / Тёмнаяwork without shipping a dictionary to the browser.Verification
All four locales checked in the browser: content,
lang, switcher state and navigation, plus theme toggle / accordion / copy still working with localized labels. Topbar gains a fourth control, so at ≤640px the switcher tightens and the GitHub button drops to its mark — checked at 390px, zero overflow.npm run validategreen; build emits 4 pages.🤖 Generated with Claude Code