Skip to content

Flutter localization - #426

Open
AsadAli93916 wants to merge 4 commits into
mainfrom
flutter_localization
Open

Flutter localization#426
AsadAli93916 wants to merge 4 commits into
mainfrom
flutter_localization

Conversation

@AsadAli93916

@AsadAli93916 AsadAli93916 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Implemented Flutter localisation setup using gen-l10n.

Added:

  • flutter_localizations
  • intl
  • l10n.yaml
  • app_en.arb

Converted:

  • Login screen
  • Register screen
  • Shared navigation labels
  • Product add-to-cart actions

Remaining hardcoded strings:

  • Settings
  • Profile
  • Admin flows

Verified app builds and runs successfully.

Summary by CodeRabbit

  • New Features

    • Implemented localization framework infrastructure to support future multi-language support.
  • Chores

    • Updated build configuration and dependencies to support localization system.
    • Refactored UI text management for centralized string handling.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces comprehensive localization support to the Flutter app. It adds Flutter localization infrastructure (configuration, translation strings, abstract contract, and English implementation), migrates 20+ feature pages and widgets to use localized strings instead of hardcoded text, wires localization into the main app, and updates Android build configuration and tests accordingly.

Changes

Localization Feature Implementation

Layer / File(s) Summary
Localization configuration and contract
l10n.yaml, lib/l10n/app_en.arb, lib/l10n/app_localizations.dart, lib/l10n/app_localizations_en.dart, pubspec.yaml
Flutter localization infrastructure: l10n.yaml configures the arb directory and output file; app_en.arb defines English translation keys for auth, navigation, products, and checkout; app_localizations.dart defines the abstract contract with locale lookup and delegates; app_localizations_en.dart implements English strings; pubspec.yaml adds flutter_localizations, intl, and enables code generation.
Main app localization integration
lib/main.dart
Registers AppLocalizations.delegate and supportedLocales in MaterialApp to enable localization across the app.
Auth and onboarding pages localization
lib/features/auth/username_setup_page.dart, lib/features/login/login_page.dart, lib/features/login/widgets/login_form.dart, lib/features/register/register_page.dart, lib/features/register/widgets/register_form.dart, lib/features/register/verify_email_page.dart, lib/features/password_flow/not_you_page/not_you_page.dart, lib/features/welcome/welcome_page.dart, lib/features/welcome/widgets/signup_card.dart, lib/features/settings/widgets/settings_category_group.dart
Migrates all authentication and onboarding UI strings from AppStrings constants and hardcoded text to AppLocalizations, including form labels, hints, buttons, toasts, and dialogs.
Core feature pages and widgets localization
lib/features/discover/discover_page.dart, lib/features/discover/widgets/discover_selection_bar.dart, lib/features/home/widgets/bottom_nav_bar.dart, lib/features/products/product_page.dart, lib/features/products/widgets/seller_information.dart, lib/features/checkout/checkout_page.dart, lib/features/checkout/widgets/delivery_options.dart, lib/features/checkout/widgets/share_location_dialog.dart
Converts discover, home navigation, product detail, and checkout UI strings to localized equivalents, replacing hardcoded labels, button text, and error messages.
Build configuration and Android gradle updates
android/app/build.gradle.kts, android/gradle.properties, pubspec.yaml
Removes local.properties-based NDK version lookup in Gradle; disables Kotlin incremental compilation for Windows compatibility; adds Flutter code generation flag.
Test infrastructure and mocks
test/auth_ui_test.dart, test/auth_ui_test.mocks.dart, test/checkout_view_model_test.mocks.dart, test/widget_test.dart
Updates test MaterialApp setup to include localization delegates; generates Mockito mocks for test dependencies (MockLoginRepository, MockNavigationProvider).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • CherryCIC

