# General Translation Knowledge Base: Как локализовать Android-приложение с помощью strings.xml?
URL: https://generaltranslation.com/ru/kb/localize-android-app.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Храните все строки по умолчанию в res/values/strings.xml, добавьте strings.xml для каждого языка в папку с квалификатором локали, например values-es или values-b+zh+Hant+TW, и получайте текст через stringResource или getString. Переводите вручную, в Play Console или с помощью CLI от General Translation, который создаёт все папки values и заново формирует формы множественного числа для каждого языка перевода.
Category: Интернационализация
Last updated: 2026-10-28
Authors: General Translation Team
Published: 2026-10-28

Android выбирает ресурсы во время выполнения из папок, названия которых соответствуют локали устройства. Текст по умолчанию хранится в `res/values/strings.xml`, а каждый перевод — это отдельный `strings.xml` с теми же именами ресурсов в папке вроде `res/values-es/`. Остаётся решить две задачи: вынести все видимые пользователю строки в `strings.xml` и разместить качественные переводы в папке каждого языка.

## Настройка строковых ресурсов

### Поместите все строки в res/values/strings.xml

Файл по умолчанию должен содержать все строки, которые использует приложение: если какой-либо строки не хватает, приложение «не запускается и выдаёт ошибку» — так сказано в руководстве Android по локализации. Переведённый файл может содержать лишь подмножество строк, а вместо любой отсутствующей в нём строки используется значение из файла по умолчанию ([Android: Localize your app](https://developer.android.com/guide/topics/resources/localization)).

Ниже приведён файл по умолчанию со всеми нужными шаблонами, каждый из которых снабжён комментарием:

```xml title="res/values/strings.xml"
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- Кнопка, запускающая оплату товаров в корзине. -->
    <string name="checkout">Checkout</string>

    <!-- Позиционные аргументы позволяют менять порядок значений в переводе. -->
    <plurals name="welcome">
        <item quantity="one">Hi %1$s, you have %2$d new message.</item>
        <item quantity="other">Hi %1$s, you have %2$d new messages.</item>
    </plurals>

    <!-- Экранируйте апострофы, иначе сборка завершится с ошибкой. -->
    <string name="cart_empty">Your cart\'s empty</string>

    <!-- xliff:g помечает текст, который не нужно переводить. -->
    <string name="countdown"><xliff:g id="time" example="5 days">%1$s</xliff:g> until your trial ends</string>

    <plurals name="items_in_cart">
        <item quantity="one">%d item</item>
        <item quantity="other">%d items</item>
    </plurals>

    <string-array name="sort_options">
        <item>Newest</item>
        <item>Price: low to high</item>
    </string-array>
</resources>
```

В Compose получайте их с помощью `stringResource`, `pluralStringResource` и `stringArrayResource`, а при работе с Views — через `context.getString` и `resources.getQuantityString` ([Android: String resources](https://developer.android.com/guide/topics/resources/string-resource)). Для форм множественного числа сначала передайте количество, по которому выбирается форма, а затем значения для заполнителей, включая само количество.

```kotlin
val greeting = pluralStringResource(R.plurals.welcome, count, name, count)
val cart = pluralStringResource(R.plurals.items_in_cart, count, count)
val sortOptions = stringArrayResource(R.array.sort_options)
```

В приложениях React Native этот файл тоже есть: в `strings.xml` из шаблона, который лежит в `android/app/src/main/res/values/`, хранится `app_name` — подпись, которую Android показывает под значком. UI на JavaScript при этом переводится отдельно. (См. [Как перевести приложение React Native?](/kb/translate-react-native-app).)

### Создайте папку для каждого языка

Имя языковой папки состоит из `values-` и квалификатора ресурса. Язык задаётся кодом ISO 639-1, регион — с префиксом `r` в нижнем регистре, а для всего, что содержит письменность или числовой регион, используется форма BCP 47: `b+`, за которым следуют подтеги, соединённые через `+`. Эта форма поддерживается начиная с Android 7.0 (API 24) ([Android: App resources overview](https://developer.android.com/guide/topics/resources/providing-resources)):

| Язык                              | Код локали   | Папка                      |
| --------------------------------- | ------------ | -------------------------- |
| Испанский                         | `es`         | `res/values-es/`           |
| Португальский (Бразилия)          | `pt-BR`      | `res/values-pt-rBR/`       |
| Испанский (Латинская Америка)     | `es-419`     | `res/values-b+es+419/`     |
| Китайский (традиционный, Тайвань) | `zh-Hant-TW` | `res/values-b+zh+Hant+TW/` |

Создавайте региональную папку только для строк, которые отличаются. В примере из документации Android весь английский текст хранится в `values/`, а в `values-en-rGB/` — только британские варианты написания; для всего остального срабатывает откат к базовым ресурсам. (См. [Что такое коды локалей?](/kb/locale-codes))

### Пишите строки, которые переводчики не смогут сломать

Эти правила из [руководства Android по строковым ресурсам](https://developer.android.com/guide/topics/resources/string-resource) не позволят переводу сломать сборку или грамматику:

* **Формы множественного числа подчиняются грамматике каждого языка.** Доступны категории `zero`, `one`, `two`, `few`, `many` и `other`, но каждый язык использует только те, которые нужны его грамматике: английский игнорирует `zero` даже для 0, а китайский и корейский используют только `other`. Не используйте `<plurals>` как оператор `if` для случая «нет элементов» — создайте для него отдельную строку.
* **Используйте позиционные аргументы.** `%1$s` и `%2$d` позволяют переводчику поставить имя после числа, если этого требует порядок слов в языке перевода.
* **Экранируйте апострофы и кавычки.** Пишите `\'` или заключайте всю строку в двойные кавычки, а для буквальной кавычки используйте `\"`. Начальные `@` или `?` экранируйте как `\@` и `\?`, иначе Android воспримет значение как ссылку на ресурс.
* **Защищайте то, что не должно меняться.** Оборачивайте заполнители и URL в `<xliff:g>` с атрибутами `id` и `example`, как в строке обратного отсчёта ([Android: Localize your app](https://developer.android.com/guide/topics/resources/localization)).
* **Помечайте ресурсы, которые не нужно переводить.** Добавьте `translatable="false"` к таким значениям, как название приложения, или перенесите их в файл `donottranslate.xml`.
* **Оставляйте комментарии.** Комментарий над ресурсом подскажет переводчикам, где отображается текст и сколько для него места. Слово «Checkout» само по себе может быть как существительным, так и глаголом.

## Как позволить пользователям выбрать язык приложения

Начиная с Android 13 (API 33), пользователи могут задать язык для отдельного приложения в системных настройках, если приложение объявляет поддерживаемые языки. Включите `generateLocaleConfig`, и Android Gradle Plugin (AGP) 8.1 или новее будет формировать список языков из ваших папок `values-*` во время сборки. Для этого нужны `compileSdk` 33 или выше и файл `res/resources.properties`, в котором указана локаль папки по умолчанию, например `unqualifiedResLocale=en-US`. Если вы предпочитаете перечислить языки вручную, добавьте файл `res/xml/locale_config.xml` и укажите путь к нему в атрибуте `android:localeConfig` в манифесте. Если использовать оба способа одновременно, сборка завершится с ошибкой ([Android: Per-app language preferences](https://developer.android.com/guide/topics/resources/app-languages)).

```kotlin title="app/build.gradle.kts"
android {
    androidResources {
        generateLocaleConfig = true
    }
}
```

Чтобы реализовать элемент выбора языка внутри приложения, используйте AppCompat 1.6.0 или новее и вызывайте `setApplicationLocales` в главном потоке. Этот вызов пересоздаёт activity, поэтому при использовании Compose activity должна наследоваться от `AppCompatActivity`:

```kotlin
// Вызывайте в главном потоке: Activity может быть перезапущена.
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags("es"))
```

На Android 12 и более ранних версиях AppCompat может сохранять выбор пользователя автоматически, если добавить в манифест его `AppLocalesMetadataHolderService` с параметром `autoStoreLocales`, равным `true`. (О дизайне элемента выбора языка см. [Рекомендации по переключателю языка](/kb/language-switcher).)

## Поиск отсутствующих и захардкоженных строк

**Translations Editor** в Android Studio показывает все ключи в виде таблицы — по одному столбцу на каждый язык — и выделяет проблемы красным. Щёлкните правой кнопкой мыши по `strings.xml` и выберите **Open Translations Editor**. Значок глобуса добавляет язык и создаёт для него папку `values-*`, а флажок **Untranslatable** автоматически проставляет `translatable="false"` ([Android: Translations Editor](https://developer.android.com/studio/write/translations-editor)).

В CI те же проверки выполняет Android Lint:

* [`MissingTranslation`](https://googlesamples.github.io/android-custom-lint-rules/checks/MissingTranslation.md.html) (error) сообщает о строке, для которой нет перевода на какой-либо язык. Чтобы отключить проверку для отдельного ресурса, используйте `tools:ignore="MissingTranslation"`, а в файле по умолчанию задайте `tools:locale` для элемента `<resources>`, чтобы lint знал, на каком он языке.
* [`ExtraTranslation`](https://googlesamples.github.io/android-custom-lint-rules/checks/ExtraTranslation.md.html) (fatal) сообщает о переведённой строке, у которой нет значения по умолчанию, — в локалях без этой строки приложение может аварийно завершиться.
* [`HardcodedText`](https://googlesamples.github.io/android-custom-lint-rules/checks/HardcodedText.md.html) (warning) сообщает о литеральном тексте в XML-файлах компоновки. Вызовы Compose `Text("...")` эта проверка не обнаруживает. (См. [Как найти непереведённые захардкоженные строки?](/kb/find-hardcoded-strings).)

## Тестируйте все языки

В Android есть две псевдолокали, позволяющие тестировать приложение ещё до появления переводов. `en-XA` добавляет диакритические знаки, удлиняет текст и заключает каждое сообщение в скобки — так сразу видны усечение и предложения, склеенные из частей. `ar-XB` переключает направление текста на right-to-left. Установите `isPseudoLocalesEnabled = true` для типа сборки debug, включите на устройстве параметры разработчика и выберите псевдолокаль в языковых настройках ([Android: Test with pseudolocales](https://developer.android.com/guide/topics/resources/pseudolocales)). (См. [Что такое псевдолокализация?](/kb/pseudo-localization).)

Для арабского, иврита и персидского установите `android:supportsRtl="true"` для элемента `<application>` и используйте атрибуты `start` и `end` (`paddingStart`, `layout_marginEnd`) вместо `left` и `right`, чтобы компоновка отражалась зеркально. Добавьте `android:autoMirrored="true"` к направленным drawable-ресурсам и оборачивайте любое значение, вставляемое в предложение, в `BidiFormatter.unicodeWrap()`, чтобы адрес или число сохраняли своё направление письма ([Android: Support different languages and cultures](https://developer.android.com/training/basics/supporting-devices/languages)). В Compose `@Preview(locale = "ar")` показывает предпросмотр экрана в режиме right-to-left. (Версию для веба см. в статье [Как поддержать RTL-языки (right-to-left) в CSS?](/kb/right-to-left-css).)

Страница приложения в Google Play переводится отдельно. В Play Console откройте страницу приложения, нажмите **Manage translations** и добавьте для каждого языка собственное название, краткое и полное описание, а также локализованные изображения ([Play Console Help: Translate and localize your app](https://support.google.com/googleplay/android-developer/answer/9844778)).

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

Папки `values-*` можно заполнить одним из следующих способов:

| Подход                                                                 | Кто переводит                            | Какой контекст получает переводчик                                        | Можно повторять при каждом релизе                                                 | Что остаётся на вас                                                                                                        |
| ---------------------------------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Ввод вручную в Translations Editor                                     | Вы или коллега, владеющий обоими языками | Всё приложение                                                            | Нет                                                                               | Каждая строка на каждом языке, вручную                                                                                     |
| Перевод строк приложения в Play Console                                | Модели Gemini в Play Console, бесплатно  | Ваш `strings.xml`                                                         | Да, для каждого бандла, загруженного в черновик релиза                            | Переводы хранятся в Play, а не в вашем репозитории, и заменяют существующие для выбранных языков                           |
| Отправка файлов переводчикам или в систему управления переводами (TMS) | Профессиональные переводчики             | Комментарии и прикреплённые вами скриншоты                                | Через синхронизацию TMS                                                           | Отдельный цикл передачи и возврата файлов на каждый релиз и ожидание результата                                            |
| Скрипт машинного перевода или LLM для обработки XML                    | Модель или API перевода                  | То, что отправляет ваш скрипт                                             | Да                                                                                | Категории множественного числа для каждого языка, экранирование, элементы `<xliff:g>`, аргументы форматирования и проверка |
| General Translation CLI                                                | Сервис перевода GT                       | Комментарии к ресурсам, а также общие Glossary и пользовательские промпты | Запускайте [`gt translate`](/docs/cli/reference/commands/translate) перед сборкой | Проверка в панели управления или Android Studio, затем тестирование приложения                                             |

Play Console также умеет переводить само приложение: если включить перевод строк приложения, для каждого бандла приложения, загруженного в черновик релиза, будут генерироваться переводы на основе последней версии его `strings.xml`. Их можно просмотреть в эмуляторе и отредактировать перед публикацией. При выборе языка все уже имеющиеся переводы на этот язык заменяются, а с помощью флажка **Translate** можно исключить отдельные строки ([Справка Play Console](https://support.google.com/googleplay/android-developer/answer/9844778)).

Translations Editor подойдёт для одного-двух языков, которыми вы владеете. Перевод в Play Console удобен, если вы публикуете приложение через Google Play и переводы не нужны в кодовой базе. Выбирайте General Translation, если переведённые файлы `strings.xml` должны коммититься с каждым релизом, а терминология — совпадать с вашим iOS-приложением и сайтом. Используйте [TMS](/kb/what-is-a-translation-management-system), если переводом занимаются профессиональные переводчики или уже привлечённый подрядчик.

## Перевод strings.xml с помощью General Translation

CLI от General Translation — `gt` — переводит строковые ресурсы Android с помощью файлового ключа `androidStrings` (`gt` версии 2.19.0 или новее). В пути к файлу по умолчанию локаль не указана, поэтому укажите этот файл в `include`, а с помощью `transform` направьте каждый перевод в папку соответствующего языка:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "pt-BR", "zh-Hant-TW"],
  "files": {
    "androidStrings": {
      "include": ["app/src/main/res/values/strings.xml"],
      "transform": {
        "match": "res/values/(.*)",
        "replace": "res/values-{locale}/$1"
      }
    }
  }
}
```

CLI преобразует каждую локаль в квалификатор, который ожидает Android, поэтому с этой конфигурацией создаются `values-es/`, `values-pt-rBR/` и `values-b+zh+Hant+TW/`. Не используйте паттерн `values-[locale]` в стандартном проекте: он ищет папку `values-en/`, ничего не находит и ничего не переводит.

Для работы CLI нужен Node.js 20 или новее. Установите его, как описано в разделе [Быстрый старт CLI](/docs/cli/quickstart), войдите с помощью [`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`.

В переведённых файлах сохраняются имена ресурсов, элементы `<xliff:g>`, аргументы форматирования и встроенная разметка. Каждая переведённая строка проверяется на их наличие, а также на экранирование апострофов и кавычек, которого требует сборка Android. `<plurals>` перестраиваются под категории языка перевода: для польского создаются `one`, `few`, `many` и `other`, для арабского — все шесть, для китайского — только `other`. Категории, которые в языке не используются, включая `zero` из исходного файла, удаляются. Комментарий над ресурсом передаётся как контекст. CLI не переводит ресурсы с пометкой `translatable="false"`, значения, ссылающиеся на другой ресурс, а также нетекстовые типы, например `<color>`. (См. [справочник по strings.xml](/docs/cli/reference/formats/android-strings-files).)

Ресурсы с пометкой `translatable="false"` во включённом файле копируются без изменений в каждый переведённый файл, и проверка Android Lint [`Untranslatable`](https://googlesamples.github.io/android-custom-lint-rules/checks/Untranslatable.md.html) выдаёт предупреждение на каждую копию. Храните такие значения в `res/values/donottranslate.xml`, а включайте только `strings.xml`.

Проверяйте переводы в [панели управления](/docs/platform/dashboard/guides/reviewing-translations) или в Android Studio. Если вы редактируете файлы локально, выполните [`npx gt save-local`](/docs/cli/reference/commands/save-local), чтобы последующие запуски не перезаписали ваши изменения. Назначьте одну [контекстную группу](/docs/platform/dashboard/guides/defining-context-for-translations) проектам для Android, [iOS](/kb/localize-ios-app) и веба — и термин из Glossary, например название тарифного плана, будет везде переводиться одинаково. Partiful использует General Translation для 2+ локалей в вебе, на iOS и Android ([развёртывания в рабочей среде](https://generaltranslation.com/enterprise)).

## Часто задаваемые вопросы

### Нужна ли папка values-en для английского языка?

Нет. Папка `values/` без квалификатора используется для всех локалей, на которые вы не переводите. Если включить `generateLocaleConfig`, файл `resources.properties` укажет сборке, какая локаль хранится в этой папке.

### Почему в переведённом приложении некоторые строки отображаются на английском?

В переведённом файле `strings.xml` нет этих имён, поэтому Android подставляет строки из `values/`. Проверка Lint `MissingTranslation` выводит их список для каждого языка.

### Переводит ли Google Play страницу приложения в магазине автоматически?

Пользователи, которые просматривают страницу приложения на языке, для которого вы не добавили перевод, могут включить её автоматический перевод. Если вы добавите собственные переводы в разделе **Manage translations**, они заменят автоматический перевод для соответствующих языков.

## Ключевые выводы

* Файл `res/values/strings.xml` должен содержать все строки; в папках с переводами может быть лишь подмножество строк, а для остальных используется этот файл.
* В именах папок используются квалификаторы: `values-pt-rBR` для региона, `values-b+zh+Hant+TW` для письменности.
* Используйте позиционные аргументы, например `%1$s`, экранируйте апострофы и позвольте каждому языку определять собственные категории `<plurals>`.
* Включите `generateLocaleConfig` (AGP 8.1+), чтобы поддержать выбор языка для отдельных приложений в Android 13, и тестируйте с псевдолокалями `en-XA` и `ar-XB`.
* CLI от General Translation переводит `strings.xml` с помощью `androidStrings` и `transform` в `values-{locale}`: он записывает квалификатор в формате, который ожидает Android, и заново формирует формы множественного числа для каждого языка.

## Related questions

- [Как локализовать iOS-приложение с помощью String Catalogs?](https://generaltranslation.com/ru/kb/localize-ios-app.mdx): Добавьте языки в Xcode, пишите текст для пользователей с помощью локализуемых API, таких как SwiftUI Text и String(localized:), и выполните сборку, чтобы Xcode собрал эти строки в String Catalog (.xcstrings). Переводите в Xcode, через XLIFF или с помощью CLI General Translation, если каталоги должны обновляться с каждым релизом и использовать общую терминологию с вашим сайтом и Android-приложением.
- [Как перевести приложение на React Native?](https://generaltranslation.com/ru/kb/translate-react-native-app.mdx): Разметьте текст в компонентах, сгенерируйте файл перевода для каждого языка, добавьте полифилы Intl и загружайте файл для языка устройства. С экспериментальной библиотекой gt-react-native от General Translation вы оборачиваете текст в `<T>`, Babel-плагин добавляет полифилы, а npx gt translate создаёт файлы.
- [Что такое псевдолокализация?](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 — нет.

## Previous and next questions

- Previous question: [Как добавить i18n в приложение Next.js на Pages Router?](https://generaltranslation.com/ru/kb/add-i18n-to-nextjs-pages-router.mdx)
- Next question: [Как обеспечить единообразие терминологии при ИИ-переводе?](https://generaltranslation.com/ru/kb/ai-translation-glossary.mdx)

## Sitemap

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