結論:
-
各 Feature モジュールごとに gen_l10n を独立運用(ARBと生成コードをモジュール内完結)。
-
App(シェル)側で delegates と supportedLocales を集約。
-
Domain/Data 層は文言を持たない(エラーはコードで表す、文言は Presentation 層でローカライズ)。
全体像(責務分離)
ディレクトリ例(melos想定)
packages/
app/
core/locale/ # (任意)Locale永続化の共通部品
features/
weather/
lib/
l10n/
weather_en.arb
weather_ja.arb
weather_localizations.dart # synthetic-package:false時の出力
src/
public/ # 外部に見せる最小API(routes/di/l10nゲッター等)
internal/ # 実装詳細(UI, repo等)
l10n.yaml
pubspec.yaml
auth/
...
ポイント
-
各 Feature 配下に l10n/ を置く(モジュール独立)。
-
l10n.yaml の output-class を モジュール固有名 に(例:WeatherLocalizations)。
-
生成物の公開は必要最小限に(barrel weather.dart から show で制御)。
l10n.yaml(Feature側:weather の例)
arb-dir: lib/l10n
template-arb-file: weather_en.arb
output-localization-file: weather_localizations.dart
output-class: WeatherLocalizations
synthetic-package: false
use-deferred-loading: false
preferred-supported-locales:
- ja
- en
# 任意: 出力先を固定したい場合
# output-dir: lib/l10n/gen
ARBキー命名(衝突回避の鉄則)
- 必ずモジュール接頭辞を付ける:weather_ / auth_ / settings_ …
例:weather_appTitle, weather_errorTimeout, weather_tempHighLow など。
lib/l10n/weather_en.arb
{
"@@locale": "en",
"weather_appTitle": "PoyoPoyo Weather",
"weather_settings": "Settings",
"weather_theme_setting": "🌗 Theme Setting",
"weather_language_setting": "🌐 Language Setting",
...
}
lib/l10n/weather_ja.arb
{
"@@locale": "ja",
"weather_appTitle": "ポヨポヨ 天気",
"weather_settings": "設定",
"weather_theme_setting": "🌗 テーマ設定",
"weather_language_setting": "🌐 言語設定",
...
}
Feature内での利用
final loc = WeatherLocalizations.of(context)!;
loc.weather_appTitle;
App(シェル)側での集約
Locale切り替えと永続化(SharedPreferences × Riverpod例)
locale_repository.dart
locale_repository_impl.dart
locale_provider
公開APIの最小化(情報隠蔽)
-
lib/src/internal/ に実装、lib/src/public/ に“壳”API(routes/di/l10nゲッター)。
-
lib/feature_xxx.dart を 唯一の公開barrel にし、export show で必要最小限を露出。
-
Lintで implementation_imports: true を有効化し、package:meta の @internal を活用。
CI / 開発フロー(melos)
melos.yaml にスクリプトを用意し、全Featureのgen_l10nを一括:
scripts:
gen-l10n:
run: melos exec -- "flutter gen_l10n"
description: "Generate localizations in all Flutter packages"
PRチェック例
-
gen_l10n の未実行防止(差分に生成物あり/なしのチェック)。
-
ARB スキーマ検査(キー重複・未翻訳・不要キー検出)。
よくあるハマりどころ
オプション名の誤記:
-
template_arbs × → template-arb-file ○
-
preferred_locales × → preferred-supported-locales ○
生成先の誤解:
- synthetic-package: false の場合は 同パッケージ配下に直接出力。output-dir 指定で固定化も可。
ARBキー衝突:
- 接頭辞で防止(weather_ など)。
Domainに文言を持ち込む:
- NG。エラーは Failure/Code で返し、UI層で文言化する。
チェックリスト
-
各Featureに l10n/ と l10n.yaml を配置、output-class は固有名
-
ARBキーは feature_ プレフィックスで衝突回避
-
Domain/Dataは文言を持たず、Presentationでローカライズ
-
Appで delegates / supportedLocales を集約
-
Localeは状態管理+永続化(Repository化)
-
公開APIはbarrelから最小限 export show、内部は src/internal
-
Lint(implementation_imports)と @internal で“越権import”を抑止
-
CIで gen_l10n と ARB検査を実行