Skip to content

add BCP-47 validation cases ported from libpalaso - #156

Merged
andrew-polk merged 2 commits into
mainfrom
bcp47-validation-tests
Sep 2, 2026
Merged

andrew-polk merged 2 commits into
mainfrom
bcp47-validation-tests

Conversation

@hahn-kev

@hahn-kev hahn-kev commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

I was checking to see if using ICU4X Locale could improve our isValid check (it didn't), but as part of that I imported the BCP-47 validation tests from libpalaso, so I figured I'd open a PR to contribute those tests. Feel free to dump it if it doesn't seem useful.


AI summary

Broadens test coverage for isValidBcp47Tag in @ethnolib/find-language with well-formedness cases ported from libpalaso's IetfLanguageTag tests (SIL.WritingSystems.Tests/IetfLanguageTagTests.cs). No behavior change to the validator itself — the implementation still uses the existing BCP-47 grammar regex.

Why: We evaluated swapping isValidBcp47Tag to an ICU4X-backed parser to see if it was more complete than the regex. It wasn't: ICU4X follows UTS-35, a strict subset of BCP-47, so it rejects well-formed tags the library itself emits (extlang tags like sgn-ads-GH, grandfathered tags like i-ami, 4–8-char primary languages, and language-less x- tags). Wrapping it with a regex fallback made it behaviorally identical to the plain regex — pure cost, no gain — so the ICU swap was dropped. The libpalaso test corpus surfaced during that comparison was worth keeping.

Changes:

  • languageTagUtils.spec.ts: +6 test cases covering
    • well-formed tags with each subtag position filled (tpi-AR, tpi-Lepc-BR-fonipa-x-blah, qed-Lepc-x-rubbish, qed)
    • extlang subtags up to the 3-max, and rejection beyond it
    • Unicode/transform extensions (en-US-u-ca-gregory, en-t-jp, de-DE-u-co-phonebk)
    • private-use subtag length limit (8 chars ok, 16 rejected)
    • empty-subtag and illegal-character rejections (-, --, en--US, qed-?~, trailing x-)
  • languageTagUtils.ts: doc comment clarifying that isValidBcp47Tag checks syntactic validity only, not registry membership — unlike libpalaso's registry-backed IetfLanguageTag.IsValid.

Note on scope: libpalaso's IsValid additionally validates subtags against the IANA/ISO registries (so e.g. zzz is invalid there). That semantic level is deliberately out of scope here; these tests only assert well-formedness, matching the existing isValidBcp47Tag contract.

Test plan

  • npm run testonce in components/language-chooser/common/find-language — 88 tests pass (was 82).
  • npx tsc --noEmit — clean.

This change is Reviewable

Broaden isValidBcp47Tag coverage with well-formedness cases drawn from
libpalaso's IetfLanguageTag tests: full subtag-position tags, extlang
limits, Unicode/transform extensions, private-use length limits, and
empty-subtag/illegal-character rejections.

Also add a doc comment clarifying that isValidBcp47Tag checks syntactic
validity only, not registry membership (unlike libpalaso's IsValid).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
font-chooser-react-mui Ready Ready Preview Sep 2, 2026 2:29am UTC

@andrew-polk

Copy link
Copy Markdown
Contributor

components/language-chooser/common/find-language/languageTagUtils.spec.ts line 822 at r1 (raw file):

  it("should return false for more than three extlang subtags", () => {
    expect(isValidBcp47Tag("abcdefgh-abc-def-ghi-jkl")).toBeFalsy();

Devin says


components/language-chooser/common/find-language/languageTagUtils.spec.ts:R822

Extlang-limit test does not test the extlang limit

abcdefgh-abc-def-ghi-jkl is rejected because an 8-letter primary language subtag cannot carry any extlang, not because it exceeds three extlangs. The assertion would pass even if the extlang-count check were broken, so it tests nothing. Only en-abc-def-ghi-jkl exercises the limit.

@andrew-polk andrew-polk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrew-polk reviewed 2 files and all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on hahn-kev).

Drop the abcdefgh-abc-def-ghi-jkl case: an 8-letter primary language
subtag cannot carry any extlang in our grammar, so it was rejected for
that reason rather than for exceeding three extlangs and tested nothing.
en-abc-def-ghi-jkl (2-letter primary + four extlangs) exercises the
limit directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@andrew-polk andrew-polk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrew-polk reviewed 1 file and all commit messages, and resolved 1 discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on hahn-kev).

@andrew-polk
andrew-polk merged commit 2e0bcaf into main Sep 2, 2026
5 checks passed
@andrew-polk
andrew-polk deleted the bcp47-validation-tests branch September 2, 2026 18:33
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.

2 participants