Repository navigation
Uses system default locale for text rendering when preferred locale isn't supported - #195997
Conversation
explicitly specified.
There was a problem hiding this comment.
Code Review
This pull request introduces TextLocaleScope and textLocaleOf to prevent text widgets from using the application's fallback locale when the user's preferred locale is unsupported, allowing the operating system's default locale to be used for font fallback. Feedback indicates a potential regression for multi-locale users and language-only matches because the implementation only checks the first preferred locale and requires an exact match. It is recommended to check all preferred locales for matching language codes and to add a test case verifying this multi-locale behavior.
|
@chunhtai can you give this a look please? I thought you you since you have experience in both CJK languages and the framework. I've tried to make the description clear, let me know if you want to chat about it. |
chunhtai
left a comment
There was a problem hiding this comment.
I felt this is more like a documentation issue
If the app is rendered in the resolved locale, I see no issue passing that into textpainer as default. Either the developer needs to set a correct locale in supported locale or preferred locale, or they can use defaultTextStyle to change the locale of a sub tree.
The only issue I saw is that we default locale to en_US if not set, but in that case the APP is rendered in en_US.
If we really want to do something for the default, then probably we need a way to tell if the app is using default locale and only pass in null in that case, but I am not sure whether that worth it though.
Like keeping the locale null, and only resolving as the default (en_US) when it's used. We could do that but it would require a lot of distributed places to edit to make it resolves correctly. Or we could introduce a new type, OptionalLocale which would make it easier to make sure we got it correct. Gut check: the fact that someone developing an app in Chinese, doesn't specify anything, runs it, and gets Japanese characters just seems bad to me. @chunhtai , am I overestimating what a problem that is? The screenshots kind of show the Japanese characters as being muddy. I wondered if they were muddy because they are more rare in Japanese. |
This is only because the OS decide the render chinese in en-US as japanese and Chinese if no locale supplied. To me that sounds like a platform bug, but I guess we probably need to do something here.
I think your current approach is fine, just need a few adjustment. We should make the API public since I imagine people who don't use Text widget will still need to access the new field, and we can probably put the new fields in existing class like Localization or WidgetsApp. Locale locale = null;
if(! Localizations.isApplicationLevelOf(context) || !Localizations.noDefaults(context)) {
locale = Localizations.maybeLocaleOf(context);
}
return RenderParagraph(
locale: locale,
)This example remove the condition where we check whether the current locale matches fallback because I worry that we may run into a opposite situation where people wants to send the resolved locale over to text painter because the app is rendered in that locale. I think it is probably better if the logic is consistence, and it will be up to developer to either use a Localization.override for a subtree or using DefaultTextStyle to override the locale in textstyle. WDYT? |
|
This pull request contains changes to Material or Cupertino, which are currently frozen in this repository. Changes should be made in Please refer to #188444 for instructions. |
@chunhtai I'm kind of out of my element here. I trust your opinion on the matter. I've updated it so that we explicitly keep track wether we are using the default locale or not. It can be overwritten with |
yup that sounds good to me. i wrote the example very quick so it seems like we don't really need the isapplicationLevel. if you can do it with one new api then I think it is fine. |
|
@chunhtai okay, sgtm. It's ready for review when you have a chance (I can't rerequest in the current state) |
|
left two comments, the approach LGTM |
| final RenderParagraph noLocale = paragraphs[0]; | ||
| final RenderParagraph withLocale = paragraphs[1]; | ||
| expect(noLocale.locale, isNull); | ||
| expect(withLocale.locale, enUS); |
There was a problem hiding this comment.
I don't think this test is meaningful after this point, in unittest the only available font is ahem and doesn't have locale difference.
There was a problem hiding this comment.
I don't think we can test this unless it is a integration test. my previous comment is just to ask for manual confirmation that code logic in skia won't do anything unexpected when putting null as locale for english text
There was a problem hiding this comment.
Gotcha removed. One way to think about that question is, what does it look like when you draw latin text when you specify zhCH as the locale? That's what it would look like. I think that can technically result in different rendering. However I would expect that to be more consistent with the rest of the experience on the machine. If you are asking about what skia does, that's kind of the limit of my familiarity. I don't maintain Skia, so I'm just relying on them to behave correctly. FWIW this remedy was suggested by someone on the skia team.
flutter/flutter@b98afb5...9c427b5 2026-11-12 [email protected] Roll Skia from d67d0f22e3ec to 9aa2513a4ac9 (2 revisions) (flutter/flutter#196429) 2026-11-12 [email protected] [flutter_tools] Move CpuArch to flutter_tools_core and define HostPlatform by osName and cpuArch (flutter/flutter#195841) 2026-11-12 [email protected] Roll Skia from 23e7e63789b8 to d67d0f22e3ec (2 revisions) (flutter/flutter#196424) 2026-11-12 [email protected] Uber compactify (flutter/flutter#196392) 2026-11-12 [email protected] Roll Skia from 3d7e335da165 to 23e7e63789b8 (12 revisions) (flutter/flutter#196422) 2026-11-12 [email protected] Roll Dart SDK from 13af329ea4f2 to e5add7a25b32 (1 revision) (flutter/flutter#196413) 2026-11-12 [email protected] Don't terminate the shared EGL display when an engine is disposed (flutter/flutter#194520) 2026-11-11 [email protected] Adds manifest flag to turn on SDFs for Android. (flutter/flutter#196056) 2026-11-11 [email protected] Remove bringup from Linux_pixel_7pro integration_ui_keyboard_inset_jump (flutter/flutter#196334) 2026-11-11 [email protected] Uses system default locale for text rendering when preferred locale isn't supported (flutter/flutter#195997) 2026-11-11 [email protected] [android]: prewarms shaders when the context is created (flutter/flutter#196069) 2026-11-11 [email protected] iOS: Recomposite platform views only if their parameters change (flutter/flutter#196287) 2026-11-11 [email protected] [flutter_tools] Forward encoding in ErrorHandlingFile.readAsStringSync (flutter/flutter#196136) 2026-11-11 [email protected] Roll Skia from b89c24bbab8c to 3d7e335da165 (8 revisions) (flutter/flutter#196390) 2026-11-11 [email protected] Add Flutter Gardener instructions on how to disable a test (flutter/flutter#196312) 2026-11-11 [email protected] [Impeller] Enable malioc analysis for framebuffer_blend shaders (flutter/flutter#196343) 2026-11-11 [email protected] [flutter_tools] Migrate general.shard Android, asset, and build tests off globals (flutter/flutter#196125) 2026-11-11 [email protected] Roll Dart SDK from 8f15c4ca2d41 to 13af329ea4f2 (1 revision) (flutter/flutter#196386) 2026-11-11 [email protected] [Impeller] Do not clamp the local coverage limit to the root render target (flutter/flutter#195860) 2026-11-11 [email protected] [Impeller] Use separate uniform buffers on VMware SVGA3D (flutter/flutter#196022) 2026-11-11 [email protected] [flutter_tools] Introduce AndroidSdkProvider for lazy native_assets SDK lookup (flutter/flutter#196122) 2026-11-11 [email protected] Moves linux to ThinLTO. (flutter/flutter#196314) 2026-11-11 [email protected] [flutter_tools] Migrate bin/fuchsia_tester.dart off globals and runInContext (flutter/flutter#196074) 2026-11-11 [email protected] Changes the tolerances for frame_rate_main_test.dart. (flutter/flutter#196304) 2026-11-11 [email protected] Roll Packages from 08faf64 to 653628e (16 revisions) (flutter/flutter#196381) 2026-11-11 [email protected] Allow SliverCrossAxisGroup children to lay out with zero cross-axis extent instead of asserting (flutter/flutter#191287) 2026-11-11 [email protected] Roll Skia from cc4c54f752ba to b89c24bbab8c (4 revisions) (flutter/flutter#196375) 2026-11-11 [email protected] [Linux] Fix layer offset when compositing with glBlitFramebuffer (flutter/flutter#196189) 2026-11-11 [email protected] [flutter_tools] Inject CrashReportSender into SwiftPM migration (flutter/flutter#196315) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Description
Makes the engine render text with the system locale when the user's preferred locale isn't one of the app's supported locales.
fixes #194931
Technical details
When the user's preferred locale isn't one of the app's
supportedLocales,WidgetsAppfalls back to another locale (en_USby default) for localization.RichTextandEditableTextwere passing that fallback locale to the engine for text rendering. With this PR they pass no locale in that case, so the platform's default locale is used (Skia's behavior). On Windows, an app that doesn't list Chinese now renders Han characters with Chinese fonts on a Chinese system, instead of Japanese fallback fonts.Alternatives considered
1) Adding new TextLocale API
This PR adds widgets that are not publicly available. Deciding on a new public API requires more forethought and maintenance than keeping one private. I've decided to keep it private for now and we can consider promoting it or replacing it with a public API later. I think the sorts of usage of Flutter that would require it are very rare, something like making a whole new alternative framework on dart:ui.
2) Considering secondary preferred locales
This PR only checks the user's first preferred locale. Counting any preferred locale would help a
[ja_JP, zh_CN]user of azh_CNapp: the app's Chinese strings would keepzh_CNglyphs instead of the OS default (likely Japanese). But it would bring back the original bug for the more common[zh_CN, en_US]user of an English-only app. That app resolves toen_US, itsen_USlocale would be passed to the engine, and Han text would render with Japanese fonts again. I chose to handle the common case and documented the trade-off in a test. Apps can opt out with an explicitWidgetsApp.localeorTextStyle.locale.Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.