# General Translation Knowledge Base: Как локализовать iOS-приложение с помощью String Catalogs?
URL: https://generaltranslation.com/ru/kb/localize-ios-app.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Добавьте языки в Xcode, пишите текст для пользователей с помощью локализуемых API, таких как SwiftUI Text и String(localized:), и выполните сборку, чтобы Xcode собрал эти строки в String Catalog (.xcstrings). Переводите в Xcode, через XLIFF или с помощью CLI General Translation, если каталоги должны обновляться с каждым релизом и использовать общую терминологию с вашим сайтом и Android-приложением.
Category: Интернационализация
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

String Catalog хранит таблицу строк сразу на всех языках в одном JSON-файле, а Xcode синхронизирует его с кодом при каждой сборке. Вам остаётся решить две задачи: добавить в каталог все строки, которые видит пользователь, и вернуть в него качественные переводы.

## Настройка локализации в Xcode

### Добавьте языки

В редакторе проекта выберите проект, откройте вкладку **Info** и нажмите кнопку добавления в разделе **Localizations** (такая же кнопка есть на боковой панели редактора String Catalog). У каждой записи есть идентификатор языка, например `de`, `ja` или `en-IN` ([Apple: Adding support for languages and regions](https://developer.apple.com/documentation/xcode/adding-support-for-languages-and-regions)). Выбирайте региональный вариант, только если текст действительно отличается, как в случае с `pt-BR` и `pt-PT`. (См. [коды локалей](/docs/platform/core/guides/locale-codes)).

### Добавьте String Catalog и выполните сборку

Выберите **File &gt; New &gt; File from Template**, введите в поле фильтра «string» и выберите **String Catalog**. Имя по умолчанию — `Localizable.xcstrings`. Затем выберите **Product &gt; Build**: Xcode найдёт локализуемые строки в вашем коде и добавит их в каталог, а затем будет обновлять каталог при каждой сборке ([Apple: Localizing and varying text with a string catalog](https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog)).

String Catalogs появились в Xcode 15 ([примечания к релизу](https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes)). Во время сборки они компилируются в файлы `.strings` и `.stringsdict`, поэтому для перехода на них не нужно повышать минимальную целевую версию развёртывания (minimum deployment target) ([WWDC23: Discover String Catalogs](https://developer.apple.com/videos/play/wwdc2023/10155/)).

### Используйте локализуемые API для текста

Xcode извлекает только строки, переданные в локализуемые API. В SwiftUI строковые литералы в представлениях являются значениями [`LocalizedStringKey`](https://developer.apple.com/documentation/swiftui/localizedstringkey) и извлекаются автоматически. В остальных местах используйте `String(localized:)` ([Apple: Preparing your app&#39;s text for translation](https://developer.apple.com/documentation/xcode/preparing-your-apps-text-for-translation)):

```swift
import SwiftUI

struct CartView: View {
    let itemCount: Int
    let couponCode: String

    var body: some View {
        VStack {
            // Строковые литералы в представлениях SwiftUI являются значениями LocalizedStringKey,
            // поэтому Xcode добавляет их в String Catalog при сборке.
            Text("Your cart")

            // Интерполяция превращается в спецификатор формата (%lld), для которого можно задать разные формы множественного числа.
            Text("\(itemCount) items")

            // Комментарий сообщает переводчикам, где и как используется текст.
            Text("Checkout", comment: "Button that starts payment for the items in the cart.")

            // Переменная типа String отображается как есть. Text(verbatim:) указывает на это явно.
            Text(verbatim: couponCode)
        }
    }
}

// Вне представлений SwiftUI создавайте локализуемый текст с помощью String(localized:).
let emptyCartMessage = String(
    localized: "Your cart is empty",
    comment: "Shown when the cart has no items."
)
```

Типичная ошибка — `Text(someString)`: переменная типа `String` не ищется в каталоге. Чтобы передавать локализуемый текст между представлениями, используйте `LocalizedStringResource`: этот тип рекомендует Apple, к тому же он хранит комментарий и имя таблицы.

Комментарии важны, ведь слово «Checkout» само по себе может быть и существительным, и глаголом. Добавляйте их через параметр `comment:` или щёлкните ключ в каталоге с зажатой клавишей Control и выберите **Generate Comment** — Xcode сам составит комментарий на основе окружающего кода.

Чтобы найти текст, который так и не попал в каталог, откройте **Product &gt; Scheme &gt; Edit Scheme &gt; Run &gt; Options** и включите **Show non-localized strings**: при запуске приложения такие строки будут отображаться заглавными буквами ([Apple: Preparing your interface for localization](https://developer.apple.com/documentation/xcode/preparing-your-interface-for-localization)). (См. [Как найти захардкоженные строки без перевода?](/kb/find-hardcoded-strings)).

## Формы множественного числа, устройства и Info.plist

Щёлкните по ключу с интерполированным числом, удерживая клавишу Control, и выберите **Vary by Plural**. Xcode добавит категории множественного числа, нужные каждому языку: `one` и `other` для английского, а при добавлении русского — `one`, `few`, `many` и `other`. **Vary by Device** позволяет задать для ключа разные значения на разных устройствах, например &quot;Tap to learn more&quot; на iPhone и &quot;Click to learn more&quot; на Mac.

За редактором скрывается обычный JSON-файл каталога, поэтому различия в пул-реквестах получаются чистыми и наглядными. Вот небольшой фрагмент с английской формой множественного числа и испанским переводом:

```json title="Localizable.xcstrings"
{
  "sourceLanguage" : "en",
  "strings" : {
    "%lld items" : {
      "comment" : "Number of items in the shopping cart.",
      "localizations" : {
        "en" : {
          "variations" : {
            "plural" : {
              "one" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld item"
                }
              },
              "other" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld items"
                }
              }
            }
          }
        }
      }
    },
    "Checkout" : {
      "comment" : "Button that starts payment for the items in the cart.",
      "localizations" : {
        "es" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Pagar"
          }
        }
      }
    }
  },
  "version" : "1.0"
}
```

Системный текст из `Info.plist`, например отображаемое имя приложения и пояснения в запросах разрешений, хранится в отдельном каталоге. Добавьте в таргет файл `InfoPlist.xcstrings`, и Xcode при каждой сборке будет заполнять его известными локализуемыми ключами `Info.plist`.

## Отслеживание состояний строк

У каждого перевода в каталоге есть состояние, которое отображается в столбце **State** редактора:

* **New:** строка ещё не переведена на этот язык.
* **Needs Review:** источник изменился после перевода или кто-то пометил строку; выберите **Mark as Reviewed**, чтобы оставить текущее значение.
* **Translated:** зелёная галочка; больше ничего делать не нужно.
* **Stale:** Xcode больше не находит строку в коде. Непереведённые строки, исчезнувшие из кода, удаляются, а переведённые сохраняются и помечаются как устаревшие, пока вы не удалите их сами.

Для строк, добавленных вручную (например, ключей, формируемых во время выполнения), можно включить ручное управление — тогда сборка не будет их обновлять или удалять.

## Миграция с .strings и .stringsdict

Чтобы преобразовать существующий проект, выберите **Edit &gt; Convert &gt; To String Catalog** (или щёлкните файл с нажатой клавишей Control и выберите **Migrate to String Catalog**). Миграция выполняется отдельно для каждого файла и каждого таргета, поэтому на время миграции каталоги могут сосуществовать с устаревшими файлами. Если в одном таргете есть каталог и файл `.strings` или `.stringsdict` с тем же именем, возникает ошибка сборки, поэтому полностью переносите каждую таблицу, прежде чем переходить к следующей. Если в `InfoPlist.strings` есть комментарии, при миграции они сохраняются.

## Выберите способ перевода

Добавить переводы в каталог можно следующими способами:

| Способ                                                                          | Кто переводит                            | Какой контекст получает переводчик                                                                                     | Можно ли повторять при каждом релизе                                          | Что остаётся на вас                                                                                                  |
| ------------------------------------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Ввод вручную в редакторе каталога                                               | Вы или коллега, владеющий обоими языками | Всё приложение                                                                                                         | Нет                                                                           | Каждая строка на каждом языке, вручную                                                                               |
| Агент для написания кода в Xcode (Xcode 27)                                     | Агент, которого вы включаете в Xcode     | Где используется каждая строка, похожие строки, требования к множественному числу, языковые руководства по стилю Apple | Запуск по запросу в Xcode                                                     | Настройка агента, проверка машинно переведённых строк, синхронизация терминов с веб- и Android-приложениями          |
| Экспорт `.xcloc` и XLIFF переводчикам или в систему управления переводами (TMS) | Профессиональные переводчики             | Комментарии, а также скриншоты, которые вы добавляете в папку `Notes`                                                  | Автоматизируется с помощью `xcodebuild`                                       | Передача файлов туда и обратно при каждом релизе и ожидание результата                                               |
| General Translation CLI                                                         | Сервис перевода GT                       | Комментарии каталога, а также общие Glossary и Custom Prompts                                                          | Запуск [`gt translate`](/docs/cli/reference/commands/translate) перед сборкой | Проверка в панели управления или в Xcode, затем тестирование приложения                                              |
| Скрипт, прогоняющий JSON через машинный перевод или LLM                         | Модель или API перевода                  | Всё, что отправляет ваш скрипт                                                                                         | Да                                                                            | Вариации, подстановки, категории множественного числа для каждого языка, спецификаторы формата, состояния и проверка |

**Экспорт.** Команда **Product &gt; Export Localizations** создаёт для каждого языка отдельный Xcode Localization Catalog (папку `.xcloc`) с файлом XLIFF внутри ([Apple: Exporting localizations](https://developer.apple.com/documentation/xcode/exporting-localizations)). Включите параметр сборки **Use Compiler to Extract Swift Strings**, чтобы в экспорт попали все строки Swift. Импортируйте переводы обратно через **Product &gt; Import Localizations** или автоматизируйте экспорт и импорт с помощью `xcodebuild -exportLocalizations` и `xcodebuild -importLocalizations` ([Apple: Importing localizations](https://developer.apple.com/documentation/xcode/importing-localizations)).

**Что изменилось в Xcode 27.** Агенты в Xcode теперь умеют переводить String Catalogs: Xcode добавляет языки, создаёт недостающие String Catalogs и передаёт агенту контекст для каждой строки ([Xcode 27 release notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-27-release-notes), [WWDC26: Translate your app using agents in Xcode](https://developer.apple.com/videos/play/wwdc2026/213/)). В редакторе каталога появилась кнопка **Generate Translations**, результат работы агента получает состояние **Machine Translated**, а в экспортированном XLIFF помечается атрибутом `state-qualifier="leveraged-mt"`. Комментарий локализации «do not translate» теперь помечает строку как **Don&#39;t Translate** в каталоге и как `translate="no"` в XLIFF. В `AGENTS.md` или `CLAUDE.md` можно сослаться на файл `TRANSLATION.md` с глоссарием и списком строк, которые агенту переводить не нужно ([Apple: Localizing your app using agents](https://developer.apple.com/documentation/xcode/localizing-your-app-using-agents)).

Редактор каталога подойдёт для одного-двух языков, которыми вы владеете. Агент Xcode — если нужен машинный перевод прямо в Xcode. General Translation стоит выбрать, когда важны воспроизводимая команда в репозитории и единая терминология во всех продуктах; при этом вы продолжаете работать в Xcode и с нативными API локализации Apple. Экспорт XLIFF подходит, когда переводом занимаются профессиональные переводчики или уже используемая [TMS](/kb/what-is-a-translation-management-system).

## Тестирование на всех языках

Выберите **Product &gt; Scheme &gt; Edit Scheme**, затем **Run** и **Options** и задайте **App Language** и **App Region** для следующего запуска ([Apple: Testing localizations](https://developer.apple.com/documentation/xcode/testing-localizations-when-running-your-app)). В том же меню **App Language** доступны псевдоязыки: **Double-Length** — для проверки увеличения длины текста, **Right-to-Left** — для зеркальных макетов, **Accented** и **Tall** — для более высоких глифов, **Bounded String** — для проверки усечения (см. [Что такое псевдолокализация?](/kb/pseudo-localization)). Для превью SwiftUI задайте `.environment(\.locale, .init(identifier: "de"))`.

Метаданные App Store (название, описание, снимки экрана) локализуются отдельно в [App Store Connect](https://developer.apple.com/help/app-store-connect/manage-app-information/localize-app-information).

## Перевод String Catalogs с помощью General Translation

Если перевод нужно запускать одной повторяемой командой, а терминология должна совпадать в iOS-приложении, на сайте и в Android-приложении, используйте CLI от General Translation — `gt`: он переводит файлы `.xcstrings` на месте (`gt` версии 2.21.0 или новее). Добавьте в `gt.config.json` запись `xcstrings`, которая напрямую указывает на каждый каталог:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "ja"],
  "files": {
    "xcstrings": {
      "include": ["Resources/Localizable.xcstrings", "Resources/InfoPlist.xcstrings"]
    }
  }
}
```

Все локали хранятся в одном файле, поэтому пути в `include` не содержат плейсхолдера `[locale]`, а значение `sourceLanguage` в каталоге должно совпадать с `defaultLocale`, иначе запуск прервётся до загрузки. Войдите с помощью [`npx gt login`](/docs/cli/reference/commands/login), задайте `GT_PROJECT_ID` ([учётные данные CLI](/docs/cli/guides/configuring#credentials)) и, если приложение уже существует, импортируйте исходные строки и проверенные переводы с помощью [`npx gt upload`](/docs/cli/reference/commands/upload). Затем выполните [`npx gt translate`](/docs/cli/reference/commands/translate), чтобы сгенерировать обновления. В CI сохраните ключ API проекта с правами **Files &gt; Write** и **Translation queue &gt; Enabled** в переменной `GT_API_KEY`.

CLI загружает только часть файла на исходном языке, а затем выполняет слияние каждой целевой локали обратно в файл, не затрагивая остальные локали и структуру каталога. При обработке String Catalog для вариаций применяются категории множественного числа языка перевода, а спецификаторы формата и подстановки сохраняются. (См. [справочник по `.xcstrings`](/docs/cli/reference/formats/xcstrings-files).) Для устаревшей структуры используйте ключи `dotStrings` и `dotStringsdict` — с ними переводятся файлы `.strings` и [`.stringsdict`](/docs/cli/reference/formats/dot-stringsdict-files).

Проверяйте каталог в Xcode или в [редакторе исходных файлов](/docs/platform/dashboard/guides/reviewing-translations) на панели управления. Если вы редактируете переводы в Xcode, выполните [`npx gt save-local`](/docs/cli/reference/commands/save-local), чтобы последующие запуски не перезаписали ваши правки. Назначьте одну [контекстную группу](/docs/platform/dashboard/guides/defining-context-for-translations) проектам для iOS, веба и [Android](/docs/cli/reference/formats/android-strings-files) — и термины из Glossary, например названия ваших тарифов, будут одинаковыми во всех областях взаимодействия с пользователем.

Ramp использует GT для более чем 11 локалей в панели управления, на лендинге и в iOS-приложении — наглядный пример того, как одна платформа перевода обслуживает и веб-, и нативные продукты. (См. [развёртывания в рабочей среде](https://generaltranslation.com/enterprise).)

## Основные выводы

* После добавления `Localizable.xcstrings` выполните сборку один раз: Xcode извлекает литералы SwiftUI и текст из `String(localized:)`, но не `Text`, созданный из переменной типа `String`.
* Для количественных значений используйте **Vary by Plural**: Xcode добавляет категории множественного числа для каждого языка — например, для русского их четыре.
* Переведённые строки, удалённые из кода, не исчезают, а получают статус **Stale**, поэтому удаляйте их вручную и осознанно.
* В Xcode 27 появились перевод с помощью агента, состояние **Machine Translated** и `leveraged-mt` в экспортируемых файлах XLIFF.
* CLI General Translation переводит каталог на месте с помощью `"xcstrings": { "include": [...] }` и [`npx gt translate`](/docs/cli/reference/commands/translate): остальные локали и структура каталога сохраняются, а для целевых языков создаются варианты.

## Related questions

- [Что такое псевдолокализация?](https://generaltranslation.com/ru/kb/pseudo-localization.mdx): Псевдолокализация — это тест, при котором исходный текст заменяется изменённой версией с диакритикой, удлинённой примерно на 40% и заключённой в скобки. Так жёстко закодированные строки, усечение, проблемы со шрифтами и склеенные из фрагментов предложения выявляются ещё до появления перевода. В Android для этого предусмотрены псевдолокали en-XA и ar-XB.
- [Как найти захардкоженные строки, которые не переведены?](https://generaltranslation.com/ru/kb/find-hardcoded-strings.mdx): Запустите в CI линтер, который находит строковые литералы, видимые пользователю, — например, правило no-literal-string из eslint-plugin-i18next для JSX, проверку HardcodedText в Android Lint или линтер HardCodedString из erb_lint для Rails. Затем пройдитесь по приложению в псевдолокали, чтобы найти текст, который статические проверки отследить не могут.
- [Как поддержать RTL-языки (right-to-left) в CSS?](https://generaltranslation.com/ru/kb/right-to-left-css.mdx): Укажите dir="rtl" и lang на элементе html — сам по себе lang не меняет направление письма, — а затем замените физические CSS-свойства вроде margin-left логическими, например margin-inline-start. Flex-строки, grid-столбцы и выравнивание текста по умолчанию зеркалятся автоматически, а translateX(), left и right — нет.
- [General Translation или TMS (Crowdin, Lokalise, Phrase)](https://generaltranslation.com/ru/kb/general-translation-vs-tms.mdx): Выбирайте General Translation, если разработчикам нужны генерация переводов, контекст из кода и проверка, привязанные к релизам продукта. Сохраните существующие каталоги и библиотеку рендеринга или пишите встроенный JSX без ключей перевода. TMS подходит для программ, построенных вокруг языковых поставщиков, CAT-редакторов и обмена XLIFF; её интеграции могут автоматизировать передачу файлов.

## Previous and next questions

- Previous question: [Интернационализация и локализация (i18n и l10n)](https://generaltranslation.com/ru/kb/internationalization-vs-localization.mdx)
- Next question: [Как называть ключи переводов i18n?](https://generaltranslation.com/ru/kb/i18n-key-naming.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ru/kb/sitemap.md) for every article.
