feat(l10n): French localization#26
Merged
Merged
Conversation
The landing page has been bilingual FR/EN since launch, but the app itself was English-only. Follow system language per macOS convention: a String Catalog carries en/fr translations, threaded through SnapshotBuilder and the views, with a build tool plugin to compile it for swift build/test (SwiftPM's own build system copies .xcstrings verbatim instead of compiling it, unlike Xcode's build system).
SwiftPM's own build system doesn't compile .xcstrings catalogs, so the prior approach shelled out to xcstringstool via a custom build plugin and leaked the raw JSON catalog into the shipped app bundle. Convert the catalog to en.lproj/fr.lproj Localizable.strings, which SwiftPM processes natively, and drop the plugin entirely. Localized.string now resolves .lproj sub-bundles directly via Bundle(path:) for explicit non-current locales, deferring to Bundle.module's standard search order otherwise.
Base automatically changed from
feat/multi-calendar
to
feat/authorization-recovery
July 13, 2026 07:35
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
CFBundleLocalizations+ a String Catalog), rather than adding an in-app language switcher.Sources/Resources/Localizable.xcstrings(source languageen,frtranslations) covering every user-facing label, status string, format string, and the two Settings authorization messages.locale: Locale = .currentthroughSnapshotBuilder.computeSnapshotand its per-state builders;EventProgressSnapshot.noCalendar/.emptyTodaybecomestatic func(locale:). Views adoptText(_:bundle:)/ a smallLocalized.string(_:locale:)helper.%02d:%02d:%02d) are intentionally left unlocalized — only labels and format-string text are translated.Why a build tool plugin
SwiftPM's native build system (
swift build/swift test, as opposed to Xcode's build system) copies.xcstringsfiles verbatim instead of compiling them into per-locale.lproj/Localizable.strings— verified empirically: the resulting resource bundle reportedlocalizations: ["en"]only, and French lookups silently fell back to the English key.Plugins/CompileStringCatalogPluginis a.buildTool()plugin that shells out to Apple'sxcstringstool compileso the catalog is correctly compiled for CLI-only builds (no.xcodeprojin this repo).A related discovery:
String(localized:bundle:locale:)does not reliably honor an explicitlocale:override when given a plainBundleon the toolchain used here — it silently falls back toLocale.current. Routing throughLocalizedStringResourcewith a.atURLbundle description (wrapped inSources/Utilities/Localization.swift'sLocalized.string(_:locale:)) resolves correctly regardless of the host machine's locale. This is what letsSnapshotComputationTestsreliably pinen(Step 4 of the task brief) even if CI or a contributor's machine is set to French.Test plan
swiftlint— 0 errors (1 pre-existingfile_lengthwarning onNotchPanelView.swift, unrelated to this PR)swift buildDEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test— 56/56 passing, including withLANG=fr_FR.UTF-8 LC_ALL=fr_FR.UTF-8set to simulate a French hostbash scripts/package.sh—dist/NotchBar.app/Contents/Resources/NotchBar_NotchBar.bundle/fr.lproj/Localizable.stringspresent