Skip to main content

Повний посібник із локалізації Flutter

Від файлів ARB до підтримки RTL: локалізуйте свій застосунок Flutter за допомогою easy_localization, налаштуйте форми множини для кожної мови й автоматизуйте переклад за допомогою ШІ.

1

Установлення easy_localization

Додайте пакет easy_localization до pubspec.yaml. Це найпопулярніший пакет i18n для Flutter із підтримкою файлів ARB/JSON, форм множини та розширень контексту. Також додайте flutter_localizations із SDK для форматування дат і чисел та визначення напрямку тексту відповідно до локалі.

easy_localization надає розширення контексту, як-от context.tr() і 'key'.tr(), для стислого доступу до перекладів. Пакет керує завантаженням і збереженням локалі, а також гарячим перезавантаженням файлів перекладу під час розроблення.
pubspec.yaml
dependencies:
  easy_localization: ^3.0.7
  flutter_localizations:
    sdk: flutter
2

Створення файлів перекладу ARB

Файли Application Resource Bundle (ARB) — стандартний формат локалізації для Flutter. Кожен файл містить пари «ключ — значення» та необов’язкові метадані з описом заповнювачів, правил множини й контексту для перекладачів. Створіть окремий файл для кожної локалі в каталозі assets/translations.

assets/translations/en.arb
{
  "@@locale": "en",
  "appTitle": "My App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "greeting": "Hello, {name}!",
  "@greeting": {
    "description": "Greeting with user name",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "num",
        "format": "compact"
      }
    }
  }
}
Ключі з префіксом @ (наприклад, @greeting) — це метадані, що описують рядок над ними. Додавайте типи та приклади заповнювачів, щоб перекладачі могли створювати точні переклади. Під час виконання ці ключі метаданих видаляються й не створюють жодного додаткового навантаження.
3

Налаштування застосунку

Огорніть свій застосунок віджетом EasyLocalization. Він керує станом локалі, завантажує переклади з файлів ресурсів і надає делегати локалі, потрібні MaterialApp. Три обов’язкові властивості делегатів — localizationsDelegates, supportedLocales і locale — доступні через розширення context.

lib/main.dart
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();

  runApp(
    EasyLocalization(
      supportedLocales: [
        Locale('en'),
        Locale('ar'),
        Locale('ja'),
        Locale('de'),
      ],
      path: 'assets/translations',  // Path to your ARB/JSON files
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      home: HomePage(),
    );
  }
}
"Easy Localization not initialized" — ця помилка означає, що Ви забули викликати EasyLocalization.ensureInitialized() до runApp(). Після WidgetsFlutterBinding.ensureInitialized() і до runApp() цей виклик потрібно виконати з await.
4

Переклад віджетів

Щоб отримати перекладений текст у будь-якому віджеті, застосуйте метод розширення .tr() до рядкового ключа. Для форм множини використовуйте .plural() зі значенням кількості. easy_localization підтримує як синтаксис розширення рядка ('key'.tr()), так і синтаксис методу контексту (context.tr('key')).

lib/widgets/home_page.dart
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('appTitle'.tr()),   // Simple key
      ),
      body: Column(
        children: [
          // String with variable interpolation
          Text('greeting'.tr(args: ['Alice'])),

          // Named arguments
          Text('greeting'.tr(namedArgs: {'name': 'Alice'})),

          // Plural form
          Text('itemCount'.plural(3)),
        ],
      ),
    );
  }
}
Якщо замість перекладів повертаються необроблені ключі, перевірте: 1) віджет EasyLocalization має огортати MaterialApp, а не навпаки; 2) файли перекладу оголошено в pubspec.yaml у розділі assets; 3) шлях до файлів у EasyLocalization відповідає фактичній структурі каталогів.
5

Опрацювання форм множини та змінних

Flutter використовує ICU MessageFormat для форм множини — той самий стандарт, що й iOS, Android та вебсередовище. Визначайте форми множини у файлах ARB за допомогою синтаксису {count, plural, ...}. Кожна мова потребує власного набору форм відповідно до правил множини CLDR. Арабська має 6 форм, російська — 4, а японська — 1.

Plural forms by language
// English: 3 useful forms (=0, =1, other)
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}"

// Arabic: 6 forms (=0, =1, =2, few, many, other)
"itemCount": "{count, plural, =0{لا عناصر} =1{عنصر واحد} =2{عنصران} few{{count} عناصر} many{{count} عنصرًا} other{{count} عنصر}}"

// Japanese: 1 form (other)
"itemCount": "{count, plural, other{{count}個のアイテム}}"

// German: 2 forms (=1, other)
"itemCount": "{count, plural, =1{1 Artikel} other{{count} Artikel}}"