🐰 A flutter of localization blooms,
Where hardcoded strings now rest in rooms,
AppLocalizations takes the stage,
Twenty pages turn a brand-new page,
English whispers ready for the world's applause!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Flutter localization' is highly relevant and accurately describes the main change: implementing a complete localization system throughout the app using Flutter's gen-l10n tool.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch flutter_localization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
android/gradle.properties (1)

4-5: ⚡ Quick win

Avoid committing an environment-specific workaround to shared build config.

kotlin.incremental=false applies globally, so it disables incremental Kotlin compilation for every developer and CI, even though the comment ties the problem to one contributor's specific Windows drive layout (project on D:, Pub cache on C:). This trades a build-speed regression for everyone to work around a local environment quirk.

Prefer keeping this in the affected user's ~/.gradle/gradle.properties (or GRADLE_USER_HOME) instead of the repo. If it must stay in-repo, consider scoping it so the slowdown isn't imposed unconditionally.

♻️ Option: keep repo default fast, override locally
-# Project on D: with Pub cache on C: breaks Kotlin incremental compilation on Windows.
-kotlin.incremental=false

Then, on the affected machine only, add to %USERPROFILE%\.gradle\gradle.properties:

# Local-only: project on D: with Pub cache on C: breaks Kotlin incremental compilation on Windows.
kotlin.incremental=false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@android/gradle.properties` around lines 4 - 5, Remove the repository-wide
kotlin.incremental=false entry (the global property key `kotlin.incremental`)
from the committed gradle.properties so you don't disable incremental Kotlin
compilation for all developers/CI; instead instruct the contributor to place
that setting in their local Gradle user properties
(`%USERPROFILE%\.gradle\gradle.properties` or `GRADLE_USER_HOME`) or implement a
conditional mechanism (e.g., environment-variable gated check) so the slowdown
is only applied on the affected Windows machine rather than in-repo.
pubspec.yaml (1)

13-13: ⚡ Quick win

Consider constraining the intl version.

Using intl: any is permissive and could lead to version conflicts. While the generated code suggests using the pinned version from flutter_localizations, specifying any doesn't enforce this. Consider using a version constraint like ^0.18.0 or relying on flutter_localizations to transitively bring in the appropriate version without explicitly declaring it here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pubspec.yaml` at line 13, The pubspec currently uses an unconstrained
dependency "intl: any", which can cause version conflicts; change the constraint
in pubspec.yaml to a specific compatible range (for example ^0.18.0) or remove
the explicit "intl" entry and rely on flutter_localizations to transitively
provide the correct intl version; update the dependency declaration for "intl"
accordingly so tools resolve a stable, compatible version.
lib/features/auth/username_setup_page.dart (1)

74-94: 💤 Low value

Consider creating a single l10n variable in _saveUsername to avoid repeated lookups.

Lines 74, 82, and 94 each call AppLocalizations.of(context)! separately. While functionally correct, creating final l10n = AppLocalizations.of(context)!; once at the start of the _saveUsername method would be more efficient and consistent with the pattern used in build.

