@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +285 -285
- package/package.json +3 -3
- package/pipeline/lib/redact.mjs +3 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/scripts/gen-skills-index.mjs +13 -1
- package/pipeline/scripts/pre-commit-check.sh +4 -0
- package/pipeline/skills/.skill-manifest.json +69 -69
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,473 +1,360 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ios-localization
|
|
3
|
-
description: "
|
|
3
|
+
description: "i18n and l10n for iOS and macOS: String Catalogs (.xcstrings), generated localizable symbols with compile-time-checked keys, stable key naming, LocalizedStringKey, LocalizedStringResource, String(localized:), plurals, device variations, locale-aware FormatStyle for numbers, dates, currency and measurements, right-to-left layout, Dynamic Type, localization testing. Use when implementing or reviewing localization, adding languages, setting up catalogs, formatting values per locale, testing translations or making UI work in Arabic or Hebrew. Not for custom or parseable FormatStyle, parsing, interval or URL format styles (swift-formatstyle)."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# iOS Localization
|
|
8
|
+
# iOS Localization
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This skill targets iOS 26+ apps built with String Catalogs, the modern Swift
|
|
11
|
+
string types, `FormatStyle` and layout that respects writing direction. Each API
|
|
12
|
+
below keeps its own, often much older, availability.
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
Retrofitting localization late is expensive. Hard-coded copy, glued-together
|
|
15
|
+
sentences and fixed widths show up as rejected builds in non-English
|
|
16
|
+
storefronts, mistranslated screens and clipped layouts. Treat every visible
|
|
17
|
+
string and every formatted value as localizable from the first commit.
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
- [String Catalogs (Xcode 15+) and Generated Symbols (Xcode 26+)](#string-catalogs-xcode-15-and-generated-symbols-xcode-26)
|
|
16
|
-
- [String Types -- Decision Guide](#string-types-decision-guide)
|
|
17
|
-
- [String Interpolation in Localized Strings](#string-interpolation-in-localized-strings)
|
|
18
|
-
- [Pluralization](#pluralization)
|
|
19
|
-
- [FormatStyle -- Locale-Aware Formatting](#formatstyle-locale-aware-formatting)
|
|
20
|
-
- [Right-to-Left (RTL) Layout](#right-to-left-rtl-layout)
|
|
21
|
-
- [Common Mistakes](#common-mistakes)
|
|
22
|
-
- [Localization Review Checklist](#review-checklist)
|
|
23
|
-
- [References](#references)
|
|
19
|
+
Deep material lives in two references:
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
- [references/string-catalogs.md](references/string-catalogs.md): catalog
|
|
22
|
+
creation, extraction rules, key management, bundles and Swift packages,
|
|
23
|
+
plurals, device variants, translator export and import, the JSON format,
|
|
24
|
+
generated symbols, testing and migration.
|
|
25
|
+
- [references/formatstyle-locale.md](references/formatstyle-locale.md):
|
|
26
|
+
locale-aware formatting for every value type, legacy formatter migration, RTL
|
|
27
|
+
in depth, `@ScaledMetric` and layout checks with Accessibility Inspector.
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
## String Catalogs
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
A String Catalog is a JSON file managed by Xcode, edited through a visual
|
|
32
|
+
table, that keeps source strings, translations, plural forms and per-device
|
|
33
|
+
variants in one place. Catalogs have been the recommended way to localize
|
|
34
|
+
since Xcode 15. Legacy `.strings` and `.stringsdict` files can live next to a
|
|
35
|
+
catalog while a project migrates, but new Swift and SwiftUI code should start
|
|
36
|
+
in a catalog.
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
Why the switch: `.strings` files needed hand-maintained keys that silently
|
|
39
|
+
drifted from the code, and `.stringsdict` plural rules were long XML
|
|
40
|
+
dictionaries. A catalog is filled in by the build, tracks the state of each
|
|
41
|
+
translation, and models plurals directly.
|
|
35
42
|
|
|
36
|
-
Xcode scans for
|
|
43
|
+
Every build, Xcode scans the source for known localizable call patterns and
|
|
44
|
+
adds any key it finds. Keys then show a state in the editor such as Needs
|
|
45
|
+
Review, Translated or Stale.
|
|
37
46
|
|
|
38
47
|
```swift
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Xcode adds discovered keys to the String Catalog automatically. Mark translations as Needs Review, Translated, or Stale in the editor.
|
|
48
|
+
struct TripHeader: View {
|
|
49
|
+
@State private var alertsOn = true
|
|
50
|
+
|
|
51
|
+
var body: some View {
|
|
52
|
+
VStack {
|
|
53
|
+
Text("Your upcoming trips") // extracted
|
|
54
|
+
Label("Boarding pass", systemImage: "ticket") // extracted
|
|
55
|
+
Button("Check in") { } // extracted
|
|
56
|
+
Toggle("Gate alerts", isOn: $alertsOn) // extracted
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
let banner = String(localized: "Seat changed") // extracted
|
|
62
|
+
let hint = LocalizedStringResource("Arrive two hours early") // extracted
|
|
63
|
+
let debugTag = "trip-header" // plain String: never extracted, never translated
|
|
64
|
+
```
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
For a SwiftUI initializer the literal itself becomes the key.
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
## Generated Symbols (Xcode 26) on Top of Catalogs
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
When a question is about generated symbols or about migrating to them, say
|
|
71
|
+
this first: catalogs are the Xcode 15+ workflow, and generated symbols are a
|
|
72
|
+
separate typed-access layer that Xcode 26 builds on those catalogs. Do not say
|
|
73
|
+
catalogs require Xcode 26, and do not tie them to iOS 17.
|
|
62
74
|
|
|
63
|
-
|
|
75
|
+
- Turn it on with Build Settings > Localization > Generate String Catalog
|
|
76
|
+
Symbols = `Yes`. New Xcode 26 projects already have it on.
|
|
77
|
+
- The catalog must use format version `1.1`.
|
|
78
|
+
- A key added by hand with the (+) button has Generate Swift Symbol ticked by
|
|
79
|
+
default. Keys that came from extraction opt in through Refactor > Convert
|
|
80
|
+
Strings to Symbols, which can be undone later.
|
|
81
|
+
- Pick stable, hand-written keys for anything reached through a symbol. A key
|
|
82
|
+
derived from the English copy renames its symbol the moment someone edits
|
|
83
|
+
the wording, and every call site churns.
|
|
64
84
|
|
|
65
85
|
```swift
|
|
66
|
-
//
|
|
67
|
-
Text(.
|
|
86
|
+
// Localizable.xcstrings: "cart_empty" -> "Your cart is empty"
|
|
87
|
+
Text(.cartEmpty)
|
|
68
88
|
|
|
69
|
-
//
|
|
70
|
-
Text(.
|
|
89
|
+
// "seats_left" -> "%1$(remaining)lld seats left"
|
|
90
|
+
Text(.seatsLeft(remaining: 3))
|
|
71
91
|
|
|
72
|
-
//
|
|
73
|
-
Text(.
|
|
92
|
+
// Separate table Payments.xcstrings, key "apply_voucher_cta"
|
|
93
|
+
Text(.Payments.applyVoucherCta)
|
|
74
94
|
```
|
|
75
95
|
|
|
76
|
-
|
|
96
|
+
Symbols are the key in camelCase: `profile.privacy.header` becomes
|
|
97
|
+
`.profilePrivacyHeader`. They are generated with `internal` access, so another
|
|
98
|
+
module needs a small public wrapper. When wrappers pile up across many modules,
|
|
99
|
+
the open-source `xcstrings-tool` package plugin generates public accessors.
|
|
77
100
|
|
|
78
|
-
|
|
101
|
+
## Picking a String Type
|
|
79
102
|
|
|
80
|
-
|
|
103
|
+
### LocalizedStringKey
|
|
81
104
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
### LocalizedStringKey (SwiftUI default)
|
|
85
|
-
|
|
86
|
-
SwiftUI views accept `LocalizedStringKey` for their text parameters. String literals are implicitly converted -- no extra work needed.
|
|
105
|
+
Text parameters of SwiftUI views are `LocalizedStringKey`, and a string literal
|
|
106
|
+
converts to it implicitly, so lookup just happens:
|
|
87
107
|
|
|
88
108
|
```swift
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Label("
|
|
92
|
-
Button("
|
|
93
|
-
|
|
109
|
+
NavigationStack {
|
|
110
|
+
List {
|
|
111
|
+
Label("Saved places", systemImage: "mappin")
|
|
112
|
+
Button("Clear history") { }
|
|
113
|
+
}
|
|
114
|
+
.navigationTitle("Places")
|
|
115
|
+
}
|
|
94
116
|
```
|
|
95
117
|
|
|
96
|
-
|
|
118
|
+
Pass literals straight into SwiftUI initializers. Building a
|
|
119
|
+
`LocalizedStringKey` by hand is rarely needed.
|
|
97
120
|
|
|
98
|
-
### String(localized:)
|
|
121
|
+
### String(localized:)
|
|
99
122
|
|
|
100
|
-
|
|
123
|
+
`String(localized:)` replaces `NSLocalizedString`. It returns a resolved
|
|
124
|
+
`String` for code that is not a SwiftUI initializer argument. The literal and
|
|
125
|
+
interpolation form needs iOS 15; resolving a `LocalizedStringResource` needs
|
|
126
|
+
iOS 16.
|
|
101
127
|
|
|
102
128
|
```swift
|
|
103
|
-
|
|
104
|
-
let
|
|
129
|
+
let title = String(localized: "Refund requested")
|
|
130
|
+
let note = String(localized: "refund.pending.note",
|
|
131
|
+
defaultValue: "Refunds take up to 5 business days")
|
|
132
|
+
let label = String(localized: "Download", table: "Offline", bundle: .module)
|
|
133
|
+
let verb = String(localized: "Book",
|
|
134
|
+
comment: "Verb on a button that reserves a table")
|
|
135
|
+
```
|
|
105
136
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
defaultValue: "Check your internet connection")
|
|
137
|
+
A Swift package that still shows English falls into one of three setup gaps.
|
|
138
|
+
Check them in order before touching bundle lookup:
|
|
109
139
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
140
|
+
1. `Package.swift` sets `defaultLocalization`.
|
|
141
|
+
2. The target's `resources` processes the folder that holds the catalog, for
|
|
142
|
+
example `.process("Resources")`.
|
|
143
|
+
3. `Localizable.xcstrings` really sits inside that processed folder.
|
|
114
144
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
comment: "Button title to save the current document")
|
|
118
|
-
```
|
|
145
|
+
Only once all three hold, debug lookup with `bundle: .module` in
|
|
146
|
+
`String(localized:)` and `Text(_:bundle:)`.
|
|
119
147
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
3. `Localizable.xcstrings` is actually inside that processed target-resource path.
|
|
124
|
-
Only after those pass, debug lookup with `bundle: .module` or `Text(..., bundle: .module)`.
|
|
148
|
+
Xcode can still export and migrate literal-key `NSLocalizedString` calls, but
|
|
149
|
+
new code uses `String(localized:)`, SwiftUI literals,
|
|
150
|
+
`LocalizedStringResource` or generated symbols.
|
|
125
151
|
|
|
126
|
-
|
|
152
|
+
### LocalizedStringResource
|
|
127
153
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
`LocalizedStringResource` (iOS 16+) carries a localizable value that someone
|
|
155
|
+
else resolves later: App Intents, widgets, notifications, generated symbols
|
|
156
|
+
and system APIs that accept it. When you need the text now, use
|
|
157
|
+
`String(localized:)`.
|
|
131
158
|
|
|
132
159
|
```swift
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
160
|
+
struct StartTimerIntent: AppIntent {
|
|
161
|
+
static let title: LocalizedStringResource = "Start Focus Timer"
|
|
162
|
+
func perform() async throws -> some IntentResult { .result() }
|
|
136
163
|
}
|
|
137
164
|
|
|
138
|
-
|
|
139
|
-
struct MyWidget: Widget {
|
|
165
|
+
struct StepsWidget: Widget {
|
|
140
166
|
var body: some WidgetConfiguration {
|
|
141
|
-
StaticConfiguration(kind: "
|
|
142
|
-
|
|
143
|
-
TimerView(entry: entry)
|
|
167
|
+
StaticConfiguration(kind: "steps", provider: StepsProvider()) { entry in
|
|
168
|
+
StepsView(entry: entry)
|
|
144
169
|
}
|
|
145
|
-
.configurationDisplayName(LocalizedStringResource("
|
|
170
|
+
.configurationDisplayName(LocalizedStringResource("Daily Steps"))
|
|
146
171
|
}
|
|
147
172
|
}
|
|
148
173
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
let resolved = String(localized: title)
|
|
174
|
+
func showToast(_ message: LocalizedStringResource) {
|
|
175
|
+
let text = String(localized: message) // resolved in the current locale
|
|
176
|
+
toastCenter.present(text)
|
|
153
177
|
}
|
|
154
178
|
```
|
|
155
179
|
|
|
156
|
-
###
|
|
180
|
+
### Which type where
|
|
157
181
|
|
|
158
182
|
| Context | Type | Why |
|
|
159
|
-
|
|
160
|
-
| SwiftUI view text parameters | `LocalizedStringKey` (implicit) | SwiftUI
|
|
161
|
-
|
|
|
162
|
-
| App Intents, widgets, system APIs | `LocalizedStringResource` |
|
|
163
|
-
| Error
|
|
164
|
-
|
|
|
165
|
-
|
|
166
|
-
## String Interpolation in Localized Strings
|
|
167
|
-
|
|
168
|
-
Interpolated values in localized strings become positional arguments that translators can reorder.
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| SwiftUI view text parameters | `LocalizedStringKey` (implicit) | SwiftUI does the lookup |
|
|
185
|
+
| Strings built in view models or services | `String(localized:)` | Logic needs the resolved value |
|
|
186
|
+
| App Intents, widgets, system APIs | `LocalizedStringResource` | The framework resolves at display time |
|
|
187
|
+
| Error text shown to the user | `String(localized:)` | Resolved inside the `catch` |
|
|
188
|
+
| Logs and analytics | `String` | Never shown to users |
|
|
169
189
|
|
|
170
|
-
|
|
171
|
-
// English: "Welcome, Alice! You have 3 new messages."
|
|
172
|
-
// German: "Willkommen, Alice! Sie haben 3 neue Nachrichten."
|
|
173
|
-
// Japanese: "Alice さん、新しいメッセージが 3 件あります。"
|
|
174
|
-
let text = String(localized: "Welcome, \(name)! You have \(count) new messages.")
|
|
175
|
-
```
|
|
190
|
+
## Interpolation
|
|
176
191
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
- Japanese: `"%@さん、新しいメッセージが%lld件あります。"`
|
|
192
|
+
Interpolated values become positional arguments, so a translator can move them
|
|
193
|
+
around the sentence:
|
|
180
194
|
|
|
181
|
-
**Type-safe interpolation** (preferred over format specifiers):
|
|
182
195
|
```swift
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
196
|
+
let summary = String(localized: "\(guestName) booked \(nights) nights")
|
|
197
|
+
// Catalog key: "%@ booked %lld nights"
|
|
198
|
+
// Japanese can place the arguments in its own order.
|
|
186
199
|
```
|
|
187
200
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
String Catalogs handle pluralization natively -- no `.stringsdict` XML required.
|
|
201
|
+
Give interpolations a format instead of raw specifiers:
|
|
202
|
+
`\(distance, format: .number)` or `\(departure, format: .dateTime.hour().minute())`.
|
|
191
203
|
|
|
192
|
-
|
|
204
|
+
## Plurals
|
|
193
205
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
| one | 1 item | 1 item |
|
|
200
|
-
| two | (not used) | 2 items (dual) |
|
|
201
|
-
| few | (not used) | 3-10 items |
|
|
202
|
-
| many | (not used) | 11-99 items |
|
|
203
|
-
| other | 2+ items | 100+ items |
|
|
204
|
-
|
|
205
|
-
English uses only `one` and `other`. Arabic uses all six. Always supply `other` as the fallback.
|
|
206
|
+
Catalogs model plurals directly; no `.stringsdict`. Interpolate an integer,
|
|
207
|
+
build, and the editor offers plural variants for that key. CLDR defines six
|
|
208
|
+
categories: zero, one, two, few, many, other. English only uses one and other.
|
|
209
|
+
Arabic uses all six: zero, one, two (dual), few (3 to 10), many (11 to 99) and
|
|
210
|
+
other (100 and up). Always fill `other`; it is the fallback.
|
|
206
211
|
|
|
207
212
|
```swift
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// String Catalog entries (English):
|
|
212
|
-
// one: "%lld unread message"
|
|
213
|
-
// other: "%lld unread messages"
|
|
213
|
+
Text("\(pendingInvites) pending invites")
|
|
214
|
+
// en one: "%lld pending invite"
|
|
215
|
+
// en other: "%lld pending invites"
|
|
214
216
|
```
|
|
215
217
|
|
|
216
|
-
### Device
|
|
218
|
+
### Device variations
|
|
217
219
|
|
|
218
|
-
|
|
220
|
+
Vary by Device lets one key read differently per device, for instance "Tap to
|
|
221
|
+
edit" on iPhone, "Tap or click to edit" on iPad and "Click to edit" on Mac.
|
|
219
222
|
|
|
220
|
-
|
|
221
|
-
// In String Catalog editor, enable "Vary by Device" for a key
|
|
222
|
-
// iPhone: "Tap to continue"
|
|
223
|
-
// iPad: "Tap or click to continue"
|
|
224
|
-
// Mac: "Click to continue"
|
|
225
|
-
```
|
|
223
|
+
### Grammar agreement (iOS 15+)
|
|
226
224
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
Use `^[...]` inflection syntax for automatic grammatical agreement:
|
|
230
|
-
|
|
231
|
-
```swift
|
|
232
|
-
// Automatically adjusts for gender/number in supported languages
|
|
233
|
-
Text("^[\(count) \("photo")](inflect: true) added")
|
|
234
|
-
// English: "1 photo added" / "3 photos added"
|
|
235
|
-
// Spanish: "1 foto agregada" / "3 fotos agregadas"
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## FormatStyle -- Locale-Aware Formatting
|
|
239
|
-
|
|
240
|
-
Never hard-code date, number, or measurement formats. Use `FormatStyle` (iOS 15+) so formatting adapts to the user's locale automatically.
|
|
241
|
-
|
|
242
|
-
Locale-aware formatting matters even in single-language apps because user locale affects separators, calendars, currency, units, names, and list formatting. When giving user-facing formatting advice, explicitly recommend testing or previewing output under multiple locales such as `en_US`, `de_DE`, `ar_SA`, and `ja_JP`.
|
|
243
|
-
|
|
244
|
-
`ios-localization` owns `FormatStyle` guidance when the issue is locale-aware user-facing display, including numbers, dates, currency, units, names, lists, calendars, separators, and locale preview/testing. For custom `FormatStyle`, `ParseableFormatStyle`, parsing, `Date.IntervalFormatStyle`, `URL.FormatStyle`, or reusable formatter API design, route to `swift-formatstyle`; keep `ios-localization` advice to locale risks and testing unless implementation is explicitly requested.
|
|
245
|
-
|
|
246
|
-
### Dates
|
|
247
|
-
|
|
248
|
-
```swift
|
|
249
|
-
let now = Date.now
|
|
250
|
-
|
|
251
|
-
// Preset styles
|
|
252
|
-
now.formatted(date: .long, time: .shortened)
|
|
253
|
-
// US: "January 15, 2026 at 3:30 PM"
|
|
254
|
-
// DE: "15. Januar 2026 um 15:30"
|
|
255
|
-
// JP: "2026年1月15日 15:30"
|
|
256
|
-
|
|
257
|
-
// Component-based
|
|
258
|
-
now.formatted(.dateTime.month(.wide).day().year())
|
|
259
|
-
// US: "January 15, 2026"
|
|
260
|
-
|
|
261
|
-
// In SwiftUI
|
|
262
|
-
Text(now, format: .dateTime.month().day().year())
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Numbers
|
|
225
|
+
Automatic grammar agreement fixes gender and number for supported languages
|
|
226
|
+
with the inflection markup `^[...](inflect: true)`:
|
|
266
227
|
|
|
267
228
|
```swift
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
count.formatted(.number.precision(.fractionLength(2)))
|
|
271
|
-
count.formatted(.percent) // For 0.85 -> "85%" (US) / "85 %" (FR)
|
|
272
|
-
|
|
273
|
-
// Currency
|
|
274
|
-
let price = Decimal(29.99)
|
|
275
|
-
price.formatted(.currency(code: "USD")) // "$29.99" (US) / "29,99 $US" (FR)
|
|
276
|
-
price.formatted(.currency(code: "EUR")) // "29,99 EUR" (DE)
|
|
229
|
+
Text("Added ^[\(bottleCount) bottle](inflect: true) to your cellar")
|
|
230
|
+
// English: 1 bottle / 3 bottles; Spanish forms agree automatically.
|
|
277
231
|
```
|
|
278
232
|
|
|
279
|
-
|
|
233
|
+
## Locale-Aware Formatting with FormatStyle
|
|
280
234
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
235
|
+
Never hard-code date, number or measurement patterns; use `FormatStyle`
|
|
236
|
+
(iOS 15+). Locale still matters in a one-language app: decimal and grouping
|
|
237
|
+
separators, calendars, currency symbols, units, name order and list
|
|
238
|
+
conjunctions all follow the user's region. Whenever you advise on user-facing
|
|
239
|
+
formatting, also tell the reader to preview or test under several locales such
|
|
240
|
+
as `en_US`, `de_DE`, `ar_SA` and `ja_JP`.
|
|
285
241
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
242
|
+
Scope boundary: this skill owns `FormatStyle` for locale-aware display
|
|
243
|
+
(numbers, dates, currency, units, names, lists, calendars, separators, and
|
|
244
|
+
locale previews and tests). Custom `FormatStyle` types, `ParseableFormatStyle`,
|
|
245
|
+
parsing, `Date.IntervalFormatStyle`, `URL.FormatStyle` and reusable formatter
|
|
246
|
+
API design belong to `swift-formatstyle`. Here, only point out locale risks and
|
|
247
|
+
testing for those, unless the user explicitly asks for an implementation.
|
|
292
248
|
|
|
293
249
|
```swift
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
250
|
+
let flight = Date.now
|
|
251
|
+
flight.formatted(date: .long, time: .shortened)
|
|
252
|
+
// en_US "June 3, 2026 at 4:05 PM", de_DE "3. Juni 2026 um 16:05"; ja_JP uses year-month-day order
|
|
253
|
+
flight.formatted(.dateTime.month(.wide).day().year())
|
|
254
|
+
Text(flight, format: .dateTime.weekday().hour().minute())
|
|
255
|
+
|
|
256
|
+
let visitors = 1_284_503
|
|
257
|
+
visitors.formatted() // "1,284,503" / "1.284.503"
|
|
258
|
+
3.14159.formatted(.number.precision(.fractionLength(2)))
|
|
259
|
+
0.18.formatted(.percent) // "18%"
|
|
260
|
+
Decimal(59.9).formatted(.currency(code: "USD"))
|
|
261
|
+
Decimal(59.9).formatted(.currency(code: "EUR")) // symbol position follows locale
|
|
262
|
+
|
|
263
|
+
Measurement(value: 42, unit: UnitLength.kilometers)
|
|
264
|
+
.formatted(.measurement(width: .wide)) // miles in en_US
|
|
265
|
+
Measurement(value: 21, unit: UnitTemperature.celsius)
|
|
266
|
+
.formatted(.measurement(width: .abbreviated)) // Fahrenheit in en_US
|
|
267
|
+
|
|
268
|
+
Duration.seconds(5_025).formatted(.time(pattern: .hourMinuteSecond)) // "1:23:45"
|
|
269
|
+
var author = PersonNameComponents(); author.givenName = "Aiko"; author.familyName = "Tanaka"
|
|
270
|
+
author.formatted(.name(style: .long)) // order differs en_US vs ja_JP
|
|
271
|
+
["tea", "coffee", "juice"].formatted(.list(type: .and)) // "tea, coffee, and juice"; French joins with "et" and no serial comma
|
|
306
272
|
```
|
|
307
273
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
## Right-to-Left (RTL) Layout
|
|
311
|
-
|
|
312
|
-
SwiftUI automatically mirrors layouts for RTL languages (Arabic, Hebrew, Urdu, Persian). Most views require zero changes.
|
|
313
|
-
|
|
314
|
-
### What SwiftUI auto-mirrors
|
|
274
|
+
Full coverage of every style is in
|
|
275
|
+
[references/formatstyle-locale.md](references/formatstyle-locale.md).
|
|
315
276
|
|
|
316
|
-
-
|
|
317
|
-
- `.leading` / `.trailing` alignment and padding swap sides
|
|
318
|
-
- `NavigationStack` back button moves to trailing edge
|
|
319
|
-
- `List` disclosure indicators flip
|
|
320
|
-
- Text alignment follows reading direction
|
|
277
|
+
## Right-to-Left Layout
|
|
321
278
|
|
|
322
|
-
|
|
279
|
+
SwiftUI mirrors layout for Arabic, Hebrew, Urdu and Persian on its own; most
|
|
280
|
+
views need nothing. It flips `HStack` order, `.leading` and `.trailing`
|
|
281
|
+
alignment and padding, puts the `NavigationStack` back button on the trailing
|
|
282
|
+
side, mirrors `List` disclosure chevrons, and aligns text to the reading
|
|
283
|
+
direction.
|
|
323
284
|
|
|
324
285
|
```swift
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
286
|
+
#Preview("Checkout, Arabic") {
|
|
287
|
+
CheckoutView()
|
|
288
|
+
.environment(\.layoutDirection, .rightToLeft)
|
|
289
|
+
.environment(\.locale, Locale(identifier: "ar"))
|
|
290
|
+
}
|
|
329
291
|
|
|
330
|
-
//
|
|
331
|
-
Image(systemName: "chevron.right")
|
|
292
|
+
Image(systemName: "arrowshape.forward") // directional: mirror it
|
|
332
293
|
.flipsForRightToLeftLayoutDirection(true)
|
|
333
294
|
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
// Forced LTR for specific content (phone numbers, code)
|
|
337
|
-
Text("+1 (555) 123-4567")
|
|
295
|
+
Text(verbatim: supportHotline) // phone numbers and code stay LTR
|
|
338
296
|
.environment(\.layoutDirection, .leftToRight)
|
|
339
297
|
```
|
|
340
298
|
|
|
341
|
-
|
|
299
|
+
Leave logos, photos, clocks and musical notation unmirrored.
|
|
342
300
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
- **DON'T** use absolute `offset(x:)` for directional positioning
|
|
301
|
+
Rules: prefer `.leading` and `.trailing` (they flip) over `.left` and `.right`
|
|
302
|
+
(they do not); build with `HStack` and `VStack`; do not use absolute
|
|
303
|
+
`offset(x:)` to place things in a direction.
|
|
347
304
|
|
|
348
305
|
## Common Mistakes
|
|
349
306
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
### DO: Use string interpolation
|
|
373
|
-
```swift
|
|
374
|
-
// CORRECT -- translators can reorder placeholders
|
|
375
|
-
let greeting = String(localized: "Hello, \(name)!")
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### DON'T: Hard-code date/number formats
|
|
379
|
-
```swift
|
|
380
|
-
// WRONG -- US-only format
|
|
381
|
-
let formatter = DateFormatter()
|
|
382
|
-
formatter.dateFormat = "MM/dd/yyyy" // Meaningless in most countries
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### DO: Use FormatStyle
|
|
386
|
-
```swift
|
|
387
|
-
// CORRECT -- adapts to user locale
|
|
388
|
-
Text(date, format: .dateTime.month().day().year())
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
### DON'T: Use fixed-width layouts
|
|
392
|
-
```swift
|
|
393
|
-
// WRONG -- German text is ~30% longer than English
|
|
394
|
-
Text(title).frame(width: 120)
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### DO: Use flexible layouts
|
|
398
|
-
```swift
|
|
399
|
-
// CORRECT
|
|
400
|
-
Text(title).fixedSize(horizontal: false, vertical: true)
|
|
401
|
-
// Or use VStack/wrapping that accommodates expansion
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### DON'T: Use .left / .right for alignment
|
|
405
|
-
```swift
|
|
406
|
-
// WRONG -- does not flip for RTL
|
|
407
|
-
HStack { Spacer(); text }.padding(.left, 16)
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### DO: Use .leading / .trailing
|
|
411
|
-
```swift
|
|
412
|
-
// CORRECT
|
|
413
|
-
HStack { Spacer(); text }.padding(.leading, 16)
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### DON'T: Put user-facing strings as plain String outside SwiftUI
|
|
417
|
-
```swift
|
|
418
|
-
// WRONG -- not localized
|
|
419
|
-
let errorMessage = "Something went wrong"
|
|
420
|
-
showAlert(message: errorMessage)
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### DO: Use LocalizedStringResource for deferred resolution
|
|
424
|
-
```swift
|
|
425
|
-
// CORRECT
|
|
426
|
-
let errorMessage = LocalizedStringResource("Something went wrong")
|
|
427
|
-
showAlert(message: String(localized: errorMessage))
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### DON'T: Use natural-language text as the key for manually-managed strings
|
|
431
|
-
```swift
|
|
432
|
-
// WRONG -- typo silently creates a new key, stales the old one, no compiler error
|
|
433
|
-
Text("Wlecome Back") // was "Welcome Back" -- silent localization break
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### DO: Use stable symbol-style keys and enable generated symbols
|
|
437
|
-
```swift
|
|
438
|
-
// CORRECT -- key is stable; UI text lives in the catalog's default value
|
|
439
|
-
Text(.welcomeBack) // generated from key "welcome_back" in String Catalog
|
|
440
|
-
// Or without generated symbols:
|
|
441
|
-
String(localized: "welcome_back", defaultValue: "Welcome Back")
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
### DON'T: Skip pseudolocalization testing
|
|
445
|
-
Testing only in English hides truncation, layout, and RTL bugs.
|
|
446
|
-
|
|
447
|
-
### DO: Test with German (long) and Arabic (RTL) at minimum
|
|
448
|
-
Use Xcode scheme settings to override the app language without changing device locale.
|
|
307
|
+
1. `NSLocalizedString` in new Swift code. It is legacy; use
|
|
308
|
+
`String(localized:defaultValue:comment:)` or a `Text` literal.
|
|
309
|
+
2. Building a sentence from localized fragments. Word order changes between
|
|
310
|
+
languages; localize one interpolated string.
|
|
311
|
+
3. `DateFormatter` with a fixed `dateFormat` such as `"MM/dd/yyyy"`. Use
|
|
312
|
+
`Text(date, format: .dateTime.month().day().year())` or another FormatStyle.
|
|
313
|
+
4. Fixed widths like `.frame(width: 120)` around text. German runs roughly 30%
|
|
314
|
+
longer than English; let text wrap with
|
|
315
|
+
`.fixedSize(horizontal: false, vertical: true)` or flexible stacks.
|
|
316
|
+
5. `.padding(.left, 12)`. Use `.padding(.leading, 12)`.
|
|
317
|
+
6. Passing user-facing text around as `String` outside SwiftUI. Carry a
|
|
318
|
+
`LocalizedStringResource` and resolve it with `String(localized:)` where it
|
|
319
|
+
is shown.
|
|
320
|
+
7. English sentences as keys for strings you manage by hand. A typo creates a
|
|
321
|
+
brand new key, the old one goes stale, and the compiler says nothing. Use
|
|
322
|
+
stable symbol-style keys, for example `order_shipped` read as
|
|
323
|
+
`Text(.orderShipped)`, or
|
|
324
|
+
`String(localized: "order_shipped", defaultValue: "Your order is on its way")`.
|
|
325
|
+
8. Testing only in English. Truncation, layout and RTL bugs stay hidden;
|
|
326
|
+
run the pseudolanguages.
|
|
327
|
+
9. Not testing German (long text) and Arabic (RTL) at minimum. Switch the app
|
|
328
|
+
language in the scheme options instead of changing the device locale.
|
|
449
329
|
|
|
450
330
|
## Review Checklist
|
|
451
331
|
|
|
452
|
-
- [ ]
|
|
453
|
-
|
|
454
|
-
- [ ]
|
|
455
|
-
- [ ]
|
|
456
|
-
- [ ]
|
|
457
|
-
- [ ]
|
|
458
|
-
- [ ]
|
|
459
|
-
- [ ]
|
|
460
|
-
- [ ]
|
|
461
|
-
- [ ]
|
|
462
|
-
- [ ]
|
|
463
|
-
- [ ]
|
|
464
|
-
- [ ]
|
|
465
|
-
- [ ]
|
|
466
|
-
|
|
467
|
-
- [ ]
|
|
468
|
-
- [ ]
|
|
332
|
+
- [ ] Every user-facing string is localized (`LocalizedStringKey` or
|
|
333
|
+
`String(localized:)`)
|
|
334
|
+
- [ ] No string concatenation for visible text
|
|
335
|
+
- [ ] Dates and numbers go through `FormatStyle`, never fixed patterns
|
|
336
|
+
- [ ] Plurals use catalog plural variants, not `if count == 1`
|
|
337
|
+
- [ ] `.leading` and `.trailing` instead of `.left` and `.right`
|
|
338
|
+
- [ ] UI checked with long text (German) and RTL (Arabic)
|
|
339
|
+
- [ ] The catalog lists every shipping language
|
|
340
|
+
- [ ] Directional images use `.flipsForRightToLeftLayoutDirection(true)`
|
|
341
|
+
- [ ] App Intents and widgets take `LocalizedStringResource`
|
|
342
|
+
- [ ] No `NSLocalizedString` in new code
|
|
343
|
+
- [ ] Ambiguous keys carry translator comments
|
|
344
|
+
- [ ] Spacing that must track Dynamic Type uses `@ScaledMetric`
|
|
345
|
+
- [ ] Currency always names an explicit currency code instead of relying on the
|
|
346
|
+
locale default
|
|
347
|
+
- [ ] Pseudolocalization run: accented, right-to-left, double-length
|
|
348
|
+
- [ ] Hand-managed keys are stable symbol-style names, not English sentences
|
|
349
|
+
- [ ] Generate String Catalog Symbols is on for targets with manual keys
|
|
350
|
+
- [ ] Localized string types are `Sendable`; UI reacting to a locale change
|
|
351
|
+
updates on `@MainActor`
|
|
469
352
|
|
|
470
353
|
## References
|
|
471
354
|
|
|
472
|
-
-
|
|
473
|
-
|
|
355
|
+
- [references/string-catalogs.md](references/string-catalogs.md): catalogs,
|
|
356
|
+
keys, bundles, packages, plurals, translator workflow, JSON, symbols,
|
|
357
|
+
testing and migration.
|
|
358
|
+
- [references/formatstyle-locale.md](references/formatstyle-locale.md):
|
|
359
|
+
FormatStyle per value type, forcing a locale, RTL, `@ScaledMetric` and
|
|
360
|
+
Accessibility Inspector.
|