// Russian: 3 forms (one, few, many)
"itemCount": "{count, plural, =0{Нет товаров} one{{count} товар} few{{count} товара} many{{count} товаров} other{{count} товаров}}"
Variables and named arguments
// Simple variable
"welcome": "Welcome, {name}!"

// Multiple variables
"orderStatus": "Order #{orderId} — {status}"

// Variable in plural context
"unreadMessages": "{count, plural, =0{No unread messages} =1{1 unread message from {sender}} other{{count} unread messages}}"

// In widgets:
Text('welcome'.tr(namedArgs: {'name': userName}));
Text('orderStatus'.tr(namedArgs: {'orderId': '1234', 'status': 'Shipped'}));
Text('unreadMessages'.plural(count, namedArgs: {'sender': senderName}));
Ніколи не прописуйте логіку однини та множини вручну за допомогою if (count == 1). У французькій 0 вважається одниною. У російській, польській та арабській є форми множини, яких узагалі немає в англійській. Завжди використовуйте синтаксис множини ICU, щоб фреймворк сам вибирав правильну форму.
6

Підтримка мов із напрямком письма справа наліво

Flutter автоматично дзеркально відображає все компонування, якщо локаль використовує напрямок письма справа наліво (арабська, іврит, перська, урду). Проте для правильного відображення у Вашому коді мають використовуватися віджети та властивості, що враховують напрямок письма. Замініть жорстко задані left/right відповідниками start/end.

lib/widgets/adaptive_layout.dart
import 'package:flutter/material.dart';

class AdaptiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final isRtl = Directionality.of(context) == TextDirection.rtl;

    return Scaffold(
      body: Row(
        children: [
          // Use start/end instead of left/right
          Expanded(
            child: Padding(
              padding: EdgeInsetsDirectional.only(
                start: 16.0,  // Leading edge (left in LTR, right in RTL)
                end: 8.0,     // Trailing edge
              ),
              child: Text('content'.tr()),
            ),
          ),
          // Flip icons for RTL
          Icon(
            isRtl ? Icons.arrow_back : Icons.arrow_forward,
          ),
        ],
      ),
    );
  }
}
RTL-aware widget patterns
// Use Directional widgets for RTL-aware layouts
EdgeInsetsDirectional.only(start: 16, end: 8)   // Not EdgeInsets.only(left: 16, right: 8)
AlignmentDirectional.centerStart                  // Not Alignment.centerLeft
BorderRadiusDirectional.only(topStart: Radius.circular(8))

// Automatically mirrors when locale changes to Arabic, Hebrew, etc.
// No conditional logic needed — Flutter handles text direction from locale
Перевірте RTL, тимчасово встановивши для застосунку арабську локаль (Locale('ar')). Flutter дзеркально відобразить увесь інтерфейс: навігаційні панелі відкриватимуться справа, стрілки повернення змінять напрямок, а текст вирівнюватиметься праворуч. Використовуйте EdgeInsetsDirectional, AlignmentDirectional і BorderRadiusDirectional, щоб власні компонування правильно віддзеркалювалися.
7

Розумні ланцюжки резервних локалей

За замовчуванням, якщо перекладу pt-BR немає, Flutter переходить безпосередньо на англійську, пропускаючи цілком придатні переклади pt-PT. Пакет locale_chain розв’язує цю проблему за допомогою налаштовуваних ланцюжків резервних локалей. Один рядок налаштування, жодної міграції — Ваші наявні виклики .tr() просто працюють.

