---
source: https://studio.eloqnt.dev/docs/formats/apple-xcstrings
docs_index: https://studio.eloqnt.dev/llms.txt
---

# 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:

```bash
npm install -D @eloqnt/format-apple-xcstrings
```

Then reference it from your configuration:

```ts title=".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:

```ts title=".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:

```json title="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:

- `stringSet` entries: 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. in `AppShortcut(phrases:)`, so that every phrase holds one value per language.
- [`srcPath`](https://studio.eloqnt.dev/docs/configuration#srcPath): Source code analysis is currently limited to `next-intl`.

---

For an index of every eloqnt/studio documentation page, see [https://studio.eloqnt.dev/llms.txt](https://studio.eloqnt.dev/llms.txt).
