Skip to content

Conversation

@untreu2
Copy link
Contributor

@untreu2 untreu2 commented Oct 6, 2025

Description

New Features:
Added multi-language support with English, German, Spanish, and Italian, Turkish, Portuguese, French, Russian translations
Implemented system language detection with fallback to user preferences
Created a state management system for locale switching using Riverpod
Added test for localization provider
Added persistent language preference storage
Built language selector dropdown UI component

Core Components:
LocalizationService: Handles translation loading and locale management
LocalizationNotifier: Manages localization state with loading and error handling
LocalizationState: Freezed data class for immutable state management
Multiple Riverpod providers for accessing current locale, selected language, loading state, and errors

UI Updates:
Localized all screens
Added language selector dropdown (like theme selector) in settings
Implemented localization extensions for easy string access throughout the app

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore
  • 🧪 Tests

Checklist

  • Run just precommit to ensure that formatting and linting are correct
  • Run just check-flutter-coverage to ensure that flutter coverage rules are passing
  • Updated the CHANGELOG.md file with your changes (if they affect the user experience)

Fixes #709

Summary by CodeRabbit

  • New Features

    • App-wide localization with language selector and persisted preference; supports English, German, Spanish, French, Italian, Portuguese, Russian, Turkish, and system locale.
  • UI

    • Extensive text localization across auth, chats, contacts, settings, wallet, dialogs, inputs, menus and message/reply displays; language changes apply immediately. Share/invite messages now localized.
  • Tests

    • New/updated tests for locale init, switching, persistence, and localized UI expectations.
  • Chores

    • Added locale assets, enabled Flutter localization, updated intl, and wired locale providers/services.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Walkthrough

Adds full localization: JSON locale assets (8 languages), LocalizationService, Riverpod LocalizationNotifier + Freezed state, string/context extensions and LocalizedText, language selector UI, wiring in main and pubspec, widespread UI string replacements to use .tr(), tests updated, and removal of one constant.

Changes

