Skip to content

fix(i18n): pt-PT translation corrections from a native speaker - #2781

Open
jvascopf wants to merge 3 commits into
ryanbr:mainfrom
jvascopf:fix/pt-PT-translation-typos
Open

jvascopf wants to merge 3 commits into
ryanbr:mainfrom
jvascopf:fix/pt-PT-translation-typos

Conversation

@jvascopf

Copy link
Copy Markdown

What this PR does

pt-PT translation corrections from a native speaker, on both platforms (Strand/Resources/Localizable.xcstrings and android/app/src/main/res/values-pt-rPT/strings.xml). Translated values only; no code changes.

  • "Descansoaurador / Descansoaurar / Descansoaurado" (a bad find-and-replace of "Rest...") -> Restaurador / Restaurar / Restaurado; "Descansoante" -> "Restante".
  • "cochilo" (pt-BR) -> "sesta", with the surrounding agreement fixed.
  • Gender/number agreement for "cópia de segurança" (feminine), about 40 strings.
  • "Livro-razão da dívida do sono" -> "Registo da dívida de sono".
  • "pega" (handle) -> "bracelete" for the strap, the term the app already uses most.
  • "esparso/esparsas" -> "escasso/escassas"; also fixes swapped placeholders in "Sparse, widened to %@ · %lld readings".
  • "Band Sleep State": Android pt-PT was "Estado de suspensão da banda", now "Estado de sono da bracelete". The Apple catalogue had no entry for this key (it fell back to English), so one was added. It covers the other focus locales too (reusing the Android strings, de/es/fr/it/ru/zh-Hans), because the i18n audit fails a new key that lacks them. pl ("Stan snu opaski") and zh-Hant (手環端睡眠狀態) are my own wording, since Android has no zh-Hant string and its pl value reads as "team"; native review welcome.
  • Minor typos: "tincronização", "tinais", "Detecção" -> "Deteção".

Not addressed here (code-level, affects every locale, better as a separate change):

  • The Explore screen interpolates an untranslated English window name ("week", "month") into "sem %1$s anterior" / "versus anterior %1$s" (TrendsExploreScreen.kt windowName, MetricExplorerView.swift range name).
  • The weekly digest card prints the English metric.label (Charge/Effort/Rest) instead of a localised label (WeeklyDigestView.swift, WeeklyDigestCard.kt).

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • CI / tooling

How it was tested

Translation-only change; no BLE, protocol or analytics code touched.

  • Localizable.xcstrings parses as JSON and values-pt-rPT/strings.xml parses as XML.
  • python -m unittest test_i18n_audit (in Tools/): 83 tests OK.
  • python Tools/i18n_audit.py --ci HEAD: output is identical to a clean main apart from the un-extracted literal count dropping by one (the new "Band Sleep State" entry). main already reports pre-existing zh-Hant/ru gaps, which are unrelated.
  • Placeholders (%@, %lld, %1$s...) are unchanged except the one reordering noted above.
  • Not built or run on a device or in Xcode.

Checklist

  • Swift package tests pass for any package I touched (no package touched)
  • Android unit tests pass if I touched android/ (only values-pt-rPT/strings.xml changed; not run locally)
  • No new build warnings introduced (no code changed)
  • UI changes use only StrandDesign tokens (no UI code changed)
  • No hardcoded hex frame bytes; protocol facts live in the schema / decoders
  • Follows the conventions in docs/CONTRIBUTING.md
  • I did not commit generated output (Strand.xcodeproj/) or any secrets/keystores

Related issues

None.

jvascopf and others added 2 commits October 13, 2026 00:07
Apple (Localizable.xcstrings) and Android (values-pt-rPT):
- Fix "Descansoaurador/Descansoaurar/..." (a bad find-and-replace of
  "Rest...") to Restaurador/Restaurar/Restaurado; "Descansoante" -> "Restante".
- Replace "cochilo" (pt-BR) with "sesta" and fix the surrounding agreement.
- Fix gender/number agreement for "cópia de segurança" (feminine).
- "Livro-razão da dívida do sono" -> "Registo da dívida de sono".
- "pega" (handle) -> "bracelete" for the strap, the app's dominant term.
- "esparso/esparsas" -> "escasso/escassas"; fix swapped placeholders in
  "Sparse, widened to %@ · %lld readings".
