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().
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 и в уеб среда. Дефинирайте формите за множествено число чрез синтаксиса {count, plural, ...} във Вашите ARB файлове. Всеки език се нуждае от собствен набор от форми според правилата за множествено число на 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 пайплайн. Метаданните в 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, преди да отстранявате проблеми с превода.

Промените в превода не се показват след hot reload

easy_localization кешира преводите в паметта. След добавяне на нови ключове или промяна на съществуващи преводи може да е необходимо пълно hot restart, а не hot reload, за да влязат промените в сила. По време на разработката използвайте hot restart (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 →

Често задавани въпроси