Skip to main content

Ο πλήρης οδηγός τοπικοποίησης Flutter

Από τα αρχεία ARB έως την υποστήριξη RTL: τοπικοποιήστε την εφαρμογή Flutter με το easy_localization, χειριστείτε σωστά τους πληθυντικούς κάθε γλώσσας και αυτοματοποιήστε τις μεταφράσεις με AI.

1

Εγκαταστήστε το easy_localization

Προσθέστε το πακέτο easy_localization στο pubspec.yaml. Είναι το δημοφιλέστερο πακέτο i18n για Flutter και υποστηρίζει αρχεία ARB/JSON, πληθυντικούς αριθμούς και επεκτάσεις context. Προσθέστε επίσης το flutter_localizations από το SDK, ώστε οι ημερομηνίες, οι αριθμοί και η κατεύθυνση του κειμένου να μορφοποιούνται ανάλογα με το locale.

Το easy_localization παρέχει επεκτάσεις context, όπως context.tr() και 'key'.tr(), για συνοπτική πρόσβαση στις μεταφράσεις. Διαχειρίζεται τη φόρτωση και την αποθήκευση του locale, καθώς και το hot reload των αρχείων μετάφρασης κατά την ανάπτυξη.
pubspec.yaml
dependencies:
  easy_localization: ^3.0.7
  flutter_localizations:
    sdk: flutter
2

Δημιουργήστε αρχεία μετάφρασης ARB

Τα αρχεία Application Resource Bundle (ARB) αποτελούν την τυπική μορφή τοπικοποίησης για το Flutter. Κάθε αρχείο περιέχει ζεύγη κλειδιών-τιμών και προαιρετικά μεταδεδομένα που περιγράφουν placeholders, κανόνες πληθυντικού και πληροφορίες περιβάλλοντος για τους μεταφραστές. Δημιουργήστε ένα αρχείο ανά locale στον κατάλογο 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, είναι μεταδεδομένα — περιγράφουν τη συμβολοσειρά που προηγείται. Συμπεριλάβετε τύπους και παραδείγματα placeholders, ώστε οι μεταφραστές να παράγουν ακριβείς μεταφράσεις. Αυτά τα κλειδιά μεταδεδομένων αφαιρούνται κατά την εκτέλεση και δεν επιβαρύνουν καθόλου την απόδοση.
3

Διαμορφώστε την εφαρμογή

Περιβάλετε την εφαρμογή σας με το widget EasyLocalization. Διαχειρίζεται την κατάσταση του locale, φορτώνει τις μεταφράσεις από τα αρχεία πόρων και παρέχει τους delegates τοπικοποίησης που χρειάζεται το MaterialApp. Οι τρεις απαιτούμενες ιδιότητες delegate είναι οι 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(). Πρέπει να το καλέσετε με await μετά το WidgetsFlutterBinding.ensureInitialized() και πριν από το runApp().
4

Μεταφράστε τα widgets

Χρησιμοποιήστε τη μέθοδο επέκτασης .tr() στα κλειδιά συμβολοσειρών, για να λαμβάνετε μεταφρασμένο κείμενο σε οποιοδήποτε widget. Για πληθυντικούς αριθμούς, χρησιμοποιήστε τη .plural() με την τιμή count. Το easy_localization παρέχει τόσο τη σύνταξη επέκτασης συμβολοσειράς ('key'.tr()) όσο και τη σύνταξη μεθόδου context (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) Το widget EasyLocalization περιβάλλει το MaterialApp και όχι το αντίστροφο. 2) Τα αρχεία μετάφρασης έχουν δηλωθεί στο pubspec.yaml, στην ενότητα assets. 3) Η διαδρομή αρχείου στο EasyLocalization αντιστοιχεί στην πραγματική δομή καταλόγων σας.
5

Χειριστείτε πληθυντικούς και μεταβλητές

