Skip to content

feat: add Spanish translation support#810

Open
Shweta-281 wants to merge 4 commits intoAOSSIE-Org:masterfrom
Shweta-281:translation-es
Open

feat: add Spanish translation support#810
Shweta-281 wants to merge 4 commits intoAOSSIE-Org:masterfrom
Shweta-281:translation-es

Conversation

@Shweta-281
Copy link
Copy Markdown
Contributor

@Shweta-281 Shweta-281 commented Apr 2, 2026

Summary

This PR adds complete Spanish language support to Resonate.

Changes made

  • Created lib/l10n/app_es.arb with all strings translated from app_en.arb
  • Added Locale('es') to supportedLocales in lib/main.dart
  • Added <string>es</string> to CFBundleLocalizations in ios/Runner/Info.plist
  • Ran flutter gen-l10n – no errors, all placeholders preserved

Testing done

  • Switched device/emulator language to Spanish – app UI shows Spanish text
  • Verified placeholders (e.g., {username}) work correctly
  • Checked ICU select/plural messages (e.g., "noAvailableRoom")
  • No JSON syntax errors

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking CHANGE which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g. code style improvements, linting)
  • Documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

Please include screenshots below if applicable.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

Summary by CodeRabbit

  • New Features

    • Spanish (es) localization added — full UI and accessibility strings translated; app now recognizes and supports Spanish.
  • Chores

    • Build and packaging configuration tidied; a media dependency switched to a pub release.
    • Tests updated for test-mode behavior and stability.
    • Minor UI/UX cleanup (snackbar behavior, playback UI initialization and small formatting fixes).

@Shweta-281 Shweta-281 requested a review from M4dhav as a code owner April 2, 2026 14:50
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

🎉 Welcome @Shweta-281!
Thank you for your pull request! Our team will review it soon. 🔍

  • Please ensure your PR follows the contribution guidelines. ✅
  • All automated tests should pass before merging. 🔄
  • If this PR fixes an issue, link it in the description. 🔗

We appreciate your contribution! 🚀

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

Adds Spanish (es) localization: new ARB and generated Dart localization, registers es in supported locales and iOS Info.plist; also updates Android buildscript formatting/signing config, swaps a Git dependency for a pub version, and includes small UI/test tweaks.

Changes

Cohort / File(s) Summary
iOS Configuration
ios/Runner/Info.plist
Added es to CFBundleLocalizations.
Localization resources (ARB)
lib/l10n/app_es.arb
New Spanish ARB with extensive translated strings, ICU placeholders, plurals, and descriptions (~+1761 lines).
Localization wiring & implementation
lib/l10n/app_localizations.dart, lib/l10n/app_localizations_es.dart
Registered Locale('es'), updated lookup/delegate to return AppLocalizationsEs, and added Spanish implementation with many overrides including plural/select logic.
Android buildscript
android/app/build.gradle.kts
Reformatted android block, moved signingConfigs up, switched unsafe casts to nullable reads with explicit GradleException on missing signing props, and reformatted manifestPlaceholders.
Dependency update
pubspec.yaml
Replaced Git-sourced flutter_lyric with pub version flutter_lyric: ^2.0.0.
Player UI & Snackbar
lib/views/screens/chapter_play_screen.dart, lib/views/widgets/snackbar.dart
Simplified UINetease instantiation; snackbar short-circuits in Get.testMode and uses safe Get.context fallback color; minor whitespace/comment cleanup.
Tests
test/controllers/change_email_controller_test.dart
Enabled Get.testMode = true, restructured widget test flow, wrapped form in Scaffold, and adjusted sequencing and verifications.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

good first issue, translations

Suggested reviewers

  • M4dhav

Poem

🐰 Saltando entre líneas, traigo voz en español,
Traduje plurales y nombres con mi pequeña razón.
Con orejas al viento canto: nuevas palabras están,
Brinco, escribo, comparto — ¡Resonate ahora habla en español! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes are out of scope: android/build.gradle.kts reformatting, pubspec.yaml dependency update to flutter_lyric, chapter_play_screen.dart UINetease simplification, snackbar.dart test mode handling, and test file modifications are unrelated to Spanish translation support. Remove or separate the following changes into a different PR: gradle formatting, flutter_lyric dependency bump, lyric UI refactoring, snackbar test mode logic, and test file modifications to keep this PR focused on Spanish localization.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add Spanish translation support' clearly and concisely summarizes the primary change, matching the main objective of adding Spanish localization.
Linked Issues check ✅ Passed The PR successfully implements all coding objectives from #809: Spanish translation file added, supportedLocales updated in app_localizations.dart, iOS Info.plist modified, and generated files created with proper ICU syntax.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@android/app/build.gradle.kts`:
- Around line 49-68: The release signing config is unconditionally created and
assigned using signingConfigs.create("release") and
buildTypes.release.signingConfig which causes Gradle exceptions when
keystoreProperties is missing; guard both the creation (the
signingConfigs.create("release") block that reads keystoreProperties["keyAlias"]
/ ["keyPassword"] / ["storeFile"] / ["storePassword"]) and the assignment
(buildTypes { release { signingConfig = ... } }) with a presence check for
keystoreProperties (or a boolean flag like hasKeystore), so only create the
"release" signingConfig and set buildTypes.release.signingConfig when
keystoreProperties exist / are valid, otherwise skip creation/assignment to
avoid configuration-time failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 163da95d-f97a-4be0-a27d-f34c920bea0f

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba5ab3 and 84bf1fa.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • android/app/build.gradle.kts
  • pubspec.yaml

