fix(i18n): complete UI localization and harden locale fallback - #201
Conversation
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.
|
Warning Review limit reached
Next review available in: 12 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (17)
WalkthroughThis 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. Changesi18n completion across app
Estimated code review effort: 4 (Complex) | ~75 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 winUse 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 winFix
ref.watchandAppLocalizationsusage in event handlers.
_resolveRoom()relies onref.watchandAppLocalizations.of(context). It is called by_buildRoomPreview(), which is triggered during_onSend(an async callback) and_onIncomingMessage(a stream listener).Using
ref.watchinside an event handler unconditionally throws a RiverpodStateError(ref.watch can only be used inside the build method...). Furthermore, retrievingAppLocalizations.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
chatRoomsNotifierProvidersecurely usingref.readwhen inside event handlers.🐛 Proposed fixes
Refactor
_resolveRoomto 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
_buildRoomPreviewto execute a saferef.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
_onSendto 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
_onIncomingMessageto 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
buildto pass the required arguments usingref.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 valueConsider using a more generic key for the copied-to-clipboard message.
The key
aboutCopiedToClipboardis prefixed withabout, indicating it was created specifically for the About screen. To improve maintainability and avoid unexpected translations in other contexts, consider creating a genericcopiedToClipboardkey, or reuse the existingmessageCopiedkey 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 liftKeep 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 winRetrieve
AppLocalizationsbefore the async gap.Looking up
AppLocalizations.of(context)after anawaitcan 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
📒 Files selected for processing (54)
.gitignorel10n.yamllib/features/account/screens/account_screen.dartlib/features/account/screens/backup_ritual_screen.dartlib/features/account/widgets/backup_trigger_sheet.dartlib/features/chat/screens/chat_room_screen.dartlib/features/chat/screens/chat_rooms_screen.dartlib/features/chat/widgets/chat_list_item.dartlib/features/chat/widgets/encrypted_file_message.dartlib/features/chat/widgets/encrypted_image_message.dartlib/features/chat/widgets/info_panels.dartlib/features/chat/widgets/message_bubble.dartlib/features/chat/widgets/message_input.dartlib/features/chat/widgets/trade_state_header.dartlib/features/disputes/screens/dispute_chat_screen.dartlib/features/disputes/widgets/dispute_messages_list.dartlib/features/disputes/widgets/disputes_list.dartlib/features/drawer/screens/drawer_menu.dartlib/features/home/screens/home_screen.dartlib/features/order/screens/add_lightning_invoice_screen.dartlib/features/order/screens/add_order_screen.dartlib/features/order/screens/take_order_screen.dartlib/features/order/widgets/currency_section.dartlib/features/order/widgets/order_preset_selector.dartlib/features/order/widgets/payment_method_section.dartlib/features/order/widgets/price_section.dartlib/features/order/widgets/range_amount_modal.dartlib/features/rate/screens/rate_counterpart_screen.dartlib/features/rate/widgets/star_rating.dartlib/features/settings/providers/settings_provider.dartlib/features/settings/screens/connect_wallet_screen.dartlib/features/settings/screens/log_report_screen.dartlib/features/settings/screens/notification_settings_screen.dartlib/features/settings/screens/wallet_settings_screen.dartlib/features/settings/widgets/currency_selector_dialog.dartlib/features/settings/widgets/mostro_node_selector.dartlib/features/trades/providers/trades_providers.dartlib/features/trades/screens/trade_detail_screen.dartlib/features/trades/screens/trades_screen.dartlib/features/trades/widgets/release_confirmation_dialog.dartlib/features/trades/widgets/trade_info_cards.dartlib/features/trades/widgets/trades_list_item.dartlib/features/walkthrough/screens/walkthrough_screen.dartlib/l10n/app_de.arblib/l10n/app_en.arblib/l10n/app_es.arblib/l10n/app_fr.arblib/l10n/app_it.arblib/l10n/app_localizations.dartlib/l10n/app_localizations_de.dartlib/l10n/app_localizations_en.dartlib/l10n/app_localizations_es.dartlib/l10n/app_localizations_fr.dartlib/l10n/app_localizations_it.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.
There was a problem hiding this comment.
Requesting changes for two user-visible gaps in the current head:
-
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.dartstill hardcodesOrder Book,My Trades, andChat(lines 55, 68, 81), andlib/shared/widgets/order_filter.dartstill 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. -
The saved-language fallback only normalizes the
Locale; it does not normalizeAppSettingsState.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.
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (21)
.github/workflows/ci.ymllib/features/chat/screens/chat_room_screen.dartlib/features/settings/providers/settings_provider.dartlib/l10n/app_de.arblib/l10n/app_en.arblib/l10n/app_es.arblib/l10n/app_fr.arblib/l10n/app_it.arblib/l10n/app_localizations.dartlib/l10n/app_localizations_de.dartlib/l10n/app_localizations_en.dartlib/l10n/app_localizations_es.dartlib/l10n/app_localizations_fr.dartlib/l10n/app_localizations_it.dartlib/shared/widgets/add_order_button.dartlib/shared/widgets/bottom_nav_bar.dartlib/shared/widgets/ln_address_confirmation_widget.dartlib/shared/widgets/mostro_reactive_button.dartlib/shared/widgets/order_filter.dartlib/shared/widgets/pay_lightning_invoice_widget.darttest/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
There was a problem hiding this comment.
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:
- 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; andnotification_card.dart:226,230. The PR closes #162 and excludes notification model strings, not the notification screen and controls. - First-run locale resolution ignores supported secondary device locales.
lib/features/settings/providers/settings_provider.dart:137-140reads onlyplatformDispatcher.locale. A device ordered aspt-BR, thenes, incorrectly gets English even though Spanish is supported. Resolve the first supported entry fromplatformDispatcher.localesand test unsupported-primary/supported-secondary. - The localization CI gate fails open.
.github/workflows/ci.yml:113-120passes and prints success whenlib/l10n/untranslated_messages.txtis absent. Becausegen-l10nis configured to emit{}on the clean path, a missing or malformed report must fail. - Localized fallback text enters cached chat state.
lib/features/chat/screens/chat_room_screen.dart:183-202putsl10n.unknownPeerHandleinto aChatRoomStatelater passed toupsertRoom, so changing locale can leave the cached fallback in the previous language. Keep the model locale-independent and localize at render time. - The localization conversion still contains presentation regressions.
lib/features/order/screens/add_order_screen.dart:484-487flattened the priorText.richstructure and removed emphasis from amounts/price/24 h.lib/features/walkthrough/screens/walkthrough_screen.dart:123-128feeds 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.
…ead of caching in state
…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.
There was a problem hiding this comment.
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:70andnwc_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.
…der list and notifications
There was a problem hiding this comment.
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-130returns English descriptions such asYou opened this dispute,Dispute resolved in your favour, andOrder cancelled cooperatively.DisputeListItemrendersdispute.descriptiondirectly atlib/features/disputes/widgets/dispute_list_item.dart:103-111.lib/features/disputes/widgets/dispute_list_item.dart:121-137renders the status chipsInitiated,In progress, andCloseddirectly.
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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/features/notifications/widgets/notification_group_card.dart (1)
383-389: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the injectable clock consistently.
Line [385] uses
DateTime.now(), whilelib/features/home/widgets/order_list_item.dartLine [227] andlib/features/notifications/widgets/notification_card.dartLine [128] useclock.now(). Useclock.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
📒 Files selected for processing (31)
.github/workflows/ci.ymllib/features/chat/providers/chat_providers.dartlib/features/chat/screens/chat_room_screen.dartlib/features/chat/widgets/chat_list_item.dartlib/features/disputes/screens/dispute_chat_screen.dartlib/features/home/widgets/order_list_item.dartlib/features/notifications/screens/notifications_screen.dartlib/features/notifications/widgets/notification_card.dartlib/features/notifications/widgets/notification_group_card.dartlib/features/notifications/widgets/system_notification_banner.dartlib/features/order/screens/add_order_screen.dartlib/features/order/screens/my_order_screen.dartlib/features/settings/providers/settings_provider.dartlib/features/trades/screens/trade_detail_screen.dartlib/features/walkthrough/utils/highlight_config.dartlib/l10n/app_de.arblib/l10n/app_en.arblib/l10n/app_es.arblib/l10n/app_fr.arblib/l10n/app_it.arblib/l10n/app_localizations.dartlib/l10n/app_localizations_de.dartlib/l10n/app_localizations_en.dartlib/l10n/app_localizations_es.dartlib/l10n/app_localizations_fr.dartlib/l10n/app_localizations_it.dartlib/shared/widgets/nwc_invoice_widget.dartlib/shared/widgets/nwc_payment_widget.dartlib/shared/widgets/nym_avatar.darttest/features/settings/settings_provider_test.darttest/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
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.
There was a problem hiding this comment.
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-130still returns hardcoded English descriptions thatDisputeListItemrenders directly.lib/features/disputes/widgets/dispute_list_item.dart:121-137still rendersInitiated,In progress, andCloseddirectly.- The cited accessibility/tooltip strings also remain at
shared/widgets/notification_bell.dart:74-85,features/drawer/screens/drawer_menu.dart:271-275, andfeatures/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.
…calized translations
There was a problem hiding this comment.
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.
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-l10nuntranslated-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:
localeProvidernow validates the language againstsupportedLocalesand 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).untranslated-messages-fileinl10n.yamlso CI can fail when a new key lands untranslated.Out of scope (separate issues): notification model strings and the Rust
CantDoprose-to-marker debt.Note: Spanish reviewed by the author; fr/de/it are a solid base pending native review.
Summary by CodeRabbit