Το Flutter χρησιμοποιεί το ICU MessageFormat για τους πληθυντικούς αριθμούς — το ίδιο πρότυπο που χρησιμοποιείται επίσης σε iOS, Android και Web. Ορίστε τις μορφές πληθυντικού με τη σύνταξη {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 και αφήστε το framework να επιλέξει τη σωστή μορφή.
6

Υποστηρίξτε γλώσσες RTL

Το Flutter αντικατοπτρίζει αυτόματα ολόκληρη τη διάταξη, όταν το locale αντιστοιχεί σε γλώσσα με γραφή από δεξιά προς τα αριστερά, όπως τα Αραβικά, τα Εβραϊκά, τα Περσικά ή τα Ουρντού. Ωστόσο, για να λειτουργεί σωστά ο αντικατοπτρισμός, ο κώδικάς σας πρέπει να χρησιμοποιεί widgets και ιδιότητες που λαμβάνουν υπόψη την κατεύθυνση. Αντικαταστήστε τις σταθερές αναφορές σε αριστερά και δεξιά με τα αντίστοιχα 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 της εφαρμογής σε Αραβικά (Locale('ar')). Το Flutter αντικατοπτρίζει ολόκληρο το UI — τα συρτάρια πλοήγησης ανοίγουν από τα δεξιά, τα βέλη επιστροφής αντιστρέφονται και το κείμενο στοιχίζεται δεξιά. Χρησιμοποιήστε EdgeInsetsDirectional, AlignmentDirectional και BorderRadiusDirectional, ώστε οι προσαρμοσμένες διατάξεις σας να αντικατοπτρίζονται σωστά.
7

Έξυπνες αλυσίδες εναλλακτικών locale

Από προεπιλογή, όταν λείπει μια μετάφραση pt-BR, το Flutter καταφεύγει απευθείας στα Αγγλικά — παρακάμπτοντας τις απολύτως κατάλληλες μεταφράσεις pt-PT. Το πακέτο locale_chain διορθώνει το πρόβλημα με διαμορφώσιμες αλυσίδες εναλλακτικών locale. Μία γραμμή ρύθμισης, χωρίς καμία μετεγκατάσταση — οι υπάρχουσες κλήσεις .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 περιλαμβάνει ενσωματωμένες αλυσίδες εναλλακτικών locale για τις τοπικές παραλλαγές των Πορτογαλικών, Ισπανικών, Γαλλικών, Γερμανικών, Ιταλικών, Ολλανδικών, Νορβηγικών και Μαλαϊκών. Ένας χρήστης pt-BR θα βλέπει περιεχόμενο pt-PT πριν από το αγγλικό περιεχόμενο. Ένας χρήστης es-MX θα βλέπει πρώτα es-419, έπειτα es και στη συνέχεια το προεπιλεγμένο locale.
8

Αυτοματοποιήστε τις μεταφράσεις

Αφού ολοκληρώσετε τη ρύθμιση τοπικοποίησης, μεταφράστε τα αρχεία ARB με AI. Στο IDE σας, ζητήστε από τον βοηθό AI να μεταφράσει το αρχείο ARB προέλευσης ή χρησιμοποιήστε το i18n Agent CLI στο pipeline CI/CD. Τα μεταδεδομένα ARB, όπως τα placeholders και οι περιγραφές, παρέχουν πληροφορίες περιβάλλοντος που βελτιώνουν την ποιότητα της μετάφρασης.

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.

Αυτοματοποιήστε τον έλεγχο ποιότητας των μεταφράσεων

Εντοπίστε κλειδιά που λείπουν και κατεστραμμένα placeholders πριν φτάσουν στην παραγωγή με το i18n-validate. Δοκιμάστε το UI με ψευδομεταφράσεις μέσω του i18n-pseudo πριν γίνουν διαθέσιμες οι πραγματικές μεταφράσεις.

Συνηθισμένες παγίδες

Τα αρχεία μετάφρασης δεν βρίσκονται κατά την εκτέλεση

Τα αρχεία ARB/JSON πρέπει να δηλώνονται στο pubspec.yaml, στην ενότητα assets. Αν παραλείψετε αυτό το βήμα, το Flutter δεν θα μπορεί να εντοπίσει τα αρχεία κατά την εκτέλεση, παρόλο που υπάρχουν στον δίσκο. Προσθέστε: assets: - assets/translations/

Μη έγκυρη σύνταξη αρχείου ARB

Τα αρχεία ARB ακολουθούν αυστηρά τη σύνταξη JSON — δεν επιτρέπονται κόμματα στο τέλος, μονά εισαγωγικά ή σχόλια. Ένα μόνο συντακτικό σφάλμα εμποδίζει σιωπηρά τη φόρτωση ολόκληρου του αρχείου. Επικυρώστε τα αρχεία ARB με ένα JSON linter πριν διερευνήσετε προβλήματα μετάφρασης.

Οι αλλαγές μετάφρασης δεν εμφανίζονται με hot reload

Το easy_localization αποθηκεύει τις μεταφράσεις στην cache της μνήμης. Η προσθήκη νέων κλειδιών ή η αλλαγή υπαρχουσών μεταφράσεων ενδέχεται να απαιτεί πλήρες 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 με το locale_chain

Όταν λείπει ένα κλειδί μετάφρασης από ένα τοπικό locale όπως το pt-BR, το Flutter μεταβαίνει απευθείας στη γλώσσα προτύπου αντί να ελέγξει πρώτα το γονικό locale 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());

Δείτε τον οδηγό μας για τα εναλλακτικά locale, με την πλήρη λίστα των υποστηριζόμενων frameworks και 75 ενσωματωμένων αλυσίδων. Learn more →

Συχνές ερωτήσεις