Copy link
Copy Markdown

@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

🧹 Nitpick comments (4)
test/controllers/change_email_controller_test.dart (2)

220-221: Missing newline at end of file.

The file ends without a trailing newline. Consider adding one for consistency with common style conventions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/controllers/change_email_controller_test.dart` around lines 220 - 221,
Add a trailing newline at the end of the test file to satisfy POSIX/style
conventions: open test/controllers/change_email_controller_test.dart and ensure
the file ends with a single newline character after the final closing braces
(the end of the test block that contains "});" / "}"). Save the file so the
repository includes the newline at EOF.

201-207: Timing-dependent verification may be fragile.

The test verifies mockAccount.updateEmail after the first pumpAndSettle(), then waits 4 seconds before verifying the database update. Given the nested .then() chain in changeEmail() (see change_email_controller.dart:136-196), if the async operations complete faster or slower than expected, this could lead to flaky tests.

Consider consolidating to a single pumpAndSettle(Duration(seconds: N)) before all verifications, or using untilCalled() from Mockito if deterministic ordering is needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/controllers/change_email_controller_test.dart` around lines 201 - 207,
The test's timing is fragile because it verifies mockAccount.updateEmail
immediately after the first tester.pumpAndSettle() then waits another 4 seconds;
updateEmail and subsequent DB updates in changeEmail() (changeEmail()) can
complete at different times leading to flakiness. Replace the two-stage waiting
with a single deterministic wait or synchronization: either call
tester.pumpAndSettle(const Duration(seconds: N)) once (choose N large enough for
the whole changeEmail() chain) before all verify calls, or use Mockito's
untilCalled(mockAccount.updateEmail(...)) to wait for that specific call before
asserting the database update; target the mockAccount.updateEmail verification
and the later DB verification so both occur after the chosen synchronization.
lib/views/widgets/snackbar.dart (2)

28-35: Defensive fallback, but callers still crash first.

The null-safe context handling with a fallback color is a reasonable defensive measure. However, based on the relevant snippets (e.g., single_room_controller.dart:173, onboarding_controller.dart:72), callers invoke AppLocalizations.of(Get.context!)! before calling customSnackbar, so they'd crash on the null-assertion before this fallback is reached.

