Description
With the app set to French (or another existing language), many screens still show English: About ("How to use", "No tracking"), most Settings rows ("Run in background", "Proof of work", …), the permission explanations in onboarding, and the hotspot sharing screen. There are two causes: keys missing from the existing values-xx/strings.xml files, and text hardcoded as Kotlin literals.
This PR has five commits:
- Move hardcoded UI text into string resources.
HotspotActivity,PermissionManager/PermissionExplanationScreen,LocationNotesSheetPresenter,VerificationSheet,InputComponentsandAboutSheet(live voice row) now read 44 new keys throughstringResource/getString, and existing keys are reused where they already existed. The English text is unchanged.PermissionTypekeeps its EnglishnameValuefor the diagnostics dump and gains a@StringRes titleResfor the UI. - Complete translations for existing European locales. Every missing key is filled in
de es fr it nl pl pt ru sv tr uk. Capitalization now follows English (settings rows and bullet lines start with a capital letter). French wording is also cleaned up: informal "tu" throughout, "Preuve de travail", "Système". - Add 24 European languages: be, bg, bs, ca, cs, da, el, et, fi, ga, hr, hu, is, lb, lt, lv, mk, mt, nb, ro, sk, sl, sq, sr. Each has all 607 strings and the CLDR plural forms its language needs, and is listed in
locales_config.xml, so it shows up in both the in-app and system language pickers. - Fix plural forms in existing European locales. These bugs already existed upstream and lint flagged them. Russian and Polish defined only
one/other, so counts like 2–4 and 5+ used the wrong word form, and Russian printed a literal "1 человек" for 21, 31, … French and Portuguese printed a literal "1 personne" / "1 pessoa", although theironeform also covers 0. French, Spanish, Italian and Portuguese gain the CLDRmanyform. - Use the ellipsis character ("…" instead of "...") in the European files, as French and German already do.
Related to #737. No issue covers the untranslated strings specifically. The companion iOS PR, permissionlesstech/bitchat#1787, adds the same 24 languages to the string catalogs.
How the translations were produced
The translations were written with an AI assistant, not by native speakers. Every file was checked mechanically:
- every key is present
- format arguments match the English exactly (
%1$s,%2$d,%%) - each language has the plural categories CLDR requires (e.g. Polish/Czech
few/many, Irish/Maltesetwo/few/many) - Android escaping is valid
- the first-letter casing matches the English
Native-speaker review is welcome. Corrections only need edits to values-xx/strings.xml.
Risk
Low. Apart from commit 1, the change is resources only. Commit 1 mechanically replaces literals with resource lookups and changes no logic. PermissionType.nameValue is unchanged, so diagnostics output stays in English.
Tests
./gradlew :app:assembleDebugpasses./gradlew testDebugUnitTestpasses (612 tests, 0 failures)./gradlew lintDebug: total findings go from 349 errors / 414 warnings onmainto 342 errors / 318 warnings. In the 35 European locales the only findings left are 8Typosfalse positives: Norwegian "internett" is the recommended lowercase spelling, and Portuguese "leem" follows the 1990 spelling reform. The remainingMissingTranslationerrors are for non-European locales that already lagged behind English, and they now include the 44 keys added in commit 1.LanguageCatalogContractTestpasses (locales_config matches thevalues-*directories)- Emulator (API 36): onboarding, About → Info and Settings, the language picker and the chat composer checked in French and Greek; switching language from the in-app picker works
Screenshots
Emulator (API 36), app language set to French, fresh install. Left: main. Right: this branch.
Onboarding: permission explanations (previously hardcoded in Kotlin)
About → Info ("No Tracking", "How To Use" and its rows were missing from values-fr)
About → Settings (setting rows were missing, live push-to-talk was hardcoded, inconsistent lowercase)
New languages: Greek, and the in-app picker listing the added languages
The remaining English line on the Settings card ("Tor connection established to …") comes from the native Tor library and is out of scope.
Not covered (possible follow-ups)
CommandProcessorreplies (/help,/who, …) are still hardcoded English. Moving them to resources needs aContextpassed in, so it's left for a separate PR.- Debug-console messages and the native Tor log line stay in English.
- The
wearmodule is not localized yet. - Non-European locales (ar, fa, hi, ja, ko, zh, …) still fall back to English for the keys added here.
- All-caps section headers are uppercased in code without a locale, so Greek capitals keep their accents ("ΡΥΘΜΊΣΕΙΣ"). That's a small cosmetic fix in the uppercase call.
Checklist
- I have read the contribution guidelines: https://github.com/permissionlesstech/bitchat-android?tab=readme-ov-file#contributing
- I have performed a self-review of my code
- I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
- If it is a core feature, I have added automated tests (not a core feature; the existing catalog contract test covers the new locales)
🤖 Generated with Claude Code
Activity
7💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23da80b677
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codex Review Summary
This comment shows the latest Codex review activity on this pull request.
23da80bℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.