Repository navigation
Deprecate decoupled localizations, add dart fixes - #192954
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces automated data-driven fixes to support migrating localization classes from flutter_localizations to external packages like material_ui and cupertino_ui. It updates the localization generator to add deprecation annotations to generated classes, constructors, variables, and factory functions, and outputs YAML transform files for the dart fix tool. Feedback on the changes suggests refactoring the collection of generated class names from a List to a Set to avoid duplicate entries and duplicate transform blocks in the generated YAML. Additionally, it is recommended to use the explicit package URI package:flutter_localizations/flutter_localizations.dart instead of the relative path in the generated fix files to ensure robust resolution by the analyzer.
| String? deprecatedReplacementPackage, | ||
| List<String>? generatedClassNames, | ||
| }) { |
There was a problem hiding this comment.
Using a Set instead of a List for generatedClassNames prevents duplicate class names from being added and subsequently generating duplicate transform blocks in the output YAML files.
| String? deprecatedReplacementPackage, | |
| List<String>? generatedClassNames, | |
| }) { | |
| String? deprecatedReplacementPackage, | |
| Set<String>? generatedClassNames, | |
| }) { |
References
- Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)
| supportedLanguagesDocMacro: widgetsSupportedLanguagesDocMacro, | ||
| ) | ||
| : null; | ||
| final materialGeneratedClasses = <String>[]; |
There was a problem hiding this comment.
Initialize materialGeneratedClasses as a Set to ensure uniqueness of the generated class names.
| final materialGeneratedClasses = <String>[]; | |
| final materialGeneratedClasses = <String>{}; |
References
- Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)
There was a problem hiding this comment.
I think Gemini is right? No need to do this multiple times for the same string.
| generatedClassNames: materialGeneratedClasses, | ||
| ) | ||
| : null; | ||
| final cupertinoGeneratedClasses = <String>[]; |
There was a problem hiding this comment.
Initialize cupertinoGeneratedClasses as a Set to ensure uniqueness of the generated class names.
| final cupertinoGeneratedClasses = <String>[]; | |
| final cupertinoGeneratedClasses = <String>{}; |
References
- Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)
| required String baseClass, | ||
| required String supportedLanguagesConstant, | ||
| required String factoryName, | ||
| required List<String> generatedClassNames, |
There was a problem hiding this comment.
Update the parameter type of generatedClassNames to Set to match the updated caller types and guarantee uniqueness.
| required List<String> generatedClassNames, | |
| required Set<String> generatedClassNames, |
References
- Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)
| final buffer = StringBuffer(''' | ||
| # Copyright 2014 The Flutter Authors. All rights reserved. | ||
| # Use of this source code is governed by a BSD-style license that can be | ||
| # found in the LICENSE file. | ||
|
|
||
| # THIS FILE IS GENERATED. DO NOT EDIT BY HAND. | ||
| # | ||
| # This file is generated by: | ||
| # dart dev/tools/localization/bin/gen_localizations.dart --overwrite | ||
|
|
||
| # For details regarding the *Flutter Fix* feature, see | ||
| # https://flutter.dev/to/flutter-fix | ||
|
|
||
| # Every fix must be tested. See the | ||
| # flutter/packages/flutter_localizations/test_fixes/README.md file for | ||
| # instructions on testing these data driven fixes. | ||
|
|
||
| # For documentation about this file format, see | ||
| # https://dart.dev/go/data-driven-fixes. | ||
|
|
||
| version: 1 | ||
| transforms: | ||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| class: '$baseClass' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| class: '$baseClass' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| variable: '$supportedLanguagesConstant' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| variable: '$supportedLanguagesConstant' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| function: '$factoryName' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| function: '$factoryName' | ||
| '''); | ||
|
|
||
| for (final className in generatedClassNames) { | ||
| buffer.write(''' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| class: '$className' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| class: '$className' | ||
| '''); | ||
| } |
There was a problem hiding this comment.
Using the explicit package URI package:flutter_localizations/flutter_localizations.dart instead of the relative/shortened flutter_localizations.dart is the standard practice for Flutter's data-driven fixes and ensures robust resolution by the analyzer.
final buffer = StringBuffer('''
# Copyright 2014 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# THIS FILE IS GENERATED. DO NOT EDIT BY HAND.
#
# This file is generated by:
# dart dev/tools/localization/bin/gen_localizations.dart --overwrite
# For details regarding the *Flutter Fix* feature, see
# https://flutter.dev/to/flutter-fix
# Every fix must be tested. See the
# flutter/packages/flutter_localizations/test_fixes/README.md file for
# instructions on testing these data driven fixes.
# For documentation about this file format, see
# https://dart.dev/go/data-driven-fixes.
version: 1
transforms:
- title: "Migrate to '$replacementPackageUri'"
date: 2026-09-17
element:
uris: ['package:flutter_localizations/flutter_localizations.dart']
class: '$baseClass'
changes:
- kind: 'replacedBy'
newElement:
uris: ['$replacementPackageUri']
class: '$baseClass'
- title: "Migrate to '$replacementPackageUri'"
date: 2026-09-17
element:
uris: ['package:flutter_localizations/flutter_localizations.dart']
variable: '$supportedLanguagesConstant'
changes:
- kind: 'replacedBy'
newElement:
uris: ['$replacementPackageUri']
variable: '$supportedLanguagesConstant'
- title: "Migrate to '$replacementPackageUri'"
date: 2026-09-17
element:
uris: ['package:flutter_localizations/flutter_localizations.dart']
function: '$factoryName'
changes:
- kind: 'replacedBy'
newElement:
uris: ['$replacementPackageUri']
function: '$factoryName'
''');
for (final className in generatedClassNames) {
buffer.write('''
- title: "Migrate to '$replacementPackageUri'"
date: 2026-09-17
element:
uris: ['package:flutter_localizations/flutter_localizations.dart']
class: '$className'
changes:
- kind: 'replacedBy'
newElement:
uris: ['$replacementPackageUri']
class: '$className'
''');
}References
- Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)
There was a problem hiding this comment.
Sounds reasonable but I'm not sure what the best practice is.
There was a problem hiding this comment.
The bot's claim is backwards. Across all existing fix_data files in the repo (packages/flutter/lib/fix_data/, packages/flutter_test/lib/fix_data/, packages/flutter_driver/lib/fix_data/) as well as Data-driven-Fixes.md:191, relative URIs (uris: ['flutter_driver.dart'], uris: ['material.dart']) are the standard convention for elements defined in the same package, while full package:... URIs are used for external packages in newElement.
| supportedLanguagesDocMacro: widgetsSupportedLanguagesDocMacro, | ||
| ) | ||
| : null; | ||
| final materialGeneratedClasses = <String>[]; |
There was a problem hiding this comment.
I think Gemini is right? No need to do this multiple times for the same string.
| final buffer = StringBuffer(''' | ||
| # Copyright 2014 The Flutter Authors. All rights reserved. | ||
| # Use of this source code is governed by a BSD-style license that can be | ||
| # found in the LICENSE file. | ||
|
|
||
| # THIS FILE IS GENERATED. DO NOT EDIT BY HAND. | ||
| # | ||
| # This file is generated by: | ||
| # dart dev/tools/localization/bin/gen_localizations.dart --overwrite | ||
|
|
||
| # For details regarding the *Flutter Fix* feature, see | ||
| # https://flutter.dev/to/flutter-fix | ||
|
|
||
| # Every fix must be tested. See the | ||
| # flutter/packages/flutter_localizations/test_fixes/README.md file for | ||
| # instructions on testing these data driven fixes. | ||
|
|
||
| # For documentation about this file format, see | ||
| # https://dart.dev/go/data-driven-fixes. | ||
|
|
||
| version: 1 | ||
| transforms: | ||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| class: '$baseClass' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| class: '$baseClass' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| variable: '$supportedLanguagesConstant' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| variable: '$supportedLanguagesConstant' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| function: '$factoryName' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| function: '$factoryName' | ||
| '''); | ||
|
|
||
| for (final className in generatedClassNames) { | ||
| buffer.write(''' | ||
|
|
||
| - title: "Migrate to '$replacementPackageUri'" | ||
| date: 2026-09-17 | ||
| element: | ||
| uris: ['flutter_localizations.dart'] | ||
| class: '$className' | ||
| changes: | ||
| - kind: 'replacedBy' | ||
| newElement: | ||
| uris: ['$replacementPackageUri'] | ||
| class: '$className' | ||
| '''); | ||
| } |
There was a problem hiding this comment.
Sounds reasonable but I'm not sure what the best practice is.
| 'Use GlobalCupertinoLocalizations from package:cupertino_ui/cupertino_ui.dart instead. ' | ||
| 'This feature was deprecated after v3.47.0-0.0.pre.', | ||
| ) | ||
| abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations { |
There was a problem hiding this comment.
There are some usages of these classes that are causing CI to fail.
| # Since these test cases live inside the `flutter_localizations` package, the | ||
| # lint `deprecated_member_use_from_same_package` is required in | ||
| # order to trigger them. Customer code (which lives outside of the | ||
| # `flutter_localizations` package) will be triggered by the analyzer warning | ||
| # `deprecated_member_use`, which is enabled by default. | ||
| - deprecated_member_use_from_same_package |
There was a problem hiding this comment.
Do we need to remove this when the deprecated code gets deleted? Maybe create an issue and/or a TODO.
There was a problem hiding this comment.
No, test_fixes/analysis_options.yaml (with deprecated_member_use_from_same_package) and the fix_data / test_fixes files are permanent and identical packages/flutter/test_fixes/analysis_options.yaml, packages/flutter_test/test_fixes/analysis_options.yaml, and packages/flutter_driver/test_fixes/analysis_options.yaml. Per Data-driven-Fixes.md:32, dart fix rules continue to work and be tested in test_fixes/ even after deprecated APIs are removed (at which point the undefined_identifier / undefined_class diagnostic triggers the exact same fix).
This is the first time this package is adopting dart fix, which is why it stands out. :)
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'package:flutter_localizations/flutter_localizations.dart'; |
There was a problem hiding this comment.
Should this import be removed from the expected output?
There was a problem hiding this comment.
package:flutter_localizations/flutter_localizations.dart is not deprecated as a whole library (since GlobalWidgetsLocalizations and WidgetsLocalization* remain in flutter_localizations). Therefore, these are element-level replacedBy transforms rather than a library-level replacedBy transform. In dart fix, element-level replacedBy transforms add the new library import (package:material_ui/material_ui.dart) so the migrated symbols resolve, and do not remove existing imports (the same behavior occurs in packages/flutter/test_fixes/material/material.dart.expect).
|
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
QuncCccccc
left a comment
There was a problem hiding this comment.
LGTM. Thanks for adding this!
Flutter deprecated GlobalMaterialLocalizations and GlobalCupertinoLocalizations, in favor of package:material_ui and package:cupertino_ui: flutter/flutter#192954 Without this change, `tools/check analyze` fails with a deprecated_member_use info on each of them, in lib/generated/l10n/zulip_localizations.dart. That has been breaking CI on every branch, most recently: https://github.com/zulip/zulip-flutter/actions/runs/35577698483/job/106263172114 Both lines are written by gen-l10n itself, and come back on every `flutter gen-l10n`. So suppress them through gen-l10n's own `header` option, which gets regenerated along with them. See zulip#2463 for the migration, which waits in part on gen-l10n learning about the new packages: flutter/flutter#191072 Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Deprecates the Material and Cupertino localization classes and symbols in
package:flutter_localizationsin favor ofpackage:material_ui/material_ui.dartandpackage:cupertino_ui/cupertino_ui.dart, and addsdart fixmigrations.GlobalMaterialLocalizations,kMaterialSupportedLanguages,getMaterialTranslation, and all generatedMaterialLocalization*classes influtter_localizationsin favor ofpackage:material_ui/material_ui.dart.GlobalCupertinoLocalizations,kCupertinoSupportedLanguages,getCupertinoTranslation, and all generatedCupertinoLocalization*classes influtter_localizationsin favor ofpackage:cupertino_ui/cupertino_ui.dart.dev/tools/localization/bin/gen_localizations.dartto generate the@Deprecatedannotations as well as the correspondingdart fixrules (fix_material_localizations.yamlandfix_cupertino_localizations.yaml).dart fixgolden tests underpackages/flutter_localizations/test_fixes/and enablesrunFixTests('flutter_localizations')in CI.Part of #172935
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.