Skip to main content

Flutter ローカライズ完全ガイド

ARB ファイルから RTL 対応まで、easy_localization で Flutter アプリをローカライズし、あらゆる言語の複数形を処理して、AI で翻訳を自動化します。

1

easy_localization のインストール

pubspec.yaml に easy_localization パッケージを追加します。ARB/JSON ファイル、複数形、コンテキスト拡張に対応する、最も広く利用されている Flutter i18n パッケージです。日付、数値、テキスト方向をロケールに応じて書式設定するため、SDK の flutter_localizations も追加してください。

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 ディレクトリにロケールごとのファイルを 1 つ作成してください。

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 に必要なロケールデリゲートを提供します。必須の 3 つのデリゲートプロパティは 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」というエラーは、runApp() より前に EasyLocalization.ensureInitialized() を呼び出していないことを示します。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 は、iOS、Android、Web と同じ標準規格である ICU MessageFormat を複数形に使用します。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

RTL 言語への対応

ロケールがアラビア語、ヘブライ語、ペルシャ語、ウルドゥー語などの右から左へ記述する言語の場合、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
アプリのロケールを一時的にアラビア語(Locale('ar'))へ設定して RTL をテストしてください。Flutter は UI 全体を反転し、ナビゲーションドロワーは右から開き、戻る矢印が反転し、テキストが右揃えになります。カスタムレイアウトを正しく反転させるには、EdgeInsetsDirectional、AlignmentDirectional、BorderRadiusDirectional を使用してください。
7

高度なロケールフォールバックチェーン

Flutter はデフォルトで、pt-BR 翻訳がない場合に適切な pt-PT 翻訳を飛ばし、英語へ直接フォールバックします。locale_chain パッケージは、設定可能なフォールバックチェーンでこの問題を修正します。設定は 1 行で、移行は不要です。既存の .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

翻訳の自動化

ローカライズの設定が完了したら、AI を使用して ARB ファイルを翻訳します。IDE で AI アシスタントにソース ARB ファイルの翻訳を依頼するか、CI/CD パイプラインで i18n Agent CLI を使用できます。プレースホルダーや説明などの 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 の疑似翻訳で UI をテストしてください。

よくある問題

実行時に翻訳ファイルが見つからない

ARB/JSON ファイルは、pubspec.yaml の assets セクションで宣言する必要があります。この手順を省くと、ファイルがディスク上に存在しても Flutter は実行時に見つけられません。assets: - assets/translations/ を追加してください。

ARB ファイルの構文が無効

ARB ファイルは厳密な JSON であり、末尾のコンマ、単一引用符、コメントは使用できません。構文エラーが 1 つでもあると、ファイル全体が通知なしで読み込まれません。翻訳の問題をデバッグする前に、JSON リンターで ARB ファイルを検証してください。

ホットリロードで翻訳の変更が反映されない

easy_localization は翻訳をメモリにキャッシュします。新しいキーの追加や既存翻訳の変更を反映するには、ホットリロードではなく完全なホットリスタートが必要な場合があります。開発時に翻訳ファイルを編集した後は、ホットリスタート(Shift+R)を使用してください。

ハードコードした left/right により RTL が崩れる

EdgeInsetsDirectional.only(start: 16) ではなく EdgeInsets.only(left: 16) を使用すると、Flutter が RTL 言語向けにレイアウトを反転できません。コードベース内で、Directional サフィックスのない EdgeInsets、Alignment、BorderRadius を検索してください。

推奨ファイル構成

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 →

よくある質問