Repository navigation
feat(l10n): complete Latin-American Spanish (es-419) - #49
Merged
Merged
Conversation
…on Pro Config.plist sat in Copy Bundle Resources, so whatever key was on disk at archive time shipped inside the IPA (1.0's key was revoked 2026-08-19). The file stays on disk and gitignored for local dev; it is simply no longer a build input. - Drop the Resources build-phase entry (file reference kept). - Retire the placeholder-plist steps in ci.yml and ci_post_clone.sh; a clean checkout now builds without it. - ci_post_clone.sh keeps one gate: refuse any archive with FeatureFlags.tipsEnabled = true, since Tips has no safe key source yet. - New invariant: gotchas.yaml#config-plist-never-bundled, CLAUDE.md §3. - Pending Xcode change: SUPPORTS_MACCATALYST and the "Designed for iPhone/iPad" on Mac and Vision Pro destinations set to NO, plus Xcode's re-sort of the PBXBuildFile/PBXFileReference sections.
Savely 1.0 makes no network calls (Tips is flagged off), but Info.plist still declared an App Transport Security exception for openai.com, visible to App Review and at odds with the "Data Not Collected" privacy answers. ITSAppUsesNonExemptEncryption stays; it is load-bearing for upload. The leftover GoogleService-Info.plist was deleted locally (gitignored, never bundled). The Firebase project itself is still open, owner-only; see docs/plans/dead-api-records.md.
testPreviewFootage walks the seeded app at human pace (home, goal, expense, payday auto-move, goal again, trend, privacy, receipt) while `simctl io recordVideo` captures it, and prints BRAGMARK lines with timestamps and tap centers so an editor can cut scenes and draw touch indicators. It also answers the first-launch notification prompt.
Mexico is Savely's primary market; 1.0 shipped with 139 of 368 catalog keys
untranslated and several screens building English in code.
- Catalog: every live key translated (134 added, 267 newly translated),
69 existing values normalized to the product voice (tú, sentence case,
no exclamation marks), 51 stale keys from removed features deleted, es-419
plural forms added. Keys kept in Xcode's order.
- Hardcoded strings routed through Strings.swift: goal pace status
(On track / Behind / 1+ year / /wk), the dashboard greeting, quick-add
sheet, the auto-move banner (AttributedString(localized:)), trackers,
goal flows, reports and PDF, achievements, notifications, receipt review,
profile, view-model errors. Display dates use Date.FormatStyle
("Lunes · 28 de septiembre"), with a sentenceCased helper.
- Money tab: "Income" as a title/segment gets its own key so Spanish reads
"Ingresos" next to "Gastos"; a single income stays "Ingreso".
- Persisted identifiers stay English: ExpenseCategory/IncomeSource gain
storageKey (stored) vs displayName (shown); the payday deposit note is the
constant GoalDeposits.autoMoveNote. Old rows keep matching; new tests in
CategoryPersistenceTests cover the round trip. GoalPaceTests pins en_US
instead of assuming the simulator's region.
- Knowledge: gotchas.yaml#persisted-identifiers-never-localized,
localization.md documents es-419 and the CI gate.
scripts/check-l10n.py (python3 stdlib) runs as the Localization completeness step after SwiftLint. It lists any live key without a translated es-419 value (plural variations included) and any translation whose format specifiers differ from the source.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
check-l10n.pypasses: 452 keys, all translated, format specifiers match.Strings.swift:AttributedString(localized:)).Date.FormatStyle("Lunes · 28 de septiembre").ExpenseCategory/IncomeSourcenow havestorageKey(stored) anddisplayName(shown), and the payday deposit note is the constantGoalDeposits.autoMoveNote. Without this the Spanish chips would have stored "Café" next to "Coffee". Old rows keep matching, and newCategoryPersistenceTestscover it.scripts/check-l10n.pyand fails when a live key lacks es-419 or its format specifiers drift.gotchas.yaml#persisted-identifiers-never-localized;localization.mddocuments es-419, the gate, and the catalog's key order (localizedStandardCompare).Why
Mexico is the primary market, but 1.0 had 139 of 368 keys untranslated and several screens building English in code. This is the headline of 1.1, and it also unblocks the es-MX screenshot set.
Test plan
xcodebuild test -scheme Savelyon iPhone 17 Pro, skipping SavelyUITests like CI: TEST SUCCEEDED, 107 passed, 0 failed (re-run after the rebase on chore: stop bundling Config.plist, drop dead API records #48).swiftlint lint --strictclean;python3 scripts/check-l10n.pyOK.-AppleLanguages (es-419) -AppleLocale es_MX): Home, Goals, goal detail (Behind / 1+ year), quick-add sheet, log expense and log income with the auto-move banner, Money (Gastos / Ingresos, 7-month trend), Profile (achievements, settings, Data & privacy) and receipt review. No truncation, no leftover English outside demo data.Risks
Strings.swiftconstants were kept and translated. Removing them is a separate cleanup.🤖 Generated with Claude Code