Canadian French (fr-CA) as its own locale, not a fallback - #39
Open
distronode-com wants to merge 1 commit into
Open
Canadian French (fr-CA) as its own locale, not a fallback#39distronode-com wants to merge 1 commit into
distronode-com wants to merge 1 commit into
Conversation
`fr-CA` currently resolves to the France copy, and the differences are not stylistic. `courriel` rather than `e-mail`, `reporter`/`report` rather than `reprogrammer`/`reprogrammation`, `renseignements personnels` rather than `données personnelles` (the Quebec statutory term, so the wrong one is wrong in a legal sense rather than a register one), and no space before `!` `?` `;` where France puts one. CLDR itself disagrees on an abbreviation: July is `juill.` in fr-CA against `juil.` in fr. It is the first REGIONAL locale, which is the only structural thing here: the matcher already prefers an exact tag, so `fr-FR` and plain `fr` are untouched by this file existing. TestResolve now pins that in both directions rather than only the new one, since the half that would break silently is the French visitor who never asked for any of this. The three guards the other eight locales already pass apply unchanged — same key set as English, matching printf verbs, and date tables cross-checked against CLDR — so the structure is verified even though the wording is not.⚠️ The copy is an unreviewed draft, like every non-English locale here. Nobody who speaks Canadian French has read it. That is said plainly in the CHANGELOG so a correction arrives as an ordinary pull request rather than as a bug report. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
ℹ️ No critical issues — two stale locale counts outside the files this PR already updated.
Reviewed changes One commit adding Canadian French as a first-class regional locale (data + Resolve pins + doc counts). No matcher or handler changes.
fr-CA.jsonlocale table New 158-key file with the claimed fr vs fr-CA differences (courriel,reporter/report,renseignements personnels, punctuation spacing, CLDRjuill.). Key set matchesen; package tests pass.TestResolvepins both directions Exactfr-CA, Europeanfr-FR/frunaffected, and?lang=fr-CAoverride — the half that would break silently if the matcher preferred the new regional tag too broadly.- Doc/CHANGELOG counts
CLAUDE.md,CONTRIBUTING.md,ARCHITECTURE§23, and the Unreleased CHANGELOG entry now say 9 locales / listfr-CA.
ℹ️ Locale counts still say 8 in two places this PR did not touch
README.md still markets "8 languages" and lists English through Swedish with no Canadian French — the most visible user-facing surface for the feature. docs/ARCHITECTURE.md (~L809, LiveKit "not translated" known issue) still says the booking surfaces "ship in 8 languages (§23)", which now contradicts §23's "9 locales". Historical "8 locales" changelog entries are fine to leave.
Technical details
# Stale locale counts outside the PR's doc set
## Affected sites
- `README.md` ~L193–195 — still "**8 languages**" and the bullet list without Canadian French
- `docs/ARCHITECTURE.md` ~L808–809 — LiveKit known-issue still "ship in 8 languages (§23)" while §23 now says 9
## Required outcome
- User-facing and cross-referenced live counts match the shipped locale set (`en es fr fr-CA de it pt nl sv` / 9)
- Do not rewrite historical CHANGELOG / ARCHITECTURE dated entries that correctly described the state at ship time
## Suggested approach (optional)
- Bump README to 9 languages and add Canadian French to the list (same register as the other names)
- Change ARCHITECTURE L809 "8 languages" → "9 languages" (or "§23's locales") so it stays consistent with §23Grok | 𝕏
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.

First of the features split out of #30, in the order of appetite you described on that thread.
fr-CAcurrently resolves to the France copy through the primary-subtag fallback. The differences are not stylistic:e-mailcourrielreprogrammer/reprogrammationreporter/reportdonnées personnellesrenseignements personnels!?;juil.juill.The third row is the one that matters most:
renseignements personnelsis the statutory term in Quebec, so the France word is wrong in a legal sense rather than a register one. The last row is CLDR's own disagreement, not a preference, which is whyTestDateTablesMatchCLDRcatches it.The only structural point
This is the first regional locale.
Resolvealready prefers an exact tag before falling back to the primary subtag, so no matcher change was needed — but that means the risk is not in the new locale, it is in the eight that already work. A visitor sendingfr-FRor plainfrmust be untouched by this file existing.TestResolvenow pins both directions:{"Canadian French resolves to its own locale", "fr-CA,fr;q=0.9", "", "fr-CA"}, {"European French is unaffected by fr-CA", "fr-FR,fr;q=0.9", "", "fr"}, {"plain fr is unaffected by fr-CA", "fr", "", "fr"}, {"fr-CA can be selected by the ?lang override", "en", "fr-CA", "fr-CA"},Mutation-checked rather than assumed: with the locale file moved aside, the two positive cases fail (
Resolve("fr-CA,fr;q=0.9", "") = "fr", want "fr-CA") while the twofr/fr-FRcases stay green, which is what they are for — they assert an absence of change and would be worthless if removing the feature moved them.What is verified and what is not
The three guards the other eight locales pass apply unchanged: same key set as English (
TestAllLocalesHaveTheSameKeys), matching printf verbs including the%[1]s/%[2]spositional pairno_available_times_hostneeds (TestAllLocalesHaveMatchingFormatVerbs), and date tables cross-checked against CLDR (TestDateTablesMatchCLDR). So the structure is verified.Currency and percent take a non-breaking space before
$and%in Canadian French. No key carries either today, so that rule is recorded in ARCHITECTURE §23 rather than applied — worth writing down before someone adds a priced-event string.Scope
Nine files: the locale, four test cases, and the doc/CHANGELOG counts that say "8 locales". No handler, no matcher, no schema.
internal/i18npasses; the full suite passes on this branch.Adding a locale is still just adding
internal/i18n/locales/<code>.json—init()globs the directory, and nothing else needed a list updating.🤖 Generated with Claude Code