Files
ResumeSite/docs/spec/I18N_SPEC.md
T
2026-07-03 21:07:25 +02:00

47 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# I18N_SPEC.md
## 1. Architecture summary
Three i18n concerns, three mechanisms — never mixed:
| Concern | Mechanism | Examples |
|---|---|---|
| **Routes** | Astro built-in i18n (defaultLocale `en` at root, `no` prefixed) + slug map module | `/projects/jobtrack``/no/prosjekter/jobtrack` |
| **UI strings** (~60 keys) | Typed dictionary modules per locale + `t(key)` accessor, compile-time checked | `nav.projects`, `cv.download`, `form.error.email`, `a11y.skipLink` |
| **Content** (prose, case studies, experience) | Content collections with per-locale entries sharing one zod schema | `projects/en/jobtrack.md` + `projects/no/jobtrack.md` |
No runtime i18n library. Locale is resolved from the URL at build time; every page is rendered once per locale into static HTML.
## 2. Dictionary spec
- Shape: nested typed object; both locale files implement the same interface → a missing key is a **compile error**, not a runtime fallback.
- Keys are semantic (`cv.download`), never English-sentence keys.
- Interpolation: simple `{param}` tokens only; no plural engine (the ~3 plural cases are written out per locale).
- A11y strings are first-class dictionary entries: skip-link, lang-switch announcement ("Bytt til norsk" labelled *in the target language* per MICRO_INTERACTIONS), image alt patterns, form validation messages.
## 3. Content collection localisation
- Each collection folder splits `en/` and `no/`; entries share the same filename (`jobtrack.md`) = the join key.
- One schema validates both locales (DATA_MODEL.md); locale-invariant fields (dates, stack chips, links, image refs, status) live in the EN entry and are **inherited** by the NO entry at load time (a small content-loader utility merges them) — this is the anti-duplication mechanism: facts exist once, prose exists twice.
- Section anchors: schema field `anchorId` per section, per locale (`architecture`/`arkitektur`) with the pageId-level mapping used by the language switch to land on the equivalent section (J5).
## 4. Fallback rules (build-time, never runtime)
1. **Full parity is the shipping rule.** CI parity test: every EN content entry has a NO twin and vice versa; every dictionary key present in both.
2. **Temporary asymmetry** (a new case study written EN-first): the NO twin must still exist, containing a native-Norwegian summary + link "Full versjon på engelsk" (CONTENT_STRATEGY rule). The schema supports `summaryOnly: true` for this state; CI allows it but the sitemap/hreflang still emit correctly.
3. No silent English fallback ever renders on a `/no/` page — a Norwegian reader must never hit unexplained English mid-page. (Machine translation is banned outright.)
## 5. Locale-sensitive rendering rules
- `<html lang>`: `en-GB` / `nb-NO` per page. Date formatting: `20152023` style is locale-neutral; long dates use locale month names via `Intl` at build time.
- Quotes: “ ” (EN) / « » (NO) — enforced in content review, not code.
- The CV split-button defaults to the *current page locale's* CV; stored language preference overrides on EN pages only if the user previously chose NO (subtle: preference sets default, page locale is tiebreak).
- OG/meta per locale (SEO_SPEC). `hreflang` emitted from the slug map: `en`, `nb`, `x-default → en`.
## 6. Translation management workflow
- Author EN and NO in the same PR (content files sit side by side; the parity test enforces it).
- Norwegian quality gate before launch: native/fluent review pass of all NO content (tracked as a Phase 3 exit criterion; the reviewer reviews *markdown files in a PR*, which keeps review diffs clean — a deliberate benefit of content-in-git).
- Glossary (CONTENT_STRATEGY §5.3) lives as a comment header in the NO dictionary file so it's in front of whoever edits translations.
- No TMS tooling: two locales, one author, git history is the audit trail.