diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 47f66614aa..1833a6f11b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -614,7 +614,35 @@ The design system provides: `SessionMaterialTheme` installs both the custom tokens and Material 3. Most Compose entry points use `setThemedContent { ... }` so screens can remain thin. -## 13. Dependency Injection +## 13. Localization and Translations + +UI strings are managed on **Crowdin** (project ID `618696`), not in this repo. This matters because the string resources here are **generated artifacts**, not editable sources. + +### Source of truth + +Every `app/src/main/res/values*/strings.xml` — including the base English `values/strings.xml` — plus `NonTranslatableStringConstants.kt` (the `{app_name}`, `{entity_stf_short}`, … substitution values) is generated from Crowdin. **Do not hand-edit these files**; changes are overwritten on the next sync. String source text (English) and translations are both authored/managed on Crowdin. + +### The sync automation lives in a different repo + +There is no Crowdin workflow in this repo. The automation is in **`session-foundation/session-shared-scripts`**, workflow `.github/workflows/check_for_crowdin_updates.yml`: + +- Triggers: scheduled (Mondays 00:00 UTC) or manual `workflow_dispatch` (input `UPDATE_PULL_REQUESTS=true`). +- Downloads from Crowdin, regenerates all `values*/strings.xml` + `NonTranslatableStringConstants.kt` (`crowdin/generate_android_strings.py`), validates via a gradle resource build, then opens/updates a PR using `peter-evans/create-pull-request`. +- The PR targets the fixed head branch `feature/update-crowdin-translations` → `dev`, opened by the `stfsession` service account. Because the branch is fixed, there is only ever one open translations PR at a time; a re-run updates it in place (unless the previous one was already merged). +- The same run produces the equivalent PRs for iOS and the desktop localization module. + +### Approved-only export + +The download requests translations with `exportApprovedOnly=true` and `skipUntranslatedStrings=true`. Consequently, machine/AI pre-translations are **excluded until a proofreader approves them** in Crowdin — unapproved strings are treated as untranslated and dropped. Approval requires a Proofreader/Manager role on the Crowdin project. (A helper for bulk-approving specific string identifiers lives at `session-shared-scripts/crowdin/approve_strings.py`.) + +### Shipping a text change + +1. Edit/add the source strings on Crowdin (new copy usually warrants **new string keys** — reusing a key keeps its now-stale translations, which will resurface as mismatched text). +2. Approve the translations you want (see above), or they won't export. +3. Run `check_for_crowdin_updates.yml` and merge the resulting Crowdin PR — this brings the keys into `strings.xml`. +4. Only then merge any code referencing the new keys (`R.string.` won't compile until the sync has landed them). + +## 14. Dependency Injection Hilt is the application-wide DI framework. @@ -629,7 +657,7 @@ Important modules include: The most important architectural convention here is not just "use Hilt", but "inject long-lived managers plus a manager-scoped coroutine scope and let them expose reactive state." -## 14. Other Important Runtime Components +## 15. Other Important Runtime Components - `ExpiringMessageManager`: disappearing-message lifecycle - `AvatarUploadManager`: avatar upload/sync behavior @@ -640,7 +668,7 @@ The most important architectural convention here is not just "use Hilt", but "in If a bug seems to "happen in the background" but does not fit config, polling, notifications, or Pro, it often lives in one of these auth-aware managers. -## 15. End-to-End Flow Summaries +## 16. End-to-End Flow Summaries ### App startup and login @@ -695,7 +723,7 @@ User action -> reactive flows refresh UI ``` -## 16. Practical Notes for new Developers +## 17. Practical Notes for new Developers For a new developer, the highest-value mental model is: diff --git a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index 2d75f0c52f..e2787b9d65 100644 --- a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -364,11 +364,11 @@ interface TextSecurePreferences { // Donation - const val HAS_DONATED = "has_donated_v3" - const val HAS_COPIED_DONATION_URL = "has_copied_donation_url_v3" - const val SEEN_DONATION_CTA_AMOUNT = "seen_donation_cta_amount_v3" - const val LAST_SEEN_DONATION_CTA = "last_seen_donation_cta_v3" - const val SHOW_DONATION_CTA_FROM_POSITIVE_REVIEW = "show_donation_cta_from_positive_review_v3" + const val HAS_DONATED = "has_donated_v4" + const val HAS_COPIED_DONATION_URL = "has_copied_donation_url_v4" + const val SEEN_DONATION_CTA_AMOUNT = "seen_donation_cta_amount_v4" + const val LAST_SEEN_DONATION_CTA = "last_seen_donation_cta_v4" + const val SHOW_DONATION_CTA_FROM_POSITIVE_REVIEW = "show_donation_cta_from_positive_review_v4" const val DEBUG_HAS_DONATED = "debug_has_donated" const val DEBUG_HAS_COPIED_DONATION_URL = "debug_has_copied_donation_url" diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDialogs.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDialogs.kt index a0cb63e0c4..7cc68a022a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDialogs.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDialogs.kt @@ -276,11 +276,11 @@ fun DonationDialog( sendCommand(HideDonationCTADialog) } - val title = Phrase.from(context,R.string.finalAppeal) + val title = Phrase.from(context,R.string.ongoingAppeal) .put(StringSubstitutionConstants.APP_NAME_KEY, NonTranslatableStringConstants.APP_NAME) .format() - val text = Phrase.from(context,R.string.finalAppealDescription) + val text = Phrase.from(context,R.string.ongoingAppealDescription) .put(StringSubstitutionConstants.ENTITY_STF_SHORT_KEY, NonTranslatableStringConstants.ENTITY_STF_SHORT) .put(StringSubstitutionConstants.APP_NAME_KEY, NonTranslatableStringConstants.APP_NAME) .format() diff --git a/app/src/main/res/drawable-nodpi/cta_hero_donation.webp b/app/src/main/res/drawable-nodpi/cta_hero_donation.webp index 697f23d6f7..27842a2262 100644 Binary files a/app/src/main/res/drawable-nodpi/cta_hero_donation.webp and b/app/src/main/res/drawable-nodpi/cta_hero_donation.webp differ