By the strings.dev team — maintainers of native .xcloc and strings.xml localization tooling for iOS and Android.
One export, every Apple form factor
The reason Apple localization scales so well is that the format doesn't change with the device. A Text("welcome_title") in SwiftUI resolves the same way whether it renders on an iPhone, a Mac window, a watch complication, an Apple TV row, a visionOS window, or a CarPlay template. When you export localizations, Xcode collects the localizable strings from all targets in the project into per-language .xcloc bundles — so a single export/translate/import cycle covers your whole app, not one platform at a time.
That means the platforms below are not seven separate localization projects. They're one:
| Apple platform |
Typical string source |
Notes |
| iOS / iPadOS |
.xcstrings / .strings |
The primary surface for most apps |
| macOS |
.xcstrings / .strings, plus menu/MainMenu XIBs |
AppKit menus and Interface Builder strings export too |
| tvOS |
.xcstrings / .strings |
Same catalog model as iOS |
| visionOS |
.xcstrings / .strings |
Shares the iOS/SwiftUI string model |
| watchOS |
.xcstrings / .strings |
Complications and notifications included |
| CarPlay |
.xcstrings / .strings |
Templates draw from your app's strings; no separate catalog |
If your app is a single target that ships to several of these (an iOS app with a watchOS companion and a CarPlay scene, for example), one .xcloc per locale is all you hand off.
What's inside a .xcloc bundle
The .xcloc is a folder-structured bundle — the native round-trip container Xcode produces. At a high level it holds:
- A
Localized Contents/ folder with an XLIFF 1.2 file (<lang>.xliff) containing the extractable key/source/target units, plus the localized String Catalog (Localizable.xcstrings) where your project uses one.
- A
Source Contents/ folder with a reference copy of the development-language resources.
- A
Notes/ folder for screenshots and translator context, and a top-level contents.json describing the bundle (development region, target locale, tool metadata).
The important property: it's Apple's own interchange format. You don't convert to a third-party XLIFF flavor and back — the same format goes out and comes in, so keys, comments, and String Catalog state survive the trip. That format boundary is exactly what strings.dev automates: you upload the .xcloc, choose target locales, and get native .xcloc files back in the same shape Xcode expects.
The Export / Import round-trip
The whole Apple localization loop is two Xcode actions plus the translation step in between.
Export — from Product → Export Localizations… (menu path Editor › Export For Localization in older Xcode), or from the command line:
xcodebuild -exportLocalizations \
-project MyApp.xcodeproj \
-localizationPath ./loc \
-exportLanguage es \
-exportLanguage ja
This writes ./loc/es.xcloc and ./loc/ja.xcloc. Omit -exportLanguage to export every language configured on the project.
Translate — the target units in each .xcloc get filled in. This is the step strings.dev handles natively, feeding your app-description context and any per-string translation notes into each translation so the output reflects what your app actually does.
Import — bring the translated bundles back with Product → Import Localizations… or:
xcodebuild -importLocalizations \
-project MyApp.xcodeproj \
-localizationPath ./loc/es.xcloc
Xcode merges the targets into the right String Catalog entries and .lproj folders, marking strings as translated. Rebuild, and every form factor that references those keys is localized. For the full add-a-language walkthrough and String Catalog editing details, see the mobile app localization guide; for the exact locale identifiers each .lproj uses, see the iOS & Android locale codes reference.
String Catalog (.xcstrings) is the modern source
Since Xcode 15, the default for new localizable strings is the String Catalog — a single JSON-backed Localizable.xcstrings file Xcode manages with a visual editor, per-string translation state, and built-in variation support. You reference a key in code and Xcode extracts it:
Text("welcome_title")
String(localized: "cart_item_count")
The String Catalog is where plural variations live (Xcode's "Vary by Plural") and where device variations are stored, following the Unicode CLDR plural categories. When you export, the catalog rides inside the .xcloc; when you import, translated variations merge straight back into it. strings.dev reads and writes String Catalog plural variations in the native file, expanding the plural categories a target language actually needs rather than mirroring English's one/other. The detailed String Catalog how-to is a separate page — this overview just marks where it sits in the pipeline.
Placeholders: %@, %lld, and friends
Apple's format specifiers must pass through translation untouched, and translators need to be free to reorder them, because word order changes across languages:
| Specifier |
Use |
%@ |
Objects and strings |
%lld |
64-bit integers |
%1$@, %2$lld |
Positional forms — let a translation reorder arguments |
Positional forms matter because German or Japanese may need the count and the subject in a different order than English:
"%1$@ sent you %2$lld files"
A translation that drops %2$lld or swaps %@ for a literal will crash or mis-format at runtime. strings.dev preserves placeholder syntax, URLs, emails, @handles, and proper nouns automatically, and lets you mark brand phrases as protected so your product's "Send" mode never becomes a French verb. Note the boundary: this is in-app string localization. App Store Connect metadata — your listing description, keywords, and screenshots — is a separate surface handled in the store console, not in your .xcloc.
Wire it into your build
Because both Xcode actions have xcodebuild equivalents, the loop scripts cleanly. A minimal continuous-localization sketch:
# 1. Export the dev-language strings to per-locale .xcloc bundles
xcodebuild -exportLocalizations -project MyApp.xcodeproj -localizationPath ./loc
# 2. Translate each .xcloc with strings.dev (CLI, REST API, or MCP)
# 3. Import the translated bundle back
xcodebuild -importLocalizations -project MyApp.xcodeproj -localizationPath ./loc/es.xcloc
strings.dev exposes that middle translation step four ways so it fits whatever you run: per-project CLI scripts for a git hook or CI job, a REST API with a per-project key, the strings-mcp-server MCP package plus a generated AI-skill prompt so an agent (Claude, Cursor, Copilot) runs the whole loop, and continuous localization from git hooks or CI. Full setup is in the API and CLI docs.
Where this fits, and what it costs
The free Indie tier covers 1 project and 1 language with unlimited word translations plus app and brand localization — enough to run the full .xcloc round-trip end to end on one locale. To localize across the Apple platform matrix in unlimited languages with 2 projects, brand context, and the QA & analytics dashboard that flags failed translations for retry, Indie Plus is $20/mo, or $10/mo billed annually (see pricing). One export format, every Apple device, translated on every build.