Rescoped after #850 landed. The original report bundled three blind spots; the biggest is fixed, one is a genuine limitation rather than a to-do, and this is what is left.
The gap
The Apple pass checks that each entry already in Localizable.xcstrings has every language. A LocalizedStringKey or String(localized:) literal that was never extracted into the catalog is simply not seen — English ships to every locale, and the audit reports green.
It measures coverage within the catalog, never completeness of it.
Live example
#826 adds two strings via the correct mechanism:
case .connectedNoData: return "No live heart rate or synced history yet this session."
String(localized: "Connected. No live heart rate or synced history yet this session.")
Neither is in Strand/Resources/Localizable.xcstrings. Both sibling chip strings ("Strap not connected. Tap to connect.", "History sync is experimental on 5.0.") are. CI is green on that PR.
What a fix looks like
Scan app-target Swift for String(localized: "…") and LocalizedStringKey literals, and fail when one has no catalog entry.
The hard part is false positives, and this gates every PR — so it needs care:
Not tracked here
Text(variable) invisibility (original item 3) — a static scan cannot resolve Text(someVar) without type inference, and the tool already documents this class of blind spot in its own comments. Recording it as a permanent limitation rather than an open task.
The locale-list gap (original item 1) — fixed in #850: both language lists are now discovered from what ships, with a ratcheting allowance over the 1019 pre-existing gaps.
Whether it/ru/zh-* should ship at all in their current state — that is a product decision, not a tooling one, and it now has its own issue.
Rescoped after #850 landed. The original report bundled three blind spots; the biggest is fixed, one is a genuine limitation rather than a to-do, and this is what is left.
The gap
The Apple pass checks that each entry already in
Localizable.xcstringshas every language. ALocalizedStringKeyorString(localized:)literal that was never extracted into the catalog is simply not seen — English ships to every locale, and the audit reports green.It measures coverage within the catalog, never completeness of it.
Live example
#826 adds two strings via the correct mechanism:
Neither is in
Strand/Resources/Localizable.xcstrings. Both sibling chip strings ("Strap not connected. Tap to connect.","History sync is experimental on 5.0.") are. CI is green on that PR.What a fix looks like
Scan app-target Swift for
String(localized: "…")andLocalizedStringKeyliterals, and fail when one has no catalog entry.The hard part is false positives, and this gates every PR — so it needs care:
"\(n) pages behind") key differently in the catalogString(localized:)withtable:/bundle:/comment:arguments#if DEBUGi18n_audit_baseline.jsonmechanism should absorb any pre-existing set so it starts green, as ci: gate on doc comments that bind to nothing #849 and ci(i18n): cover every shipped locale, not the four in a constant #850 both didNot tracked here
Text(variable)invisibility (original item 3) — a static scan cannot resolveText(someVar)without type inference, and the tool already documents this class of blind spot in its own comments. Recording it as a permanent limitation rather than an open task.The locale-list gap (original item 1) — fixed in #850: both language lists are now discovered from what ships, with a ratcheting allowance over the 1019 pre-existing gaps.
Whether
it/ru/zh-*should ship at all in their current state — that is a product decision, not a tooling one, and it now has its own issue.