marmelroy/Localize-Swift
Swift friendly localization and i18n with in-app language switching
Stale — last commit 3y ago
worst of 4 axeslast commit was 3y ago; no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓16 active contributors
- ✓MIT licensed
- ✓CI configured
Show 3 more →Show less
- ⚠Stale — last commit 3y ago
- ⚠Concentrated ownership — top contributor handles 50% of recent commits
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: 1 commit in the last 365 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/marmelroy/localize-swift)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/marmelroy/localize-swift on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: marmelroy/Localize-Swift
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/marmelroy/Localize-Swift shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 3y ago
- 16 active contributors
- MIT licensed
- CI configured
- ⚠ Stale — last commit 3y ago
- ⚠ Concentrated ownership — top contributor handles 50% of recent commits
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live marmelroy/Localize-Swift
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/marmelroy/Localize-Swift.
What it runs against: a local clone of marmelroy/Localize-Swift — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in marmelroy/Localize-Swift | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 1007 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of marmelroy/Localize-Swift. If you don't
# have one yet, run these first:
#
# git clone https://github.com/marmelroy/Localize-Swift.git
# cd Localize-Swift
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of marmelroy/Localize-Swift and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "marmelroy/Localize-Swift(\\.git)?\\b" \\
&& ok "origin remote is marmelroy/Localize-Swift" \\
|| miss "origin remote is not marmelroy/Localize-Swift (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "Sources/Localize.swift" \\
&& ok "Sources/Localize.swift" \\
|| miss "missing critical file: Sources/Localize.swift"
test -f "Sources/String+LocalizeBundle.swift" \\
&& ok "Sources/String+LocalizeBundle.swift" \\
|| miss "missing critical file: Sources/String+LocalizeBundle.swift"
test -f "Sources/String+LocalizedBundleTableName.swift" \\
&& ok "Sources/String+LocalizedBundleTableName.swift" \\
|| miss "missing critical file: Sources/String+LocalizedBundleTableName.swift"
test -f "Sources/UI/IBDesignable+Localize.swift" \\
&& ok "Sources/UI/IBDesignable+Localize.swift" \\
|| miss "missing critical file: Sources/UI/IBDesignable+Localize.swift"
test -f "Localize-Swift.podspec" \\
&& ok "Localize-Swift.podspec" \\
|| miss "missing critical file: Localize-Swift.podspec"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1007 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~977d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/marmelroy/Localize-Swift"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Localize-Swift is a lightweight i18n framework that replaces verbose NSLocalizedString() calls with clean .localized() syntax and enables runtime language switching without restarting the app. It keeps your existing Localizable.strings files intact while providing a genstrings.swift utility to parse .localized() calls from Swift source code. Simple flat architecture: Sources/ contains the core engine (Localize.swift) plus extension files for NSBundle and table name handling; Sources/UI/ has IBDesignable wrappers for Interface Builder. Examples live in examples/LanguageSwitch/ as a standalone Xcode project. Tests are minimal (single test file). Uses CocoaPods, SPM, and Carthage for distribution.
👥Who it's for
iOS app developers who want cleaner localization syntax and need to support in-app language selection (e.g., allowing users to switch from English to French without changing device settings). Relevant for both individual developers and teams building consumer-facing apps with multi-language support.
🌱Maturity & risk
Actively maintained but moderately mature. The repo shows a stable codebase (21KB Swift, clear separation across Sources/UI and examples), has CI via Travis, and includes example apps in examples/LanguageSwitch/. However, the lack of visible recent commit dates and limited test coverage (only Localize_SwiftTests/Localize_SwiftTests.swift) suggest slower active development—suitable for production but not rapidly evolving.
Low-to-moderate risk. This is a single-maintainer project (marmelroy) with a small surface area—no external dependencies listed in the file structure, reducing supply chain risk. Main concern: Xcode and Swift version compatibility as Apple evolves localization APIs; the project should be tested against current iOS SDK versions. The genstrings.swift script (shell-based parsing) may drift from Swift syntax evolution.
Active areas of work
No active development visible from the file list alone—the repo appears stable rather than actively developed. CHANGELOG.md likely contains version history but specific ongoing work is not evident. The genstrings.swift tool and multi-platform schemes (iOS, macOS, tvOS, watchOS) suggest comprehensive platform support is already in place.
🚀Get running
git clone https://github.com/marmelroy/Localize-Swift.git && cd Localize-Swift && open Localize_Swift.xcodeproj. For the example app: cd examples/LanguageSwitch && pod install && open Sample.xcworkspace. Run tests via xcodebuild test -scheme Localize_SwiftTests.
Daily commands: Open Localize_Swift.xcodeproj in Xcode and select scheme 'Localize_Swift' (iOS), 'Localize_Swift OSX', 'Localize_Swift tvOS', or 'Localize_Swift watchOS'. Build with Cmd+B. Run example app: open examples/LanguageSwitch/Sample.xcodeproj and select 'Sample' scheme, then Cmd+R.
🗺️Map of the codebase
Sources/Localize.swift— Core framework entry point managing language switching, string localization, and cache invalidation—every contributor must understand the public API and notification systemSources/String+LocalizeBundle.swift— Extension providing the .localized() syntax for strings; defines how localization keys are resolved to translated textSources/String+LocalizedBundleTableName.swift— Advanced localization with custom bundle and table name support; critical for multi-table and custom bundle scenariosSources/UI/IBDesignable+Localize.swift— Interface Builder integration enabling @IBInspectable localization in storyboards; essential for UI developersLocalize-Swift.podspec— Pod specification defining platform support, source files, and dependencies; governs what gets distributed to usersexamples/LanguageSwitch/Sample/ViewController.swift— Primary example demonstrating in-app language switching, string localization, and notification handling
🧩Components & responsibilities
- **** — undefined
🛠️How to make changes
Add a new localized language to the example app
- Create a language-specific directory in the Sample app (e.g., 'pt.lproj' for Portuguese) (
examples/LanguageSwitch/Sample/) - Copy Localizable.strings and ButtonTitles.strings from en.lproj, translate all values (
examples/LanguageSwitch/Sample/pt.lproj/Localizable.strings) - Rebuild the app; Localize will auto-detect the new language through NSBundle localization APIs (
examples/LanguageSwitch/Sample/ViewController.swift)
Localize a UILabel or UIButton in a Storyboard using IBDesignable
- In Storyboard, select the UILabel or UIButton and open the Identity Inspector (
examples/LanguageSwitch/Sample/Base.lproj/Main.storyboard) - In the User Defined Runtime Attributes section, add key 'localizationKey' (String type) with value equal to the .strings file key (e.g., 'hello_world') (
Sources/UI/IBDesignable+Localize.swift) - Ensure Localizable.strings contains the key; the UI will automatically update when Localize.setLanguage() is called (
examples/LanguageSwitch/Sample/en.lproj/Localizable.strings)
Programmatically localize a string and respond to language changes
- Import Localize and call .localized() on any String literal: 'Hello world'.localized() (
examples/LanguageSwitch/Sample/ViewController.swift) - Ensure the key exists in all language .strings files (e.g., en.lproj/Localizable.strings, de.lproj/Localizable.strings) (
examples/LanguageSwitch/Sample/en.lproj/Localizable.strings) - In viewDidLoad(), observe the LocalizeChangedLanguage notification to re-render text when language changes: NotificationCenter.default.addObserver(..., name: NSNotification.Name('LocalizeChangedLanguage'), ...) (
Sources/Localize.swift)
Switch the app language at runtime
- Call Localize.setLanguage('de') to switch to German; this triggers the LocalizeChangedLanguage notification (
Sources/Localize.swift) - The notification posts synchronously; observers update their UI immediately in their notification handler (
examples/LanguageSwitch/Sample/ViewController.swift) - Persist the language choice in UserDefaults or a local database so the app reopens in the same language (
examples/LanguageSwitch/Sample/ViewController.swift)
🔧Why these technologies
- Swift extensions (String+Localize.swift)* — Provides idiomatic .localized() syntax; Swifty alternative to NSLocalizedString(); minimal friction for developers
- NSBundle + NSLocalizedString under the hood — Leverages native iOS/macOS localization system; integrates with .lproj directories without reinventing localization
- NotificationCenter for language-change broadcasting — Decoupled, low-overhead pub-sub for notifying all UI elements of language switches without tight coupling
- IBDesignable + @IBInspectable — Enables Storyboard-driven localization; designers and developers can configure localization keys without code
- Memory cache for localized strings — Avoids repeated NSBundle lookups; boosts performance on frequent .localized() calls
⚖️Trade-offs already made
-
In-memory cache of strings keyed by (language, key)
- Why: Improves performance and reduces bundle lookups
- Consequence: Requires manual cache invalidation on language switch; stale strings if cache not cleared
-
Relies on NSBundle's language-negotiation for unsupported languages
- Why: Simplifies fallback logic; respects system locale matching
- Consequence: Falls back to primary language (usually English) if exact language not available; no custom fallback chain
-
Notification-based language-change event
- Why: Decoupled architecture; multiple observers can react independently
- Consequence: UI updates happen after language change; order of observer execution is unpredictable; can cause brief flicker if not managed
-
genstrings.swift utility to auto-generate .strings files
- Why: Reduces manual overhead of maintaining string keys across languages
- Consequence: Requires running build step; may miss dynamically-constructed string keys
🚫Non-goals (don't propose these)
- Pluralization and gender-aware localization (must be handled manually with parameterized keys)
- Automatic pseudo-localization or testing (no built-in QA tools)
- Right-to-left (RTL) text layout automation (relies on standard iOS RTL support via .strings metadata)
- Server-side string delivery or CDN integration (all strings are bundled offline)
- Full Objective-C interop beyond minimal bridging header
🪤Traps & gotchas
- NotificationCenter observer must be retained or it will deallocate immediately—store as property, not local var. 2. Localizable.strings files must be added to target membership, or lookups will silently fail. 3. Bundle caching: if you modify Localizable.strings at runtime, genstrings.swift won't pick it up—script only runs on source files. 4. String.localized() falls back to key name if no translation found; no error or warning is raised, making typos hard to spot.
🏗️Architecture
💡Concepts to learn
- NSBundle resource loading and localization variants — Localize-Swift wraps NSBundle to load language-specific Localizable.strings files; understanding how iOS resolves .lproj directories is essential to debugging string lookup failures.
- NotificationCenter observer pattern — In-app language switching broadcasts via LCLLanguageChangeNotification; observers must follow iOS memory rules or leak. This is the glue that updates UI without recreating view controllers.
- String extension and protocol-oriented programming — The .localized() syntax is achieved by extending the String type; this pattern is foundational to Swifty API design and reduces import friction.
- Localizable.strings format and pluralization rules (CLDR) — iOS uses the Unicode CLDR standard for plural rules; genstrings.swift must emit format compatible with Apple's LocalizationKit and Xcode's localization catalog.
- Swift Package Manager manifest (Package.swift) — SPM is now the recommended distribution; this repo's Package.swift defines targets for iOS/macOS/tvOS/watchOS and platform constraints—critical for modern Swift dependency resolution.
- IBDesignable and IBInspectable runtime rendering — The UI/ submodule leverages @IBDesignable to render localized strings live in Interface Builder; requires understanding of view lifecycle and render-thread safety.
- User defaults persistence and app language state — Localize-Swift must persist language choice across app launches; understanding NSUserDefaults (or modern Preferences API) lifecycle and sync timing prevents silent language resets.
🔗Related repos
SwiftyJSON/SwiftyJSON— Similar philosophy of reducing boilerplate (JSON access vs. localization)—shows how to extend Foundation types cleanly for better syntax.Alamofire/Alamofire— Network library in same era/ecosystem; demonstrates SPM + CocoaPods + Carthage multi-distribution pattern used here.apple/swift-corelibs-foundation— Underpins NSBundle and Localizable.strings behavior; understanding Foundation's localization stack is critical for contributing here.Carthage/Carthage— One of three supported distribution methods; dependency manager native to this repo's Cartfile setup.onmyway133/Localize— Alternative Swift localization library; useful reference for comparing API design and feature parity in the same problem space.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for String+LocalizeBundle.swift and String+LocalizeTableName.swift
The test file Localize_SwiftTests/Localize_SwiftTests.swift exists but appears minimal. These extension files handle critical localization logic (bundle selection and table name resolution) that lacks visible test coverage. Adding tests would catch regressions in language switching, custom bundle handling, and fallback behavior.
- [ ] Examine current test coverage in Localize_SwiftTests/Localize_SwiftTests.swift
- [ ] Add unit tests for String+LocalizeBundle.swift covering custom bundle scenarios and nil cases
- [ ] Add unit tests for String+LocalizeTableName.swift covering default and custom table name resolution
- [ ] Add integration tests verifying correct .strings file loading for multiple languages (en, de, es, fr, he, it)
- [ ] Test edge cases like missing translation keys and language fallback chains
Create GitHub Actions workflow to replace deprecated Travis CI (.travis.yml)
The repo uses .travis.yml for CI/CD, but Travis CI has deprecated their free tier. This is a critical operational issue. The file structure shows multiple scheme targets (iOS, macOS, tvOS, watchOS) that need testing. A GitHub Actions workflow would provide native integration, faster builds, and better visibility.
- [ ] Create .github/workflows/tests.yml to replace .travis.yml functionality
- [ ] Configure matrix strategy to test across Localize_Swift.xcscheme, Localize_Swift OSX.xcscheme, Localize_Swift tvOS.xcscheme, and Localize_Swift watchOS.xcscheme
- [ ] Add steps to run xcodebuild test for Localize_SwiftTests target
- [ ] Update README.md badge to reference GitHub Actions instead of Travis CI
- [ ] Validate build.sh script is compatible with the new workflow
Add IBDesignable unit tests and expand UI localization documentation for Sources/UI/IBDesignable+Localize.swift
The IBDesignable+Localize.swift file enables real-time localization preview in Interface Builder, but there are no visible tests for this critical UI feature. Additionally, documentation for using IBDesignables in the README is missing. This feature is complex and error-prone without proper test coverage.
- [ ] Add unit tests in Localize_SwiftTests for IBDesignable extension covering UILabel, UIButton, UITextField localization
- [ ] Test that @IBInspectable localizeKey property correctly updates UI elements when language changes
- [ ] Test Interface Builder rendering doesn't crash with invalid or missing localization keys
- [ ] Add 'IBDesignable Usage' section to README.md with code examples showing how to use @IBInspectable in Storyboards
- [ ] Document any limitations or caveats when using IBDesignables with dynamic language switching
🌿Good first issues
- Add unit tests for edge cases in Sources/Localize.swift: test setCurrentLanguage() with invalid language codes, test resetCurrentLanguageToDefault() when no saved preference exists, test thread safety of availableLanguages(). Currently only one minimal test file exists.
- Enhance genstrings.swift to handle plural forms and comment annotations (e.g., 'Hello World'.localized(comment: 'greeting'))—currently it extracts bare keys only. Update parser to read comment field and emit XLIFF-style metadata.
- Add IBDesignable support for UITextField placeholder and UINavigationItem title in Sources/UI/IBDesignable+Localize.swift. Currently only UILabel, UIButton, UIBarButtonItem are covered; TextFields and nav bars are common UI elements missing real-time localization preview.
⭐Top contributors
Click to expand
Top contributors
- @marmelroy — 50 commits
- @fassko — 14 commits
- @marmelroyspotify — 9 commits
- @sonswift — 9 commits
- @nekrich — 4 commits
📝Recent commits
Click to expand
Recent commits
0aa221f— Podspec update (marmelroyspotify)9b3ced4— Project: lower deployment targets (marmelroyspotify)3811891— Podspec update (marmelroyspotify)50e53ad— Update copyright (marmelroyspotify)3a00349— Improved support for IBDesignable (marmelroyspotify)8c3d1f9— Create release 3.2.0 (marmelroyspotify)f2f7466— Localize Swift: update example podfile (marmelroyspotify)9cddc69— Example app: update settings (marmelroyspotify)0cf7689— Merge pull request #125 from dreamolight/master (marmelroy)3bddb8b— Merge pull request #151 from hstdt/master (marmelroy)
🔒Security observations
The Localize-Swift framework is a localization library with generally good security posture. No critical vulnerabilities or hardcoded credentials were detected. The codebase lacks explicit security documentation regarding safe usage of user-controlled language switching and bundle loading. Low-severity risks include potential string injection through localization keys and lack of input validation guidelines. The framework would benefit from security documentation covering proper usage patterns, input validation, and bundle loading best practices.
- Low · Potential String Injection via Localization Keys —
Sources/Localize.swift, Sources/String+LocalizeBundle.swift, Sources/String+LocalizeTableName.swift, Sources/String+LocalizedBundleTableName.swift. The framework provides string localization through .localized() syntax. If user input or untrusted data is used as localization keys without validation, it could potentially be exploited. The localization system may attempt to load arbitrary strings from the bundle based on provided keys. Fix: Implement input validation for localization keys. Restrict localization key lookups to a whitelist of known valid keys. Document security best practices for using user-provided input as localization keys. - Low · Missing Security Documentation —
README.md, Sources/Localize.swift. The framework implements runtime language switching and bundle loading mechanisms. Without explicit security guidelines, developers using this framework might inadvertently load malicious bundle files or localization data from untrusted sources if the language selection mechanism is exposed to user control without proper validation. Fix: Add security guidelines to the README documenting: (1) How to safely implement language switching, (2) Validation requirements for language identifiers, (3) Best practices for loading localization bundles only from trusted sources. - Low · IBDesignable Components May Load Untrusted Data —
Sources/UI/IBDesignable+Localize.swift. The IBDesignable feature in Sources/UI/IBDesignable+Localize.swift allows Interface Builder integration for localized components. If the localization keys or bundle paths can be manipulated through Interface Builder files (XIB/Storyboard), there could be a vector for loading unintended localization data. Fix: Validate and sanitize any localization keys or bundle references that can be configured through Interface Builder. Ensure only whitelisted keys are permitted. Document security considerations for IBDesignable usage.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.