|
File Extensions |
.xcstrings |
|
API Extension |
strings_catalog |
|
Import |
Yes |
|
Export |
Yes |
|
Plural forms support |
Yes |
|
Description support |
Yes |
|
Format options These options that can be specified when a file is uploaded and/or downloaded. Depending on the upload/download method (API, CLI, Repo sync etc.), they can be specified in query parameters |
convert_placeholder default_extraction_state |
Apple Strings Catalog (.xcstrings) is a localization format introduced in Xcode 15. It enhances the way developers manage localized strings by supporting structured formats for handling pluralization, device-specific variations, and more. This format is becoming the recommended approach for managing localizations in iOS and macOS application.
The comment, extractionState and shouldTranslate metadata fields are imported and exported in the required order to ensure compatibility with Xcode.
Phrase also maps Xcode translation states to the closest Strings equivalents during import and converts them back to Xcode-compatible values on export. If no specific mapping applies, translated is used as the default export value. If required, use the option to skip state mapping.
Code Sample
{
"sourceLanguage": "en",
"strings": {
"Sync Warning": {
"comment": "Sync function unavailable message",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Cloud Sync must be enabled to use this feature."
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "La synchronisation cloud doit être activée pour utiliser cette fonction."
}
}
}
},
"Chosen Collections": {
"comment": "View title indicating selected photo collections",
"localizations": {
"fr": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%ld collection sélectionnée"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%ld collections sélectionnées"
}
}
}
}
},
"en": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%ld Collection Selected"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%ld Collections Selected"
}
}
}
}
}
}
},
"Settings Hub": {
"localizations": {
"es": {
"stringUnit": {
"state": "translated",
"value": "Centro de configuración"
}
}
}
}
},
"version": "1.0"
}
When using the Phrase CLI, file exports follow the structure defined in the .phrase.yml configuration file. To ensure multiple languages are exported into a single .XCSTRINGS file during pull operations:
-
Specify only one file target in the CLI configuration file.
-
Use the
locale_idsparameter to list all the language locales included in the export.
Example .phrase.yml configuration
pull:
targets:
- file: ./i18n-test/Localizable.xcstrings
params:
locale_id: en # Main language for the download
locale_ids: # Additional languages to include
- de
- es
- fr
file_format: strings_catalog
Device variations
Apple Strings Catalog supports device variations, which allow different translation contents for the same key depending on the Apple device being used.
To handle device variations in Phrase Strings, separate keys are created for each device using the separator |==|. When importing .XCSTRINGS files, the device type is added to the base key name using this separator.
Example
The key named %lld Product(s) Ordered for the applewatch device is imported as a plural key named %lld Product(s) Ordered|==|device.applewatch into Phrase Strings.
During export, Phrase Strings detects the device variant using the separator and restores its original nested structure for Apple’s localization format.
{
"sourceLanguage": "en",
"strings": {
"%lld Product(s) Ordered": {
"comment": "Indicates the number of products ordered, with device-specific variations",
"localizations": {
"en": {
"variations": {
"device": {
"applewatch": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld Product ordered (Apple Watch)"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%lld Products ordered (Apple Watch)"
}
}
}
}
},
"ipad": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld Product ordered (iPad)"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%lld Products ordered (iPad)"
}
}
}
}
},
"iphone": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld Product ordered (iPhone)"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%lld Products ordered (iPhone)"
}
}
}
}
},
"mac": {
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld Product ordered (Mac)"
}
},
"other": {
"stringUnit": {
"state": "translated",
"value": "%lld Products ordered (Mac)"
}
}
}
}
}
}
}
},
"fr": {
"variations": {
"plural": {
"few": {
"stringUnit": {
"state": "translated",
"value": "%lld produit(s) commandé(s)"
}
},
"many": {
"stringUnit": {
"state": "translated",
"value": "%lld produits commandés"
}
},
"one": {
"stringUnit": {
"state": "translated",
"value": "%lld produit commandé"
}
}
}
}
}
}
}
}
}
String substitutions
Apple Strings Catalog supports string substitutions that provide flexible placeholders for dynamic content.
To handle string substitutions in Phrase Strings, separate keys are created using the separator |==|. When importing .XCSTRINGS files, the substitution is added to the base key name using this separator.
Phrase Strings also supports creating substitution strings directly in the project. When substitution structures are created manually, a base key and a corresponding substitution key must be defined to ensure the correct nested format is generated during export.
Substitutions always require a specific key naming format: keyName|==|substitution.[specifier].
Example: Importing substitution structures from existing .XCSTRINGS files
The key named birdSightingAlert for the BIRDS substitution is imported as a plural key named birdSightingAlert|==|substitution.BIRDS into Phrase Strings.
During export, Phrase Strings detects the substitution using the separator and restores its original nested structure for Apple’s localization format.
"birdSightingAlert": {
"comment": "Alert message indicating the number of birds spotted",
"localizations": {
"en": {
"stringUnit": {
"state": "new",
"value": "You spotted %#@BIRDS@!"
},
"substitutions": {
"BIRDS": {
"formatSpecifier": "BIRDS",
"variations": {
"plural": {
"one": {
"stringUnit": {
"state": "new",
"value": "a bird"
}
},
"other": {
"stringUnit": {
"state": "new",
"value": "several birds"
}
},
"zero": {
"stringUnit": {
"state": "new",
"value": "no birds"
}
}
}
}
}
}
}
}
Example: Creating substitution strings from scracth
-
Base key
A base key named
keyNamerepresents the top-level format string that contains the substitution placeholder%#@format@.When exported, this key is written as the primary
stringUnitfor the entry:"keyName": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "%#@format@" } } } } -
Substitution key
A substitution string is defined as separate key using the substitution naming format:
keyName|==|substitution.li.This key contains the substitution text, typically with plural variations. During export, Phrase Strings detects the substitution using the
|==|substitution.separator and restores the corresponding nested structure under the base key:{ "sourceLanguage": "en", "strings": { "keyName": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "%#@format@" }, "substitutions": { "li": { "formatSpecifier": "li", "variations": { "plural": { "one": { "stringUnit": { "state": "translated", "value": "%@ day" } }, "other": { "stringUnit": { "state": "translated", "value": "%@ days" } } } } } } } } } }, "version": "1.0" }
Format Options
|
Identifier |
convert_placeholder |
|
Type |
boolean |
|
Upload |
No |
|
Download |
Yes |
|
Default |
false |
|
Description |
Placeholder will be converted to match format specific requirements. Example: |
|
Identifier |
default_extraction_state |
|
Type |
string |
|
Upload |
No |
|
Download |
Yes |
|
Default |
null |
|
Description |
Defines the Supported in:
|