幫助中心

Flutter 本地化:ARB 檔案、Intl 與自動化

Flutter 內建的本地化系統使用應用程式資源包 (ARB) 檔案與 intl 套件,能在任何語言中提供完全原生的體驗。本指南涵蓋了從專案設定、ARB 格式細節,到語言切換、複數化以及使用 l10n.dev 自動化翻譯的所有內容。

什麼是 Flutter 本地化?

Flutter 本地化是將您的應用程式適應多種語言與地區的官方方法。它依賴 ARB 檔案來儲存翻譯後的字串,並使用 flutter_gen 程式碼產生器來產生型別安全的 Dart 存取器。在執行時期,Flutter 會根據裝置的地區設定自動選擇正確的 ARB 檔案,以程式方式切換地區時無需重新啟動。

專案設定

Flutter 的本地化流程由兩個設定檔驅動:pubspec.yaml 與 l10n.yaml。請在 pubspec.yaml 中啟用程式碼產生功能,並將 Flutter 指向您的 ARB 目錄。

1. 更新 pubspec.yaml

新增 flutter_localizations 與 intl 作為依賴項,然後啟用 generate 旗標,讓 Flutter 從您的 ARB 檔案自動產生 Dart 本地化類別。

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: any

flutter:
  generate: true

2. 建立 l10n.yaml

在專案根目錄放置一個 l10n.yaml 檔案,以設定 ARB 目錄、範本檔案以及產生的輸出檔名。

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

ARB 檔案格式

ARB (Application Resource Bundle) 是一種專為 Flutter 國際化設計的 JSON 格式。每個鍵對應一個可翻譯的字串,而選用的中繼資料鍵(以 @ 為前綴)則包含說明、預留位置定義以及給翻譯人員的上下文。

  • @@locale: 宣告檔案的地區(例如 "en"、"fr"、"zh_CN")。l10n.dev 會自動將其更新為目標語言代碼。
  • @@last_modified: 最後修改的時間戳記。l10n.dev 在產生翻譯檔案時會自動將其設為當前的 UTC 時間戳記。
  • @key 中繼資料: 說明、範例與預留位置等中繼資料項目預設不會被翻譯,它們會保持不變以保留給翻譯人員的上下文。若您希望翻譯這些內容,請啟用 translateMetadata 設定。
  • 預留位置與 ICU 訊息: 字串可以包含具名預留位置 ({name}) 以及用於複數化與選擇的 ICU 訊息語法,所有這些在翻譯過程中都會被正確保留。

來源 ARB 檔案 (英文)