Consider whether a broader refactor is needed to pass context as a parameter (some call sites already do this), or at minimum document that this fallback only covers edge cases where context becomes null between the caller's lookup and the snackbar's theme access.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/views/widgets/snackbar.dart` around lines 28 - 35, The snackbar currently
reads Get.context internally which leads callers using
AppLocalizations.of(Get.context!) to crash before the snackbar's fallback runs;
change the snackbar API to accept an explicit BuildContext parameter (e.g.,
update customSnackbar to customSnackbar(BuildContext context, ...)) and update
callers (notably in single_room_controller.dart and onboarding_controller.dart)
to pass their local context instead of using Get.context!, removing the internal
null-assertion reliance; if you must keep the current signature, add clear
documentation on the limited fallback and audit callers to stop calling
AppLocalizations.of(Get.context!) before invoking the snackbar.

48-48: Missing newline at end of file.

Most style guides and linters expect a trailing newline. Consider adding one for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/views/widgets/snackbar.dart` at line 48, Add a trailing newline to the
end of lib/views/widgets/snackbar.dart so the file ends with a newline character
after the final closing brace; simply open snackbar.dart, place the cursor after
the final "}" (the file's closing brace for the snack bar widget) and insert a
newline, then save to satisfy linters and style guides.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/controllers/change_email_controller_test.dart`:
- Around line 195-196: Remove the leftover development comment "// ❌ REMOVE
overlay hack completely" from
test/controllers/change_email_controller_test.dart; locate the comment in the
test file (near tests for ChangeEmailController) and delete that line so the
test file contains only actual test code and comments relevant to the tests (no
dev-hack reminders).

---

Nitpick comments:
In `@lib/views/widgets/snackbar.dart`:
- Around line 28-35: The snackbar currently reads Get.context internally which
leads callers using AppLocalizations.of(Get.context!) to crash before the
snackbar's fallback runs; change the snackbar API to accept an explicit
BuildContext parameter (e.g., update customSnackbar to
customSnackbar(BuildContext context, ...)) and update callers (notably in
single_room_controller.dart and onboarding_controller.dart) to pass their local
context instead of using Get.context!, removing the internal null-assertion
reliance; if you must keep the current signature, add clear documentation on the
limited fallback and audit callers to stop calling
AppLocalizations.of(Get.context!) before invoking the snackbar.
- Line 48: Add a trailing newline to the end of lib/views/widgets/snackbar.dart
so the file ends with a newline character after the final closing brace; simply
open snackbar.dart, place the cursor after the final "}" (the file's closing
brace for the snack bar widget) and insert a newline, then save to satisfy
linters and style guides.

In `@test/controllers/change_email_controller_test.dart`:
- Around line 220-221: Add a trailing newline at the end of the test file to
satisfy POSIX/style conventions: open
test/controllers/change_email_controller_test.dart and ensure the file ends with
a single newline character after the final closing braces (the end of the test
block that contains "});" / "}"). Save the file so the repository includes the
newline at EOF.
- Around line 201-207: The test's timing is fragile because it verifies
mockAccount.updateEmail immediately after the first tester.pumpAndSettle() then
waits another 4 seconds; updateEmail and subsequent DB updates in changeEmail()
(changeEmail()) can complete at different times leading to flakiness. Replace
the two-stage waiting with a single deterministic wait or synchronization:
either call tester.pumpAndSettle(const Duration(seconds: N)) once (choose N
large enough for the whole changeEmail() chain) before all verify calls, or use
Mockito's untilCalled(mockAccount.updateEmail(...)) to wait for that specific
call before asserting the database update; target the mockAccount.updateEmail
verification and the later DB verification so both occur after the chosen
synchronization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd3c9ac1-3d34-4ca5-9170-ca3ed0e58593

📥 Commits

Reviewing files that changed from the base of the PR and between 84bf1fa and c43a580.

📒 Files selected for processing (3)
  • lib/views/screens/chapter_play_screen.dart
  • lib/views/widgets/snackbar.dart
  • test/controllers/change_email_controller_test.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/views/screens/chapter_play_screen.dart

Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
test/controllers/change_email_controller_test.dart (1)

205-205: Replace fixed-duration settle with deterministic async synchronization.

Line 205 uses a hard-coded 4-second settle duration, which can make tests slower and more flaky. The subsequent mock verification (lines 207-214) can instead be awaited directly with untilCalled() from mockito.

Proposed refactor
-  await tester.pumpAndSettle(const Duration(seconds: 4));
+  await untilCalled(
+    mockDatabases.updateDocument(
+      databaseId: userDatabaseID,
+      collectionId: usernameCollectionID,
+      documentId: 'TestUser',
+      data: {'email': 'test2@test.com'},
+    ),
+  );
+  await tester.pump();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/controllers/change_email_controller_test.dart` at line 205, Replace the
fixed 4-second wait (tester.pumpAndSettle(const Duration(seconds: 4))) with
deterministic async synchronization by awaiting mockito's untilCalled for the
mocked method you expect to be invoked in this test (e.g.,
untilCalled(mockYourRepo.changeEmail(...)) ), then call tester.pumpAndSettle()
without a long duration to flush UI frames; update the subsequent verification
to run after the untilCalled await so the mock invocation is guaranteed before
verify() is asserted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/controllers/change_email_controller_test.dart`:
- Line 205: Replace the fixed 4-second wait (tester.pumpAndSettle(const
Duration(seconds: 4))) with deterministic async synchronization by awaiting
mockito's untilCalled for the mocked method you expect to be invoked in this
test (e.g., untilCalled(mockYourRepo.changeEmail(...)) ), then call
tester.pumpAndSettle() without a long duration to flush UI frames; update the
subsequent verification to run after the untilCalled await so the mock
invocation is guaranteed before verify() is asserted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 807a5271-55ef-4af3-9d83-c0a809d11d46

📥 Commits

Reviewing files that changed from the base of the PR and between c43a580 and e0402bc.

📒 Files selected for processing (1)
  • test/controllers/change_email_controller_test.dart

@Shweta-281
Copy link
Copy Markdown
Contributor Author

@M4dhav

Hi! I've added Spanish (es) translations to Resonate. Could you please review it when you have time?

The changes include:

  • app_es.arb with full Spanish translation
  • Updated main.dart and ios/Runner/Info.plist
  • Ran flutter gen-l10n successfully

Note: There's an unrelated Gradle build error (build.gradle.kts line 50) that existed before my PR. My translation changes are not the cause.

Thank you! 🙌

@Shweta-281
Copy link
Copy Markdown
Contributor Author

@M4dhav

This PR is ready to be merged. All checks have passed and the Spanish translation is complete. Please let me know if any changes are required.

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.

feat: add Spanish (es) language support

1 participant