---
title: "Localize an iOS App in 40+ Languages with .xcstrings"
description: "How to localize an iOS app with String Catalogs (.xcstrings): plurals, permission strings, formatting, right-to-left, testing and App Store metadata."
url: https://develak.com/blog/localize-ios-app-xcstrings/
language: en
updated: 2026-09-24
source: Develak
translations:
  fr: https://develak.com/fr/blog/localiser-application-ios-xcstrings.md
---

Canonical page: <https://develak.com/blog/localize-ios-app-xcstrings/>

[Guides](https://develak.com/blog/) 9 min read

# How to localize an iOS app into 40+ languages with String Catalogs (.xcstrings)

A practical guide to iOS app localization with Xcode String Catalogs: plurals, InfoPlist permission strings, dates and units, right-to-left layouts, pseudolanguage testing, App Store metadata and translation workflow.

Develak studio

Published September 24, 2026

[Lire en français](https://develak.com/fr/blog/localiser-application-ios-xcstrings/)

To localize an iOS app into 40+ languages, keep every user-facing string in Xcode String Catalogs (`Localizable.xcstrings` and `InfoPlist.xcstrings`), let Xcode extract them automatically, handle plurals in the catalog and formatting with `FormatStyle`, test with pseudolanguages and right-to-left layouts, then translate with machine translation for speed and human review where it matters. Finish with the App Store product page, which is localized separately in App Store Connect. This is how Develak ships its own apps in up to 44 languages.

## Key takeaways

- String Catalogs (`.xcstrings`, Xcode 15 and later) replace `.strings` and `.stringsdict`: one file per table, with plurals and device variations built in.
- Never build sentences by concatenation or format dates and numbers by hand.
- Localize `InfoPlist.xcstrings` too: permission prompts and the app name are part of the first impression.
- Test with pseudolanguages before paying for a single translation.
- Localize the App Store product page (name, subtitle, keywords, description, screenshots) for each market.
- Machine translation, LLMs included, is a good first pass; have people review the strings that sell, charge or warn.

## Why localize an iOS app?

The App Store is available in 175 countries and regions, and people search, read reviews and decide in their own language. A localized app with a localized product page competes for local keywords and feels trustworthy in markets where most English-only apps don’t bother. Users can also choose a language per app in iOS Settings, so each language you add is used by people who explicitly want it.

Once the process exists, each extra language costs far less than the first. Our most recent apps ship in 44 languages, including Arabic, Hebrew and Urdu (right-to-left) and Indian languages such as Hindi, Bengali, Tamil and Telugu. That is only sustainable because the steps below are routine.

## String Catalogs in five minutes

A String Catalog is a JSON file with the `.xcstrings` extension, introduced in Xcode 15, that stores every string of a table and all its translations. Add one named `Localizable` to your target and build: Xcode extracts strings from SwiftUI views, `String(localized:)`, `LocalizedStringResource` and `NSLocalizedString`. Each entry shows a state (New, Needs Review, Translated, Stale) and a comment for translators. Existing `.strings` and `.stringsdict` files can be migrated from the file’s context menu.

```swift
// Extracted automatically into Localizable.xcstrings
Text("Take your medication")

// A comment gives translators the context they need
Text("Open", comment: "Button: opens the selected bottle's details")

// Outside SwiftUI views
let title = String(localized: "Cellar", comment: "Tab title for the list of bottles")
```

Comments are the cheapest quality improvement in localization: “Open” can be a verb or an adjective, and “Archive” a noun or an action. Xcode 26 can also draft translator comments with an on-device model and generate type-safe Swift symbols for strings you add manually to the catalog. In Swift packages, set `defaultLocalization` in `Package.swift` and look strings up in `Bundle.module`.

## Plurals and device variations

Write the sentence once with interpolation, then choose **Vary by Plural** on that key in the catalog. Xcode shows exactly the plural categories each language needs:

```swift
// Catalog key: "%lld reminders" → Vary by Plural
Text("\(count) reminders")
```

| Languages | Plural categories | What goes wrong with “count == 1” |
| --- | --- | --- |
| English, German | one, other | Nothing, which is why the bug stays hidden |
| Japanese, Chinese, Korean, Thai, Vietnamese | other | A needless singular form appears |
| Russian, Ukrainian, Polish | one, few, many, other | “5 reminders” takes the wrong ending |
| Arabic | zero, one, two, few, many, other | Four of six forms are wrong |

*Plural categories (Unicode CLDR) handled by String Catalogs*

A string with two numbers (“%lld photos in %lld albums”) can vary on each one independently. **Vary by Device** handles wording that depends on the hardware, such as “Tap to start” on iPhone and “Click to start” on Mac.

## InfoPlist.xcstrings: permission prompts and the app name

Add a second String Catalog named `InfoPlist` to the target and Xcode fills it with the localizable keys of `Info.plist`: the Home Screen name (`CFBundleDisplayName`) and every purpose string, from `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` to `NSHealthShareUsageDescription`. A permission prompt is the moment you ask for trust, and an English prompt in a French app looks unfinished at exactly that moment. App Review also reads these strings under guideline 5.1.1, so their translations should stay precise.

Two more places are easy to forget: App Shortcuts phrases live in `AppShortcuts.xcstrings`, and widget extensions need their strings available in the extension target.

## Dates, numbers and units: let FormatStyle do it

Date order, 12- or 24-hour clocks, decimal separators, currency placement, the first day of the week and the measurement system all change with the user’s region. Never hard-code `"MM/dd/yyyy"` or a currency symbol:

```swift
// Weekday and time, in the user's language and clock format
Text(dose.scheduledAt, format: .dateTime.weekday(.wide).hour().minute())

// Currency with the right symbol and separators
Text(price, format: .currency(code: "EUR"))

// Kilometers or miles, depending on the user's region
Text(distance, format: .measurement(width: .abbreviated, usage: .road))

// "Pillio, Seizly, and ApexLap" or "Pillio, Seizly et ApexLap"
Text(appNames.formatted(.list(type: .and)))
```

Sort user-visible lists with `localizedStandardCompare` and search with `localizedStandardContains`, so accents and case behave as people expect.

## Right-to-left languages: Arabic, Hebrew, Urdu

SwiftUI mirrors layouts automatically when you use leading and trailing instead of left and right. Directional SF Symbols flip on their own; for your own directional images, opt in explicitly. Do not mirror what isn’t directional: logos, photos, checkmarks. Check the result in a preview:

```swift
Image("swipe-hint")
    .flipsForRightToLeftLayoutDirection(true)

#Preview("Arabic, right-to-left") {
    ContentView()
        .environment(\.locale, Locale(identifier: "ar"))
        .environment(\.layoutDirection, .rightToLeft)
}
```

## Test before you translate: pseudolanguages

In the scheme editor (Run › Options › App Language), Xcode offers pseudolanguages that reveal localization bugs with no translation at all. Turn on “Show non-localized strings” in the same panel to spot hard-coded text.

| Pseudolanguage | What it catches |
| --- | --- |
| Double-Length | Truncated labels and clipped buttons, as with long German or Finnish strings |
| Accented | Clipped diacritics and tight line heights; hard-coded strings stay unaccented |
| Bounded String | Concatenated or truncated strings, since you see where each one starts and ends |
| Right-to-Left | Layouts that don’t mirror, with readable text |
| Right-to-Left with Right-to-Left Strings | The full right-to-left experience, text included |

*Xcode pseudolanguages and the bugs they reveal*

UI tests can launch the app in any language, which is also how localized App Store screenshots can be automated:

```swift
let app = XCUIApplication()
app.launchArguments += ["-AppleLanguages", "(de)", "-AppleLocale", "de_DE"]
app.launch()
```

## Localize the App Store product page too

The binary and the product page are localized separately. The “Languages” line of your listing comes from the app bundle; everything else is set per localization in App Store Connect, which accepts metadata in roughly 40 languages and regional variants:

- Name and subtitle (30 characters each), promotional text, description and What’s New.
- Keywords (100 characters per localization), researched in each language rather than translated: a French user looking for a pill reminder may type “pilulier”, a word no translation of “pill reminder” produces.
- Screenshots and app previews with translated captions; without them, the primary language’s are shown. Arabic and Hebrew screenshots should show the mirrored interface.
- In-app purchase display names, descriptions and subscription group names.

Localized keywords and screenshots are core App Store Optimization work, which is why our [ASO service](https://develak.com/services/app-store-optimization/) treats each market separately.

## Human, machine or both?

Large language models now translate interface strings well when they get context: the translator comment, the surrounding screen, a glossary of product terms. They still stumble on register (formal or informal “you” in French, German or Spanish), gender agreement, length, and placeholders that must survive untouched. Our rule: machine translation for the first pass on everything, then human review for onboarding, the paywall and subscription terms, permission prompts, App Store metadata and anything medical, legal or safety-related. Brand names such as Pillio or Seizly are marked “Don’t translate”, and TestFlight builds go to native speakers before release.

## Our tool: Xlocalize for .xcstrings files

Localizing a catalogue of 34 apps pushed us to build our own Mac app. [Xlocalize](https://develak.com/apps/xlocalize/) opens a `.xcstrings` file, lets you pick target languages and translates with OpenAI, Anthropic Claude or Google Gemini, using your own API key stored in the macOS Keychain. It preserves plurals, device variations and substitutions, sends per-key comments as context, and flags placeholder mismatches and missing translations before they reach a build.

## A localization workflow checklist

1. Internationalize the code: no hard-coded strings, `FormatStyle` everywhere, leading and trailing layouts, flexible sizes and Dynamic Type.
2. Create `Localizable`, `InfoPlist` and, if needed, `AppShortcuts` catalogs, then build to extract.
3. Add comments to ambiguous strings and mark brand names “Don’t translate”.
4. Set up plural and device variations.
5. Test with pseudolanguages and right-to-left.
6. Translate: machine first pass, human review of critical strings.
7. Check placeholders and truncation in every language on the smallest supported iPhone.
8. Localize App Store metadata, keywords, screenshots and in-app purchase names.
9. Ship to native speakers through TestFlight.
10. Every release, translate new and stale strings before you submit.

## Common pitfalls

- **Concatenation.** `"Hello " + name` breaks word order; use one localized string with interpolation.
- **One key, two meanings.** Reusing “Open” for a verb and an adjective forces a bad translation in half the languages.
- **Argument order.** Translators may need to reorder values; positional specifiers such as `%1$@` and `%2$lld` make that possible.
- **Text inside images**, which no String Catalog can translate.
- **Fixed widths** and single-line labels that collapse in German.
- **Accessibility labels.** VoiceOver reads `.accessibilityLabel` text aloud; it is extracted like any other string, so check that it is translated rather than left in English.
- **Server-side text:** push notifications and e-mails need localization too, for example with `loc-key` in the notification payload.
- **Stale strings** left untranslated after a redesign.

If you would rather hand the whole process to a team that does it every week, our [app localization service](https://develak.com/services/app-localization/) covers the code, the translations, the review and the App Store listing.

## FAQ

### What is an .xcstrings file?

An `.xcstrings` file is an Xcode String Catalog: a JSON file, introduced in Xcode 15, that stores every localizable string of a table with all its translations, plural forms, device variations, comments and translation states. It replaces the older `.strings` and `.stringsdict` files.

### Do String Catalogs work on older iOS versions?

Yes. String Catalogs are a build-time format: Xcode compiles them into the classic `.strings` and `.stringsdict` resources inside the app. You need Xcode 15 or later to build, but the app’s deployment target is not affected.

### How many languages should an iOS app start with?

Start with the languages of the markets you already see in App Store Connect analytics, plus the ones your competitors neglect. Once the code is internationalized and the workflow is in place, adding a language is mostly translation and review, which is why studios like ours can ship apps in 40 or more languages.

### Can I translate my iOS app with ChatGPT, Claude or Gemini?

Yes, as a first pass. Give the model context (translator comments, a glossary, the screen the string appears on), use a tool that edits the `.xcstrings` file without breaking plurals or placeholders, such as Xlocalize, and have native speakers review onboarding, paywall, permission prompts and App Store metadata.

### How do I localize my app’s name?

There are two names. The one under the icon on the Home Screen is `CFBundleDisplayName`, translated in `InfoPlist.xcstrings`. The one on the App Store is set per localization in App Store Connect, with a limit of 30 characters. Many apps keep the brand identical everywhere and localize only the descriptive part, such as the subtitle.

### How do I test an Arabic layout without speaking Arabic?

Run the app with Xcode’s Right-to-Left pseudolanguage, which mirrors the interface while keeping readable text, and add SwiftUI previews with a right-to-left layout direction. Check that navigation, progress indicators and directional icons flip, and that logos and photos don’t.

Written by

## The Develak studio

Develak is an independent iOS app studio. We have published 34 apps on the App Store since 2025, in up to 44 languages, and we write these guides from that hands-on experience.

[See our 34 apps](https://develak.com/apps/) [About the studio](https://develak.com/about/)

## More iOS guides

[All guides](https://develak.com/blog/)

Guides 9 min read

### [SwiftUI vs Flutter vs React Native in 2026: which should you choose for an iPhone app?](https://develak.com/blog/swiftui-vs-flutter-vs-react-native/)

An honest 2026 comparison of SwiftUI, Flutter and React Native for iPhone apps: performance, Apple frameworks, UI fidelity, time to market, hiring, maintenance and Android reach, with a decision checklist.

September 17, 2026

Guides 10 min read

### [App Store submission checklist (2026): everything Apple checks before approving your app](https://develak.com/blog/app-store-submission-checklist/)

The complete 2026 checklist for submitting an iPhone app: App Store Connect setup, privacy policy and support URLs, privacy manifest, account deletion, subscriptions, screenshots, age rating, TestFlight and the rejections to avoid.

September 10, 2026

## Turn this guide into a shipped app

Develak designs, builds and publishes native iOS apps for founders and teams worldwide, in English or French.

[Start a project](https://develak.com/contact/) [contact@develak.com](mailto:contact@develak.com)

---

*Markdown version of <https://develak.com/blog/localize-ios-app-xcstrings/> for AI assistants, published by Develak. Links lead to the web pages; add .md to a page URL for its Markdown version. Site index: <https://develak.com/llms.txt>.*