{
  "@@locale": "en",
  "@@last_modified": "2026-01-15T10:30:00Z",

  "appTitle": "My App",
  "@appTitle": {
    "description": "The title of the application"
  },

  "welcome": "Welcome, {name}!",
  "@welcome": {
    "description": "Welcome message shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },

  "unreadMessages": "{count, plural, =0{No unread messages} =1{1 unread message} other{{count} unread messages}}",
  "@unreadMessages": {
    "description": "Number of unread messages",
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

翻譯後的 ARB 檔案 (法文)

翻譯後,UI 字串會被本地化,而中繼資料結構則保持完整。l10n.dev 會自動更新 @@locale 與 @@last_modified。

{
  "@@locale": "fr",
  "@@last_modified": "2026-01-15T10:30:01Z",

  "appTitle": "Mon Application",
  "@appTitle": {
    "description": "The title of the application"
  },

  "welcome": "Bienvenue, {name} !",
  "@welcome": {
    "description": "Welcome message shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },

  "unreadMessages": "{count, plural, =0{Aucun message non lu} =1{1 message non lu} other{{count} messages non lus}}",
  "@unreadMessages": {
    "description": "Number of unread messages",
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

檔案命名慣例

ARB 檔案遵循簡單的命名模式:前綴(預設為 app_)後接地區代碼與 .arb 副檔名。Flutter 與 l10n.dev 使用底線來分隔語言與地區代碼。

ARB 檔案使用底線而非連字號 - 請寫成 app_en_US.arb 與 app_zh_CN.arb,而非 app_en-US.arb 或 app_zh-CN.arb。
# Default pattern (recommended)
app_en.arb
app_fr.arb
app_en_US.arb          # Locale with region (underscore format)
app_zh_CN.arb          # Chinese Simplified

# Custom prefix patterns also supported
my_app_en.arb
my_app_fr.arb

# Note: ARB files use underscores, not hyphens
# ✓  app_en_US.arb
# ✗  app_en-US.arb

專案結構

將所有 ARB 檔案整理在 lib/ 內的專屬 l10n 資料夾中。Flutter 的程式碼產生器會根據 l10n.yaml 中的 arb-dir 設定自動抓取它們,並輸出可直接使用的 Dart 類別。

lib/
├── l10n/
│   ├── app_en.arb        ← Source (English)
│   ├── app_fr.arb        ← French
│   ├── app_de.arb        ← German
│   ├── app_ja.arb        ← Japanese
│   ├── app_zh_CN.arb     ← Chinese Simplified
│   └── app_es.arb        ← Spanish
├── main.dart
└── ...

# Generated output (do not edit manually)
.dart_tool/
└── flutter_gen/
    └── gen_l10n/
        └── app_localizations.dart

初始化

透過提供 localizationsDelegates 與 supportedLocales,將產生的 Dart 本地化類別與 MaterialApp 連結起來。Flutter 隨後會根據裝置的地區設定解析正確的 ARB 資料。

MaterialApp 設定

傳入四個必要的代理 (delegates) - 您產生的 AppLocalizations.delegate 加上三個 Flutter SDK 代理 - 並列出您的應用程式支援的所有地區。在 Widget 樹的任何位置使用 AppLocalizations.of(context)! 來存取翻譯後的字串。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',

      // Required delegates
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],

      // Supported locales
      supportedLocales: AppLocalizations.supportedLocales,

      home: const HomePage(),
    );
  }
}

// Use in a widget
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(title: Text(l10n.appTitle)),
      body: Center(child: Text(l10n.welcome('Alice'))),
    );
  }
}

執行時期語言切換

Flutter 允許您透過更新 MaterialApp 的 locale 屬性在執行時期切換應用程式語言。常見的模式是在 StatefulWidget 或狀態管理解決方案中持有 Locale,並公開一個回呼函式來變更它。Widget 樹會自動以新的地區設定重新建構。

// Manage locale state at the app level
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Locale _locale = const Locale('en');

  void _changeLocale(Locale locale) {
    setState(() => _locale = locale);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      locale: _locale,
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: AppLocalizations.supportedLocales,
      home: SettingsPage(onLocaleChange: _changeLocale),
    );
  }
}

// Language selector widget
class LanguageSelector extends StatelessWidget {
  final void Function(Locale) onLocaleChange;

  const LanguageSelector({super.key, required this.onLocaleChange});

  @override
  Widget build(BuildContext context) {
    return DropdownButton<Locale>(
      value: Localizations.localeOf(context),
      items: AppLocalizations.supportedLocales
          .map((locale) => DropdownMenuItem(
                value: locale,
                child: Text(locale.toLanguageTag()),
              ))
          .toList(),
      onChanged: (locale) {
        if (locale != null) onLocaleChange(locale);
      },
    );
  }
}

複數化

Flutter 在 ARB 檔案內使用 ICU 訊息語法進行複數化。intl 套件會處理所有 CLDR 複數類別,並根據目標語言規則自動套用正確的形式。

  • 在 ARB 字串值內使用 {count, plural, =0{...} =1{...} other{...}} 語法。
  • 在 @key 中繼資料中宣告型別為 int 的 count 預留位置。
  • l10n.dev 會為每個目標語言產生所有必要的複數形式 - 包括阿拉伯文、俄文與波蘭文等複雜語言 - 無需手動介入。
{
  "cartItems": "{count, plural, =0{Your cart is empty} =1{1 item in your cart} other{{count} items in your cart}}",
  "@cartItems": {
    "description": "Cart item count",
    "placeholders": {
      "count": { "type": "int" }
    }
  },

  "daysLeft": "{days, plural, =1{1 day left} other{{days} days left}}",
  "@daysLeft": {
    "description": "Days remaining",
    "placeholders": {
      "days": { "type": "int" }
    }
  }
}

l10n.dev 對 ARB 的完整支援

