@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.
Files changed (284) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +285 -285
  5. package/package.json +3 -3
  6. package/pipeline/lib/redact.mjs +3 -2
  7. package/pipeline/scripts/_notices.mjs +1 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +13 -1
  9. package/pipeline/scripts/pre-commit-check.sh +4 -0
  10. package/pipeline/skills/.skill-manifest.json +69 -69
  11. package/pipeline/skills/shared/README.md +70 -70
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  16. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  17. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  18. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  19. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  20. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  21. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  22. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  23. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
  24. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  25. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
  26. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
  27. package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
  28. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  29. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  30. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  31. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
  32. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  34. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  35. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  37. package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
  38. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  39. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
  40. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  41. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  42. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  43. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  44. package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
  45. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  46. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
  47. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  48. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  49. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  50. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  51. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  52. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  53. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  54. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  55. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  56. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
  57. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  58. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  59. package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
  60. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  61. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  62. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  63. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  64. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  65. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  66. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  67. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  68. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  69. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  70. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  71. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  72. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  73. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  74. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  75. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  76. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  77. package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
  78. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  79. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  80. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  81. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  82. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  83. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  84. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  85. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  86. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  87. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  88. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  89. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  90. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  91. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  92. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  93. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  94. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  95. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  96. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  97. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  98. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  99. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  100. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  101. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  102. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  103. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  104. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  105. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  106. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  107. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  108. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  109. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  111. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  112. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  113. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  114. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
  115. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
  116. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
  117. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
  118. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
  119. package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
  120. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
  121. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
  122. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
  123. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
  124. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
  125. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
  126. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
  127. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
  128. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
  129. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
  130. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
  131. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  132. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  133. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  134. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  135. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  136. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  137. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  138. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  139. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  140. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  141. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  142. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  143. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  144. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  145. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  146. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  147. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  148. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  149. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  150. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  151. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  152. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  153. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  154. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  155. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  156. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  157. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  158. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  159. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  160. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  161. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  162. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  163. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  164. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  165. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  166. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  167. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  168. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  169. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  170. package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
  171. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  172. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  173. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  174. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  175. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  176. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  177. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
  178. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  179. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  180. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  181. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  182. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  183. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  184. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  185. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  186. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  187. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  188. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  189. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  191. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
  193. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  194. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  195. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  196. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  197. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  198. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  199. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  200. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  201. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  202. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  203. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  204. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  205. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  206. package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
  207. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  208. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  209. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
  210. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  211. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  212. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  213. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  214. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  215. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  216. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
  217. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  218. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  219. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  220. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
  221. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  222. package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
  223. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  224. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
  225. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  226. package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
  227. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  228. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  229. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  230. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  231. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  232. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  233. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  234. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  235. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  236. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  237. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  238. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  239. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  240. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  241. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  242. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  243. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  244. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  245. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  246. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  247. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  248. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  249. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  250. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  251. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
  252. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  253. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
  254. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  255. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
  256. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  257. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  258. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  259. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  260. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  261. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  262. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  263. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  264. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  265. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  266. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  267. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  268. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  269. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  270. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  271. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  272. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  273. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  274. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  275. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  276. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  277. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  278. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  279. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  280. package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
  281. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  282. package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
  283. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
  284. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,369 +1,254 @@
1
- # String Catalogs (.xcstrings) -- Detailed Reference
1
+ # String Catalogs in Depth
2
2
 
3
3
  ## Contents
4
4
 