lib/main.dart with LocaleChain
import 'package:locale_chain/locale_chain.dart';
import 'package:locale_chain/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  LocaleChain.configure();  // Enable smart fallback chains

  runApp(
    EasyLocalization(
      supportedLocales: [
        Locale('en'),
        Locale('pt', 'BR'),
        Locale('pt', 'PT'),
        Locale('es'),
        Locale('es', 'MX'),
      ],
      path: 'assets/translations',
      assetLoader: LocaleChainAssetLoader(  // Swap in the chain loader
        baseLoader: RootBundleAssetLoader(),
      ),
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

// Result: pt-BR user sees pt-PT translations when pt-BR keys are missing,
// instead of falling back directly to English.
Custom fallback configuration
// Override specific chains while keeping built-in defaults
LocaleChain.configure(
  fallbacks: {
    'pt-BR': ['pt-PT', 'pt'],      // pt-BR → pt-PT → pt → en
    'es-MX': ['es-419', 'es'],     // es-MX → es-419 → es → en
    'fr-CA': ['fr'],               // fr-CA → fr → en
  },
);

// Or replace all defaults with your own chains
LocaleChain.configure(
  fallbacks: {
    'zh-Hant-HK': ['zh-Hant-TW', 'zh-Hans'],
    'pt-BR': ['pt-PT', 'pt'],
  },
  mergeDefaults: false,  // Only your chains, no built-in defaults
);
locale_chain містить вбудовані ланцюжки резервних локалей для регіональних варіантів португальської, іспанської, французької, німецької, італійської, нідерландської, норвезької та малайської мов. Користувач із локаллю pt-BR побачить вміст pt-PT раніше за англійський. Користувач із локаллю es-MX спершу побачить es-419, потім es і лише тоді стандартну локаль.
8

Автоматизація перекладу

Завершивши налаштування локалізації, перекладіть файли ARB за допомогою ШІ. Попросіть ШІ-помічника у Вашому IDE перекласти вихідний файл ARB або скористайтеся i18n Agent CLI у своєму CI/CD pipeline. Метадані ARB (заповнювачі, описи) надають контекст, що покращує якість перекладу.

Terminal
# In your IDE, ask your AI assistant:
> Translate assets/translations/en.arb to Arabic, Japanese, and German

✓ ar.arb created (1.4s)
✓ ja.arb created (1.2s)
✓ de.arb created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate assets/translations/en.arb --lang ar,ja,de
Перекладайте поступово: додаючи нові ключі до вихідного файлу ARB, перекладайте лише різницю замість повторного створення всіх файлів. Так Ви збережете переклади, перевірені людиною, і цілісність метаданих ARB.

Автоматизація контролю якості перекладу

Виявляйте відсутні ключі та пошкоджені заповнювачі до випуску за допомогою i18n-validate. Тестуйте інтерфейс із псевдоперекладами через i18n-pseudo, перш ніж будуть готові справжні переклади.

Поширені помилки

Файли перекладу не знайдено під час виконання

Файли ARB/JSON потрібно оголосити в pubspec.yaml у розділі assets. Якщо пропустити цей крок, Flutter не зможе знайти файли під час виконання, навіть якщо вони є на диску. Додайте: assets: - assets/translations/

Неприпустимий синтаксис файлу ARB

Файли ARB — це JSON із суворим синтаксисом: без кінцевих ком, одинарних лапок і коментарів. Одна синтаксична помилка без повідомлення унеможливлює завантаження всього файлу. Перш ніж діагностувати проблеми з перекладом, перевірте файли ARB за допомогою лінтера JSON.

Зміни перекладу не з’являються після гарячого перезавантаження

easy_localization кешує переклади в пам’яті. Після додавання нових ключів або зміни наявних перекладів може знадобитися повний гарячий перезапуск (а не гаряче перезавантаження). Під час розроблення виконуйте гарячий перезапуск (Shift+R) після редагування файлів перекладу.

Жорстко задані left/right порушують RTL

Використання EdgeInsets.only(left: 16) замість EdgeInsetsDirectional.only(start: 16) заважає Flutter дзеркально відображати компонування для мов RTL. Знайдіть у кодовій базі EdgeInsets, Alignment і BorderRadius без суфікса Directional.

Рекомендована структура файлів

Project Structure
my_flutter_app/
├── assets/
│   └── translations/
│       ├── en.arb          # Source language (English)
│       ├── ar.arb          # Arabic (with 6 plural forms)
│       ├── de.arb          # German
│       ├── ja.arb          # Japanese
│       ├── pt-BR.arb       # Brazilian Portuguese
│       └── pt-PT.arb       # European Portuguese
├── lib/
│   ├── main.dart           # App entry with EasyLocalization
│   ├── app.dart            # MaterialApp with locale delegates
│   └── widgets/
│       └── language_switcher.dart
├── pubspec.yaml            # Dependencies
└── analysis_options.yaml

Спробуйте i18n Agent зараз

Перетягніть сюди файл для перекладу

JSON, YAML, PO, XML, CSV, Markdown, Properties

або натисніть, щоб вибрати

Цільові мови

Реєстрація не потрібнаМиттєвий розрахунок

Резервний пошук локалі за допомогою locale_chain

Якщо ключа перекладу немає в регіональній локалі, наприклад pt-BR, Flutter відразу переходить до мови шаблону замість того, щоб спочатку перевірити батьківську локаль pt.

Terminal
flutter pub add locale_chain
Configuration
import 'package:locale_chain/locale_chain.dart';

LocaleChain.configure(fallbacks: {
  'pt-BR': ['pt', 'en'],
  'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
});

LocaleChainAssetLoader(baseLoader: RootBundleAssetLoader());

Перегляньте наш посібник із резервного пошуку локалі, щоб отримати повний перелік підтримуваних фреймворків і 75 вбудованих ланцюжків. Learn more →

Поширені запитання