l10n.dev 專為與 Flutter 的 ARB 工作流程無縫整合而建。上傳您的來源 ARB 檔案,即可獲得準確且結構正確的翻譯結果:

  • 自動中繼資料更新: @@locale 會自動更新為目標語言代碼,@@last_modified 則會自動設為當前的 UTC 時間戳記。
  • 中繼資料翻譯控制: 預設情況下,@key 中繼資料項目(說明、範例、上下文)不會被翻譯且保持不變,以保留翻譯註記。若要將其與 UI 字串一併翻譯,請啟用 translateMetadata 設定。
  • 自訂檔案前綴: 支援任何命名模式 - app_en.arb、my_app_en_US.arb、strings_fr.arb 等等。
  • 底線地區格式: ARB 地區代碼使用底線 (en_US, zh_CN) 而非連字號 - l10n.dev 能正確處理此格式,讓產生的檔案可直接放入您的 Flutter 專案中。
  • 支援複數化: ICU 複數形式會根據 CLDR 規則為每個目標語言產生,因此翻譯後無需手動編輯複數形式。

使用 npm 自動化翻譯

使用 ai-l10n npm 套件從命令列或作為 CI/CD 流程的一部分來翻譯您的來源 ARB 檔案。安裝一次,即可透過單一指令翻譯成任意數量的語言。

# Install the CLI
npm install ai-l10n

# Translate your source ARB to multiple languages
npx ai-l10n translate lib/l10n/app_en.arb \
  --languages fr,de,ja,zh_CN,es,ko

整合至 Flutter 建置流程

您可以將 ai-l10n 直接整合至 Flutter 建置流程中,確保在編譯應用程式前翻譯皆為最新狀態。常見的兩種方式是使用 package.json 指令碼或 Makefile。

透過 package.json 指令碼

新增一個翻譯指令碼,並使用 npm 的 prebuild 生命週期鉤子,在每次建置前自動執行。執行 npm run build:android(或 build:ios / build:web)時,ai-l10n 會先進行翻譯,隨後再交由 Flutter 執行。

{
  "scripts": {
    "translate": "ai-l10n translate lib/l10n/app_en.arb --languages fr,de,ja,zh_CN,es,ko --update",
    "prebuild": "npm run translate",
    "build:android": "flutter build apk",
    "build:ios": "flutter build ios",
    "build:web": "flutter build web"
  }
}

透過 Makefile

若您的團隊使用 Make,請宣告一個翻譯目標 (target),並讓每個建置目標都依賴於它。執行 make build-android(或 build-ios / build-all)時,會在呼叫 flutter build 前先翻譯所有目標語言。

LANGUAGES = fr,de,ja,zh_CN,es,ko

translate:
	npx ai-l10n translate lib/l10n/app_en.arb --languages $(LANGUAGES) --update

build-android: translate
	flutter build apk

build-ios: translate
	flutter build ios

build-web: translate
	flutter build web

build-all: translate
	flutter build apk
	flutter build ios
	flutter build web

若需 CI/CD 整合、增量更新、跨多個檔案的批次翻譯以及 GitHub Actions 工作流程範例,請參閱 本地化自動化指南。

VS Code 擴充功能

l10n.dev VS Code 擴充功能將 Flutter ARB 翻譯直接帶入您的編輯器。在任何 ARB 檔案上按右鍵,即可在不離開 VS Code 的情況下將其翻譯為目標語言。

VS Code 中的運作方式:

  1. 在編輯器中開啟您的來源 ARB 檔案 (例如 app_en.arb)。
  2. 在編輯器中按右鍵並選擇 "Translate JSON"。
  3. 選擇一種或多種目標語言(例如法文、日文、德文)。
  4. 擴充功能會在您的來源檔案旁建立本地化的 ARB 檔案,並自動更新 @@locale 與 @@last_modified。

實際操作演示

以下是在 VS Code 中將 Flutter ARB 檔案翻譯為烏茲別克文的實際範例:

Flutter ARB localization in VS Code

開始本地化您的 Flutter 應用程式

準備好接觸全球使用者了嗎?您可以直接在 l10n.dev 工作區翻譯 ARB 檔案、使用 npm CLI 自動化,或直接在 VS Code 內進行翻譯: