明けましておめでとうございます、 id:numanuma08 です。先日、flutterを使って多言語に対応したWebページの実装とデプロイをしたのでノウハウを共有します。
flutter の多言語対応事情
flutterは標準で多言語に対応しています。基本的には公式ドキュメントにある通り
- flutter_localizationの依存を追加
- intlの依存を追加
- l10n.yamlに設定を記述
- 言語ごとの arb ファイルを作成・編集して
flutter gen-l10n
を実行
以上の流れとなります。
依存関係の追加
pubspec.yaml
に以下の内容を追記して、flutter pub get
をします。
dependencies: flutter: sdk: flutter flutter_web_plugins: sdk: flutter flutter_localizations: sdk: flutter intl: ^0.18.1 # intlのバージョンは適切な物を選ぶ
l10n.yamlの記述
ファイル形式の詳細は公式ドキュメントを確認してください。最低限、日本語と英語に対応するため以下の内容を記入します。
arb-dir: lib/l10n template-arb-file: app_en.arb
arbファイルの記述
言語ごとにarbファイルを作ります。l10n.yaml
で指定した場所に作るため、今回の場合は次のファイル構成となります。
lib ├── l10n │ ├── app_en.arb │ └── app_ja.arb
flutter gen-l10n
を実行するとarbファイルを読み込んで言語の定数を定義したdartのコードが生成されます。文字列は以下のようなコードで参照できます。
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const text = AppLocalizations.of(context)!.your_defined_text;
システムの言語設定を反映させる
flutter webアプリケーションの場合、ブラウザの言語設定を読み込んで現在の言語を調べます。ブラウザの言語設定はJavaScriptのwindow.navigator.language
で取得しますが、flutterから取得する場合はIntlクラスのsystemLocale
プロパティで取得可能です。systemLocale
は呼び出し前にfindSystemLocale()
を呼び出さなければならない点に注意してください。
import 'package:flutter/foundation.dart'; import 'package:intl/intl_standalone.dart' as intl_standalone; import 'package:intl/intl_browser.dart' as intl_browser; void main() async { if (kIsWeb) { await intl_browser.findSystemLocale(); } else { await intl_standalone.findSystemLocale(); }
アプリ内の言語設定変更に対応する
多言語対応アプリっぽくするため、アプリ内で好きに言語設定変更に対応します。今回は、言語設定管理クラスをChangeNotifier
のサブクラスで実装し、provderライブラリでアプリ内から参照・変更できるように実装しました。
import 'package:flutter/material.dart'; // 言語設定を管理するクラス // 必要に応じて言語設定を永続化・復元する class LocaleNotifier extends ChangeNotifier { LocaleNotifier(this._locale); Locale _locale; Locale get locale => _locale; void changeLocale(Locale locale) { _locale = locale; notifyListeners(); } } // main.dart import 'package:intl/intl_standalone.dart' as intl_standalone; import 'package:intl/intl_browser.dart' as intl_browser; import 'package:provider/provider.dart'; void main() async { // システムの言語設定を読み込んで、アプリ内で利用可能にする if (kIsWeb) { await intl_browser.findSystemLocale(); } else { await intl_standalone.findSystemLocale(); } // システムの言語設定をデフォルトの言語とする // 今回は日本語設定意外であれば英語とした final Locale defaultLocale; if (Intl.getCurrentLocale().startsWith('ja')) { defaultLocale = const Locale("ja", "JP"); } else { defaultLocale = const Locale("en"); } runApp( ChangeNotifierProvider(create: (_) => LocalNotifier(defaultLocale) child: const MyApp() ); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { // 言語設定を監視する final localeNotifier = context.watch<LocaleNotifier>(); return MaterialApp.router( title: 'MyApp', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, // アプリ内で設定された言語を使ってUIを構成する locale: localeNotifier.locale, // 以下省略
アプリ内で言語を変更する
言語変更のUIは様々な実装があると思いますが、例えばAppBar
のactionsにDropDownMenu
を配置する方法が考えられます。
AppBar( actions: [ DropdownButton<Locale>( value: Locale(AppLocalizations.of(context)!.localeName), items: const [ DropdownMenuItem( value: Locale('en'), child: Text('English'), ), DropdownMenuItem( value: Locale('ja'), child: Text('日本語'), ), ], onChanged: (newLocale) { if (newLocale != null) { // アプリ全体の言語設定を切り替える context.read<LocaleNotifier>().changeLocale(newLocale); } }, ) ]
まとめ
flutterで多言語対応をしたWebページ・アプリの実装を紹介しました。言語設定をアプリ全体の状態として持つと、好きなタイミングで設定が変更できるため、アプリの要件などによっては便利なものとなるでしょう。