Skip to content

fix(i18n): complete UI localization and harden locale fallback - #201

Merged
AndreaDiazCorreia merged 30 commits into
mainfrom
fix/i18n-locale-consistency
Jul 22, 2026
Merged

fix(i18n): complete UI localization and harden locale fallback#201
AndreaDiazCorreia merged 30 commits into
mainfrom
fix/i18n-locale-consistency

Conversation

@AndreaDiazCorreia

@AndreaDiazCorreia AndreaDiazCorreia commented Jul 21, 2026

Copy link
Copy Markdown
Member

Closes #162.

Localizes the remaining hardcoded UI strings across every feature (drawer, walkthrough, account, settings, trades, chat, order, disputes, rate, home) so switching language translates the whole UI. Adds ~300 keys, kept at full parity across en/es/fr/de/it (582/582, verified by an empty gen-l10n untranslated-messages report).

The original issue assumed ~52% of keys were missing; that was a metadata counting artifact. Key parity was already complete — the real gap was strings that never went through AppLocalizations.

Also:

  • localeProvider now validates the language against supportedLocales and falls back intentionally; first run defaults to the device language when supported (behavior change: users who never picked a language now get their device locale instead of English).
  • Enables untranslated-messages-file in l10n.yaml so CI can fail when a new key lands untranslated.

Out of scope (separate issues): notification model strings and the Rust CantDo prose-to-marker debt.

Note: Spanish reviewed by the author; fr/de/it are a solid base pending native review.

Summary by CodeRabbit

  • New Features
    • Rolled out comprehensive UI localization across account, backup/secret words, wallet/NWC, trading, chat, disputes, settings, notifications, orders, and walkthrough experiences.
    • Expanded English, German, Spanish, French, and Italian translations with new flow copy, validation, and success/error messages.
  • Bug Fixes
    • Improved language preference handling by normalizing stored language codes and reliably falling back to a supported device language.
  • Tests / Chores
    • Added a CI localization completeness check to prevent untranslated keys from being shipped.

Replace hardcoded English text in walkthrough slides with localized strings from AppLocalizations. Moves slide titles and bodies (6 slides), plus "Skip" and "Done" button labels, into l10n system.
Replace all hardcoded English text in account_screen.dart with localized strings from AppLocalizations. Adds 18 new l10n keys across en/de/es/fr/it for error messages, dialog content, button labels, tooltips, and UI text including:
Replace hardcoded English text in backup_ritual_screen.dart and backup_trigger_sheet.dart with localized strings from AppLocalizations. Adds 28 new l10n keys across en/de/es/fr/it for:
Replace hardcoded English text in connect_wallet_screen.dart and wallet_settings_screen.dart with localized strings from AppLocalizations. Adds 16 new l10n keys across en/de/es/fr/it for error messages, button labels, field labels, and UI text including connection status, wallet info rows, and relay formatting.
Replace hardcoded English text in notification_settings_screen.dart and currency_selector_dialog.dart with localized strings from AppLocalizations. Adds 11 new l10n keys across en/de/es/fr/it for notification toggle titles/subtitles (trade updates, new messages, payment alerts, dispute updates), screen subtitle, and currency search UI (dialog title, search hint, no results message).
Replace hardcoded English text in log_report_screen.dart and mostro_node_selector.dart with localized strings from AppLocalizations. Adds 15 new l10n keys across en/de/es/fr/it for:
Replace hardcoded English text in trades feature with localized strings from AppLocalizations. Adds 29 new l10n keys across en/de/es/fr/it for:
Replace hardcoded English text in trade_detail_screen.dart with localized strings from AppLocalizations.
Replace hardcoded English text in chat_room_screen.dart, chat_rooms_screen.dart, and info_panels.dart with localized strings from AppLocalizations. Adds 27 new l10n keys across en/de/es/fr/it for error messages, tooltips, tab labels, empty states, and trade/user information panel content including field labels, placeholders, and safety notes.
Replace hardcoded English text in add_lightning_invoice_screen.dart, add_order_screen.dart, and take_order_screen.dart with localized strings from AppLocalizations.
Replace hardcoded English text in currency_section.dart, order_preset_selector.dart, payment_method_section.dart, price_section.dart, and range_amount_modal.dart with localized strings from AppLocalizations.
Replace hardcoded English text in dispute_chat_screen.dart, dispute_messages_list.dart, disputes_list.dart, rate_counterpart_screen.dart, star_rating.dart, and home_screen.dart with localized strings from AppLocalizations. Adds 8 new l10n keys across en/de/es/fr/it for dispute details (title, IDs, reason, admin label), rating UI (submit/close buttons, star tooltips, error messages), and menu tooltip.
Replace hardcoded 'en' default with device language when supported by AppLocalizations. Add validation in localeProvider to fall back to English when stored language is unknown or corrupted. Extracts supported language codes from AppLocalizations.supportedLocales to ensure consistency between settings and available translations.
Add untranslated-messages-file to l10n.yaml to track missing translations across locales. Ignore generated lib/l10n/untranslated_messages.txt from version control as it's regenerated by flutter gen-l10n and intended for CI validation.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@AndreaDiazCorreia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e392cb1a-dd90-4a7e-a1b2-2f3423da1605