- "Band Sleep State": Android pt-PT was "Estado de suspensão da banda";
  now "Estado de sono da bracelete".
- Minor typos: "tincronização", "tinais", "Detecção" -> "Deteção".

"Band Sleep State" had no Apple catalogue entry, so it fell back to English.
Added it for the other focus locales too (reusing the Android strings),
because the i18n audit fails a new key that lacks them.
- week/month/quarter/year were left in English in the Apple catalogue,
  which produced captions like "sem week anterior".
- "o tempo todo" (all the time) -> "todo o período" for the all-time window.
- "toda a histórico" -> "todo o histórico" (Apple and Android).
- "versus anterior %@" -> "vs. %@ anterior" (Apple and Android).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ryanbr

ryanbr commented Oct 15, 2026

Copy link
Copy Markdown
Owner

The Portuguese work here is good, and I would like to take it, but the pega replacement was applied across the whole catalogue rather than only to the pt-PT entries, and it has broken four Spanish strings. Please see below before this lands.

The Spanish regression

In Spanish pega is the imperative of pegar, "paste". Four values in the AI Coach key setup now read as instructions to strap the key:

key before after
Paste your %@ API key Pega tu clave de API de %@ Bracelete tu clave de API de %@
Paste the corrected key. Your conversation is kept. Pega la clave corregida. Bracelete la clave corregida.
Coach uses your own API key... (iOS) ...Elige un proveedor, pega una clave... ...Elige un proveedor, bracelete una clave...
Coach uses your own API key... (macOS) ...Elige un proveedor, pega una clave... ...Elige un proveedor, bracelete una clave...

No Spanish value contains pega at the head commit any more, so the sweep caught every occurrence rather than any being a deliberate choice. Restoring those four to Pega is all that is needed.

This is invisible to CI: the key set and placeholders are unchanged, so the i18n audit has nothing to flag. I only saw it by parsing the catalogue per locale instead of reading the diff, because the one-line-per-key format rewrites the whole line including every other locale on it.

What checks out

The 82 pt-PT corrections are exactly right, and several are substantive rather than cosmetic:

  • pega to bracelete is the correct call for pt-PT. pega is a handle or grip, which is a machine-translation artefact for "strap".
  • cochilo to sesta, which is the European rather than Brazilian term.
  • The cópia de segurança gender and number agreement, including the broken plural cópia de seguranças becoming cópias de segurança. Pluralising the head noun is right.
  • Detecção to Deteção, following the 1990 orthographic agreement that pt-PT uses.
  • Livro-razão to Registo, since the English sense is a running record rather than an accounting ledger.
  • Estado de suspensão da banda to Estado de sono da bracelete. The old text had read "sleep" as the computer power state.

The one added key, Band Sleep State, is a real gap rather than scope creep: Repository.swift:1887 calls String(localized: "Band Sleep State") and the catalogue had no entry, so every non-English locale was falling back to the English. Worth keeping.

Two notes for later, not for this PR

Several pt-PT values still carry untranslated English tails, for example "so back up first if unsure", "the latest %1$s", and the "Note: continuous background HRV capture..." sentence. Happy to see those in a follow-up.

The pt-PT explore_vs_prev_window change to vs. %1$s anterior puts the placeholder in the right position for Portuguese, which is a better answer than the one currently in that file. It does overlap with the explore window work in #2784, so whichever of the two lands second will want a look at that block.

The pt-PT 'pega' -> 'bracelete' sweep also rewrote four Spanish AI Coach
key-setup strings, where 'pega' is the imperative of 'pegar' (paste).
Restore them to their values on main.
@jvascopf

Copy link
Copy Markdown
Author

Thanks for the careful review, and apologies for the regression. The sweep was applied catalogue-wide by mistake. Restored the four Spanish values (Paste your %@ API key, Paste the corrected key, and the two Coach key-setup strings) to their values on main in the latest commit; I verified by parsing the catalogue per locale that no non-pt-PT value differs from main now. Noted on the English tails and the #2784 overlap: happy to do a follow-up for the tails, and I will rebase whichever lands second.

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.

2 participants