$npx -y skills add dpearson2699/swift-ios-skills --skill ios-localizationImplement, review, or improve localization and internationalization in iOS/macOS apps — String Catalogs (.xcstrings), generated localizable symbols, stable key naming, LocalizedStringKey, LocalizedStringResource, pluralization, FormatStyle for numbers/dates/measurements, right-to
| 1 | # iOS Localization & Internationalization |
| 2 | |
| 3 | Localize Apple-platform apps with String Catalogs, modern string types, |
| 4 | locale-aware formatting, and right-to-left layout. |
| 5 | |
| 6 | ## Contents |
| 7 | |
| 8 | - [String Catalogs and Generated Symbols](#string-catalogs-and-generated-symbols) |
| 9 | - [String Types -- Decision Guide](#string-types-decision-guide) |
| 10 | - [String Interpolation in Localized Strings](#string-interpolation-in-localized-strings) |
| 11 | - [Pluralization](#pluralization) |
| 12 | - [FormatStyle -- Locale-Aware Formatting](#formatstyle-locale-aware-formatting) |
| 13 | - [Right-to-Left (RTL) Layout](#right-to-left-rtl-layout) |
| 14 | - [Common Mistakes](#common-mistakes) |
| 15 | - [Localization Review Checklist](#review-checklist) |
| 16 | - [References](#references) |
| 17 | |
| 18 | ## String Catalogs and Generated Symbols |
| 19 | |
| 20 | String Catalogs are the recommended Xcode 15+ workflow for new localization work. They keep localizable strings, pluralization rules, and device variations together in an Xcode-managed JSON file with a visual editor. Legacy `.strings` and `.stringsdict` files can coexist during migration, but new Swift and SwiftUI code should default to String Catalogs. |
| 21 | |
| 22 | **How automatic extraction works:** |
| 23 | |
| 24 | Xcode scans for these patterns on each build: |
| 25 | |
| 26 | ```swift |
| 27 | // SwiftUI -- automatically extracted (LocalizedStringKey) |
| 28 | Text("Welcome back") // key: "Welcome back" |
| 29 | Label("Settings", systemImage: "gear") |
| 30 | Button("Save") { } |
| 31 | Toggle("Dark Mode", isOn: $dark) |
| 32 | |
| 33 | // Programmatic -- automatically extracted |
| 34 | String(localized: "No items found") |
| 35 | LocalizedStringResource("Order placed") |
| 36 | |
| 37 | // Plain String: not extracted or localized |
| 38 | let msg = "Hello" |
| 39 | ``` |
| 40 | |
| 41 | Xcode adds discovered keys to the String Catalog automatically. Mark translations as Needs Review, Translated, or Stale in the editor. |
| 42 | |
| 43 | For detailed String Catalog workflows, migration, and testing strategies, see [references/string-catalogs.md](references/string-catalogs.md). |
| 44 | |
| 45 | Generated symbols are an Xcode 26 typed-access layer on top of String Catalogs; |
| 46 | they do not change the catalog's Xcode 15 availability. |
| 47 | |
| 48 | **Enable:** Build Settings > Localization > Generate String Catalog Symbols → `Yes` (on by default in new Xcode 26 projects). Requires catalog format version `1.1`. |
| 49 | |
| 50 | **Workflow:** Add a key manually via the (+) button in the String Catalog editor — manual keys have the **Generate Swift Symbol** checkbox enabled by default. Auto-extracted keys can also opt in via Refactor > Convert Strings to Symbols. Use stable manual keys for generated-symbol strings. Avoid source-copy-derived keys for API-facing strings because wording edits can rename generated identifiers and churn call sites. |
| 51 | |
| 52 | ```swift |
| 53 | // Generated from key "room_available" in Localizable.xcstrings |
| 54 | Text(.roomAvailable) |
| 55 | |
| 56 | // Parameterized key "landmarks_count" with %1$(count)lld |
| 57 | Text(.landmarksCount(count: 42)) |
| 58 | |
| 59 | // Non-default table "Booking.xcstrings" |
| 60 | Text(.Booking.confirmBookingCta) |
| 61 | ``` |
| 62 | |
| 63 | Xcode derives symbol names by camelCasing the key: `settings.notifications.toggle` → `.settingsNotificationsToggle`. You can convert existing extracted strings to symbols via Refactor > Convert Strings to Symbols (reversible). |
| 64 | |
| 65 | Generated symbols are `internal`. For cross-module access, create a public wrapper extension. For heavier multi-module setups, use [xcstrings-tool](https://github.com/liamnichols/xcstrings-tool) instead. |
| 66 | |
| 67 | For the full generated symbols reference — extraction states, symbol derivation rules, and cross-module patterns — see [references/string-catalogs.md](references/string-catalogs.md). |
| 68 | |
| 69 | ## String Types -- Decision Guide |
| 70 | |
| 71 | | Context | Type | Why | |
| 72 | |---|---|---| |
| 73 | | SwiftUI view text | `LocalizedStringKey` (implicit) | SwiftUI performs lookup | |
| 74 | | View models, services, and errors | `String(localized:)` | Resolves to `String` now | |
| 75 | | App Intents, widgets, deferred system UI | `LocalizedStringResource` | Carries localization until display | |
| 76 | | Non-user-facing logs and analytics | Plain `String` | No localization needed | |
| 77 | |
| 78 | ### LocalizedStringKey (SwiftUI default) |
| 79 | |
| 80 | SwiftUI views accept `LocalizedStringKey` for their text parameters. String literals are implicitly converted -- no extra work needed. |
| 81 | |
| 82 | ```swift |
| 83 | Text("Welcome back") |
| 84 | Button("Delete") { deleteItem() } |
| 85 | ``` |
| 86 | |
| 87 | Use `LocalizedStringKey` when passing strings directly to SwiftUI view initializers. Do not construct `LocalizedStringKey` manually in mos |