Repository navigation
Single-source i18n: raco rivet i18n with parity check and embedded host tables - #275
Merged
Merged
Conversation
Every host re-solved user-visible string loading, and the third copy was already diverging: taskly staged shared/i18n JSON with per-host fallback tables and a CI parity check, syncpilot built a private generator for the same idea, and fulcrum's Windows/Linux hosts hardcoded English inline while mac read the shared source — the single source silently rotted. raco rivet i18n closes that class (issue #242): it verifies the parity contract of shared/i18n/{zh,en}.json (flat string->string maps, identical key sets, named file and key on violation) and regenerates the embedded tables for every host template the project keeps — windows/ and linux/ GeneratedI18n.hpp and macos-host GeneratedI18n.swift. C++ literals encode non-ASCII bytes as three-digit UTF-8 octal escapes (fixed width, so consecutive escapes cannot run together, and no \xNNNN out-of-range char escape); Swift keeps UTF-8 source literal and escapes only quotes, backslashes, and control characters. The host templates ship the matching loader: rivet_app::i18n::tr consults the active language, then the other language, then the key — identical to the generated Swift tr — so a key can never exist in one host's fallback and not another's. doctor --release gains a sixth check: projects with a shared/i18n source gate its parity and the freshness of the embedded tables (the plan/writer split from generate-clients! means the gate and the writer cannot disagree); projects without one skip it. docs/configuration.md documents the single source and the lookup order. The suite compiles the generated table with the shipped loader and asserts tr()'s lookup order against real UTF-8 values, covers parity violations (drifted keys, nested values, missing tables), and the freshness gate (stale, missing, repaired).
turinglambdaai
force-pushed
the
feat/i18n-loader
branch
from
October 16, 2026 15:47
5a1db8d to
9628e6e
Compare
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.
Closes #242.
What
Hosts re-solved user-visible string loading three times, and the third copy was diverging: taskly had the full pattern (shared/i18n JSON → staged res/i18n → per-host loaders → embedded fallbacks → CI parity check), syncpilot built a private generator for the same idea, and fulcrum's Windows/Linux hosts hardcoded English inline while mac read the shared source. The single source silently rotted.
raco rivet i18nverifies the parity contract ofshared/i18n/{zh,en}.json(flatstring -> string, identical key sets — violations name the file and key) and regenerates the embedded host tables for every host template the project keeps:windows/GeneratedI18n.hpp,linux/GeneratedI18n.hpp—rivet_app::I18nEntrytablemacos-host/Sources/RivetHost/GeneratedI18n.swift—GeneratedI18ntable +trfunctionThe host templates ship the matching loader:
rivet_app::i18n::tr(language, key)consults the active language, then the other language, then the key — byte-for-byte the same lookup order as the generated Swifttr, so a key can never exist in one host's fallback and not another's.Escaping: C++ encodes non-ASCII as three-digit UTF-8 octal escapes (fixed width — consecutive escapes cannot run together, and no
\xNNNNout-of-range char escape, which clang rejects); Swift keeps UTF-8 source literal and escapes only quotes, backslashes, and C0 controls.Release gate:
doctor --releasegains a sixth check — projects with ashared/i18nsource gate its parity and the freshness of the embedded tables (same plan/writer split asgenerate-clients!, so gate and writer cannot disagree); projects without one skip it.Docs:
docs/configuration.mddocuments the single source, the loader lookup order, and the staging relationship.Verification
rivet/tests/i18n.rkt: parity violations (drifted keys, nested values, missing tables), generated-content assertions, the freshness gate (stale/missing/repaired), and — the load-bearing one — the generated C++ table compiled with the shipped loader andtr()'s lookup order asserted against real UTF-8 values.