📥 Commits

Reviewing files that changed from the base of the PR and between 28be4fb and 2ef53b3.

📒 Files selected for processing (17)
  • lib/features/disputes/providers/disputes_providers.dart
  • lib/features/disputes/widgets/dispute_list_item.dart
  • lib/features/drawer/screens/drawer_menu.dart
  • lib/features/order/screens/my_order_screen.dart
  • lib/features/order/screens/pay_lightning_invoice_screen.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart
  • lib/shared/widgets/notification_bell.dart

Walkthrough

This PR expands localization coverage across the Flutter app, adds translations for five locales, normalizes selected language codes, updates localized UI flows, and adds CI validation for untranslated messages.

Changes

i18n completion across app

Layer / File(s) Summary
Localization contract and translation catalogs
lib/l10n/*, .gitignore, l10n.yaml
Adds localization keys and implementations for account, wallet, trade, chat, order, dispute, rating, notification, and settings UI, with translations in English, German, Spanish, French, and Italian.
Feature UI localization
lib/features/*, lib/shared/widgets/*
Replaces hardcoded user-visible strings across account, chat, disputes, navigation, orders, rating, settings, trades, notifications, walkthroughs, and shared widgets with AppLocalizations lookups.
Locale normalization and validation
lib/features/settings/providers/settings_provider.dart, test/features/settings/settings_provider_test.dart
Normalizes stored and incoming language codes against supported locales, applies device-locale fallback, and tests persistence and provider consistency.
Localization CI enforcement and regression tests
.github/workflows/ci.yml, test/features/walkthrough/highlight_config_test.dart, lib/features/walkthrough/utils/highlight_config.dart
Checks that generated localization reports contain no untranslated keys and verifies walkthrough highlighting across supported locales.

Estimated code review effort: 4 (Complex) | ~75 minutes

Suggested reviewers: grunch

Poem

A rabbit hops where strings once hid,
Now every screen speaks as it should.
Five tongues bloom from one small key,
CI checks them carefully. 🐰

🚥 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 is concise and accurately summarizes the main localization and locale-fallback changes.
Linked Issues check ✅ Passed The PR addresses #162 by replacing hardcoded strings, adding translations, normalizing locale fallback, and adding tests.
Out of Scope Changes check ✅ Passed The changes stay focused on localization, locale fallback, CI checks, and related tests without clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/i18n-locale-consistency

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 666936e13c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread l10n.yaml

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/l10n/app_localizations_de.dart (1)

680-681: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use one pronoun register in the German cancellation dialog.

This switches to formal “Sie” while the surrounding German UI consistently addresses users with informal “du”. Use the informal form here as well.

Proposed fix
-      'Sind Sie sicher, dass Sie dieses Angebot stornieren möchten? Diese Aktion kann nicht rückgängig gemacht werden.';
+      'Bist du sicher, dass du dieses Angebot stornieren möchtest? Diese Aktion kann nicht rückgängig gemacht werden.';
🤖 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_localizations_de.dart` around lines 680 - 681, Update the
cancelOrderDialogContent getter to use the informal German “du” pronoun
consistently, replacing the formal “Sie” wording while preserving the message’s
meaning and cancellation warning.
lib/features/chat/screens/chat_room_screen.dart (1)

174-187: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Fix ref.watch and AppLocalizations usage in event handlers.

_resolveRoom() relies on ref.watch and AppLocalizations.of(context). It is called by _buildRoomPreview(), which is triggered during _onSend (an async callback) and _onIncomingMessage (a stream listener).

Using ref.watch inside an event handler unconditionally throws a Riverpod StateError (ref.watch can only be used inside the build method...). Furthermore, retrieving AppLocalizations.of(context) from inside an event handler or after an async gap is an anti-pattern that can cause unexpected dependency registrations or context-lookup errors.

To fix this, retrieve the localized strings before the async gap and retrieve chatRoomsNotifierProvider securely using ref.read when inside event handlers.

🐛 Proposed fixes

Refactor _resolveRoom to accept the room list and the localized handle:

-  ChatRoomState _resolveRoom() {
-    final rooms = ref.watch(chatRoomsNotifierProvider);
+  ChatRoomState _resolveRoom(List<ChatRoomState> rooms, AppLocalizations l10n) {
     return rooms.firstWhere(
       (r) => r.orderId == widget.orderId,
       orElse: () => ChatRoomState(
         orderId: widget.orderId,
         peerPubkey: '',
-        peerHandle: AppLocalizations.of(context).unknownPeerHandle,
+        peerHandle: l10n.unknownPeerHandle,
         peerIconIndex: 0,
         peerColorHue: 180,
         isSelling: false,
       ),
     );
   }

Update its usage in _buildRoomPreview to execute a safe ref.read:

-  ChatRoomState _buildRoomPreview({required rust_types.ChatMessage lastMsg}) {
-    final room = _resolveRoom();
+  ChatRoomState _buildRoomPreview({
+    required rust_types.ChatMessage lastMsg,
+    required AppLocalizations l10n,
+  }) {
+    final rooms = ref.read(chatRoomsNotifierProvider);
+    final room = _resolveRoom(rooms, l10n);

Update _onSend to cache the localizations before the async gap:

   Future<void> _onSend(String text) async {
     if (text.trim().isEmpty || _isSending) return;
+    final l10n = AppLocalizations.of(context);
     setState(() => _isSending = true);
     try {
       final sent = await messages_api.sendMessage(
         tradeId: widget.orderId,
         content: text.trim(),
       );
       if (!mounted) return;
       setState(() => _messages.add(sent));
       _scrollToBottom();
       ref.read(chatRoomsNotifierProvider.notifier).upsertRoom(
-            _buildRoomPreview(lastMsg: sent),
+            _buildRoomPreview(lastMsg: sent, l10n: l10n),
           );
     } catch (e) {
       if (!mounted) return;
       ScaffoldMessenger.of(context).showSnackBar(
         SnackBar(
-          content: Text(AppLocalizations.of(context).messageSendFailed),
+          content: Text(l10n.messageSendFailed),
           backgroundColor: Colors.red,
         ),
       );
     } finally {

Update _onIncomingMessage to pass the localizations:

   void _onIncomingMessage(rust_types.ChatMessage msg) {
     if (_messages.any((m) => m.id == msg.id)) return; // deduplicate
+    final l10n = AppLocalizations.of(context);
     setState(() => _messages.add(msg));
     _scrollToBottom();
     _markRead();
     ref.read(chatRoomsNotifierProvider.notifier).upsertRoom(
-          _buildRoomPreview(lastMsg: msg),
+          _buildRoomPreview(lastMsg: msg, l10n: l10n),
         );
   }

Update build to pass the required arguments using ref.watch:

-    final room = _resolveRoom();
-    final colors = Theme.of(context).extension<AppColors>();
-    if (colors == null) {
-      throw StateError('AppColors theme extension must be registered');
-    }
-    final l10n = AppLocalizations.of(context);
+    final l10n = AppLocalizations.of(context);
+    final room = _resolveRoom(ref.watch(chatRoomsNotifierProvider), l10n);
+    final colors = Theme.of(context).extension<AppColors>();
+    if (colors == null) {
+      throw StateError('AppColors theme extension must be registered');
+    }
🤖 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/chat/screens/chat_room_screen.dart` around lines 174 - 187,
Refactor _resolveRoom to accept the current room list and localized unknown-peer
handle instead of accessing ref or context. In event-driven _buildRoomPreview,
_onSend, and _onIncomingMessage, obtain rooms with
ref.read(chatRoomsNotifierProvider) and capture AppLocalizations before any
async gap, then pass both values through. Keep build’s reactive path using
ref.watch and pass the watched rooms and localized handle into
_buildRoomPreview.
🧹 Nitpick comments (3)
lib/features/disputes/widgets/dispute_messages_list.dart (1)

196-196: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using a more generic key for the copied-to-clipboard message.

The key aboutCopiedToClipboard is prefixed with about, indicating it was created specifically for the About screen. To improve maintainability and avoid unexpected translations in other contexts, consider creating a generic copiedToClipboard key, or reuse the existing messageCopied key if appropriate.

🤖 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/disputes/widgets/dispute_messages_list.dart` at line 196,
Replace the About-specific localization reference in the dispute message
copy-confirmation UI with a generic copied-to-clipboard key, reusing the
existing messageCopied key if it provides the intended wording; otherwise add
and use copiedToClipboard across localization resources.
lib/l10n/app_localizations.dart (1)

2027-2037: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Keep translatable sentences intact instead of splitting them into fragments.

These getters divide complete sentences around styled text or interpolated values. That prevents languages from reordering clauses naturally and can produce awkward or incorrect translations. Use one localized message with placeholders/markup, then style the relevant span after formatting.

Also applies to: 2105-2115, 3275-3285, 3323-3333

🤖 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_localizations.dart` around lines 2027 - 2037, Update the
localization entries represented by backupRitualWarningTitle and
backupRitualWarningBody, along with the referenced entries, so each translatable
sentence is defined as one complete localized message rather than split
fragments. Use placeholders or markup for styled/interpolated spans, then apply
styling after formatting while preserving natural clause reordering for each
locale.
lib/features/chat/widgets/encrypted_file_message.dart (1)

122-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Retrieve AppLocalizations before the async gap.

Looking up AppLocalizations.of(context) after an await can be risky or trigger linter warnings (e.g., use_build_context_synchronously) because the widget's position in the tree or its dependencies might have shifted. It is best practice to cache inherited widget dependencies before entering an async gap.

♻️ Proposed fix
   Future<void> _startDownload(BuildContext context) async {
+    final l10n = AppLocalizations.of(context);
     setState(() => _downloading = true);
     await Future<void>.delayed(const Duration(milliseconds: 1500));
     if (!mounted) return;
     setState(() => _downloading = false);
     // Use this.context (State.context) which is guarded by the mounted check above.
     ScaffoldMessenger.of(this.context).showSnackBar(
       SnackBar(
-        content: Text(AppLocalizations.of(this.context).fileDownloadPlaceholder),
+        content: Text(l10n.fileDownloadPlaceholder),
         duration: const Duration(seconds: 2),
       ),
     );
   }
🤖 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/chat/widgets/encrypted_file_message.dart` around lines 122 -
124, Cache AppLocalizations before the async gap in the surrounding
file-download flow, then use the cached localization when constructing the
SnackBar in place of AppLocalizations.of(this.context). Keep the existing
fileDownloadPlaceholder message and SnackBar behavior unchanged.
🤖 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/l10n/app_en.arb`:
- Around line 809-814: Remove the duplicate mostroNodeTitle and
trustedBadgeLabel entries and their metadata from lib/l10n/app_en.arb lines
809-814, preserving currentNodePublicKeyLabel; remove the duplicate
mostroNodeTitle and trustedBadgeLabel entries from lib/l10n/app_de.arb,
lib/l10n/app_es.arb, lib/l10n/app_fr.arb, and lib/l10n/app_it.arb at lines
394-396, leaving the earlier definitions intact.

In `@lib/l10n/app_localizations_de.dart`:
- Around line 1608-1610: Update the secureChatUnread method so its German label
includes the noun “Nachrichten” after the count, producing wording such as
“Sicherer Chat · 3 neue Nachrichten.”

---

Outside diff comments:
In `@lib/features/chat/screens/chat_room_screen.dart`:
- Around line 174-187: Refactor _resolveRoom to accept the current room list and
localized unknown-peer handle instead of accessing ref or context. In
event-driven _buildRoomPreview, _onSend, and _onIncomingMessage, obtain rooms
with ref.read(chatRoomsNotifierProvider) and capture AppLocalizations before any
async gap, then pass both values through. Keep build’s reactive path using
ref.watch and pass the watched rooms and localized handle into
_buildRoomPreview.

In `@lib/l10n/app_localizations_de.dart`:
- Around line 680-681: Update the cancelOrderDialogContent getter to use the
informal German “du” pronoun consistently, replacing the formal “Sie” wording
while preserving the message’s meaning and cancellation warning.

---

Nitpick comments:
In `@lib/features/chat/widgets/encrypted_file_message.dart`:
- Around line 122-124: Cache AppLocalizations before the async gap in the
surrounding file-download flow, then use the cached localization when
constructing the SnackBar in place of AppLocalizations.of(this.context). Keep
the existing fileDownloadPlaceholder message and SnackBar behavior unchanged.

In `@lib/features/disputes/widgets/dispute_messages_list.dart`:
- Line 196: Replace the About-specific localization reference in the dispute
message copy-confirmation UI with a generic copied-to-clipboard key, reusing the
existing messageCopied key if it provides the intended wording; otherwise add
and use copiedToClipboard across localization resources.

In `@lib/l10n/app_localizations.dart`:
- Around line 2027-2037: Update the localization entries represented by
backupRitualWarningTitle and backupRitualWarningBody, along with the referenced
entries, so each translatable sentence is defined as one complete localized
message rather than split fragments. Use placeholders or markup for
styled/interpolated spans, then apply styling after formatting while preserving
natural clause reordering for each locale.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68545296-254f-4a9b-a1a6-1247953c3c39

📥 Commits

Reviewing files that changed from the base of the PR and between 44ebe94 and 666936e.

📒 Files selected for processing (54)
  • .gitignore
  • l10n.yaml
  • lib/features/account/screens/account_screen.dart
  • lib/features/account/screens/backup_ritual_screen.dart
  • lib/features/account/widgets/backup_trigger_sheet.dart
  • lib/features/chat/screens/chat_room_screen.dart
  • lib/features/chat/screens/chat_rooms_screen.dart
  • lib/features/chat/widgets/chat_list_item.dart
  • lib/features/chat/widgets/encrypted_file_message.dart
  • lib/features/chat/widgets/encrypted_image_message.dart
  • lib/features/chat/widgets/info_panels.dart
  • lib/features/chat/widgets/message_bubble.dart
  • lib/features/chat/widgets/message_input.dart
  • lib/features/chat/widgets/trade_state_header.dart
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • lib/features/disputes/widgets/dispute_messages_list.dart
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/features/drawer/screens/drawer_menu.dart
  • lib/features/home/screens/home_screen.dart
  • lib/features/order/screens/add_lightning_invoice_screen.dart
  • lib/features/order/screens/add_order_screen.dart
  • lib/features/order/screens/take_order_screen.dart
  • lib/features/order/widgets/currency_section.dart
  • lib/features/order/widgets/order_preset_selector.dart
  • lib/features/order/widgets/payment_method_section.dart
  • lib/features/order/widgets/price_section.dart
  • lib/features/order/widgets/range_amount_modal.dart
  • lib/features/rate/screens/rate_counterpart_screen.dart
  • lib/features/rate/widgets/star_rating.dart
  • lib/features/settings/providers/settings_provider.dart
  • lib/features/settings/screens/connect_wallet_screen.dart
  • lib/features/settings/screens/log_report_screen.dart
  • lib/features/settings/screens/notification_settings_screen.dart
  • lib/features/settings/screens/wallet_settings_screen.dart
  • lib/features/settings/widgets/currency_selector_dialog.dart
  • lib/features/settings/widgets/mostro_node_selector.dart
  • lib/features/trades/providers/trades_providers.dart
  • lib/features/trades/screens/trade_detail_screen.dart
  • lib/features/trades/screens/trades_screen.dart
  • lib/features/trades/widgets/release_confirmation_dialog.dart
  • lib/features/trades/widgets/trade_info_cards.dart
  • lib/features/trades/widgets/trades_list_item.dart
  • lib/features/walkthrough/screens/walkthrough_screen.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart

Comment thread lib/l10n/app_en.arb Outdated
Comment thread lib/l10n/app_localizations_de.dart
…ings

Update AppLocalizations documentation for mostroNodeTitle and trustedBadgeLabel to reflect their actual usage context. Remove unused mostroNodeTitle and trustedBadgeLabel keys from de/es/fr/it translations. Change Italian trustedBadgeLabel from 'Attendibile' to 'Affidabile' for consistency.
…dRoomPreview

Move AppLocalizations and chatRoomsNotifierProvider reads to call sites instead of accessing them inside _resolveRoom and _buildRoomPreview methods. This makes dependencies explicit and improves testability by removing context/ref access from helper methods.
…at message string

Change cancelOrderDialogContent from formal 'Sie' to informal 'du' for consistency with app tone. Complete secureChatUnread string by adding 'Nachrichten' (messages) after count to match other language implementations.
Add workflow step to validate all l10n keys are translated across locales by running flutter gen-l10n and checking untranslated_messages.txt report. Fails build if any locale is missing keys that exist in app_en.arb template.

@ermeme ermeme 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.

Requesting changes for two user-visible gaps in the current head:

  1. The PR still leaves core, reachable UI hardcoded in English, despite closing #162 and claiming that locale switching translates the whole UI. For example, lib/shared/widgets/bottom_nav_bar.dart still hardcodes Order Book, My Trades, and Chat (lines 55, 68, 81), and lib/shared/widgets/order_filter.dart still hardcodes the complete home filter dialog (Filters, Reset, Currency, Payment Method, Rating, Premium, Apply; lines 65-181). These widgets are directly used by Home/Trades/Chat, so changing to Spanish/French/etc. still leaves primary navigation and a main workflow in English. Please finish the shared UI audit (including other reachable shared widgets) or explicitly split and track the remaining scope instead of closing #162 as complete.

  2. The saved-language fallback only normalizes the Locale; it does not normalize AppSettingsState.language. An unsupported or region-qualified stored value can therefore render one locale while Settings displays the raw code and the language picker has no selected item. The state and effective locale need to agree.

CI is green and the ARB files parse cleanly with full 582-key parity and matching placeholders, but these two behavioral gaps block approval.

Comment thread lib/features/settings/providers/settings_provider.dart Outdated
Add 13 new localization keys across en/de/es/fr/it for filter dialog (title, reset/apply buttons, currency/rating labels), Lightning invoice UI (copy/share buttons, send prompt, change button, success label), and add-order button (buy/sell labels). Replace hardcoded English text in add_order_button.dart and bottom_nav_bar.dart with localized strings from AppLocalizations.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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 @.github/workflows/ci.yml:
- Around line 108-121: Update the “Check localizations are fully translated”
workflow step to fail when lib/l10n/untranslated_messages.txt is missing, rather
than treating absence as success. Preserve the existing "{}" success condition
and non-empty report failure behavior, and keep the validation anchored to the
report variable.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a14c1d03-0cad-45c4-8e85-936d9d61c147

📥 Commits

Reviewing files that changed from the base of the PR and between 666936e and c369944.

📒 Files selected for processing (21)
  • .github/workflows/ci.yml
  • lib/features/chat/screens/chat_room_screen.dart
  • lib/features/settings/providers/settings_provider.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart
  • lib/shared/widgets/add_order_button.dart
  • lib/shared/widgets/bottom_nav_bar.dart
  • lib/shared/widgets/ln_address_confirmation_widget.dart
  • lib/shared/widgets/mostro_reactive_button.dart
  • lib/shared/widgets/order_filter.dart
  • lib/shared/widgets/pay_lightning_invoice_widget.dart
  • test/features/settings/settings_provider_test.dart
🚧 Files skipped from review as they are similar to previous changes (11)
  • lib/features/settings/providers/settings_provider.dart
  • lib/l10n/app_de.arb
  • lib/features/chat/screens/chat_room_screen.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_fr.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_en.arb
  • lib/l10n/app_localizations_en.dart

Comment thread .github/workflows/ci.yml

@ermeme ermeme 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.

The two blockers from my previous review are materially improved: the shared navigation/filter/payment widgets are now localized, and saved regional/unsupported language strings are normalized at the state boundary with focused tests. ARB parity, placeholders, duplicate-key checks, and current CI are clean.

I am still requesting changes on the current head for these issues:

  1. The whole-UI completion claim is still false outside the explicitly excluded notification model prose. The reachable Notifications UI remains hardcoded in English: lib/features/notifications/screens/notifications_screen.dart:40,55,59,194; notification_group_card.dart:368,372; system_notification_banner.dart:159,163; and notification_card.dart:226,230. The PR closes #162 and excludes notification model strings, not the notification screen and controls.
  2. First-run locale resolution ignores supported secondary device locales. lib/features/settings/providers/settings_provider.dart:137-140 reads only platformDispatcher.locale. A device ordered as pt-BR, then es, incorrectly gets English even though Spanish is supported. Resolve the first supported entry from platformDispatcher.locales and test unsupported-primary/supported-secondary.
  3. The localization CI gate fails open. .github/workflows/ci.yml:113-120 passes and prints success when lib/l10n/untranslated_messages.txt is absent. Because gen-l10n is configured to emit {} on the clean path, a missing or malformed report must fail.
  4. Localized fallback text enters cached chat state. lib/features/chat/screens/chat_room_screen.dart:183-202 puts l10n.unknownPeerHandle into a ChatRoomState later passed to upsertRoom, so changing locale can leave the cached fallback in the previous language. Keep the model locale-independent and localize at render time.
  5. The localization conversion still contains presentation regressions. lib/features/order/screens/add_order_screen.dart:484-487 flattened the prior Text.rich structure and removed emphasis from amounts/price/24 h. lib/features/walkthrough/screens/walkthrough_screen.dart:123-128 feeds translated bodies into regex patterns that currently miss slide 6 in ES/FR/DE and slides 4-6 in IT, silently dropping intended highlighting.

Reviewed head: c3699448df110d8a6b51fdeb1f81acdd7fd9a01e.

…cales

Add test to verify each onboarding slide produces at least one highlighted phrase in all supported languages. Extend highlight regex patterns to match verb conjugation variants (crear/crea, creare/crea, créer/créez, erstellen) and gender inflections (cifrato/cifrata) that appear in translated slide bodies.
…lations

Replace hardcoded English text in notifications screen and widgets with AppLocalizations strings. Add unableToOpenNotification key across all locales (en/de/es/fr/it) for snackbar error message. Change PopupMenuButton itemBuilder parameters from `_` to `context` to access localization context.
Wrap amounts, prices, and durations in order preview sentences with asterisks in ARB files across all locales (en/de/es/fr/it). Update add_order_screen.dart to split preview text on '*' delimiters and render odd-indexed segments with bold weight and primary text color while keeping even-indexed segments in base style.

@ermeme ermeme 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.

The latest commits correctly resolve the previously reported device-locale-list fallback, fail-open localization report, cached localized peer handle, walkthrough highlighting, notification header/menu strings, and order-preview emphasis. Current Flutter/Rust checks pass; all five ARBs have 595 message keys with no duplicates or parity gaps, and the preview markers are balanced.

I am still requesting changes because one scope-defining blocker remains: the app-wide hardcoded-string audit is incomplete. Issue #162 explicitly asks to find hardcoded English copy across the app and expects locale switching to translate the whole UI as much as possible. The latest notification commit localizes only part of the same reachable feature; substantial UI copy remains English, outside the explicitly excluded notification model prose:

  • lib/features/notifications/screens/notifications_screen.dart:251-259,374,383,445: filter chips, backup reminder, and empty state.
  • lib/features/notifications/widgets/notification_group_card.dart:166-168,190,215-220,318,383-386: expansion/footer actions, group titles, and relative time.
  • lib/features/home/widgets/order_list_item.dart:65-78,152-155,184-185,226-231,343: order-book reason badges, market-price label, trade/day counts, timestamps, and empty state.
  • lib/shared/widgets/nwc_payment_widget.dart:70 and nwc_invoice_widget.dart:50,68: wallet payment/generation status and failure copy.

These are normal visible controls and status labels, not notification payload/model strings. Switching to ES/FR/DE/IT still leaves central screens partially in English, so the PR's stated purpose is not yet met.

Reviewed head: ffc69b291cfad1839303a4becd8a4c663732c08e.

@ermeme ermeme 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.

The latest commit correctly localizes the previously cited Home/order-book, notification, and NWC strings. Current Flutter and Rust checks pass; all five ARBs contain 616 message keys with no duplicates, key gaps, or ICU-placeholder mismatches.

One scope-level blocker still remains: the full reachable-UI audit is not complete. In particular, the Disputes feature that the PR explicitly claims to localize still renders hardcoded English:

  • lib/features/disputes/providers/disputes_providers.dart:118-130 returns English descriptions such as You opened this dispute, Dispute resolved in your favour, and Order cancelled cooperatively. DisputeListItem renders dispute.description directly at lib/features/disputes/widgets/dispute_list_item.dart:103-111.
  • lib/features/disputes/widgets/dispute_list_item.dart:121-137 renders the status chips Initiated, In progress, and Closed directly.

The broad follow-up pass also still finds untranslated UI/accessibility copy outside the explicit notification-model exclusion, for example shared/widgets/notification_bell.dart:74-85 (tooltip and semantics), features/drawer/screens/drawer_menu.dart:271-275 (badge semantics), and features/order/screens/pay_lightning_invoice_screen.dart:205-210 (QR semantics).

These are reachable user-facing strings, not protocol tokens, logs, payment-method identifiers, or excluded notification payload prose. Switching to ES/FR/DE/IT therefore still leaves the UI partially English, including a central feature named in the PR body.

Reviewed head: 28be4fba826682504dda2a16a5bcef49484caa1e.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/features/notifications/widgets/notification_group_card.dart (1)

383-389: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the injectable clock consistently.

Line [385] uses DateTime.now(), while lib/features/home/widgets/order_list_item.dart Line [227] and lib/features/notifications/widgets/notification_card.dart Line [128] use clock.now(). Use clock.now() here as well so fake-clock tests remain deterministic and all relative-time widgets agree at minute/hour boundaries.

Suggested change
+import 'package:clock/clock.dart';

-  final diff = DateTime.now().difference(dt);
+  final diff = clock.now().difference(dt);
🤖 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/notifications/widgets/notification_group_card.dart` around lines
383 - 389, Update relativeTime to use the injectable clock’s now() method
instead of DateTime.now(), preserving the existing duration and localization
behavior for all relative-time thresholds.
🤖 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/order/screens/my_order_screen.dart`:
- Around line 207-208: Update the premium formatting in the order display around
marketPricePremiumLabel to use NumberFormat with the active locale instead of
resolvedOrder.premium.toStringAsFixed(1). Preserve the existing positive-sign
prefix and pass the locale-formatted one-decimal value to the localization
label.

---

Nitpick comments:
In `@lib/features/notifications/widgets/notification_group_card.dart`:
- Around line 383-389: Update relativeTime to use the injectable clock’s now()
method instead of DateTime.now(), preserving the existing duration and
localization behavior for all relative-time thresholds.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 056d983b-2eb5-41a5-85e9-2d5fb2c0e38d

📥 Commits

Reviewing files that changed from the base of the PR and between c369944 and 28be4fb.

📒 Files selected for processing (31)
  • .github/workflows/ci.yml
  • lib/features/chat/providers/chat_providers.dart
  • lib/features/chat/screens/chat_room_screen.dart
  • lib/features/chat/widgets/chat_list_item.dart
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • lib/features/home/widgets/order_list_item.dart
  • lib/features/notifications/screens/notifications_screen.dart
  • lib/features/notifications/widgets/notification_card.dart
  • lib/features/notifications/widgets/notification_group_card.dart
  • lib/features/notifications/widgets/system_notification_banner.dart
  • lib/features/order/screens/add_order_screen.dart
  • lib/features/order/screens/my_order_screen.dart
  • lib/features/settings/providers/settings_provider.dart
  • lib/features/trades/screens/trade_detail_screen.dart
  • lib/features/walkthrough/utils/highlight_config.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart
  • lib/shared/widgets/nwc_invoice_widget.dart
  • lib/shared/widgets/nwc_payment_widget.dart
  • lib/shared/widgets/nym_avatar.dart
  • test/features/settings/settings_provider_test.dart
  • test/features/walkthrough/highlight_config_test.dart
🚧 Files skipped from review as they are similar to previous changes (16)
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • .github/workflows/ci.yml
  • lib/features/chat/widgets/chat_list_item.dart
  • lib/l10n/app_it.arb
  • lib/features/order/screens/add_order_screen.dart
  • lib/features/settings/providers/settings_provider.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_it.dart
  • lib/l10n/app_localizations_es.dart
  • lib/features/trades/screens/trade_detail_screen.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations.dart

Comment thread lib/features/order/screens/my_order_screen.dart Outdated
Replace toStringAsFixed(1) with NumberFormat.decimalPattern configured for current locale when displaying order premium. Ensures decimal separator and digit grouping follow user's language preferences while maintaining 1 decimal place precision.

@ermeme ermeme 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.

I reviewed the exact latest commit. 4c80470 changes only lib/features/order/screens/my_order_screen.dart, replacing toStringAsFixed(1) with locale-aware NumberFormat; that change looks correct and git diff --check is clean.

It does not touch the remaining scope blocker from the previous review, which is still present verbatim on this head:

  • lib/features/disputes/providers/disputes_providers.dart:118-130 still returns hardcoded English descriptions that DisputeListItem renders directly.
  • lib/features/disputes/widgets/dispute_list_item.dart:121-137 still renders Initiated, In progress, and Closed directly.
  • The cited accessibility/tooltip strings also remain at shared/widgets/notification_bell.dart:74-85, features/drawer/screens/drawer_menu.dart:271-275, and features/order/screens/pay_lightning_invoice_screen.dart:205-210.

So the locale-aware premium fix is valid, but it does not resolve the current CHANGES_REQUESTED reason. Rust CI is green; Flutter CI is still running at review time.

Reviewed head: 4c8047065421be43951d2c688d6ae9a95561dee7.

@ermeme ermeme 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.

Approved on current head 2ef53b346c5a8b9698ee12755af267f6425921f9.

The latest delta fixes the remaining review checklist without reintroducing locale-dependent model state: dispute descriptions and status chips now resolve through AppLocalizations at render time, and the notification bell, drawer badge, and Lightning QR accessibility strings are localized. The previous locale fallback, CI fail-closed behavior, chat fallback, walkthrough highlighting, notification/Home/NWC coverage, and order-preview formatting fixes remain intact.

Verification: Flutter and Rust checks are green; all five ARBs contain 628 message keys with no duplicates or key-parity gaps; ICU arguments are consistent; git diff --check is clean; and no unresolved review threads remain. I found no remaining blocker.

@AndreaDiazCorreia
AndreaDiazCorreia merged commit c6e3dd4 into main Jul 22, 2026
3 checks passed
@AndreaDiazCorreia
AndreaDiazCorreia deleted the fix/i18n-locale-consistency branch July 22, 2026 02:46
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.

i18n: complete missing translations and make locale switching consistent

1 participant