Skip to main content

Комплетан водич за Flutter локализацију

Од ARB датотека до RTL подршке: локализујте Flutter апликацију помоћу easy_localization, обрадите множине за сваки језик и аутоматизујте преводе помоћу AI технологије.

1

Инсталирајте easy_localization

Додајте пакет easy_localization у pubspec.yaml. То је најпопуларнији Flutter i18n пакет, са подршком за 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 — сва су доступна преко проширења контекста.

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

Подржите RTL језике

Flutter аутоматски пресликава цео распоред када се локал пише здесна налево (арапски, хебрејски, персијски, урду). Али Ваш код мора да користи виџете и својства која разумеју смер како би пресликавање исправно радило. Замените директно уписано лево/десно еквивалентима почетак/крај.

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 датотеке помоћу AI технологије. У IDE окружењу затражите од AI помоћника да преведе изворну 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 lint алатком пре отклањања проблема са преводом.

Измене превода се не појављују након hot reload поступка

easy_localization кешира преводе у меморији. Додавање нових кључева или измена постојећих превода може да захтева потпуни hot restart (не hot reload) да ступи на снагу. Током развоја користите hot restart (Shift+R) након уређивања датотека превода.

Директно уписано лево/десно нарушава 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 →

Честа питања