Skip to content

Localize Solstice into 8 new languages + add a translation-completeness CI gate#151

Open
daneden wants to merge 9 commits into
mainfrom
claude/swiftui-audit-localization
Open

Localize Solstice into 8 new languages + add a translation-completeness CI gate#151
daneden wants to merge 9 commits into
mainfrom
claude/swiftui-audit-localization

Conversation

@daneden

@daneden daneden commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

Adds full localization for 8 new languages — German, French, Spanish, Japanese, Arabic, Dutch, Simplified Chinese, and Polish — and completes Italian coverage (it was missing from the Info.plist / App Shortcuts catalogs). All five String Catalogs are now complete for all 9 shipping locales.

Also adds a CI gate so we never ship untranslated strings again, and bumps the marketing version to 3.2.0 to reflect the scope.

What's included

  • Translations — machine-translated all .xcstrings (Localizable + the four Info.plist/AppShortcuts catalogs) into the new languages, preserving format specifiers, Markdown, ${…} tokens, and language-appropriate typography. Registered the new catalogs and knownRegions in the project.
  • CI gate (ci_scripts/) — validate-localizations.swift fails on any string in the new state (or missing) for a required locale. It runs from ci_pre_xcodebuild.sh only on Xcode Cloud archive (distribution) builds, so PR/test workflows aren't affected. Required locales are derived from the catalogs themselves, so future languages are enforced automatically.
  • Version bump — marketing version → 3.2.0.

Policy note

Most new strings are in the machine_translated state, which the gate treats as shippable by default (the app intentionally ships machine translations). Set LOCALIZATION_STRICT=1 to raise the bar to human-reviewed translated state.

Verification

  • ✅ Localization gate passes (swift ci_scripts/validate-localizations.swift → exit 0).
  • ✅ Clean build (iOS) succeeds.
  • ⚠️ Not visually verified in Simulator (skipped this round) — recommend a spot-check under ar for RTL before release.

Scope note

This branch also carries the earlier SwiftUI-audit commits (refactor, hard-coded-string localization, swiftformat), so they're part of this PR.

🤖 Generated with Claude Code

daneden and others added 9 commits July 10, 2026 14:20
- Cache sorted collections instead of re-sorting every body evaluation
  (SidebarListView location sort, SupporterSettings tip products).
- Make TemporaryLocation an immutable reference type, removing the
  data-race surface and the need for actor isolation.
- Isolate LocationSearchService to @mainactor with nonisolated
  MKLocalSearchCompleter delegate callbacks.
- Give AsyncButton/ContentToggle/ShareSolarChartView explicit inits so
  their @State can be private.
- Modernize .cornerRadius -> .clipShape.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Type NTSolar.Event.label as LocalizedStringResource so solar-event
  names are compiler-extracted and resolve per-locale (they were shown
  untranslated). Event identity now keys on date + phase.
- Fix the 'more'/'less' daylight comparison in DailyOverview, which
  injected raw English into a localized string.
- Localize 'Current Location' fallbacks (standardized to one key),
  and the 'Unknown'/'Custom Location' fallbacks in the Intents.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Project-wide formatting pass (no logic changes): blank line after
MARK comments, indented compiler-conditional blocks, etc.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Machine-translated all String Catalogs into eight new languages and
completed Italian coverage for the Info.plist and App Shortcuts catalogs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add a String Catalog completeness gate that runs from Xcode Cloud's
pre-xcodebuild step, but only for archive (distribution) actions. The
validator derives required locales from the catalogs themselves and
fails on any string in the "new" state or missing for a required locale.
Machine translations count as shippable by default; set
LOCALIZATION_STRICT=1 to require human-reviewed translations.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…on grammar

The annual daylight chart legend rendered in English for every locale
because NTSolar.Phase is Plottable via its raw String value, and Swift
Charts builds the default legend from those raw values without consulting
the String Catalog. Hide the default legend and render a custom one from
Phase.localizedName so the labels route through the catalog. Adds the
newly-extracted "Day"/"Night" keys, translated across all 9 locales.

Also fix machine-translation grammar defects in the daylight-comparison
sentence: the shared more/less word keys carried their own prepositions
that collided with the sentence templates ("en en plus", "en moins de",
"menos de de"). Correct fr "less" to "en moins" and drop the redundant
literal "en" from the fr templates; correct es "less" to "menos".

Co-Authored-By: Claude Opus 4.8 <[email protected]>
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.

1 participant