♻️ Suggested refactor
 Future<void> _saveUsername() async {
+  final l10n = AppLocalizations.of(context)!;
   final validationError = _validateUsername();
   if (validationError != null) {
     setState(() => _errorText = validationError);
     return;
   }
   
   // ... rest of method ...
   
   if (!isTakenResult.isSuccess) {
     setState(() {
       _isSubmitting = false;
-      _errorText = isTakenResult.error ?? AppLocalizations.of(context)!.authUsernameSaveFailed;
+      _errorText = isTakenResult.error ?? l10n.authUsernameSaveFailed;
     });
     return;
   }

   if (isTakenResult.value == true) {
     setState(() {
       _isSubmitting = false;
-      _errorText = AppLocalizations.of(context)!.authUsernameTakenError;
+      _errorText = l10n.authUsernameTakenError;
     });
     return;
   }
   
   // ... more code ...
   
   if (!saveResult.isSuccess) {
     setState(() {
       _isSubmitting = false;
-      _errorText = saveResult.error ?? AppLocalizations.of(context)!.authUsernameSaveFailed;
+      _errorText = saveResult.error ?? l10n.authUsernameSaveFailed;
     });
     return;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/auth/username_setup_page.dart` around lines 74 - 94, In
_saveUsername, avoid repeated AppLocalizations.of(context)! calls by creating a
single local variable (e.g., final l10n = AppLocalizations.of(context)!) at the
top of the method, then replace the three occurrences where you use
AppLocalizations.of(context)! (used to assign _errorText for
authUsernameSaveFailed and authUsernameTakenError and any other localized
strings) with l10n to improve consistency and slight performance.
lib/features/checkout/widgets/share_location_dialog.dart (1)

13-36: ⚡ Quick win

Consider localizing the dialog content for consistency.

The dialog's Cancel and Ok buttons are now localized (lines 31, 36), but the main dialog message at line 20 still uses AppStrings.wantToShareLocation. For a consistent user experience, the dialog content should also be localized when the action buttons are.

💬 Suggested fix
 Text(
-  AppStrings.wantToShareLocation,
+  l10n.checkoutShareLocationMessage,
   style: Theme.of(context).textTheme.titleSmall,
 ),

Note: This assumes checkoutShareLocationMessage is added to the ARB file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/checkout/widgets/share_location_dialog.dart` around lines 13 -
36, Replace the hardcoded string reference AppStrings.wantToShareLocation in the
AlertDialog body with the localized resource from the l10n instance (e.g.,
l10n.checkoutShareLocationMessage), ensuring the ARB/localization files include
checkoutShareLocationMessage; keep the existing usage of l10n for the action
buttons and leave the Confirm handler
(context.read<CheckoutViewModel>().onConfirmLocation) unchanged.
lib/features/checkout/checkout_page.dart (1)

50-58: ⚡ Quick win

Reuse the l10n variable instead of calling AppLocalizations.of(context)! again.

Line 50 creates l10n, but line 58 calls AppLocalizations.of(context)! directly instead of reusing it. This is inconsistent and performs an unnecessary lookup.

♻️ Suggested fix
 if (status == StatusType.success) {
-  Fluttertoast.showToast(msg: AppLocalizations.of(context)!.checkoutPaymentSuccessfulToast);
+  Fluttertoast.showToast(msg: l10n.checkoutPaymentSuccessfulToast);
   vm.resetCreateOrderStatus();
   vm.gotoCheckoutComplete();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/checkout/checkout_page.dart` around lines 50 - 58, The success
branch is calling AppLocalizations.of(context)! directly instead of reusing the
already-created l10n variable; replace the direct lookup with the existing l10n
instance (use l10n.checkoutPaymentSuccessfulToast) so the code consistently
reuses l10n (ensure l10n is in scope where the StatusType.success branch runs).
lib/features/discover/discover_page.dart (1)

25-25: 💤 Low value

Consider caching the localization instance for consistency.

While functionally correct, this file calls AppLocalizations.of(context)! inline, whereas all other files in this PR cache it as final l10n = AppLocalizations.of(context)!; at the start of build(). For consistency and to avoid repeated lookups if more localized strings are added later, consider adopting the same pattern:

♻️ Proposed refactor for consistency
 `@override`
 Widget build(BuildContext context) {
+  final l10n = AppLocalizations.of(context)!;
   return Scaffold(
     body: Consumer<DiscoverViewModel>(
       builder: (context, viewModel, _) {
         final charities = viewModel.fetchCharities();
         final products = viewModel.fetchProducts();

         return SafeArea(
           bottom: false,
           child: CustomScrollView(
             slivers: [
               SliverAppBar(
-                title: Text(AppLocalizations.of(context)!.navDiscoverTitle),
+                title: Text(l10n.navDiscoverTitle),
                 floating: true,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/discover/discover_page.dart` at line 25, The code calls
AppLocalizations.of(context)! inline in the widget tree (title:
Text(AppLocalizations.of(context)!.navDiscoverTitle)) rather than caching it;
update the build() method to declare final l10n = AppLocalizations.of(context)!
at the top and replace the inline call with l10n.navDiscoverTitle to match other
files and avoid repeated lookups.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/features/password_flow/not_you_page/not_you_page.dart`:
- Line 67: The TextField in not_you_page.dart is using l10n.authEmailLabel as
its hintText which should be the placeholder string; update the hint to use
l10n.authEmailHint instead. Locate the TextField instance in the NotYouPage
widget (or the build method) and replace the hintText reference from
authEmailLabel to authEmailHint so the placeholder matches login_form.dart and
the rest of the auth flow.

In `@lib/l10n/app_en.arb`:
- Line 34: The string value for the localization key authUsernameSetupSubtitle
contains a grammatical mistake ("you will like"); update the localized text to
proper grammar by changing the value to "Enter the name you would like to go
by." so the user-facing message reads correctly.

---

Nitpick comments:
In `@android/gradle.properties`:
- Around line 4-5: Remove the repository-wide kotlin.incremental=false entry
(the global property key `kotlin.incremental`) from the committed
gradle.properties so you don't disable incremental Kotlin compilation for all
developers/CI; instead instruct the contributor to place that setting in their
local Gradle user properties (`%USERPROFILE%\.gradle\gradle.properties` or
`GRADLE_USER_HOME`) or implement a conditional mechanism (e.g.,
environment-variable gated check) so the slowdown is only applied on the
affected Windows machine rather than in-repo.

In `@lib/features/auth/username_setup_page.dart`:
- Around line 74-94: In _saveUsername, avoid repeated
AppLocalizations.of(context)! calls by creating a single local variable (e.g.,
final l10n = AppLocalizations.of(context)!) at the top of the method, then
replace the three occurrences where you use AppLocalizations.of(context)! (used
to assign _errorText for authUsernameSaveFailed and authUsernameTakenError and
any other localized strings) with l10n to improve consistency and slight
performance.

In `@lib/features/checkout/checkout_page.dart`:
- Around line 50-58: The success branch is calling AppLocalizations.of(context)!
directly instead of reusing the already-created l10n variable; replace the
direct lookup with the existing l10n instance (use
l10n.checkoutPaymentSuccessfulToast) so the code consistently reuses l10n
(ensure l10n is in scope where the StatusType.success branch runs).

In `@lib/features/checkout/widgets/share_location_dialog.dart`:
- Around line 13-36: Replace the hardcoded string reference
AppStrings.wantToShareLocation in the AlertDialog body with the localized
resource from the l10n instance (e.g., l10n.checkoutShareLocationMessage),
ensuring the ARB/localization files include checkoutShareLocationMessage; keep
the existing usage of l10n for the action buttons and leave the Confirm handler
(context.read<CheckoutViewModel>().onConfirmLocation) unchanged.

In `@lib/features/discover/discover_page.dart`:
- Line 25: The code calls AppLocalizations.of(context)! inline in the widget
tree (title: Text(AppLocalizations.of(context)!.navDiscoverTitle)) rather than
caching it; update the build() method to declare final l10n =
AppLocalizations.of(context)! at the top and replace the inline call with
l10n.navDiscoverTitle to match other files and avoid repeated lookups.

In `@pubspec.yaml`:
- Line 13: The pubspec currently uses an unconstrained dependency "intl: any",
which can cause version conflicts; change the constraint in pubspec.yaml to a
specific compatible range (for example ^0.18.0) or remove the explicit "intl"
entry and rely on flutter_localizations to transitively provide the correct intl
version; update the dependency declaration for "intl" accordingly so tools
resolve a stable, compatible version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a3ee7e88-43bc-4180-b090-dbe413ebdb76

📥 Commits

Reviewing files that changed from the base of the PR and between 132c18f and be664f2.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • android/app/build.gradle.kts
  • android/gradle.properties
  • l10n.yaml
  • lib/features/auth/username_setup_page.dart
  • lib/features/checkout/checkout_page.dart
  • lib/features/checkout/widgets/delivery_options.dart
  • lib/features/checkout/widgets/share_location_dialog.dart
  • lib/features/discover/discover_page.dart
  • lib/features/discover/widgets/discover_selection_bar.dart
  • lib/features/home/widgets/bottom_nav_bar.dart
  • lib/features/login/login_page.dart
  • lib/features/login/widgets/login_form.dart
  • lib/features/password_flow/not_you_page/not_you_page.dart
  • lib/features/products/product_page.dart
  • lib/features/products/widgets/seller_information.dart
  • lib/features/register/register_page.dart
  • lib/features/register/verify_email_page.dart
  • lib/features/register/widgets/register_form.dart
  • lib/features/settings/widgets/settings_category_group.dart
  • lib/features/welcome/welcome_page.dart
  • lib/features/welcome/widgets/signup_card.dart
  • lib/l10n/app_en.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_en.dart
  • lib/main.dart
  • pubspec.yaml
  • test/auth_ui_test.dart
  • test/auth_ui_test.mocks.dart
  • test/checkout_view_model_test.mocks.dart
  • test/widget_test.dart

TextField(
decoration: InputDecoration(
hintText: AppStrings.email,
hintText: l10n.authEmailLabel,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use authEmailHint for the field hint, not authEmailLabel.

This TextField uses l10n.authEmailLabel as its hintText, whereas login_form.dart (Line 83) uses l10n.authEmailHint for the equivalent hint. The label string (e.g. "Email") reads incorrectly as placeholder text; this is inconsistent with the rest of the auth flow.

Proposed fix
-                          hintText: l10n.authEmailLabel,
+                          hintText: l10n.authEmailHint,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hintText: l10n.authEmailLabel,
hintText: l10n.authEmailHint,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/password_flow/not_you_page/not_you_page.dart` at line 67, The
TextField in not_you_page.dart is using l10n.authEmailLabel as its hintText
which should be the placeholder string; update the hint to use
l10n.authEmailHint instead. Locate the TextField instance in the NotYouPage
widget (or the build method) and replace the hintText reference from
authEmailLabel to authEmailHint so the placeholder matches login_form.dart and
the rest of the auth flow.

Comment thread lib/l10n/app_en.arb
"authSendEmailButton": "Send email",
"authNotYouLink": "Not you",
"authUsernameSetupTitle": "Who is this?",
"authUsernameSetupSubtitle": "Enter the name you will like to go by.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Grammatical error in user-facing text.

The phrase "you will like" should be "you would like" for proper grammar.

📝 Suggested correction
-  "authUsernameSetupSubtitle": "Enter the name you will like to go by.",
+  "authUsernameSetupSubtitle": "Enter the name you would like to go by.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"authUsernameSetupSubtitle": "Enter the name you will like to go by.",
"authUsernameSetupSubtitle": "Enter the name you would like to go by.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/l10n/app_en.arb` at line 34, The string value for the localization key
authUsernameSetupSubtitle contains a grammatical mistake ("you will like");
update the localized text to proper grammar by changing the value to "Enter the
name you would like to go by." so the user-facing message reads correctly.

@CherryCIC

CherryCIC commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Hey @AsadAli93916 thank you for this.

However, due to the structure of cherry and how logistics processes work with it, we can't have an 'add to cart' option available.

@CherryCIC

Copy link
Copy Markdown
Collaborator

@AsadAli93916 which issue does this aim to fix? 🫶

@CherryCIC

CherryCIC commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Hey @AsadAli93916 is this aiming to do: #381 (comment)

Before I can merge, we need to clarify the scope and fix the merge conflicts.

Other than that, coderabbit came back positive and I see no immediately pressing issues.

Thank you for this work, it is not an overstatement to say you are supporting us in our mission to help charities through this difficult and increasingly digital time.

I appreciate your efforts.

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