Formats
Apple .xcstrings (iOS)
Translate Apple String Catalogs, the localization format of Xcode 15 and later.
String Catalogs (.xcstrings) are Apple's modern localization format. One catalog holds a table of strings with every locale inside, and Xcode keeps it in sync with your code on each build.
Install the format package:
npm install -D @eloqnt/format-apple-xcstrings
Then reference it from your configuration:
.eloqnt/config.ts
import {defineConfig} from '@eloqnt/cli';export default defineConfig({messages: {path: './MyApp/Localizable',locales: 'infer',sourceLocale: 'en',format: {codec: '@eloqnt/format-apple-xcstrings',extension: '.xcstrings'}}});
Since all locales live in one file, path points at the catalog itself (without the extension) and uses no {locale} placeholder. With locales: 'infer', the locales are read from inside the catalog, and sourceLocale should match the catalog's sourceLanguage.
Namespaces
Projects with several catalogs can use the {namespace} placeholder, which prefixes each message ID with its catalog name:
.eloqnt/config.ts
path: './MyApp/{namespace}';
This matches files like MyApp/Localizable.xcstrings and MyApp/InfoPlist.xcstrings.
Plurals
Plural variations appear as ICU messages in eloqnt/cli, using count as the variable:
MyApp/Localizable.xcstrings (excerpt)
"%lld songs" : {"localizations" : {"en" : {"variations" : {"plural" : {"one" : {"stringUnit" : {"state" : "translated", "value" : "%lld song"}},"other" : {"stringUnit" : {"state" : "translated", "value" : "%lld songs"}}}}}}}
The English entry above reads as {count, plural, one {%lld song} other {%lld songs}} in lint output and during translation. Each target locale receives the plural categories its language needs, which can differ from the source.
Substitutions
Multi-argument plurals via substitutions work the same way: each %#@name@ reference reads as a named plural in place, with %arg appearing as #. A catalog value of Found %#@count@ whose count substitution varies between %arg file and %arg files reads as Found {count, plural, one {# file} other {# files}}, and translations are written back into the substitution's variations.
Device variations
Device variations appear as separate strings: the other variant keeps the key as its ID, and every named device gets ::device. appended, e.g. Tap to continue::device.mac. Each variant is translated on its own (the device is passed along as context), and written back into the catalog's device variations.
Not supported
The following features are not supported:
stringSetentries: Their items are positional and unnamed, which is why most localization tools can't translate them reliably. To solve this, declare each phrase variant explicitly, e.g. inAppShortcut(phrases:), so that every phrase holds one value per language.srcPath: Source code analysis is currently limited tonext-intl.