5
- - [What is a String Catalog?](#what-is-a-string-catalog)
6
- - [Creating a String Catalog](#creating-a-string-catalog)
7
- - [Automatic String Extraction](#automatic-string-extraction)
8
- - [Manual Key Management](#manual-key-management)
9
- - [Handling Strings in Non-SwiftUI Code](#handling-strings-in-non-swiftui-code)
10
- - [Bundle Access Patterns](#bundle-access-patterns)
11
- - [Multi-Module / SPM Localization](#multi-module-spm-localization)
12
- - [Pluralization in String Catalogs](#pluralization-in-string-catalogs)
13
- - [Device Variations](#device-variations)
14
- - [Exporting for Translators (XLIFF / xcloc)](#exporting-for-translators-xliff-xcloc)
15
- - [String Catalog JSON Structure](#string-catalog-json-structure)
16
- - [Generated Localizable Symbols (Xcode 26+)](#generated-localizable-symbols-xcode-26)
17
- - [Testing Strategies](#testing-strategies)
18
- - [Migration from .strings / .stringsdict](#migration-from-strings-stringsdict)
19
- - [Best Practices](#best-practices)
20
-
21
- ## What is a String Catalog?
22
-
23
- A String Catalog is a single Xcode-managed `.xcstrings` file (JSON-based) that holds localizable strings in a target, along with translations, plural forms, and device variations. In Xcode 15 and later, String Catalogs are the recommended workflow for new localization work because they replace much of the manual synchronization previously required across `.strings` and `.stringsdict` files.
24
-
25
- **Availability:** Xcode 15+, all Apple platforms. String Catalogs are the recommended Xcode 15+ workflow for app localization. Xcode 26 adds generated localizable symbols on top of String Catalogs; do not describe catalogs themselves as requiring Xcode 26 or iOS 17.
26
-
27
- ## Creating a String Catalog
28
-
29
- 1. File > New > File > String Catalog
30
- 2. Name it `Localizable.xcstrings` (the default table name, matching the legacy `Localizable.strings`)
31
- 3. Place it in the target's source directory
32
- 4. Add target languages in Project > Info > Localizations
33
-
34
- For a non-default table name (e.g., `Onboarding.xcstrings`), reference it explicitly:
5
+ 1. [What a catalog is](#what-a-catalog-is)
6
+ 2. [Creating one](#creating-one)
7
+ 3. [What extraction picks up](#what-extraction-picks-up)
8
+ 4. [Managing keys by hand](#managing-keys-by-hand)
9
+ 5. [Strings outside SwiftUI](#strings-outside-swiftui)
10
+ 6. [Bundles](#bundles)
11
+ 7. [Swift packages and multiple modules](#swift-packages-and-multiple-modules)
12
+ 8. [Plurals](#plurals)
13
+ 9. [Device variants](#device-variants)
14
+ 10. [Working with translators](#working-with-translators)
15
+ 11. [The JSON format](#the-json-format)
16
+ 12. [Generated symbols (Xcode 26)](#generated-symbols-xcode-26)
17
+ 13. [Testing](#testing)
18
+ 14. [Migrating from .strings and .stringsdict](#migrating-from-strings-and-stringsdict)
19
+ 15. [Practices that scale](#practices-that-scale)
20
+
21
+ ## What a catalog is
22
+
23
+ One `.xcstrings` file per target, stored as JSON, holds the source strings,
24
+ their translations, plural forms and device variants. Catalogs arrived in
25
+ Xcode 15 and work on every platform Xcode targets. Xcode 26 adds generated Swift
26
+ symbols as an extra layer; the catalog itself does not need Xcode 26.
27
+
28
+ ## Creating one
29
+
30
+ 1. File > New > File, choose String Catalog.
31
+ 2. Call it `Localizable.xcstrings`. That name is the default table, the same
32
+ role `Localizable.strings` used to play.
33
+ 3. Put it in the target's source folder.
34
+ 4. Add languages under Project > Info > Localizations.
35
+
36
+ Any other name is a separate table. A file named `Help.xcstrings` is read with
37
+ `String(localized: "faq.title", table: "Help")`.
38
+
39
+ ## What extraction picks up
40
+
41
+ The compiler finds localizable strings on every build by looking at known
42
+ initializers and parameter types.
35
43
 
36
44
  ```swift
37
- String(localized: "welcome.title", table: "Onboarding")
38
- ```
39
-
40
- ## Automatic String Extraction
41
-
42
- On every build, Xcode scans source files and extracts strings from known localizable initializers. Extraction is compiler-driven -- it recognizes these patterns:
43
-
44
- ### SwiftUI (LocalizedStringKey)
45
- ```swift
46
- Text("Hello, world") // extracted
47
- Label("Settings", systemImage: "gear") // extracted
48
- Button("Save") { } // extracted
49
- Toggle("Enable notifications", isOn: $on) // extracted
50
- .navigationTitle("Home") // extracted
51
- Section("Account") { } // extracted
52
-
53
- // NOT extracted -- computed or variable strings
54
- Text(viewModel.title) // not extracted (runtime value)
55
- Text(verbatim: "v1.2.3") // not extracted (verbatim skips localization)
56
- ```
57
-
58
- ### Foundation (String(localized:))
59
- ```swift
60
- String(localized: "No results found") // extracted
61
- String(localized: "error.title",
62
- defaultValue: "Something went wrong",
63
- comment: "Generic error alert title") // extracted with default + comment
64
- ```
65
-
66
- ### LocalizedStringResource
67
- ```swift
68
- LocalizedStringResource("Order placed") // extracted
69
- static var title: LocalizedStringResource = "Title" // extracted
70
- ```
45
+ // Picked up
46
+ Text("Welcome aboard")
47
+ Label("Downloads", systemImage: "arrow.down.circle")
48
+ Button("Retry") { }
49
+ Toggle("Offline mode", isOn: $offline)
50
+ Section("Account") { }
51
+ someView.navigationTitle("Library")
52
+
53
+ String(localized: "sync.failed", defaultValue: "Sync failed", comment: "Toast after a failed sync")
54
+ LocalizedStringResource("Open in Maps")
55
+
56
+ enum Copy {
57
+ static let emptyInbox: LocalizedStringResource = "Nothing new today"
58
+ }
71
59
 
72
- ### What is NOT extracted
73
- ```swift
74
- let x: String = "Not localized" // plain String assignment
75
- print("debug info") // not user-facing
76
- NSLocalizedString("legacy", comment: "") // legacy API; Xcode can export literal keys
60
+ // Not picked up
61
+ Text(viewModel.headline) // value known only at runtime
62
+ Text(verbatim: "v2.4.1") // opts out of localization
63
+ let screenName = "Library" // plain String
64
+ print("Library opened") // logging
77
65
  ```
78
66
 
79
- Prefer `String(localized:)`, SwiftUI localizable literals, or `LocalizedStringResource` in new Swift code so String Catalog syncing and generated-symbol workflows stay straightforward. If automatic extraction misses a string, add it manually in the String Catalog editor.
80
-
81
- ## Manual Key Management
67
+ `NSLocalizedString` is legacy, but Xcode can still export its literal keys.
68
+ If extraction misses something, add the key in the catalog editor.
82
69
 
83
- Open the `.xcstrings` file in Xcode to use the visual editor:
70
+ ## Managing keys by hand
84
71
 
85
- - **Add key**: Click + at the bottom of the key list
86
- - **Remove key**: Select key, press Delete (marks as Stale, removed on next build if no code reference)
87
- - **Edit comment**: Select key, edit the Comment field (provides translator context)
88
- - **Mark state**: Right-click a translation to set Needs Review / Reviewed
89
- - **Vary by plural**: Select a key, click Vary > Plural to add plural categories
90
- - **Vary by device**: Select a key, click Vary > Device to add iPhone/iPad/Mac variants
72
+ In the editor:
91
73
 
92
- ### Key naming conventions
74
+ - (+) adds a key.
75
+ - Delete marks a key Stale; if no code references it, the next build drops it.
76
+ - The Comment field gives translators context they cannot see in the UI.
77
+ - Right-click to mark an entry Needs Review or Reviewed.
78
+ - Vary > Plural and Vary > Device add variants.
93
79
 
94
- For manually-managed strings, use stable symbol-style keys rather than English text as the key. This prevents silent localization breaks when UI copy changes (a typo or rewording just creates a new key and stales the old one - no compiler error). With Xcode 26's generated symbols, stable keys also produce readable, predictable Swift accessors.
80
+ Name keys like stable identifiers, grouped with dots:
95
81
 
96
- ```text
97
- onboarding.welcome.title -> "Welcome"
98
- onboarding.welcome.subtitle -> "Get started in minutes"
99
- settings.notifications.toggle -> "Enable Notifications"
100
- error.network.title -> "Connection Error"
101
- error.network.message -> "Check your internet and try again"
102
82
  ```
103
-
104
- Use `String(localized:defaultValue:)` when you want a structured key that differs from the English text:
105
-
106
- ```swift
107
- let title = String(localized: "error.network.title",
108
- defaultValue: "Connection Error",
109
- comment: "Title for network error alert")
83
+ checkout.summary.title
84
+ checkout.summary.total
85
+ error.offline.title
86
+ error.offline.message
110
87
  ```
111
88
 
112
- For SwiftUI auto-extracted strings, the literal text IS the key by default. This is fine for simple views. For any string you manage manually - shared keys, keys referenced across modules, or keys where copy changes frequently - use a stable key instead.
89
+ With Xcode 26 symbols these keys also become readable, predictable accessors.
90
+ For simple SwiftUI screens it is fine to let the literal be the key. Strings
91
+ that are shared, used across modules, or reworded often should get a stable key.
113
92
 
114
- ## Handling Strings in Non-SwiftUI Code
115
-
116
- ### View models, services, and utilities
93
+ ## Strings outside SwiftUI
117
94
 
118
95
  ```swift
119
- class OrderService {
120
- func statusMessage(for order: Order) -> String {
121
- switch order.status {
122
- case .shipped:
123
- return String(localized: "order.status.shipped",
124
- defaultValue: "Your order has shipped!",
125
- comment: "Order status when item is in transit")
96
+ struct DeliveryStatusText {
97
+ func text(for status: DeliveryStatus, eta: Date) -> String {
98
+ switch status {
99
+ case .preparing:
100
+ String(localized: "delivery.preparing",
101
+ defaultValue: "The kitchen is preparing your order",
102
+ comment: "Order tracking, first step")
103
+ case .onTheWay:
104
+ String(localized: "delivery.on_the_way",
105
+ defaultValue: "Arriving \(eta, format: .dateTime.month().day())",
106
+ comment: "Order tracking with the expected day")
126
107
  case .delivered:
127
- return String(localized: "order.status.delivered",
128
- defaultValue: "Delivered on \(order.deliveryDate!, format: .dateTime.month().day())",
129
- comment: "Order status with delivery date")
130
- case .processing:
131
- return String(localized: "order.status.processing",
132
- defaultValue: "Processing your order...",
133
- comment: "Order status while being prepared")
108
+ String(localized: "delivery.done",
109
+ defaultValue: "Delivered",
110
+ comment: "Order tracking, final step")
134
111
  }
135
112
  }
136
113
  }
137
- ```
138
-
139
- ### Specifying table and bundle
140
114
 
141
- ```swift
142
- // From a specific table
143
- String(localized: "greeting",
144
- table: "Onboarding",
145
- comment: "First-launch greeting")
146
-
147
- // From a specific bundle (framework or Swift package)
148
- String(localized: "button.save",
149
- table: "SharedUI",
150
- bundle: .module,
151
- comment: "Save button in shared component")
115
+ let help = String(localized: "faq.title", table: "Help")
116
+ let packaged = String(localized: "player.skip",
117
+ table: "Player",
118
+ bundle: .module,
119
+ comment: "Skips 15 seconds forward")
152
120
  ```
153
121
 
154
- ## Bundle Access Patterns
122
+ ## Bundles
155
123
 
156
- ### Main app
157
- ```swift
158
- // Uses Bundle.main by default -- no bundle argument needed
159
- String(localized: "Hello")
160
- ```
124
+ - App target: `Bundle.main` is implied, so pass nothing.
125
+ - Swift package: `.module` is the package's resource bundle. Use
126
+ `String(localized: "...", bundle: .module)`, and in SwiftUI pass it
127
+ explicitly, `Text("...", bundle: .module)`. `Text` does not pick up the
128
+ package bundle on its own.
129
+ - Framework: find the bundle through a class that lives in it.
161
130
 
162
- ### Swift Package (SPM)
163
131
  ```swift
164
- // .module refers to the package's resource bundle
165
- String(localized: "Hello", bundle: .module)
132
+ final class ChartsBundleToken {}
166
133
 
167
- // In SwiftUI, pass the package bundle explicitly for package resources
168
- Text("Hello", bundle: .module)
134
+ let chartsBundle = Bundle(for: ChartsBundleToken.self)
135
+ let axisLabel = String(localized: "axis.time", bundle: chartsBundle)
169
136
  ```
170
137
 
171
- ### Framework
172
- ```swift
173
- // Reference the framework's bundle
174
- let frameworkBundle = Bundle(for: MyFrameworkClass.self)
175
- String(localized: "Hello",
176
- bundle: .init(frameworkBundle.bundleURL))
177
- ```
138
+ Any code that is not in the main bundle has to name its bundle: `.module` in a
139
+ package, `Bundle(for:)` in a framework, or the current-target bundle macro
140
+ where the toolchain provides it.
178
141
 
179
- ## Multi-Module / SPM Localization
142
+ ## Swift packages and multiple modules
180
143
 
181
- Each Swift package target that contains user-facing strings needs its own String Catalog.
144
+ Every package target that shows text needs its own catalog.
182
145
 
183
- ### Package.swift setup
184
146
  ```swift
147
+ // swift-tools-version: 6.0
148
+ import PackageDescription
149
+
185
150
  let package = Package(
186
- name: "SharedUI",
151
+ name: "ProfileKit",
187
152
  defaultLocalization: "en",
188
153
  targets: [
189
- .target(
190
- name: "SharedUI",
191
- dependencies: [],
192
- resources: [
193
- .process("Resources") // Localizable.xcstrings goes here
194
- ]
195
- )
154
+ .target(name: "ProfileKit", resources: [.process("Resources")])
196
155
  ]
197
156
  )
157
+ // Catalog path: Sources/ProfileKit/Resources/Localizable.xcstrings
198
158
  ```
199
159
 
200
- ### Directory structure
201
- ```text
202
- Sources/
203
- SharedUI/
204
- Resources/
205
- Localizable.xcstrings <- String Catalog for this module
206
- Views/
207
- ButtonStyles.swift
208
- ```
209
-
210
- ### Accessing strings from the package
211
160
  ```swift
212
- // Inside the package -- bundle: .module resolves package-owned resources
213
- public struct SaveButton: View {
161
+ public struct SignOutButton: View {
162
+ let action: () -> Void
214
163
  public var body: some View {
215
- Button(String(localized: "Save", bundle: .module)) { }
164
+ Button(String(localized: "Sign out", bundle: .module), action: action)
216
165
  }
217
166
  }
218
167
  ```
219
168
 
220
- **Important:** Code outside the main app bundle needs an explicit bundle. Use `bundle: .module` in Swift packages, `Bundle(for:)` in frameworks, or the current-target bundle macro when available.
221
-
222
- For Swift package localization failures, answer with this explicit resource checklist before bundle debugging:
223
- 1. `Package.swift` declares `defaultLocalization`.
224
- 2. The target `resources` list processes the catalog location, such as `.process("Resources")`.
225
- 3. `Localizable.xcstrings` is actually inside that processed target-resource path.
226
- Only after those pass, debug lookup with `bundle: .module` or `Text(..., bundle: .module)`.
227
-
228
- ## Pluralization in String Catalogs
229
-
230
- ### Setup
169
+ When a package keeps falling back to the development language, check setup
170
+ before lookup:
231
171
 
232
- 1. Write code with integer interpolation:
233
- ```swift
234
- Text("\(itemCount) items in your cart")
235
- ```
236
- 2. Build the project -- Xcode adds the key to the String Catalog
237
- 3. Open the String Catalog, select the key
238
- 4. Click "Vary by Plural" in the inspector
239
- 5. Fill in plural forms for each language
172
+ 1. `defaultLocalization` is set in `Package.swift`.
173
+ 2. The target's `resources` processes the catalog's folder, for example
174
+ `.process("Resources")`.
175
+ 3. The catalog file is actually inside that folder.
240
176
 
241
- ### English plural forms
242
- ```text
243
- one: "%1$(itemCount)lld item in your cart"
244
- other: "%1$(itemCount)lld items in your cart"
245
- ```
246
-
247
- ### Arabic plural forms (all six categories)
248
- ```text
249
- zero: "لا توجد عناصر في سلتك"
250
- one: "عنصر واحد في سلتك"
251
- two: "عنصران في سلتك"
252
- few: "%lld عناصر في سلتك" (3-10)
253
- many: "%lld عنصرًا في سلتك" (11-99)
254
- other: "%lld عنصر في سلتك" (100+)
255
- ```
177
+ ## Plurals
256
178
 
257
- ### Multiple plural variables
179
+ 1. Write the string with an integer interpolation.
180
+ 2. Build.
181
+ 3. Select the key in the catalog.
182
+ 4. Choose Vary by Plural in the inspector.
183
+ 5. Fill each form every language needs.
258
184
 
259
- When a string has two integer interpolations, the String Catalog shows a matrix of plural combinations:
185
+ English, with a named positional placeholder:
260
186
 
261
- ```swift
262
- Text("\(photoCount) photos in \(albumCount) albums")
263
- // English needs: one/one, one/other, other/one, other/other
264
- ```
187
+ | Category | Value |
188
+ |---|---|
189
+ | one | `%1$(songCount)lld song` |
190
+ | other | `%1$(songCount)lld songs` |
265
191
 
266
- ## Device Variations
192
+ Arabic fills all six categories: zero, one, two, few (`%lld` ...), many
193
+ (`%lld` ...) and other (`%lld` ...), each with its own wording.
267
194
 
268
- Enable "Vary by Device" for a key to provide different text on iPhone, iPad, Apple Watch, Mac, Apple TV, and Apple Vision Pro.
195
+ Two integer interpolations in one string create a matrix. For
196
+ `"\(photos) photos in \(albums) albums"` English needs one/one, one/other,
197
+ other/one and other/other.
269
198
 
270
- ```swift
271
- // Code is the same everywhere:
272
- Text("Tap to continue")
273
-
274
- // String Catalog provides:
275
- // iPhone: "Tap to continue"
276
- // iPad: "Tap or click to continue"
277
- // Mac: "Click to continue"
278
- // Vision: "Look and tap to continue"
279
- ```
199
+ ## Device variants
280
200
 
281
- ## Exporting for Translators (XLIFF / xcloc)
201
+ Vary by Device lets a key read differently on iPhone, iPad, Apple Watch, Mac,
202
+ Apple TV and Apple Vision Pro. The Swift call site does not change.
282
203
 
283
- ### Export
204
+ ## Working with translators
284
205
 
285
- 1. Product > Export Localizations... (or `xcodebuild -exportLocalizations`)
286
- 2. Select target languages
287
- 3. Xcode creates `.xcloc` bundles (one per language)
288
- 4. Send `.xcloc` files to translators (they contain XLIFF 1.2 inside)
206
+ Export with Product > Export Localizations... or on the command line. The
207
+ result is one `.xcloc` bundle per language, with XLIFF 1.2 inside.
289
208
 
290
- ### Command-line export
291
209
  ```bash
292
210
  xcodebuild -exportLocalizations \
293
- -project MyApp.xcodeproj \
294
- -localizationPath ./Localizations \
295
- -exportLanguage de -exportLanguage ja -exportLanguage ar
211
+ -project Journal.xcodeproj \
212
+ -localizationPath ./l10n-out \
213
+ -exportLanguage fr \
214
+ -exportLanguage ko
296
215
  ```
297
216
 
298
- ### Import
299
-
300
- 1. Product > Import Localizations...
301
- 2. Select the completed `.xcloc` file
302
- 3. Xcode merges translations into the String Catalog
303
- 4. Review changes in the diff viewer
217
+ Bring translations back with Product > Import Localizations...; Xcode merges
218
+ them into the catalog, and the diff viewer shows what changed.
304
219
 
305
- ### Command-line import
306
220
  ```bash
307
221
  xcodebuild -importLocalizations \
308
- -project MyApp.xcodeproj \
309
- -localizationPath ./Localizations/de.xcloc
222
+ -project Journal.xcodeproj \
223
+ -localizationPath ./l10n-in/fr.xcloc
310
224
  ```
311
225
 
312
- ## String Catalog JSON Structure
226
+ ## The JSON format
313
227
 
314
- The `.xcstrings` file is Xcode-managed JSON. Understanding the observed structure can help with parser-backed validation or careful batch updates, but prefer Xcode's editor/export/import workflows for normal localization changes and validate any automated edit before committing.
228
+ Edit through the Xcode editor or the export/import round trip where possible.
229
+ Knowing the format helps when a parser-based check or a careful bulk edit is
230
+ needed; validate any scripted change before committing it.
315
231
 
316
232
  ```json
317
233
  {
318
- "sourceLanguage": "en",
319
- "version": "1.0",
320
- "strings": {
321
- "Welcome, %@!": {
322
- "comment": "Greeting shown on home screen with user name",
323
- "localizations": {
324
- "en": {
325
- "stringUnit": {
326
- "state": "translated",
327
- "value": "Welcome, %@!"
328
- }
329
- },
330
- "de": {
331
- "stringUnit": {
332
- "state": "translated",
333
- "value": "Willkommen, %@!"
334
- }
335
- }
336
- }
337
- },
338
- "item_available": {
339
- "comment": "Button label on product search results",
340
- "extractionState": "manual",
341
- "localizations": {
342
- "en": {
343
- "stringUnit": {
344
- "state": "translated",
345
- "value": "Add this item"
346
- }
347
- }
234
+ "sourceLanguage" : "en",
235
+ "version" : "1.1",
236
+ "strings" : {
237
+ "cart_empty" : {
238
+ "comment" : "Shown when the cart has no items",
239
+ "extractionState" : "manual",
240
+ "localizations" : {
241
+ "en" : { "stringUnit" : { "state" : "translated", "value" : "Your cart is empty" } },
242
+ "de" : { "stringUnit" : { "state" : "translated", "value" : "Dein Warenkorb ist leer" } }
348
243
  }
349
244
  },
350
- "%1$(count)lld items": {
351
- "localizations": {
352
- "en": {
353
- "variations": {
354
- "plural": {
355
- "one": {
356
- "stringUnit": {
357
- "state": "translated",
358
- "value": "%1$(count)lld item"
359
- }
360
- },
361
- "other": {
362
- "stringUnit": {
363
- "state": "translated",
364
- "value": "%1$(count)lld items"
365
- }
366
- }
245
+ "reviews_count" : {
246
+ "localizations" : {
247
+ "en" : {
248
+ "variations" : {
249
+ "plural" : {
250
+ "one" : { "stringUnit" : { "state" : "translated", "value" : "%lld review" } },
251
+ "other" : { "stringUnit" : { "state" : "translated", "value" : "%lld reviews" } }
367
252
  }
368
253
  }
369
254
  }
@@ -373,199 +258,187 @@ The `.xcstrings` file is Xcode-managed JSON. Understanding the observed structur
373
258
  }
374
259
  ```
375
260
 
376
- Note the `"item_available"` key above: it uses `"extractionState": "manual"` and a stable symbol-style key with the English text in `"value"`, not in the key itself. 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.
261
+ The top level has `sourceLanguage`, `version` and `strings`. Each key may hold
262
+ `comment`, `extractionState` and `localizations`, where every language has a
263
+ `stringUnit` with `state` and `value`. Plurals nest under
264
+ `localizations.<lang>.variations.plural.<category>.stringUnit`. Note that
265
+ `cart_empty` is a manual key: the English copy lives in `value`, not in the key.
377
266
 
378
- ### Translation states
379
- - `"new"` -- Xcode extracted the key but no translation exists
380
- - `"translated"` -- Translation provided
381
- - `"needs_review"` -- Marked for review (source string changed or manual flag)
382
- - `"stale"` -- Key no longer found in code (removed on next clean build)
267
+ Translation `state`:
383
268
 
384
- ### Extraction states
269
+ | State | Meaning |
270
+ |---|---|
271
+ | `new` | Not translated yet |
272
+ | `translated` | Done |
273
+ | `needs_review` | Source text changed or someone flagged it |
274
+ | `stale` | The key is gone from code; a clean build removes it |
385
275
 
386
- The `extractionState` field (separate from translation `state`) tracks how a key entered the catalog:
276
+ `extractionState`:
387
277
 
388
- | Value | Meaning |
389
- |-------|---------|
390
- | `extracted_with_value` | Xcode found the string in source code and extracted it automatically |
391
- | `manual` | Added by hand via the (+) button - not discovered from code. Xcode will never update or remove manual keys during build sync |
392
- | `stale` | Previously extracted from code, but Xcode can no longer find it. Orphaned translations still exist |
393
- | `migrated` | Converted from a legacy `.strings` or `.stringsdict` file |
278
+ | State | Meaning |
279
+ |---|---|
280
+ | `extracted_with_value` | Found in source by the build |
281
+ | `manual` | Added by hand; build sync never changes or deletes it |
282
+ | `stale` | No longer found; its translations are orphaned |
283
+ | `migrated` | Came from `.strings` or `.stringsdict` |
394
284
 
395
- The `manual` state is significant: manual keys have the **Generate Swift Symbol** checkbox enabled by default, so they automatically produce compiler-checked `LocalizedStringResource` accessors when the build setting is on. Auto-extracted keys can also generate symbols - enable the checkbox per-key or use Refactor > Convert Strings to Symbols.
285
+ Manual keys have Generate Swift Symbol on by default and, with the build
286
+ setting on, turn into compiler-checked `LocalizedStringResource` accessors.
287
+ Extracted keys opt in one at a time or through Convert Strings to Symbols.
396
288
 
397
- ## Generated Localizable Symbols (Xcode 26+)
289
+ ## Generated symbols (Xcode 26)
398
290
 
399
- For generated-symbol or migration answers, start by stating: "String Catalogs are the recommended Xcode 15+ localization workflow. Xcode 26 generated symbols are a separate typed-access layer on top of String Catalogs." Then explain generated symbols, plurals, or migration details. Do not describe catalogs themselves as requiring Xcode 26 or iOS 17.
291
+ Frame answers the same way as in the main skill: catalogs are the Xcode 15+
292
+ workflow; generated symbols are Xcode 26's typed layer on top. Never state that
293
+ catalogs need Xcode 26 or iOS 17.
400
294
 
401
- ### Enabling symbol generation
295
+ Xcode 26 writes format version `"1.1"` into the file as soon as symbol metadata
296
+ exists.
402
297
 
403
- 1. Build Settings > Localization > **Generate String Catalog Symbols** → `Yes` (on by default in new Xcode 26 projects)
404
- 2. The catalog must use format version `"1.1"` - Xcode 26 writes this automatically when symbol generation metadata is present
405
- 3. Each key has a **Generate Swift Symbol** checkbox in the String Catalog editor. Manual keys (added via the (+) button) have this enabled by default. Auto-extracted keys can opt in via Refactor > Convert Strings to Symbols, which enables the checkbox
298
+ Naming: the key is camelCased and its first segment lowercased.
406
299
 
407
- ### How Xcode derives symbol names
300
+ | Key | Symbol |
301
+ |---|---|
302
+ | `cart_empty` | `.cartEmpty` |
303
+ | `profile.privacy.header` | `.profilePrivacyHeader` |
304
+ | `DONE` | `.done` |
408
305
 
409
- Xcode camelCases the key name, lowercasing the first segment:
306
+ Keys with format specifiers turn into functions. A named positional placeholder
307
+ such as `%1$(nights)lld` gives a readable label; a bare `%lld` gives a generic
308
+ one.
410
309
 
411
- | Catalog key | Generated symbol |
412
- |-------------|-----------------|
413
- | `item_available` | `.itemAvailable` |
414
- | `settings.notifications.toggle` | `.settingsNotificationsToggle` |
415
- | `TITLE` | `.title` |
310
+ | Key and value | Symbol |
311
+ |---|---|
312
+ | `stay_length` = `%1$(nights)lld nights` | `.stayLength(nights: Int)` |
313
+ | `welcome_user` = `Hi %@` | `.welcomeUser(_ arg1: String)` |
416
314
 
417
- Keys with format specifiers become functions. Use positional named placeholders such as `%1$(name)lld` for descriptive argument labels; bare `%lld` produces generic labels:
418
-
419
- | Catalog key | Format | Generated symbol |
420
- |-------------|--------|-----------------|
421
- | `products_count` | `%1$(count)lld` | `.productsCount(count: Int)` |
422
- | `greeting` | `%@` | `.greeting(_ param1: String)` |
423
-
424
- You can rename parameters during refactoring for more descriptive signatures.
425
-
426
- ### Using generated symbols
315
+ Parameters can be renamed while refactoring.
427
316
 
428
317
  ```swift
429
- // Simple key - static property
430
- Text(.itemAvailable)
431
-
432
- // Parameterized key - function
433
- Text(.productsCount(count: 42))
318
+ Text(.cartEmpty)
319
+ Text(.stayLength(nights: 4))
434
320
 
435
- // Non-default table (Checkout.xcstrings)
436
- Text(.Checkout.confirmOrderCta)
437
-
438
- // In non-SwiftUI code
439
- let title = String(localized: .itemAvailable)
440
- let attributed = AttributedString(localized: .greeting(userName))
321
+ let plain = String(localized: .cartEmpty)
322
+ let styled = AttributedString(localized: .welcomeUser(member.firstName))
441
323
  ```
442
324
 
443
- Code completion supports generated symbols - type `.` and choose from the menu.
444
-
445
- ### Refactoring existing strings to symbols
446
-
447
- Select one or more keys in the String Catalog editor, Control-click, and choose **Refactor > Convert Strings to Symbols**. Xcode replaces string literal usage in code with the generated symbol. This is reversible via **Convert Symbols to Strings**.
325
+ Code completion lists the symbols after you type `.`.
448
326
 
449
- ### Cross-module limitations
327
+ Converting existing literals: select the keys, Control-click, Refactor > Convert
328
+ Strings to Symbols. Xcode rewrites the literals at their call sites. Convert
329
+ Symbols to Strings goes the other way.
450
330
 
451
- Generated symbols are declared `internal`. Code in other modules cannot access them directly. Default to a public wrapper; reach for `xcstrings-tool` if the wrapper becomes unwieldy across many modules:
331
+ Across modules: symbols are `internal`. The usual fix is a public extension on
332
+ `LocalizedStringResource` that forwards to them:
452
333
 
453
- - **Public wrapper** (default): Create a public extension on `LocalizedStringResource` that delegates to the internal symbols
454
- - **[xcstrings-tool](https://github.com/liamnichols/xcstrings-tool)**: A Swift Package Plugin that generates public constants from `.xcstrings` files - use this for heavier multi-module setups where maintaining manual wrappers becomes tedious
455
-
456
- For Swift Packages, the generated symbols use the `.module` bundle automatically. The `internal` visibility means only code within the same package target can reference them.
334
+ ```swift
335
+ public extension LocalizedStringResource {
336
+ static var sharedRetry: LocalizedStringResource { .retryButton }
337
+ }
338
+ ```
457
339
 
458
- ## Testing Strategies
340
+ When those wrappers become tedious, `xcstrings-tool`, an open-source Swift
341
+ package plugin, generates public constants for you.
459
342
 
460
- ### Scheme language override
343
+ Inside a Swift package, generated symbols read from the `.module` bundle
344
+ automatically, and they are only visible within the same package target.
461
345
 
462
- Edit Scheme > Run > Options > App Language. Choose any added language to launch the app in that locale without changing the device/simulator system language.
346
+ ## Testing
463
347
 
464
- ### Pseudolocalization options
348
+ Scheme override: Edit Scheme > Run > Options > App Language starts the app in
349
+ another language without touching the system setting.
465
350
 
466
- Xcode provides built-in pseudolocalization modes (Edit Scheme > Run > Options > App Language):
351
+ Pseudolanguages from the same menu:
467
352
 
468
- | Option | Effect | Catches |
469
- |--------|--------|---------|
470
- | Accented Pseudolanguage | Adds accents: "Hello" -> "[Hellо]" | Hardcoded strings (unlocalized text is obvious) |
471
- | Right-to-Left Pseudolanguage | Forces RTL layout | Layout mirroring bugs |
472
- | Double-Length Pseudolanguage | Doubles all strings | Truncation and overflow |
473
- | Bounded String Pseudolanguage | Wraps strings in brackets | Missing localizations |
353
+ | Pseudolanguage | Finds |
354
+ |---|---|
355
+ | Accented | Hard-coded strings that bypass lookup |
356
+ | Right-to-Left | Mirroring bugs |
357
+ | Double-Length | Truncation and overflow |
358
+ | Bounded String | Missing localizations (strings are wrapped in brackets) |
474
359
 
475
- ### UI tests with locale override
360
+ UI test in a specific locale:
476
361
 
477
362
  ```swift
478
- func testGermanLayout() {
479
- let app = XCUIApplication()
480
- app.launchArguments += ["-AppleLanguages", "(de)"]
481
- app.launchArguments += ["-AppleLocale", "de_DE"]
482
- app.launch()
483
-
484
- // Verify no truncation on key screens
485
- let saveButton = app.buttons["Speichern"]
486
- XCTAssertTrue(saveButton.exists)
487
- XCTAssertTrue(saveButton.isHittable)
488
- }
489
- ```
490
-
491
- ### Snapshot testing per locale
492
-
493
- Use a snapshot testing library to capture screenshots in multiple locales and compare them for layout regressions:
494
-
495
- ```swift
496
- let locales = ["en_US", "de_DE", "ar_SA", "ja_JP"]
497
- for locale in locales {
498
- app.launchArguments = ["-AppleLanguages", "(\(locale.prefix(2)))"]
499
- app.launch()
500
- // Capture and compare snapshot
363
+ import XCTest
364
+
365
+ final class GermanCheckoutUITests: XCTestCase {
366
+ @MainActor
367
+ func testPayButtonIsLocalized() {
368
+ let app = XCUIApplication()
369
+ app.launchArguments += ["-AppleLanguages", "(de)", "-AppleLocale", "de_DE"]
370
+ app.launch()
371
+
372
+ let pay = app.buttons["Jetzt bezahlen"]
373
+ XCTAssertTrue(pay.exists)
374
+ XCTAssertTrue(pay.isHittable)
375
+ }
501
376
  }
502
377
  ```
503
378
 
504
- ### Translation coverage validation
379
+ Screenshot comparison per locale: loop over `en_US`, `de_DE`, `ar_SA` and
380
+ `ja_JP`, set `-AppleLanguages` for each, launch, capture, compare against the
381
+ stored image.
505
382
 
506
- Check that all keys are translated before release:
383
+ Translation coverage in CI: parse the catalog and fail when any language entry
384
+ is untranslated or empty.
507
385
 
508
- ```bash
509
- # Parse the .xcstrings JSON and check for "new" or empty states
510
- python3 -c "
386
+ ```python
387
+ #!/usr/bin/env python3
511
388
  import json, sys
512
- with open('Localizable.xcstrings') as f:
513
- data = json.load(f)
514
- missing = []
515
- for key, info in data['strings'].items():
516
- for lang, loc in info.get('localizations', {}).items():
517
- unit = loc.get('stringUnit', {})
518
- if unit.get('state') in ('new', None) or not unit.get('value'):
519
- missing.append(f'{lang}: {key}')
520
- if missing:
521
- print('Missing translations:')
522
- for m in missing: print(f' {m}')
523
- sys.exit(1)
524
- print('All translations complete.')
525
- "
526
- ```
527
-
528
- ## Migration from .strings / .stringsdict
529
389
 
530
- ### Automatic migration
531
-
532
- 1. Select the `.strings` file in the project navigator
533
- 2. Right-click > Migrate to String Catalog...
534
- 3. Xcode creates a `.xcstrings` file with all existing keys and translations
535
- 4. Verify in the String Catalog editor
536
- 5. Remove the old `.strings` / `.stringsdict` files from the target
390
+ catalog = json.load(open(sys.argv[1], encoding="utf-8"))
391
+ gaps = []
392
+ for key, entry in catalog.get("strings", {}).items():
393
+ for lang, loc in entry.get("localizations", {}).items():
394
+ units = [loc["stringUnit"]] if "stringUnit" in loc else [
395
+ v["stringUnit"]
396
+ for group in loc.get("variations", {}).values()
397
+ for v in group.values() if "stringUnit" in v
398
+ ]
399
+ for unit in units:
400
+ if unit.get("state", "new") == "new" or not unit.get("value"):
401
+ gaps.append(f"{lang}: {key}")
402
+
403
+ print("\n".join(gaps) or "all strings translated")
404
+ sys.exit(1 if gaps else 0)
405
+ ```
537
406
 
538
- ### Manual migration
407
+ ## Migrating from .strings and .stringsdict
539
408
 
540
- If automatic migration fails (complex bundle setups, CocoaPods):
409
+ Automatic: right-click the `.strings` file, choose Migrate to String Catalog...,
410
+ check the result, then remove the old files from the target.
541
411
 
542
- 1. Create a new `Localizable.xcstrings`
543
- 2. Build to extract keys from code
544
- 3. Copy translations from old `.strings` files into the String Catalog editor
545
- 4. Copy plural rules from `.stringsdict` into plural variants
546
- 5. Remove old files
412
+ By hand, when a bundle setup is unusual or files come from CocoaPods:
547
413
 
548
- ### Migration checklist
414
+ 1. Create a new catalog.
415
+ 2. Build so extraction fills it.
416
+ 3. Copy translations across from the old files.
417
+ 4. Rebuild `.stringsdict` rules as plural variants.
418
+ 5. Remove the legacy files.
549
419
 
550
- - [ ] All `.strings` keys present in the new String Catalog
551
- - [ ] All `.stringsdict` plural rules converted to String Catalog plural variants
552
- - [ ] Bundle references updated (if custom bundle was used)
553
- - [ ] Build succeeds with no missing-localization warnings
554
- - [ ] Test every language the app supports
555
- - [ ] Remove old `.strings` and `.stringsdict` files from the target
556
- - [ ] Commit the `.xcstrings` file (it is JSON, diffs well in version control)
420
+ Before calling it done:
557
421
 
558
- ### Coexistence
422
+ - [ ] Every key made it across
423
+ - [ ] Plurals are variants now
424
+ - [ ] Custom bundle references point to the right place
425
+ - [ ] The build shows no missing-localization warnings
426
+ - [ ] Every language was run
427
+ - [ ] Legacy files are gone
428
+ - [ ] `.xcstrings` is committed (it diffs cleanly as JSON)
559
429
 
560
- String Catalogs and `.strings` files can coexist in the same target during migration. Xcode resolves keys from the String Catalog first, then falls back to `.strings`. Remove legacy files after verifying the migration.
430
+ During the transition both formats work: lookup tries the catalog first, then
431
+ the `.strings` file. Delete the legacy file once you have verified the catalog.
561
432
 
562
- ## Best Practices
433
+ ## Practices that scale
563
434
 
564
- 1. **One String Catalog per target** -- keep `Localizable.xcstrings` as the single source of truth for each target.
565
- 2. **Use comments** -- provide context for every ambiguous key. Translators cannot see your UI.
566
- 3. **Review extraction on every build** -- new keys appear with state "new". Translate them promptly.
567
- 4. **Version control the .xcstrings file** -- it is JSON and diffs clearly. Review translation changes in PRs.
568
- 5. **Automate coverage checks** -- integrate translation-coverage validation in CI to catch missing translations before release.
569
- 6. **Export regularly** -- send updated `.xcloc` bundles to translators after each sprint or feature merge.
570
- 7. **Test with pseudolocalizations in CI** -- run UI tests with double-length and RTL pseudo-languages to catch layout issues early.
571
- 8. **Prefer stable keys with generated symbols** -- for manually-managed strings, use symbol-style keys and enable Generate String Catalog Symbols to get compile-time safety and autocompletion.
435
+ 1. One catalog per target as the source of truth.
436
+ 2. A comment on every ambiguous key; translators never see the screen.
437
+ 3. After each build, look for keys in state `new` and get them translated.
438
+ 4. Keep `.xcstrings` in version control and review translation diffs in pull
439
+ requests.
440
+ 5. Run a translation coverage check in CI.
441
+ 6. Send `.xcloc` exports to translators at every sprint or feature merge.
442
+ 7. Run UI tests under the double-length and RTL pseudolanguages in CI.
443
+ 8. Prefer stable keys with generated symbols for compile-time checking and
444
+ autocompletion.