Cohort / File(s) Summary
Core: service, provider, state, extensions
lib/services/localization_service.dart, lib/config/providers/localization_provider.dart, lib/config/states/localization_state.dart, lib/config/states/localization_state.freezed.dart, lib/utils/localization_extensions.dart
Add LocalizationService (JSON loading, translate, device resolution, preference handling), LocalizationState (Freezed) + generated code, LocalizationNotifier StateNotifier + Riverpod providers, String/BuildContext .tr() extension and LocalizedText consumer widget.
App wiring & deps
lib/main.dart, pubspec.yaml, CHANGELOG.md
Initialize localization before auth; wire locale & delegates into MaterialApp.router; add flutter_localizations, bump intl, and register lib/locales/ assets; update changelog entry.
Locale assets
lib/locales/*.json (en.json, es.json, de.json, it.json, fr.json, pt.json, ru.json, tr.json)
Add comprehensive JSON translation files for eight languages preserving placeholders and key structure.
Language selector UI
lib/ui/widgets/language_selector_dropdown.dart
New LanguageSelectorDropdown ConsumerStatefulWidget (+ private _LanguageOption) listing supported locales and invoking notifier.changeLocale on selection.
Bulk UI localization
lib/ui/* (many files; examples in summary)
Replace hard-coded strings with .tr() across auth, chat, contact list, settings, wallet, dialogs, toasts, and many widgets; add localization imports and adjust const usage where required.
Reaction & menu adjustments
lib/ui/chat/widgets/reaction/reaction_default_data.dart, lib/ui/chat/widgets/reaction/reactions_dialog_widget.dart, lib/ui/chat/widgets/reaction/reaction_hero_dialog_route.dart
Convert static const MenuItem lists/items to getters with localized labels; ReactionsDialogWidget constructor changed to accept nullable menuItems with getter fallback; barrierLabel localized.
Message & input widgets
lib/ui/chat/widgets/message_widget.dart, lib/ui/chat/widgets/chat_input.dart, related reply widgets
Several reply-related widgets converted to ConsumerWidget (build now takes WidgetRef) to watch locale provider; reply sender display name logic extracted to MessageUtils and localized fallbacks used.
Settings integration
lib/ui/settings/app_settings/app_settings_screen.dart, various lib/ui/settings/*
Add LanguageSelectorDropdown to settings UI and localize labels, dialogs and related widgets.
Utilities
lib/utils/message_utils.dart
New MessageUtils.getDisplayName to centralize localized display name resolution for replies/edits.
Tests
test/config/providers/localization_provider_test.dart, updated test/ui/contact_list/*
Add comprehensive provider/unit tests and update UI tests to expect localization keys/texts.
Constants change
lib/config/constants.dart
Remove top-level kInviteMessage constant.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant App as main.dart
  participant LN as LocalizationNotifier
  participant SP as SharedPreferences
  participant LS as LocalizationService
  participant UI as MaterialApp

  App->>LN: instantiate & initialize()
  LN->>SP: read persisted locale
  LN->>LS: setLocalePreference(saved or "system")
  LS->>LS: resolve locale (device/fallback) and load JSON assets
  LS-->>LN: return load result / currentLocale
  LN-->>App: providers updated (currentLocale, selectedLanguage, isLoading, error)
  App->>UI: build MaterialApp with locale & delegates
  UI-->>User: render localized UI
Loading
sequenceDiagram
  autonumber
  actor User
  participant Dropdown as LanguageSelectorDropdown
  participant LN as LocalizationNotifier
  participant SP as SharedPreferences
  participant LS as LocalizationService
  participant Widgets as WidgetsBinding

  User->>Dropdown: tap language option
  Dropdown->>LN: changeLocale(code)
  alt code != 'system'
    LN->>SP: persist code
    LN->>LS: setLocale(code)
  else code == 'system'
    LN->>SP: persist "system"
    LN->>LS: setLocalePreference("system")
    LS->>Widgets: getDeviceLocale()
    Widgets-->>LS: device locale
  end
  LS-->>LN: load success/failure
  LN-->>Dropdown: update state
  Dropdown-->>User: UI updates with new translations
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • josefinalliende
  • Quwaysim
  • codeswot

Poem

In my burrow I nibble keys and code,
I teach the app each tongue along the road.
Menus now chatter in Deutsch, French and more,
Dropdowns hop open, translations galore.
Hop, translate, repeat — the rabbit claps for lore. 🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Beyond localization, the PR includes unrelated API modifications such as removing the messagePosition parameter from ChatDialogService.showReactionDialog, which is not part of the linked localization objectives and alters an existing public API. These changes fall outside the scope of the localization issue. Revert or extract the API signature change in ChatDialogService.showReactionDialog into a separate PR so that this branch focuses solely on localization features.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “Localization” directly reflects the primary focus of the changeset, which adds comprehensive multi-language support, runtime locale switching, and localization infrastructure throughout the app. It is concise, specific to the main change, and clear to a reviewer. Although a more descriptive phrase (e.g., “Implement multi-language support”) could add context, the existing title accurately summarizes the PR.
Linked Issues Check ✅ Passed The pull request fully implements the objectives of issue #709 by removing the English-only limitation, adding translations for eight languages, supporting system language detection and fallback, enabling runtime locale switching, integrating translations across all UI screens, and managing locale state via Riverpod with persistence. All linked requirements are met through the introduced service, notifier, state, providers, assets, extensions, UI updates, and tests.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (6)
lib/ui/contact_list/new_group_chat_sheet.dart (5)

37-46: Incomplete localization in the bottom sheet.

The title 'New group chat' at line 37 is hard-coded and should be localized to support multiple languages.

Apply this diff to localize the title:

-      title: 'New group chat',
+      title: 'ui.newGroupChat'.tr(),

103-111: Localize the empty state messages.

The messages 'No contacts found' and 'No contacts match your search' are hard-coded and should be localized.

Apply this diff:

      return Center(
        child: Text(
-          _searchQuery.isEmpty ? 'No contacts found' : 'No contacts match your search',
+          _searchQuery.isEmpty ? 'chats.noContactsFound'.tr() : 'chats.noContactsMatchSearch'.tr(),
          style: TextStyle(fontSize: 16.sp),
        ),
      );

177-193: Localize the search placeholder.

The hint text 'Search contact or public key...' is hard-coded and should be localized.

Apply this diff:

                child: WnTextFormField(
                  controller: _searchController,
-                  hintText: 'Search contact or public key...',
+                  hintText: 'chats.searchContactOrPublicKey'.tr(),
                  size: FieldSize.small,

215-221: Localize the error message.

The error message 'Error loading contacts' is hard-coded and should be localized.

Apply this diff:

                          Text(
-                            'Error loading contacts',
+                            'chats.errorLoadingContacts'.tr(),
                            style: TextStyle(fontSize: 16.sp),
                          ),

244-257: Localize the button label.

The button label 'Continue' is hard-coded and should be localized.

Apply this diff:

          WnFilledButton(
            onPressed:
                _selectedContacts.isNotEmpty
                    ? () {
                      Navigator.pop(context);
                      GroupChatDetailsSheet.show(
                        context: context,
                        selectedContacts: _selectedContacts.toList(),
                        onGroupCreated: widget.onGroupCreated,
                      );
                    }
                    : null,
-            label: 'Continue',
+            label: 'shared.continue'.tr(),
          ),
lib/ui/contact_list/widgets/profile_ready_card.dart (1)

62-62: Localize the card title.

The title "Your Profile is Ready" at line 62 is still hard-coded while other text in this widget has been localized. This should be replaced with a localization key for consistency.

Apply this diff:

                 child: Text(
-                  'Your Profile is Ready',
+                  'chats.profileReady'.tr(),
                   style: TextStyle(
🧹 Nitpick comments (7)
lib/ui/settings/profile_keys/profile_keys_screen.dart (1)

207-207: Consider parameterized translation for error message.

The error message construction uses string concatenation. For better localization support, consider using a parameterized translation key.

Apply this approach:

-'${'nostrKeys.errorLoadingPrivateKey'.tr()}: ${nostrKeys.error}'
+'nostrKeys.errorLoadingPrivateKeyWithDetails'.tr({'error': nostrKeys.error ?? ''})

Then add to locale files:

"errorLoadingPrivateKeyWithDetails": "Error loading private key: {error}"

This allows translators to adjust the error message format for different languages.

lib/ui/chat/widgets/chat_search_widget.dart (1)

9-9: LGTM!

The localization implementation is functional and consistent with the translation file format. The manual placeholder replacement using .replaceAll() works correctly for the matches counter.

Optional: Consider a helper function for placeholder replacement.

While the current .replaceAll() approach works, you might want to create a reusable helper function for template string replacement to improve maintainability and reduce duplication if this pattern is used elsewhere:

// In localization_extensions.dart
extension LocalizationHelpers on String {
  String trWith(Map<String, String> replacements) {
    String result = tr();
    replacements.forEach((key, value) {
      result = result.replaceAll(key, value);
    });
    return result;
  }
}

// Usage in chat_search_widget.dart
'chats.matchesCounter'.trWith({
  '{current}': searchNotifier.currentMatchNumber.toString(),
  '{total}': searchNotifier.totalMatches.toString(),
})

This would provide a more maintainable and type-safe approach for handling multiple placeholder replacements.

Also applies to: 71-71, 149-152, 191-191

lib/ui/settings/app_settings/app_settings_screen.dart (1)

198-199: Consider using .tr() consistently instead of mixing with LocalizedText.

While both LocalizedText widget and .tr() method work correctly, the file mixes both approaches inconsistently. For example, section headers use LocalizedText (lines 198-199, 227-228, 243-244, 254-255) while button labels and dropdown options use .tr() (lines 264, 305, 307, 309, etc.).

For consistency with the rest of the codebase (as seen in other reviewed files), consider refactoring to use .tr() exclusively:

-            child: LocalizedText(
-              'settings.appSettings',
+            child: Text(
+              'settings.appSettings'.tr(),
               style: TextStyle(

Apply the same pattern to lines 227-228, 243-244, and 254-255.

Also applies to: 227-228, 243-244, 254-255

lib/ui/chat/chat_info/dm_chat_info.dart (1)

31-41: Consider using the tr() params feature for string interpolation.

The code currently uses .replaceAll('{name}', displayName) for string interpolation. Based on the localization extensions in lib/utils/localization_extensions.dart, the .tr() method supports a params argument.

Consider refactoring to:

-    successMessage = 'ui.unfollowed'.tr().replaceAll('{name}', displayName);
+    successMessage = 'ui.unfollowed'.tr({'name': displayName});

and

-    successMessage = 'ui.followed'.tr().replaceAll('{name}', displayName);
+    successMessage = 'ui.followed'.tr({'name': displayName});

This would be more consistent with the localization framework's design and eliminate the need for manual string replacement.

lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (1)

90-93: Use parameterized translations instead of manual replaceAll

Prefer passing parameters to the translator to avoid brittle string ops.

Option A (if .tr supports params):

-        ref.showSuccessToast(
-          'chats.removedFromGroupSuccess'.tr().replaceAll('{name}', widget.member.displayName),
-        );
+        ref.showSuccessToast(
+          'chats.removedFromGroupSuccess'.tr(params: {'name': widget.member.displayName}),
+        );
-                text: 'chats.removeFromGroupConfirmation'.tr().replaceAll(
-                  '{name}',
-                  widget.member.displayName,
-                ),
+                text: 'chats.removeFromGroupConfirmation'.tr(
+                  params: {'name': widget.member.displayName},
+                ),

Option B (if .tr does not support params):

+import 'package:whitenoise/services/localization_service.dart';
-        ref.showSuccessToast(
-          'chats.removedFromGroupSuccess'.tr().replaceAll('{name}', widget.member.displayName),
-        );
+        ref.showSuccessToast(
+          LocalizationService.translate(
+            'chats.removedFromGroupSuccess',
+            params: {'name': widget.member.displayName},
+          ),
+        );
-                text: 'chats.removeFromGroupConfirmation'.tr().replaceAll(
-                  '{name}',
-                  widget.member.displayName,
-                ),
+                text: LocalizationService.translate(
+                  'chats.removeFromGroupConfirmation',
+                  params: {'name': widget.member.displayName},
+                ),

Also applies to: 138-141

test/config/providers/localization_provider_test.dart (1)

500-501: Avoid hard-coded supported codes in tests

Derive from the source of truth to prevent drift.

-        final supportedCodes = ['en', 'es', 'de', 'it'];
+        final supportedCodes = LocalizationService.supportedLocales.keys
+            .where((k) => k != 'system')
+            .toList();
lib/services/localization_service.dart (1)

6-14: Consider aligning with Flutter’s AppLocalizations

Project guidelines prefer AppLocalizations over a custom service. Migration would bring pluralization, formatting, and delegate integration out of the box.

As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c5ddb2 and 50d5426.

⛔ Files ignored due to path filters (2)
  • ios/Podfile.lock is excluded by !**/*.lock
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (61)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/localization_provider.dart (1 hunks)
  • lib/config/states/localization_state.dart (1 hunks)
  • lib/config/states/localization_state.freezed.dart (1 hunks)
  • lib/locales/de.json (1 hunks)
  • lib/locales/en.json (1 hunks)
  • lib/locales/es.json (1 hunks)
  • lib/locales/i18n.ts (1 hunks)
  • lib/locales/it.json (1 hunks)
  • lib/main.dart (4 hunks)
  • lib/services/localization_service.dart (1 hunks)
  • lib/ui/auth_flow/create_profile_screen.dart (6 hunks)
  • lib/ui/auth_flow/info_screen.dart (4 hunks)
  • lib/ui/auth_flow/login_screen.dart (5 hunks)
  • lib/ui/auth_flow/qr_scanner_bottom_sheet.dart (3 hunks)
  • lib/ui/auth_flow/welcome_screen.dart (4 hunks)
  • lib/ui/chat/chat_info/chat_info_screen.dart (2 hunks)
  • lib/ui/chat/chat_info/dm_chat_info.dart (6 hunks)
  • lib/ui/chat/chat_info/edit_group_screen.dart (11 hunks)
  • lib/ui/chat/chat_info/group_chat_info.dart (8 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (9 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (6 hunks)
  • lib/ui/chat/chat_screen.dart (2 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (2 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (2 hunks)
  • lib/ui/chat/widgets/chat_input.dart (4 hunks)
  • lib/ui/chat/widgets/chat_search_widget.dart (4 hunks)
  • lib/ui/chat/widgets/reaction/reaction_default_data.dart (2 hunks)
  • lib/ui/chat/widgets/reaction/reaction_hero_dialog_route.dart (2 hunks)
  • lib/ui/chat/widgets/reaction/reactions_dialog_widget.dart (2 hunks)
  • lib/ui/contact_list/chat_list_screen.dart (5 hunks)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart (11 hunks)
  • lib/ui/contact_list/new_group_chat_sheet.dart (2 hunks)
  • lib/ui/contact_list/share_invite_bottom_sheet.dart (3 hunks)
  • lib/ui/contact_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/contact_list/widgets/chat_list_item_tile.dart (3 hunks)
  • lib/ui/contact_list/widgets/contact_list_tile.dart (2 hunks)
  • lib/ui/contact_list/widgets/empty_chat_widget.dart (3 hunks)
  • lib/ui/contact_list/widgets/profile_ready_card.dart (4 hunks)
  • lib/ui/contact_list/widgets/share_invite_button.dart (3 hunks)
  • lib/ui/contact_list/widgets/share_invite_callout.dart (2 hunks)
  • lib/ui/contact_list/widgets/user_profile.dart (2 hunks)
  • lib/ui/contact_list/widgets/welcome_tile.dart (3 hunks)
  • lib/ui/settings/app_settings/app_settings_screen.dart (11 hunks)
  • lib/ui/settings/developer/developer_settings_screen.dart (22 hunks)
  • lib/ui/settings/donate/donate_screen.dart (6 hunks)
  • lib/ui/settings/general_settings_screen.dart (11 hunks)
  • lib/ui/settings/network/add_relay_bottom_sheet.dart (9 hunks)
  • lib/ui/settings/network/network_screen.dart (3 hunks)
  • lib/ui/settings/network/widgets/relay_section.dart (4 hunks)
  • lib/ui/settings/profile/connect_profile_bottom_sheet.dart (5 hunks)
  • lib/ui/settings/profile/edit_profile_screen.dart (15 hunks)
  • lib/ui/settings/profile/share_profile_screen.dart (6 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (5 hunks)
  • lib/ui/settings/profile_keys/profile_keys_screen.dart (12 hunks)
  • lib/ui/settings/wallet/wallet_screen.dart (5 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/widgets/language_selector_dropdown.dart (1 hunks)
  • lib/utils/localization_extensions.dart (1 hunks)
  • pubspec.yaml (3 hunks)
  • test/config/providers/localization_provider_test.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/contact_list/widgets/user_profile.dart
  • lib/ui/settings/profile_keys/profile_keys_screen.dart
  • lib/ui/settings/donate/donate_screen.dart
  • lib/ui/contact_list/widgets/profile_ready_card.dart
  • lib/ui/contact_list/widgets/share_invite_callout.dart
  • lib/ui/settings/wallet/wallet_screen.dart
  • lib/ui/chat/widgets/chat_input.dart
  • lib/ui/auth_flow/welcome_screen.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/contact_list/widgets/empty_chat_widget.dart
  • lib/ui/auth_flow/create_profile_screen.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
  • lib/ui/chat/chat_info/dm_chat_info.dart
  • lib/config/states/localization_state.dart
  • lib/ui/settings/profile/share_profile_screen.dart
  • lib/ui/contact_list/share_invite_bottom_sheet.dart
  • lib/ui/settings/profile/edit_profile_screen.dart
  • lib/ui/contact_list/chat_list_screen.dart
  • test/config/providers/localization_provider_test.dart
  • lib/ui/contact_list/widgets/share_invite_button.dart
  • lib/ui/chat/widgets/chat_search_widget.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
  • lib/utils/localization_extensions.dart
  • lib/ui/auth_flow/qr_scanner_bottom_sheet.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/contact_list/widgets/chat_list_item_tile.dart
  • lib/ui/contact_list/widgets/contact_list_tile.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/settings/app_settings/app_settings_screen.dart
  • lib/config/states/localization_state.freezed.dart
  • lib/ui/chat/chat_info/chat_info_screen.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/settings/profile/connect_profile_bottom_sheet.dart
  • lib/ui/settings/network/widgets/relay_section.dart
  • lib/ui/auth_flow/info_screen.dart
  • lib/ui/chat/widgets/reaction/reactions_dialog_widget.dart
  • lib/ui/contact_list/new_group_chat_sheet.dart
  • lib/ui/auth_flow/login_screen.dart
  • lib/ui/widgets/language_selector_dropdown.dart
  • lib/config/providers/localization_provider.dart
  • lib/ui/contact_list/start_chat_bottom_sheet.dart
  • lib/ui/chat/widgets/reaction/reaction_hero_dialog_route.dart
  • lib/ui/chat/chat_screen.dart
  • lib/main.dart
  • lib/services/localization_service.dart
  • lib/ui/chat/chat_info/group_chat_info.dart
  • lib/ui/chat/widgets/reaction/reaction_default_data.dart
  • lib/ui/settings/network/network_screen.dart
  • lib/ui/contact_list/widgets/welcome_tile.dart
  • lib/ui/settings/network/add_relay_bottom_sheet.dart
  • lib/ui/chat/chat_info/edit_group_screen.dart
**/*_test.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*_test.dart: Follow the Arrange-Act-Assert convention for tests.
Name test variables clearly. Follow the convention: inputX, mockX, actualX, expectedX, etc.
Write unit tests for each public function. Use test doubles to simulate dependencies, except for third-party dependencies that are not expensive to execute.
Write acceptance tests for each module. Follow the Given-When-Then convention.
Use the standard widget testing for Flutter.

Files:

  • test/config/providers/localization_provider_test.dart
**/*.md

📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)

**/*.md: NIPs (Nostr Implementation Possibilities) are numbered like NIP-XX where XX are two capitalized hexadecimal digits, e.g., NIP-01 and NIP-C7.
To read a specific NIP, construct the NIP URL following this template: https://raw.githubusercontent.com/nostr-protocol/nips/refs/heads/master/{nip}.md (replace {nip} in the URL template with the relevant NIP name, e.g., 07 for NIP-07, or C7 for NIP-C7).
To read the definition of a specific kind, construct a URL following this template: https://nostrbook.dev/kinds/{kind}.md (replace {kind} in the template with the kind number, e.g., https://nostrbook.dev/kinds/0.md for kind 0).

Files:

  • CHANGELOG.md
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/settings/wallet/wallet_screen.dart
  • lib/ui/auth_flow/welcome_screen.dart
  • lib/ui/contact_list/widgets/empty_chat_widget.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
  • lib/ui/settings/profile/share_profile_screen.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/contact_list/widgets/chat_list_item_tile.dart
  • lib/ui/contact_list/widgets/contact_list_tile.dart
  • lib/ui/settings/app_settings/app_settings_screen.dart
  • lib/ui/chat/chat_info/chat_info_screen.dart
  • lib/ui/auth_flow/info_screen.dart
  • lib/ui/auth_flow/login_screen.dart
  • lib/ui/contact_list/start_chat_bottom_sheet.dart
  • lib/ui/contact_list/widgets/welcome_tile.dart
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.

Applied to files:

  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/settings/wallet/wallet_screen.dart
  • lib/ui/auth_flow/welcome_screen.dart
  • lib/ui/auth_flow/create_profile_screen.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
  • lib/ui/settings/profile/edit_profile_screen.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
  • lib/utils/localization_extensions.dart
  • lib/ui/settings/app_settings/app_settings_screen.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/main.dart
  • lib/services/localization_service.dart
  • lib/ui/contact_list/widgets/welcome_tile.dart
  • pubspec.yaml
📚 Learning: 2025-09-06T09:32:55.455Z
Learnt from: codeswot
PR: parres-hq/whitenoise_flutter#595
File: lib/ui/settings/profile/share_profile_qr_scan_screen.dart:73-90
Timestamp: 2025-09-06T09:32:55.455Z
Learning: The whitenoise_flutter project does not use localization (AppLocalizations) - hard-coded strings are acceptable and should not be flagged for localization.

Applied to files:

  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/auth_flow/welcome_screen.dart
  • lib/utils/localization_extensions.dart
  • lib/ui/auth_flow/login_screen.dart
  • lib/main.dart
📚 Learning: 2025-09-07T13:10:16.542Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#597
File: lib/config/providers/group_provider.dart:311-314
Timestamp: 2025-09-07T13:10:16.542Z
Learning: In the whitenoise_flutter codebase, the User class used in group_provider.dart (and similar contexts) is presentational only, not the actual user class from the Rust API. There are plans to remove this User class and replace it with UserProfileData, similar to the planned consolidation with ContactModel.

Applied to files:

  • lib/ui/contact_list/widgets/user_profile.dart
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use freezed to manage UI states.

Applied to files:

  • lib/config/states/localization_state.dart
📚 Learning: 2025-09-16T06:28:24.648Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#640
File: lib/ui/chat/services/chat_dialog_service.dart:21-25
Timestamp: 2025-09-16T06:28:24.648Z
Learning: In lib/ui/core/ui/wn_bottom_sheet.dart, the WnBottomSheet.show method has barrierDismissible parameter that defaults to false, not true.

Applied to files:

  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (85)
CHANGELOG.md (1)

11-11: LGTM!

The changelog entry accurately documents the addition of multi-language support.

lib/ui/contact_list/widgets/user_profile.dart (2)

10-10: LGTM!

The localization extension import is correctly added.


33-33: LGTM!

The success message is now properly localized using the chats.publicKeyCopied key.

lib/ui/contact_list/new_group_chat_sheet.dart (2)

19-19: LGTM!

The localization extension import is correctly added.


237-237: LGTM!

The button text is now properly localized using the shared.goBack key.

pubspec.yaml (3)

33-34: LGTM!

The flutter_localizations dependency is correctly added to enable Flutter's localization support.


121-121: LGTM!

The asset declaration for lib/locales/ is correctly added to make translation JSON files accessible at runtime.


61-61: Verify intl v0.20.2 for breaking changes

  • Security check shows no known vulnerabilities up to v0.20.2.
  • Manually review the intl CHANGELOG (e.g., on pub.dev) for any API deprecations or changes that could impact your code.
lib/ui/contact_list/widgets/welcome_tile.dart (3)

11-11: LGTM!

The localization extension import is correctly added.


36-36: LGTM!

The fallback name for unknown users is now properly localized using the chats.unknownUser key.


88-90: LGTM!

The invitation messages are now properly localized. The interpolation syntax for passing the groupName parameter in line 90 is correct.

lib/ui/contact_list/new_chat_bottom_sheet.dart (9)

27-27: LGTM!

The localization extension import is correctly added.


39-39: LGTM!

The bottom sheet title is now properly localized using the ui.startNewChat key.


132-139: LGTM!

The error messages are now properly localized using consistent error key patterns (settings.noActiveAccountFound and chats.errorLoadingFollows).


169-169: LGTM!

The fallback name for unknown users is now properly localized using the chats.unknownUser key, consistent with usage in other files.


202-202: LGTM!

The error message is now properly localized using the chats.errorStartingChat key.


218-236: LGTM!

The error widget text and retry button are now properly localized using the chats.errorLoadingFollows and shared.retry keys.


247-279: LGTM!

The main option titles are now properly localized using ui.newGroupChat, ui.helpAndFeedback, and ui.support keys.


372-375: LGTM!

The empty state messages are now properly localized using chats.noFollowsFound, chats.loadingMetadata, and chats.noFollowsMatchSearch keys.


443-443: LGTM!

The search placeholder is now properly localized using the chats.searchContactPlaceholder key.

lib/ui/chat/widgets/chat_header_widget.dart (2)

12-12: LGTM!

The localization extension import is correctly added.


105-105: LGTM!

The "Group Description:" label is now properly localized using the chats.groupDescription key.

lib/ui/settings/widgets/active_account_tile.dart (3)

13-13: LGTM!

The localization extension import is correctly added.


42-42: LGTM!

The empty state message is now properly localized using the ui.noAccountsFound key.


46-46: LGTM!

The error message is now properly localized with correct string interpolation syntax.

lib/ui/chat/chat_screen.dart (1)

27-27: LGTM!

The localization import and error text replacement are correct. Removing const from the Center widget is necessary since .tr() is a runtime operation.

Also applies to: 257-259

lib/ui/contact_list/widgets/empty_chat_widget.dart (1)

7-7: LGTM!

The localization keys are well-structured and the implementation is correct.

Also applies to: 21-21, 30-30

lib/ui/contact_list/widgets/profile_ready_card.dart (1)

14-14: Good localization of button labels and description.

The localization of the profile description and button labels is implemented correctly.

Also applies to: 84-84, 93-93, 105-105

lib/ui/auth_flow/info_screen.dart (1)

13-13: Excellent localization implementation!

All user-facing text in this screen is properly localized with appropriate keys. This is a good example of complete localization.

Also applies to: 74-74, 85-86, 91-92, 97-98, 118-118

lib/ui/settings/network/widgets/relay_section.dart (1)

11-11: LGTM!

Error and loading messages are correctly localized. The string interpolation with exception messages is properly handled.

Also applies to: 55-55, 72-72, 142-142

lib/ui/contact_list/widgets/chat_list_item_tile.dart (1)

20-20: Excellent use of parameterized translations!

The implementation correctly handles both simple translations (line 103) and parameterized translations with dynamic content (line 249). The 'chats.youMessage'.tr({'content': content}) pattern is the proper way to handle variable substitution in localized strings.

Also applies to: 103-103, 249-249

lib/ui/contact_list/share_invite_bottom_sheet.dart (1)

12-12: LGTM! Localization properly integrated.

The localization changes are correctly implemented:

  • Import added for localization extensions
  • Hard-coded strings replaced with .tr() calls
  • WnCallout correctly made non-const to support runtime translation (line 72)

Also applies to: 31-31, 72-75

lib/ui/settings/donate/donate_screen.dart (1)

15-15: LGTM! Localization with parameter substitution correctly implemented.

All localization changes are properly implemented, including parameterized translation at line 24 using {'type': type} for dynamic content substitution.

Also applies to: 24-24, 53-53, 82-82, 92-92, 122-122

lib/ui/contact_list/chat_list_screen.dart (1)

32-32: LGTM! Consistent localization across chat list UI.

All hard-coded strings properly replaced with localization keys throughout the chat list screen, maintaining consistent user experience across languages.

Also applies to: 341-342, 345-345, 394-394, 418-418, 523-523

lib/locales/en.json (1)

1-433: LGTM! Comprehensive English translation resource.

The translation file is well-structured with:

  • Clear section organization (shared, settings, profile, etc.)
  • Proper placeholder syntax for dynamic content ({count}, {name}, etc.)
  • Comprehensive coverage of UI strings
lib/ui/chat/widgets/reaction/reaction_hero_dialog_route.dart (1)

2-2: LGTM! Accessibility label properly localized.

The barrierLabel getter now returns a localized string for screen readers, improving accessibility across languages.

Also applies to: 57-57

lib/ui/settings/profile_keys/profile_keys_screen.dart (1)

15-15: LGTM! Profile keys screen localized.

All user-facing strings properly localized using .tr() extension.

Also applies to: 45-45, 55-55, 99-99, 124-124, 152-152, 161-161, 185-185, 251-251, 285-285, 294-294

lib/locales/i18n.ts (1)

1-13: Clarify placement of i18n.ts file

The file lib/locales/i18n.ts uses svelte-i18n and TypeScript but there’s no JS/TS build config in the repo—this isn’t typical for a Flutter/Dart project. Confirm if this is intentional for a web or hybrid component and whether it should be moved outside the Flutter lib/ directory or integrated with the existing Flutter LocalizationService.

lib/ui/settings/profile/switch_profile_bottom_sheet.dart (1)

15-15: LGTM!

The localization integration is clean and consistent. All UI strings are properly replaced with localized keys following the 'ui.' namespace pattern.

Also applies to: 40-40, 98-98, 129-129, 243-243

lib/ui/settings/profile/share_profile_screen.dart (1)

17-17: LGTM!

The localization changes are well-structured, using appropriate namespaces ('profile.' and 'ui.') for different types of content. The implementation maintains the existing functionality while adding multi-language support.

Also applies to: 46-46, 54-54, 82-82, 168-168, 178-178, 193-195

lib/ui/settings/profile/edit_profile_screen.dart (1)

19-19: LGTM!

Comprehensive localization coverage across error messages, form labels, dialog content, and button text. The namespace organization ('errors.', 'profile.', 'shared.', 'auth.') provides clear semantic grouping.

Also applies to: 64-64, 68-68, 114-114, 132-132, 176-178, 188-188, 198-198, 207-207, 217-217, 226-226, 236-236, 271-272, 289-289, 306-306, 314-314, 328-328

lib/ui/auth_flow/login_screen.dart (1)

18-18: LGTM!

The authentication screen localization follows a consistent namespace pattern ('auth.') and covers all user-facing strings appropriately.

Also applies to: 80-80, 115-115, 141-141, 205-205

lib/ui/settings/profile/connect_profile_bottom_sheet.dart (1)

11-11: LGTM!

The localization implementation is clean and follows appropriate namespace conventions ('ui.' for UI elements, 'errors.' for error messages).

Also applies to: 21-21, 43-43, 68-68, 80-80

lib/locales/es.json (1)

1-434: LGTM!

The Spanish translation file is well-structured with:

  • Clear namespace organization matching the UI code structure
  • Consistent placeholder formatting ({name}, {count}, etc.)
  • Comprehensive coverage of all UI strings
  • Valid JSON syntax

The placeholder format aligns with the code usage (e.g., line 272's {current} and {total} match the .replaceAll() calls in chat_search_widget.dart).

Recommend native speaker review for translation quality.

While the technical implementation is correct, having a native Spanish speaker review the translations would ensure natural phrasing and appropriate terminology for the target audience. This is optional but recommended for production quality.

lib/ui/settings/network/add_relay_bottom_sheet.dart (1)

17-17: LGTM!

Thorough localization coverage of all user-facing strings including titles, labels, toast messages, and error states. The namespace organization ('network.' for network-specific content, 'clipboard.' for clipboard operations) provides clear semantic grouping.

Also applies to: 37-37, 117-117, 128-128, 133-133, 155-155, 157-157, 160-160, 171-171, 187-187, 223-223, 249-249

lib/ui/auth_flow/welcome_screen.dart (1)

10-10: LGTM! Clean localization integration.

The localization implementation is straightforward and consistent. All hard-coded strings are properly replaced with translation keys using the .tr() extension method.

Also applies to: 64-64, 75-75, 99-99, 105-105

lib/ui/settings/network/network_screen.dart (1)

14-14: LGTM! Comprehensive localization of network settings.

All user-facing strings including the app bar title, relay section titles, and help messages are properly localized using the .tr() method. The implementation is consistent throughout the file.

Also applies to: 146-146, 169-169, 176-176, 183-183, 190-190, 197-197, 204-204

lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

14-14: LGTM! Good localization and error handling improvements.

The localization implementation is correct with proper use of .tr() for static strings and .replaceAll('{name}', ...) for dynamic content. The addition of the finally block (lines 71-77) ensures that the loading state is properly reset even when exceptions occur, which is a good improvement.

Also applies to: 31-31, 61-61, 67-67, 87-87, 113-113, 116-116, 138-138

lib/config/states/localization_state.dart (1)

1-16: LGTM! Well-structured localization state.

The LocalizationState is properly implemented using Freezed with appropriate fields for managing locale state. The default value of 'system' for selectedLanguage allows system locale detection as a fallback, which aligns with the PR objectives.

As per coding guidelines, this correctly uses Freezed to manage UI states.

lib/ui/chat/chat_info/group_chat_info.dart (1)

93-94: LGTM! Comprehensive localization of group chat UI.

All user-facing strings are properly localized, including fallback values used in sorting logic (lines 93-94). The conditional rendering of localized strings based on user roles (admin, current user) is correctly implemented.

Also applies to: 150-150, 156-156, 165-165, 184-184, 200-200, 215-215, 266-266, 269-269, 279-279

lib/ui/settings/developer/developer_settings_screen.dart (1)

16-16: LGTM! Thorough localization of developer settings.

All user-facing strings are properly localized with consistent use of .tr(). Dynamic content is correctly interpolated using .replaceAll() with placeholders like {count}, {id}, {number}, and {date}. The implementation maintains good separation between UI text and business logic.

Also applies to: 42-42, 52-53, 58-58, 70-70, 89-91, 101-101, 112-112, 126-131, 133-133, 144-144, 154-154, 161-161, 172-172, 182-186, 191-191, 203-203, 223-223, 228-228, 261-261, 291-291, 300-300, 306-306, 312-312, 326-329, 359-359, 453-453, 483-483, 492-495

lib/ui/contact_list/start_chat_bottom_sheet.dart (1)

25-25: LGTM! Complete localization with improved error handling.

The localization implementation is thorough, covering all user-facing strings including titles, buttons, and toast messages. The addition of the finally block (lines 161-167) ensures proper cleanup of the loading state regardless of success or failure, which improves the user experience.

Also applies to: 61-61, 89-89, 113-113, 150-150, 157-157, 175-175, 178-178, 193-193, 260-260, 273-273, 284-284

lib/ui/settings/app_settings/app_settings_screen.dart (1)

242-252: LGTM! Language selector successfully integrated.

The new language selector section is properly integrated between the theme selector and danger zone sections, following the same UI pattern as the theme dropdown. The implementation aligns with the PR objectives to provide language selection functionality similar to the existing Tauri app.

lib/ui/settings/general_settings_screen.dart (7)

23-23: LGTM!

The localization extensions import is necessary for the .tr() method used throughout this file.


62-74: LGTM!

The localization of toast messages is implemented correctly. The error message at line 71 properly interpolates the translated prefix with the exception message.


99-114: LGTM!

The dialog strings are correctly localized using the .tr() extension method.


162-168: LGTM!

The logout toast messages are correctly localized.


194-194: LGTM!

The app bar title is correctly localized.


214-298: LGTM!

All button labels and list tile text are correctly localized throughout the settings screen.


311-311: LGTM!

The version string correctly localizes the "Version" label while preserving the dynamic version and build number information.

lib/ui/chat/chat_info/dm_chat_info.dart (3)

54-62: LGTM!

The clipboard-related messages are correctly localized.


95-100: LGTM!

The displayName fallbacks are consistently localized using 'chats.unknown'.tr().


143-177: LGTM!

All button labels are correctly localized, including the conditional follow/unfollow button text.

lib/main.dart (3)

3-14: LGTM!

The necessary imports for localization support are correctly added.


79-98: LGTM!

The MaterialApp is correctly configured with locale support:

  • Watches currentLocaleProvider for reactive locale changes
  • Uses LocalizationService.supportedLocaleObjects for supported locales
  • Includes standard Flutter localization delegates

This follows Flutter localization best practices.


54-66: Localization initialized before UI build: runApp is invoked after awaiting localizationNotifier.initialize(), so all .tr() calls in auth screens occur post-initialization.

lib/ui/widgets/language_selector_dropdown.dart (5)

1-16: LGTM!

The imports and class declaration follow the project's coding guidelines and best practices.


21-27: LGTM!

The getLanguageText method correctly handles the special case for 'system' language and falls back to the locale code for unknown languages. The use of ref.read is acceptable here since the widget already watches localizationProvider at line 31, ensuring rebuilds when needed.


29-108: LGTM!

The build method correctly:

  • Watches localizationProvider for reactive updates
  • Uses local state for the expand/collapse animation
  • Maps over supported locales to build language options
  • Handles tap interactions appropriately

88-102: LGTM!

The language option selection logic correctly:

  • Only triggers a locale change if the selected language differs from the current one
  • Uses async/await for the locale change operation
  • Collapses the dropdown after selection

111-151: LGTM!

The _LanguageOption widget is well-structured:

  • Clean separation as a private helper widget
  • Provides clear visual feedback for the selected language
  • Follows the project's coding guidelines
lib/ui/chat/widgets/reaction/reaction_default_data.dart (2)

3-3: LGTM!

The localization extensions import is necessary for the .tr() method used in the menu item labels.


19-37: No const contexts use these getters.
Search found no const ReactionDefaultData.* usages; converting to getters for runtime localization won’t break callers.

lib/ui/chat/chat_info/edit_group_screen.dart (4)

18-18: LGTM!

The localization extensions import is correctly added.


85-121: LGTM!

Error messages are correctly localized, with proper interpolation for dynamic exception information.


139-227: LGTM!

All UI text elements are correctly localized, including titles, labels, and hint text.


247-254: LGTM!

Button labels are correctly localized using shared translation keys, which promotes consistency across the app.

lib/ui/chat/widgets/reaction/reactions_dialog_widget.dart (1)

20-41: LGTM! Good refactor pattern.

The constructor parameter is now optional, with a clean getter-based default fallback to DefaultData.menuItems. This change:

  • Maintains backward compatibility (existing callers without menuItems will get the default)
  • Follows best practices for optional parameters with defaults
  • Provides a clean API for consumers
lib/utils/localization_extensions.dart (4)

1-4: LGTM!

All necessary imports are present for the localization extensions.


6-12: LGTM!

The String extension provides a clean API for translation and correctly delegates to LocalizationService.translate.


14-29: LGTM!

The BuildContext extension correctly:

  • Uses try-catch to handle cases where Localizations.localeOf might throw (e.g., during app initialization)
  • Falls back to LocalizationService.currentLocale
  • Provides a convenient tr() method for context-based translation

31-60: LGTM!

The LocalizedText widget is well-implemented:

  • Extends ConsumerWidget for Riverpod integration
  • Watches currentLocaleProvider to rebuild when the locale changes
  • Provides a clean API for localized text with styling options
  • Delegates translation to the extension method
lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (1)

19-19: LGTM: consistent localization adoption

Import and key usages look correct across title, toasts, dialog text, and buttons.

Also applies to: 37-37, 55-57, 62-62, 118-118, 155-155, 163-163, 265-265, 285-285

lib/config/states/localization_state.freezed.dart (1)

1-241: No review needed for generated code

Freezed-generated; looks standard.

lib/services/localization_service.dart (1)

45-57: Assets path is declared in pubspec pubspec.yaml includes lib/locales/ under assets and locale JSON files (de.json, en.json, es.json, it.json) are present.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

Love to see the app translated to spanish!! 🎉 Typsecript file needs to be removes and also I realized there are lots of keys that are unused that I'd prefer to remove. I'm making a list with the help of claude

if (state.selectedLanguage == 'system') {
final deviceLocale = LocalizationService.getDeviceLocale();
final deviceLanguageName = LocalizationService.supportedLocales[deviceLocale] ?? 'English';
return 'System ($deviceLanguageName)';
Copy link
Contributor

Choose a reason for hiding this comment

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

This reads oddly, in Spanish it shows as "System (Español)" instead of "Sistema (Español)". Maybe we could have a separate translation for system settings in the json file, so that all the text is in the device locale and it's not a mix with english. This would also be more flexible for future languages where parentheses might not be used or might not sound natural.

Copy link
Contributor

Choose a reason for hiding this comment

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

What I mean is that here the first select is ok, it shows System translated to spanish (Sistema) but in the second select I still see it in "spanglish" instead of showing it full in spanish, that would be "Sistema (Español)" .

Its weird to have the same word translated correctly above but in english below

"failedToLoadAccounts": "Error al cargar las cuentas"
},
"errors": {
"failedToChangeLanguage": "No se pudo cambiar el idioma a",
Copy link
Contributor

Choose a reason for hiding this comment

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

"No se pudo cambiar el idioma a {languageName}"
I seems to me that here a param is needed, in some languages the language name could be in the middle of the sentence I guess. It's not the case of spanish, here the language name at the end it's ok. I noticed this because at first I though that the last a was typo, then realized that it was a sentence to be continued...

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
test/ui/contact_list/start_chat_bottom_sheet_test.dart (1)

284-305: Incomplete localization updates: some tests still use hardcoded English strings.

The tests in the "when loading key package fails" group still use hardcoded English strings ('Follow', 'Unfollow', 'Start Chat', 'Invite to White Noise', 'Add to Group') instead of localization keys, which is inconsistent with the updates made elsewhere in this file.

For consistency, either:

  1. Update these to use localization keys (though the key-based approach is problematic—see previous comment), or
  2. Update the entire file to validate actual translated text instead of keys.

Example of inconsistency:

// Lines 202, 253: Updated to use keys
expect(find.text('ui.follow'), findsOneWidget);

// Line 284: Still uses hardcoded English
expect(find.text('Follow'), findsNothing);

Apply consistent expectations throughout the test file.

♻️ Duplicate comments (1)
lib/locales/de.json (1)

77-77: Fix the typo in the key name.

The key "deleteAllKeyPackagesescription" is missing a capital 'D' and should be "deleteAllKeyPackagesDescription" to match the naming convention used throughout the file (e.g., line 36: "deleteAppDataDescription", line 75: "publishKeyPackageDescription").

Apply this diff:

-        "deleteAllKeyPackagesescription": "Bist du sicher, dass du alle Schlüsselpakete löschen möchtest?",
+        "deleteAllKeyPackagesDescription": "Bist du sicher, dass du alle Schlüsselpakete löschen möchtest?",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50d5426 and 343c216.

📒 Files selected for processing (10)
  • lib/locales/de.json (1 hunks)
  • lib/locales/en.json (1 hunks)
  • lib/locales/es.json (1 hunks)
  • lib/locales/it.json (1 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (7 hunks)
  • lib/ui/contact_list/widgets/contact_list_tile.dart (2 hunks)
  • lib/ui/contact_list/widgets/share_invite_callout.dart (2 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (2 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (3 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • lib/locales/it.json
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/locales/es.json
  • lib/locales/en.json
  • lib/ui/contact_list/widgets/share_invite_callout.dart
🧰 Additional context used
📓 Path-based instructions (2)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • lib/ui/contact_list/widgets/contact_list_tile.dart
**/*_test.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*_test.dart: Follow the Arrange-Act-Assert convention for tests.
Name test variables clearly. Follow the convention: inputX, mockX, actualX, expectedX, etc.
Write unit tests for each public function. Use test doubles to simulate dependencies, except for third-party dependencies that are not expensive to execute.
Write acceptance tests for each module. Follow the Given-When-Then convention.
Use the standard widget testing for Flutter.

Files:

  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*_test.dart : Use the standard widget testing for Flutter.

Applied to files:

  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/contact_list/widgets/contact_list_tile.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/contact_list/widgets/contact_list_tile.dart (2)

10-10: LGTM!

The import is necessary for the .tr() extension method used in the localized strings below.


145-162: Approve translation keys and placeholders
All required keys (ui.removeContact, ui.confirmRemoveContact, shared.cancel, shared.remove) are defined in lib/locales/{en,de,es,it}.json and include the {name} placeholder.

@josefinalliende
Copy link
Contributor

josefinalliende commented Oct 6, 2025

This is the list that claude 🤖 made of kesy that seem to be unused (167). Hope it helps

Shared (14 keys)

  • shared.notImplementedYet
  • shared.finish
  • shared.continue
  • shared.accept
  • shared.decline
  • shared.copy
  • shared.reply
  • shared.edit
  • shared.send
  • shared.search
  • shared.add
  • shared.view
  • shared.scan
  • shared.share
  • shared.errorOccurred
  • shared.noDataFound

Settings (45 keys)

  • settings.logoutSuccess
  • settings.logoutError
  • settings.deleteAllDataSuccess
  • settings.deleteAllDataError
  • settings.deleteKeyPackagesSuccess
  • settings.deleteKeyPackagesError
  • settings.publishKeyPackageSuccess
  • settings.publishKeyPackageError
  • settings.profile
  • settings.addNewProfile
  • settings.switchProfile
  • settings.nostrKeys
  • settings.network
  • settings.wallet
  • settings.signOutDescription
  • settings.privacyAndSecurity
  • settings.deleteAllDataTitle
  • settings.deleteAllDataDescription
  • settings.publishAKeyPackage
  • settings.publishKeyPackage
  • settings.publishKeyPackageDescription
  • settings.deleteAllKeyPackages
  • settings.testNotifications
  • settings.notificationSuccess
  • settings.toastSuccess
  • settings.testToastSuccess
  • settings.testToastError
  • settings.toastError
  • settings.qrCode

Profile (7 keys)

  • profile.title
  • profile.displayName
  • profile.name
  • profile.about
  • profile.website
  • profile.lightningAddress
  • profile.saveChanges

Nostr Keys (3 keys)

  • nostrKeys.title
  • nostrKeys.copyPublicKey

Network (20 keys)

  • network.title
  • network.connectedRelays
  • network.noRelaysConnected
  • network.relayStatuses.pending
  • network.relayStatuses.initialized
  • network.relayStatuses.connecting
  • network.relayStatuses.connected
  • network.relayStatuses.disconnected
  • network.relayStatuses.terminated
  • network.inboxRelayList
  • network.addInboxRelay
  • network.noInboxRelays
  • network.keyPackageRelaysList
  • network.addKeyPackageRelay
  • network.noKeyPackageRelays
  • network.removeRelay
  • network.addNewRelay
  • network.addRelay
  • network.fetchRelayDataError
  • network.invalidRelayUrlFormat
  • network.inboxRelayAlreadyConfigured
  • network.keyPackageRelayAlreadyConfigured
  • network.noActiveAccountError
  • network.addRelayError

Wallet (8 keys)

  • wallet.title
  • wallet.unexpectedError
  • wallet.lightningWalletConnected
  • wallet.balance
  • wallet.removing
  • wallet.disconnectWallet
  • wallet.informationAnswerLink
  • wallet.connectWallet

Donate (1 key)

  • donate.title

Chats (40 keys)

  • chats.errorLoadingChats
  • chats.newChat
  • chats.chatDetails
  • chats.search
  • chats.contactsLoadingError
  • chats.unknownError
  • chats.contacts
  • chats.noContactsFound
  • chats.searching
  • chats.searchResults
  • chats.searchPlaceholder
  • chats.noChatSelected
  • chats.startSecureChat
  • chats.contactNotSetUp
  • chats.sendInviteQuestion
  • chats.sendingInvite
  • chats.sendInvite
  • chats.creatingChat
  • chats.startChatAndSendInvite
  • chats.messageDeleted
  • chats.invitation
  • chats.noMessageContent
  • chats.invoicePaid
  • chats.copyInvoice
  • chats.copy
  • chats.reply
  • chats.delete
  • chats.admin
  • chats.groupRelays
  • chats.closeMessageMenu
  • chats.video
  • chats.audio
  • chats.pdf
  • chats.privateChatInvite
  • chats.groupChatInvite
  • chats.paySats
  • chats.declineInvite
  • chats.decliningInvite
  • chats.acceptInvite
  • chats.acceptingInvite
  • chats.inviteAccepted
  • chats.inviteDeclined
  • chats.waitMediaUpload
  • chats.messageNotFound
  • chats.profileReadyTitle

Login (6 keys)

  • login.signInWithNostrKey
  • login.createNewNostrKey
  • login.signInDescription
  • login.logIn
  • login.welcomeTo
  • login.slogan

Clipboard (1 key)

  • clipboard.error

Media (2 keys)

  • media.downloadError
  • media.image

Auth (2 keys)

  • auth.createNewNostrKey
  • auth.signInWithNostrKey

UI (17 keys)

  • ui.newChat
  • ui.shareYourProfile
  • ui.searchForFriends
  • ui.groupChatDetails
  • ui.chatDetails
  • ui.addRelay
  • ui.addNewRelay
  • ui.removeRelay
  • ui.members
  • ui.member
  • ui.admin
  • ui.groupRelays
  • ui.noRelaysConnected
  • ui.connectWallet
  • ui.viewQrCode
  • ui.whatWalletCanIConnect
  • ui.publishNewKeyPackage
  • ui.inspectRelayKeyPackages
  • ui.deleteAllKeyPackagesFromRelays
  • ui.scanQrCode

Errors (4 keys)

  • errors.failedToChangeLanguage
  • errors.unexpectedError
  • errors.errorLoading
  • errors.failedToDeleteData

@josefinalliende
Copy link
Contributor

@untreu2 let me know when you want me to review this again. From my side, the most relevant comment in my opinion is the one related to the unused keys list

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

I tried it locally and noticed some last details:

  • 'Your Profile is Ready' text is not translated. The text is only in en.json but in the component ProfileReadyCard is not used
  • Also, the quote of what the button says does not match what the button actually says. It happens in english too and I hadn't realized before, but in spanish for me it was evident that something was off. It says to click the button that says "Comenzar a chatear" but there is no button with that text, it has the text "Buscar amigos". I think that the quote on what to click should have the same text that the button we are refering to.
your profile is ready

Also in the screens to create a new group chat, I still see all the texts without translation:

New Group Chat Group Chat Details
new group screen

another detail: the invite message ( "Join me on ...") is also is in english and I think it should be translated too

Finally, I realized that the error handling utils still have messages visible to the user that are in english.

if (state.selectedLanguage == 'system') {
final deviceLocale = LocalizationService.getDeviceLocale();
final deviceLanguageName = LocalizationService.supportedLocales[deviceLocale] ?? 'English';
return 'System ($deviceLanguageName)';
Copy link
Contributor

Choose a reason for hiding this comment

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

What I mean is that here the first select is ok, it shows System translated to spanish (Sistema) but in the second select I still see it in "spanglish" instead of showing it full in spanish, that would be "Sistema (Español)" .

Its weird to have the same word translated correctly above but in english below

"errorLoadingFollows": "Error al cargar los usuarios que sigues",
"noFollowsFound": "No se encontraron los usuarios que sigues",
"loadingMetadata": "Cargando metadatos...",
"noFollowsMatchSearch": "Ningún seguido coincide con tu búsqueda",
Copy link
Contributor

Choose a reason for hiding this comment

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

[sug] I didn't noticed this "seguido" here before, but I would replace it too with "usuario al que sigues", "seguido" sounds odd. It would be: "Ningún usuario al que sigues coincide con la búsqueda"

"failedToAddRelay": "Error al agregar el relé",
"failedToDeleteRelay": "Error al eliminar el relé"
},
"wallet": {
Copy link
Contributor

Choose a reason for hiding this comment

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

There are still some keys unused, here is the updated list of keys that seem to be unused and should be used or removed (+ All the keys under the "wallet" key):

  • auth.createNewNostrKey
  • auth.signInWithNostrKey
  • ui.newChat
  • ui.shareYourProfile
  • ui.searchForFriends
  • ui.groupChatDetails
  • ui.chatDetails
  • ui.addRelay
  • ui.addNewRelay
  • ui.removeRelay
  • ui.admin
  • ui.groupRelays
  • ui.noRelaysConnected
  • ui.connectWallet
  • ui.scanQrCode
  • errors.failedToChangeLanguageName
  • errors.unexpectedError
  • errors.errorLoading
  • errors.failedToDeleteData

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 9, 2025

Maybe I should have written the files from scratch instead of using ones in the tauri code because it led to a bunch of unused keys. Btw, do you think we should remove the wallet keys? Because we'll use them in the future when we add NWC again.

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 9, 2025

I'll fix that profile_ready_card button in another PR. Because It's not correct on the master too.
Figma:
image
Master:
image

@josefinalliende
Copy link
Contributor

Maybe I should have written the files from scratch instead of using ones in the tauri code because it led to a bunch of unused keys. Btw, do you think we should remove the wallet keys? Because we'll use them in the future when we add NWC again.

Yes, I would prefer to remove them, cause probably the the design and wording will have changed by the time we implement that again.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
lib/config/providers/localization_provider.dart (1)

79-82: Comment still contradicts behavior.

We persist all locale selections, including "system", yet the comment says “only if not system.” Please align the comment with the actual behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f1c753 and 8c89ae6.

📒 Files selected for processing (15)
  • lib/config/constants.dart (0 hunks)
  • lib/config/providers/localization_provider.dart (1 hunks)
  • lib/locales/de.json (1 hunks)
  • lib/locales/en.json (1 hunks)
  • lib/locales/es.json (1 hunks)
  • lib/locales/fr.json (1 hunks)
  • lib/locales/it.json (1 hunks)
  • lib/locales/pt.json (1 hunks)
  • lib/locales/ru.json (1 hunks)
  • lib/locales/tr.json (1 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (5 hunks)
  • lib/ui/contact_list/group_chat_details_sheet.dart (7 hunks)
  • lib/ui/contact_list/new_group_chat_sheet.dart (7 hunks)
  • lib/ui/contact_list/widgets/profile_ready_card.dart (5 hunks)
  • lib/ui/contact_list/widgets/share_invite_button.dart (3 hunks)
💤 Files with no reviewable changes (1)
  • lib/config/constants.dart
✅ Files skipped from review due to trivial changes (2)
  • lib/locales/tr.json
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
🚧 Files skipped from review as they are similar to previous changes (7)
  • lib/locales/es.json
  • lib/locales/it.json
  • lib/locales/pt.json
  • lib/locales/de.json
  • lib/ui/contact_list/widgets/profile_ready_card.dart
  • lib/ui/contact_list/widgets/share_invite_button.dart
  • lib/locales/fr.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/contact_list/group_chat_details_sheet.dart
  • lib/config/providers/localization_provider.dart
  • lib/ui/contact_list/new_group_chat_sheet.dart
🔇 Additional comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

19-19: LGTM!

The localization extensions import is necessary for the .tr() method calls used throughout this file.


37-37: Localization keys presence verified. All keys used in new_group_chat_sheet.dart exist across all lib/locales/*.json.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

Thanks for the system case fix! 🚀

I think there is no point in keeping unused translations, by leaving them here we then have the cost of having to add for other languages translations that weren't really necessary. Now that we have 8 languages, 50 unused keys are at least 400 lines of unused code.

I checked with Claude 🤖 and says there are still 97 keys unused. Here's the list it made.

Total Keys Analyzed: 362
Used Keys: 265
Unused Keys: 97


Settings (3 keys)

  • settings.signOutDescription
  • settings.deleteAllDataTitle
  • settings.deleteAllDataDescription
  • settings.deleteAllKeyPackageDescription

Network (23 keys)

  • network.title
  • network.connectedRelays
  • network.noRelaysConnected
  • network.relayStatuses.pending
  • network.relayStatuses.initialized
  • network.relayStatuses.connecting
  • network.relayStatuses.connected
  • network.relayStatuses.disconnected
  • network.relayStatuses.terminated
  • network.inboxRelayList
  • network.addInboxRelay
  • network.noInboxRelays
  • network.keyPackageRelaysList
  • network.addKeyPackageRelay
  • network.noKeyPackageRelays
  • network.removeRelay
  • network.addNewRelay
  • network.fetchRelayDataError
  • network.invalidRelayUrlFormat
  • network.inboxRelayAlreadyConfigured
  • network.keyPackageRelayAlreadyConfigured
  • network.noActiveAccountError
  • network.addRelayError

Wallet (7 keys)

  • wallet.title
  • wallet.unexpectedError
  • wallet.lightningWalletConnected
  • wallet.balance
  • wallet.removing
  • wallet.disconnectWallet
  • wallet.informationAnswerLink
  • wallet.connectWallet

Donate (1 key)

  • donate.title

Chats (42 keys)

  • chats.errorLoadingChats
  • chats.newChat
  • chats.chatDetails
  • chats.unknownError
  • chats.searching
  • chats.searchResults
  • chats.searchPlaceholder
  • chats.noChatSelected
  • chats.startSecureChat
  • chats.contactNotSetUp
  • chats.sendInviteQuestion
  • chats.sendingInvite
  • chats.sendInvite
  • chats.creatingChat
  • chats.startChatAndSendInvite
  • chats.messageDeleted
  • chats.invitation
  • chats.noMessageContent
  • chats.invoicePaid
  • chats.copyInvoice
  • chats.groupRelays
  • chats.closeMessageMenu
  • chats.video
  • chats.audio
  • chats.pdf
  • chats.privateChatInvite
  • chats.groupChatInvite
  • chats.paySats
  • chats.declineInvite
  • chats.decliningInvite
  • chats.acceptInvite
  • chats.acceptingInvite
  • chats.inviteAccepted
  • chats.inviteDeclined
  • chats.waitMediaUpload

Login (6 keys)

  • login.signInWithNostrKey
  • login.createNewNostrKey
  • login.signInDescription
  • login.logIn
  • login.welcomeTo
  • login.slogan

Media (1 key)

  • media.downloadError

Auth (2 keys)

  • auth.createNewNostrKey
  • auth.signInWithNostrKey

UI (11 keys)

  • ui.newChat
  • ui.shareYourProfile
  • ui.searchForFriends
  • ui.chatDetails
  • ui.addRelay
  • ui.addNewRelay
  • ui.removeRelay
  • ui.admin
  • ui.groupRelays
  • ui.noRelaysConnected
  • ui.connectWallet
  • ui.scanQrCode
  • ui.enterGroupName

Errors (4 keys)

  • errors.failedToChangeLanguage
  • errors.unexpectedError
  • errors.errorLoading
  • errors.failedToDeleteData

final deviceLocale = LocalizationService.getDeviceLocale();
final deviceLanguageName = LocalizationService.supportedLocales[deviceLocale] ?? 'English';
return 'System ($deviceLanguageName)';
return '${'shared.system'.tr()} ($deviceLanguageName)';
Copy link
Contributor

Choose a reason for hiding this comment

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

🚀

@josefinalliende
Copy link
Contributor

@untreu2 btw this ts tool that I made some time ago can help you to detect which keys are missing in some languages. https://github.com/mok-labs/locales-check .... I tried it locally in this branch and warned me about 80 cases. Probably after removing the unused keys that number is reduced.

I don't want to add this as a .ts depency to this proyect (makes no sense because is another language and also I don't know of someone from moklabs is maintaining that library now) but running locally could be enough. If we want to have a CI check to avoid having missing translations (eg: we add a new text in en.json. but then forget to add it in the ru.json) we could maybe pass that logic to dart or sh and run it in github actions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
lib/locales/de.json (1)

149-283: Standardize informal German pronouns.

The German copy mixes informal “du/dein” with formal “Sie/Ihr” (e.g., Lines 149, 154–168, 277–283). Please pick one style—usually informal “du”—and update the affected strings for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c89ae6 and 90c4cd8.

📒 Files selected for processing (9)
  • CHANGELOG.md (1 hunks)
  • lib/locales/de.json (1 hunks)
  • lib/locales/en.json (1 hunks)
  • lib/locales/es.json (1 hunks)
  • lib/locales/fr.json (1 hunks)
  • lib/locales/it.json (1 hunks)
  • lib/locales/pt.json (1 hunks)
  • lib/locales/ru.json (1 hunks)
  • lib/locales/tr.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • lib/locales/en.json
  • lib/locales/tr.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/locales/es.json
  • lib/locales/pt.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.md

📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)

**/*.md: NIPs (Nostr Implementation Possibilities) are numbered like NIP-XX where XX are two capitalized hexadecimal digits, e.g., NIP-01 and NIP-C7.
To read a specific NIP, construct the NIP URL following this template: https://raw.githubusercontent.com/nostr-protocol/nips/refs/heads/master/{nip}.md (replace {nip} in the URL template with the relevant NIP name, e.g., 07 for NIP-07, or C7 for NIP-C7).
To read the definition of a specific kind, construct a URL following this template: https://nostrbook.dev/kinds/{kind}.md (replace {kind} in the template with the kind number, e.g., https://nostrbook.dev/kinds/0.md for kind 0).

Files:

  • CHANGELOG.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
lib/ui/auth_flow/login_screen.dart (1)

158-158: Consider localizing the hint text for consistency.

The hint text 'nsec...' remains hardcoded. While nsec is a technical prefix from the Nostr protocol specification and could reasonably remain in English, consider whether the hint should be localized for consistency with the rest of the UI. For example, different locales might prefer different ellipsis styles or might want to add explanatory text.

This is a minor consistency consideration and not blocking.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f5796c and 86cf27f.

📒 Files selected for processing (4)
  • lib/ui/auth_flow/create_profile_screen.dart (6 hunks)
  • lib/ui/auth_flow/info_screen.dart (4 hunks)
  • lib/ui/auth_flow/login_screen.dart (5 hunks)
  • lib/ui/auth_flow/welcome_screen.dart (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • lib/ui/auth_flow/create_profile_screen.dart
  • lib/ui/auth_flow/welcome_screen.dart
  • lib/ui/auth_flow/info_screen.dart
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/auth_flow/login_screen.dart
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
📚 Learning: 2025-09-06T09:32:55.455Z
Learnt from: codeswot
PR: parres-hq/whitenoise_flutter#595
File: lib/ui/settings/profile/share_profile_qr_scan_screen.dart:73-90
Timestamp: 2025-09-06T09:32:55.455Z
Learning: The whitenoise_flutter project does not use localization (AppLocalizations) - hard-coded strings are acceptable and should not be flagged for localization.

Applied to files:

  • lib/ui/auth_flow/login_screen.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/auth_flow/login_screen.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/auth_flow/login_screen.dart (2)

18-18: LGTM!

The import is necessary for the .tr() extension method used throughout the file.


81-81: All auth translation keys verified across all locale files All four keys are present in en, de, es, it, tr, pt, fr, and ru.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

@untreu2 I tested this branch in my phone at commit bfafba5 and I found that replies are now broken 🐛.... I tested in master and there they work fine

replies-broken.MP4

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 10, 2025

Fixed.
image
@josefinalliende

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 10, 2025

Moving getDisplayName func to /utils..

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 10, 2025

Done!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
lib/utils/message_utils.dart (1)

4-23: Handle empty sender.displayName and clarify parameter precedence

  • Fallback to 'chats.unknownUser'.tr() when sender.displayName is empty
  • Add a doc comment or refactor to explicitly prioritize replyingTo over editingMessage when both are non-null
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9b032 and b07a164.

📒 Files selected for processing (3)
  • lib/ui/chat/widgets/chat_input.dart (6 hunks)
  • lib/ui/chat/widgets/message_widget.dart (3 hunks)
  • lib/utils/message_utils.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/chat/widgets/message_widget.dart
  • lib/utils/message_utils.dart
  • lib/ui/chat/widgets/chat_input.dart
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (8)
lib/ui/chat/widgets/message_widget.dart (3)

3-3: LGTM!

The imports are appropriate for the localization changes: flutter_riverpod for ConsumerWidget, localization_provider for locale watching, and message_utils for centralized display name logic.

Also applies to: 7-7, 13-13


433-441: LGTM!

The conversion to ConsumerWidget and locale watching is correctly implemented. Watching currentLocaleProvider ensures the widget rebuilds when the user changes the app language, which is necessary for the localized "you" string in MessageUtils.getDisplayName.


465-465: Verify the MessageUtils call maintains correct behavior.

The change from direct field access to MessageUtils.getDisplayName(replyingTo, null) centralizes the display name logic and adds localization for "you". This is a good refactor.

However, ensure this handles all edge cases correctly:

  • The old code returned replyingTo?.sender.displayName which could be null or empty
  • The new code will never return null but could return an empty string if displayName is empty

Consider adding a test case to verify that when replyingTo.isMe is true, the localized "you" string is displayed correctly.

lib/ui/chat/widgets/chat_input.dart (5)

9-9: LGTM!

The localization-related imports are correctly added to support the localized strings and MessageUtils usage.

Also applies to: 17-18


336-351: LGTM!

The conversion to ConsumerWidget and locale watching is correctly implemented, ensuring the header updates when the user changes languages.


374-374: LGTM!

The display name logic is correctly centralized using MessageUtils.getDisplayName(replyingTo, editingMessage), which handles both reply and edit scenarios with proper localization for the current user.


400-400: Localization key and fallback logic verified

chats.quoteText exists in all locale files, and the fallback only occurs when both replyingTo?.content and editingMessage?.content are null.


266-266: Localization key verified

Verified chats.message exists in all locale files (en, de, es, it, tr, pt, fr, ru).

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

Replies are still not working for me. I've just built at commit b07a164 and recorded what I see:

ScreenRecording_10-10-2025.14-03-42_1.MP4

@josefinalliende
Copy link
Contributor

@untreu2 I also found that now I see an extra {name} in the invite message. I think it's missing to pass the name as param right?

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 10, 2025

Exactly.

Fixed now.
image

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

29-78: Localize error messages in createNewGroup
Replace the raw strings used for error states:

  • “No active account found”
  • “Failed to create group due to an internal error. Please try again.”
    with localization calls (e.g. ‘errors.noActiveAccount’​.tr()), and add corresponding keys/translations.
🧹 Nitpick comments (1)
lib/ui/settings/developer/developer_settings_screen.dart (1)

126-131: Use tr named replacements instead of manual replaceAll.

You already rely on tr({'count': deletedCount}) elsewhere, so the extension clearly supports named args. Stick to that here instead of string replaceAll; it keeps placeholder handling centralized, avoids typos, and lets translators reuse the same token multiple times without extra work. Suggested tweak:

-      ref.showSuccessToast(
-        'settings.fetchedKeyPackagesSuccess'.tr().replaceAll(
-          '{count}',
-          keyPackages.length.toString(),
-        ),
-      );
+      ref.showSuccessToast(
+        'settings.fetchedKeyPackagesSuccess'.tr({'count': keyPackages.length}),
+      );

and likewise for the other replaceAll usages (deleteKeyPackageDescription, keyPackagesCount, keyPackageCreatedAt).

Also applies to: 183-186, 326-329, 492-495

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b07a164 and c9328b6.

📒 Files selected for processing (7)
  • lib/ui/chat/chat_info/dm_chat_info.dart (6 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (9 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (6 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (7 hunks)
  • lib/ui/chat/widgets/chat_search_widget.dart (4 hunks)
  • lib/ui/contact_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/settings/developer/developer_settings_screen.dart (22 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • lib/ui/chat/chat_info/dm_chat_info.dart
  • lib/ui/chat/widgets/chat_search_widget.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/contact_list/start_chat_bottom_sheet.dart
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.

Applied to files:

  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/settings/developer/developer_settings_screen.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (7)
lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (3)

19-19: LGTM!

The localization extensions import is correctly added to support the .tr() method calls throughout the file.


37-37: LGTM!

All simple localization key replacements follow the correct pattern and use appropriate namespace prefixes (chats., ui., shared.).

Also applies to: 55-56, 62-62, 155-155, 163-163, 265-265, 284-284


96-96: LGTM!

The error message correctly combines the localized prefix with the error details using string interpolation.

lib/ui/chat/chat_info/widgets/member_action_buttons.dart (4)

14-14: LGTM! Import added for localization support.

The localization_extensions import is correctly added to enable the .tr() extension method used throughout the file.


71-77: LGTM! Finally block ensures proper state cleanup.

The addition of the finally block is excellent. It guarantees that _isCreatingGroup is reset even if an exception occurs, preventing the button from being stuck in a loading state.


107-127: LGTM! Follow/unfollow messages properly localized.

The implementation correctly uses localized messages with dynamic {name} placeholders for follow/unfollow actions. The localization keys are checked in the verification script from the previous comment.


80-96: LGTM! Button labels properly localized.

The button labels are correctly localized using the .tr() extension method. The conditional logic for the follow/unfollow button (line 138) appropriately switches between localized strings based on the follow state.

Also applies to: 129-145

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2)

62-62: Consider consolidating namespace usage for chat-related strings.

The file mixes ui and chats namespaces for group member actions. For example, ui.removeFromGroup (lines 160, 281) and ui.addToAnotherGroup (line 262) are chat/group-specific actions but use the ui namespace, while other group actions like chats.removedFromGroupSuccess and chats.removeFromGroupTitle use the chats namespace. Similarly, line 62 uses ui.noUserToAddToGroup.

Consolidating related keys under a single namespace (e.g., chats) would improve maintainability and make it easier to locate all group-related translations.

Also applies to: 160-160, 262-262, 281-281


96-96: Include error details via placeholder for better localization.

The hard-coded colon and space ': ' between the translated message and error variable may not be appropriate for all locales (e.g., French typically includes a space before colons).

Consider including the error as a placeholder in the translation key:

-        ref.showErrorToast('${'chats.failedToRemoveMember'.tr()}: $e');
+        ref.showErrorToast('chats.failedToRemoveMember'.tr({'error': e.toString()}));

Then update the translation strings to include the {error} placeholder (e.g., "Failed to remove member: {error}" in English, with locale-appropriate formatting in other languages).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9328b6 and b9cc2cb.

📒 Files selected for processing (1)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (9 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2)

19-19: LGTM!

The import of localization_extensions.dart is necessary for the .tr() extension method used throughout this file.


90-92: Placeholder substitution now consistent.

The previous review comment about inconsistent placeholder substitution patterns has been addressed. Both locations now consistently use the Map-based approach .tr({'name': widget.member.displayName}) for placeholder substitution.

Also applies to: 138-138

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

I deleted the app, pulled, checked that I was in the last commit b9cc2cb , built the app, installed and tried again. Still can't see the replies in my iphone. When I switch to master, build an install I can see the replies.... so something is broken in this branch. I tried multiple times. I also checked that my master branch was up to date.

💡 Something new that I've found is that in only happened to me in spanish. When I switched my system settings in my iphone to english, I could see replies properly

@josefinalliende
Copy link
Contributor

I deleted the app, pulled, checked that I was in the last commit b9cc2cb , built the app, installed and tried again. Still can't see the replies in my iphone. When I switch to master, build an install I can see the replies.... so something is broken in this branch. I tried multiple times. I also checked that my master branch was up to date.

💡 Something new that I've found is that in only happened to me in spanish. When I switched my system settings in my iphone to english, I could see replies properly

it happened to me in italian too, in french too and in portuguese. I won't check in other languages cause I'm afraid that if I change to russian I will no longer be able to go back to spanish without understading a word 😅

@untreu2
Copy link
Contributor Author

untreu2 commented Oct 10, 2025

All right, I've solved the problem. The reply button was broken in non-English langs because the code was comparing menu item labels with hardcoded strings like 'Reply' instead of using the localized strings like 'chats.replyAction'.tr().

Screen.Recording.2025-10-11.at.01.48.36.mov

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
lib/ui/chat/services/chat_dialog_service.dart (1)

44-44: Localize remaining hard-coded user-facing strings.

Several user-facing strings remain hard-coded in English:

  • Line 44: 'No Recents'
  • Line 68: 'Search emoji'
  • Line 130: 'Message copied to clipboard'

For consistency with the localization effort, these strings should be translated using the tr() extension method.

Example for line 130:

-                  successMessage: 'Message copied to clipboard',
+                  successMessage: 'chats.messageCopied'.tr(),

Note: Ensure the corresponding locale keys are added to all locale JSON files and verified with the locales-check tool mentioned in the PR comments.

Also applies to: 68-68, 130-130

🧹 Nitpick comments (1)
lib/ui/chat/services/chat_dialog_service.dart (1)

124-139: Use action identifiers instead of comparing translated labels
Comparing menuItem.label to .tr() results is brittle—translations may change. Add an actionId (e.g. enum or constant) to MenuItem and switch on that for handling taps.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9cc2cb and 76c8479.

📒 Files selected for processing (1)
  • lib/ui/chat/services/chat_dialog_service.dart (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/chat/services/chat_dialog_service.dart
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use AppLocalizations to manage translations.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (1)
lib/ui/chat/services/chat_dialog_service.dart (1)

14-14: LGTM!

The localization extensions import is correctly added to support the tr() method used throughout this file.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

✅ LGTM!!! replies work!

@untreu2 untreu2 merged commit 16318b7 into master Oct 10, 2025
2 checks passed
This was referenced Oct 22, 2025
@untreu2 untreu2 deleted the localization branch November 5, 2025 18:29
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.

Localization (l10n)

3 participants