Skip to content

[intl4x] Convert Platform.localeName to BCP47 in Locale.system - #1104

Open
mosuem wants to merge 4 commits into
dart-lang:mainfrom
mosuem:intl4x-fix-system-locale
Open

mosuem wants to merge 4 commits into
dart-lang:mainfrom
mosuem:intl4x-fix-system-locale

Conversation

@mosuem

@mosuem mosuem commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Note

This PR was generated by an AI coding agent (Jetski) on behalf of @mosuem.

Locale.system passed Platform.localeName straight to Locale.parse. On most non-web platforms that name is not a BCP47 tag, so ICU4X rejects it and Locale.system silently falls back to und.

What Platform.localeName returns, per the Dart SDK (runtime/bin/platform_*.cc):

Platform Source Example Before After
Linux / Android getenv("LANG"), default en_US en_US.UTF-8, sr_RS.UTF-8@latin, C.UTF-8 und en-US, sr-Latn-RS, und
Windows GetUserDefaultLocaleName en-US, de-DE_phoneb (sort order) en-US, und en-US, de-DE-u-co-phonebk
macOS / iOS first preferred language, else CFLocale identifier zh-Hans-CN, en_US@calendar=japanese;hours=h23 zh-Hans-CN, und zh-Hans-CN, en-US-u-ca-japanese-hc-h23

Changes:

  • Add platformLocaleNameToBcp47 in lib/src/locale/platform_locale_name.dart. It strips the POSIX codeset, maps glibc's @latin/@cyrillic modifiers to script subtags, maps C/POSIX to und, and replaces _ with -. The regexes are top-level finals, so they are compiled once, and the main regex is documented piece by piece.
  • Keep locale preferences as Unicode extensions:
    • Apple's ICU-style keywords become -u- keywords, mapping legacy names and values (calendar=gregorian → ca-gregory, collation=phonebook → co-phonebk, hours → hc, numbers → nu, measure=imperial → ms-uksystem, …). Keys are sorted, and unknown keys or invalid values (such as timezone=America/New_York) are dropped.
    • Windows sort orders become collations: _phoneb → co-phonebk, _tradnl → co-trad, _stroke → co-stroke, _pronun → co-zhuyin, _radstr → co-unihan. Hungarian _tchncl and Georgian _modern have no CLDR equivalent and are dropped.
    • glibc's @euro becomes -u-cu-eur.
    • Names that already are BCP47 tags keep their own extensions unchanged.
  • Use it in findSystemLocale() on non-web platforms. Web is unchanged, as navigator.language is already BCP47.
  • Document on Locale.system that Platform.localeName does not reflect the device locale on Android, as LANG is usually unset there, and how Flutter apps should pass the locale instead.
  • Add tests covering all of the above formats, checking both the converted tag and that Locale.parse accepts it.

Verified locally: dart analyze --fatal-infos, dart format, and dart test (VM) pass. With LANG=en_US.UTF-8, Locale.system now returns en-US instead of und. Checked end to end on native that the extensions take effect: en_US@calendar=japanese formats as Jan 2, 8 Reiwa, en_US@hours=h23 as 22:23:00, th_TH@calendar=buddhist;numbers=thai as ๒ ม.ค. ๒๕๖๙, and de-DE_phoneb sorts Müller next to Mueller. Chrome and wasm tests run in CI.

Fixes #1026

@mosuem
mosuem requested a review from robertbastian as a code owner October 6, 2026 12:43
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where Locale.system would incorrectly fall back to 'und' on various platforms because the raw platform locale strings were not compatible with BCP47 parsing. By implementing a normalization layer, the library now correctly interprets diverse locale formats from Linux, Windows, and Apple platforms, significantly improving the reliability of system locale detection.

Highlights

  • Locale Normalization: Introduced a utility to convert platform-specific locale strings into BCP47-compliant tags, ensuring compatibility with ICU4X.
  • Platform Support: Improved system locale detection for Linux, Windows, and macOS/iOS by handling POSIX codesets, modifiers, and platform-specific suffixes.
  • Documentation: Updated documentation for Locale.system to clarify behavior on different platforms and provide guidance for Android developers.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request improves Locale.system resolution by converting Platform.localeName to a BCP47 tag, resolving issues where it returned und on Linux, Windows, and Apple platforms. Feedback on the changes highlights a bug in the parsing logic where hybrid locale names (such as en_US-POSIX or sr_Latn-RS) would be incorrectly truncated. The reviewer suggested refining the truncation logic to ensure the underscore appears after the hyphen before truncating, and adding corresponding test cases to verify this behavior.

final tag = platformLocaleNameToBcp47(localeName);
expect(tag, expected);
// Only check that the tag is accepted, as the canonical form differs
// between backends: ICU4X turns `en-US-POSIX` into `en-US-posix`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this might be an ICU4X bug

mosuem added 4 commits October 8, 2026 08:32
Platform.localeName returns POSIX locale names on Linux (en_US.UTF-8),
Windows sort orders (de-DE_phoneb), and Apple CFLocale identifiers
(en_US@calendar=japanese), none of which ICU4X can parse, so
Locale.system silently fell back to und.

Fixes dart-lang#1026
Map Apple's ICU-style keywords (en_US@calendar=japanese;hours=h23) to
-u- extensions, Windows sort orders (de-DE_phoneb) to -u-co-, and
glibc's @euro modifier to -u-cu-eur.
@mosuem
mosuem force-pushed the intl4x-fix-system-locale branch from b1957ba to cf30036 Compare October 8, 2026 08:48

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default Locale problem

2 participants