Skip to content

Add String Catalog localization with Turkish translations (1/3) - #760

Draft
zersoft wants to merge 5 commits into
loopandlearn:devfrom
zerloop:feat/localization-pr1
Draft

zersoft wants to merge 5 commits into
loopandlearn:devfrom
zerloop:feat/localization-pr1

Conversation

@zersoft

@zersoft zersoft commented Sep 26, 2026

Copy link
Copy Markdown

Summary

Adds a String Catalog (LoopFollow/Resources/Localizable.xcstrings, source language en) and registers tr so Loop Follow follows the device language. This is the first of three focused PRs: infrastructure plus every SwiftUI string. Dynamic strings (Text(variable), UIKit, enum names) and notifications / Live Activity / Info.plist follow in two further PRs.

Opened as a draft while the Turkish copy is reviewed by a native speaker on a TestFlight build; the code and tests are final.

Changes

  • Localizable.xcstrings with Turkish values for all 548 keys; units, symbols, bare format specifiers and hashtags are marked "Don't translate". Terms that happen to be identical in Turkish (Bolus, IOB, Override, ...) carry an explicit translation so other languages can still translate them.
  • AlarmType.displayName and an explicit localized DayNightDisplayable.displayName. The persisted rawValues stay English and are no longer shown directly (tile, editor title, list and add-sheet search, notification title, default alarm name).
  • Two patterns that could not be localized as they stood: Text("Calculated \(n) minute\(s) ago") becomes a single %lld minutes ago key with an English plural variation, and four footers that joined literals with + (which selects the non-localized Text overload) are single literals again.
  • Scripts/localization/missing_translations.py and apply_translations.py: TSV round-trip helpers for translators (no build dependency; plain Python 3).
  • Tests: catalog coverage (every translatable key has a translated value, printf placeholders preserved and positional in multi-argument strings, no stale keys), a source lint that fails on Text("a" + "b"), persisted raw values pinned, and Turkish / English-plural lookups from the compiled bundle.

Notes for maintainers

  • xcodebuild -exportLocalizations only emitted Text("…") literals here, so Toggle, Picker, Section, Label, TextField, navigationTitle and alert literals (185 keys) were added from a source scan with extractionState: "manual". A build in Xcode may re-extract them; if it does, the marker can simply be dropped. Runtime lookup for these was verified on a simulator (Button("Skip") renders as "Atla").
  • Xcode may re-sort the catalog on first save; that would be a formatting-only diff.

Testing

  • Tests target: 106 passed, 0 failed (iOS 27 simulator).
  • SwiftFormat --lint clean.
  • Simulator launched with -AppleLanguages (tr): first screen renders Turkish for both extracted and manually added keys.

🤖 Generated with Claude Code

zersoft and others added 5 commits September 27, 2026 01:59
Adds LoopFollow/Resources/Localizable.xcstrings (source language en) and
registers tr in knownRegions. Keys come from xcodebuild
-exportLocalizations plus a scan of SwiftUI LocalizedStringKey call
sites (Toggle, Picker, Section, Label, navigationTitle, ...) that the
extractor does not emit; those are marked extractionState "manual".
No translations yet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 345c02582e5878ba12922177d89edbf96ef836f7)
Fails until every translatable key has a Turkish value; also checks
printf placeholders and stale keys.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 38286cfcb1ae0da53444786b2cc326e75318f23b)
AlarmType.rawValue and the day/night option raw values are persisted, so
they must stay English. Add AlarmType.displayName and make
DayNightDisplayable.displayName an explicit localized switch; route the
tile, editor title, list and add-sheet search, notification title and
default alarm name through them. Tests pin the raw values.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit ca2276f80102049c02f5e88cc3b3829725e0c3dc)
Fills the tr locale of Localizable.xcstrings for every extracted key,
marks units, symbols and product names as do-not-translate, and adds
two small scripts for listing and applying translations from TSV.

Two call sites are adjusted so they can be localized at all: the
"minute(s) ago" plural suffix becomes a plural variation on a single
"%lld minutes ago" key, and three alarm-editor footers that joined two
literals with "+" (which selects the non-localized Text overload) are
single literals again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 0f417a115c1b09b3444112935a19b5ee8185b231)
…er don't-translate set

- AlarmSettingsView's day/night footer joined three literals with "+",
  which selects the non-localized Text overload; merge into one literal
  and translate the whole footer. Drop the dead fragment and "(" keys.
- Add a source lint test that fails on Text("a" + "b") patterns.
- Require positional indexes (%1$@, %2$@) in every multi-placeholder
  translation so argument order can be changed safely; update the five
  affected Turkish values.
- Keep shouldTranslate=false only for units, symbols, bare specifiers and
  hashtags; ordinary terms that happen to match in Turkish get an explicit
  translation so other languages can translate them.
- Verify the English plural variation at runtime from en.lproj.
- Fix "Snoozed until %@" (argument is a time, not a date) and refine
  "Proactive Low" and the "Remote" title.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bjorkert

Copy link
Copy Markdown
Member

Thanks for putting this together, and for the Turkish translation! Users have been asking for LoopFollow in their own language, so we know there's demand.

We won't merge this as it stands, though. Before we take on localization, we want form a strategy for how translations are added, reviewed and kept up to date across releases. We'll come back to this once that's settled, and your work here will be a useful input.

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