Skip to content

refactor(i18n)!: rewrite the locales service - #47

Merged
JumpLink merged 3 commits into
mainfrom
feat/i18n-refactor
Oct 4, 2026
Merged

JumpLink merged 3 commits into
mainfrom
feat/i18n-refactor

Conversation

@JumpLink

@JumpLink JumpLink commented Oct 4, 2026

Copy link
Copy Markdown

Summary

Rewrites @ribajs/i18n and moves its consumers along. Breaking, documented in MIGRATION.md (section "2.0.0 release candidates → next").

  • Translator: pure per-key fallback chain (de-AT → de → fallbackLangcodes), Intl.PluralRules plurals, {{ var }} interpolation, no catalog cloning, empty strings are valid translations.
  • Language state: sourceLangcode, detect (query/storage/html/navigator), persist, <html lang> sync, all document/navigator/localStorage access guarded (SSR-safe).
  • Lifecycle: explicit init()/whenReady(), typed events ready/changed/missing/error per service instance, errors as events and rejections instead of return values, dispose(), stale-switch protection.
  • Sources: LocalesRestService loads one language at a time (url or (langcode) => url), with buildUrl/parse/resolveLangcodes hooks; the Shopify ?shop= coupling moved to @ribajs/shopify-tda.
  • Binder/formatter/switcher/share: the binder remembers the markup as the source and restores it when a key is missing or the source language is active, symmetrical unbind; t is synchronous and accepts variables and a langcode.
  • Consumers: shopify-tda, shopify-nest, doc site spec.
  • Docs: package README, doc/reference/i18n/*, MIGRATION.md.

Verification

  • yarn test: 941 passed (874 before)
  • tsc --noEmit: i18n, shopify-tda, shopify-nest, demos/i18n-static, infra/doc
  • build:demos 45/45, smoke:demos 45 ok, yarn workspace @ribajs/doc build ok
  • Browser: demos/i18n-static switches en → de → en → de correctly without console errors
  • e2e/ has no references to i18n; yarn test:e2e does not run locally (Playwright PnP loader), so CI is its first run

Not run: ESLint (the repo config fails to load on main as well), yarn build:libs.

Pascal Garber added 3 commits October 4, 2026 17:00
Split the old LocalesService into a pure Translator (per-key fallback chain, Intl plurals, no catalog cloning), a language state with detection, persistence and SSR-safe guards, and sources that load one language at a time. Errors are events and rejections, never return values. Binders restore the source markup when a key is missing or the source language is active. Consumers follow in the next commit.
shopify-tda requests one file for all languages and adds ?shop= in a buildUrl hook (the Shopify coupling left the generic rest service). shopify-nest reads the service from I18nService instead of the removed static instances. The doc site test used a catalog with a bogus langcode.
README, reference pages and a MIGRATION.md section for the breaking changes of the rewrite.
@JumpLink
JumpLink merged commit 08fd2df into main Oct 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant