半農半エンジニアの記録

関西在住エンジニア。個人で勉強・開発したこと、その他趣味のことを書いてます。農業してます。

Flutter の多言語対応(Intl)

Flutter で多言語対応した。

公式ドキュメントでもよく説明されていると思うし、 flutter.dev

こちらの mono さんの記事もすごく参考になる。
Dart/Flutter での多言語対応あれこれ - Flutter 🇯🇵 - Medium

今のところ DateFormat や NumberFormat は不要なので、文言をロケールに合わせて変更する部分だけ行った。

目次

パッケージのインストール

pubspec.yaml に追加。

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  flutter_cupertino_localizations: ^1.0.1

flutter_cupertino_localizations は iOS でちゃんと動作させたいなら入れなさい、とのこと。

追記したら flutter pub get を実行、もしくはAndroid Studio なら、Packages get をクリック。

Android Studio で Packages get をクリック

MaterialApp修正

import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_cupertino_localizations/flutter_cupertino_localizations.dart';

MaterialApp(
 localizationsDelegates: [
   // ... app-specific localization delegate[s] here
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
   GlobalCupertinoLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en'), // English
    const Locale('ja'), // Japanese
    // ... other locales the app supports
  ],
  // ...
)

localizationsDelegates

ローカライズした value を使うためのファクトリを指定する。

  • GlobalMaterialLocalizations.delegate
    文字などの文言や他の MaterialApp コンポーネントようライブラリ
  • GlobalWidgetsLocalizations.delegate
    文字列の方向(英語は左から右、アラビア語は右から左、みたいな)を定義するためのライブラリ

ということなのでおまじない的に両方入れておけばいいのかな。アラビア語とか対応しない限りは GlobalWidgetsLocalizations.delegate は無くてもいいのかはわからない。(試してない)

supportedLocales

アプリが対応する言語のロケールを指定する。
中国の繁体字/簡体字みたいに方言?がある場合はLocale.fromSubtags(languageCode: 'zh') という感じでできるらしいが、今回は日本語と英語のみなので省略。

ローカライズリソースの定義

class DemoLocalizations {
  DemoLocalizations(this.localeName);

  static Future<DemoLocalizations> load(Locale locale) {
    final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      return DemoLocalizations(localeName);
    });
  }

  static DemoLocalizations of(BuildContext context) {
    return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
  }

  final String localeName;

  String get hello {
    return Intl.message(
      'こんにちは',
      name: 'hello',
      locale: localeName,
    );
  }
}

initializeMessages() がローカライズされたメッセージカタログで読み込み、intl パッケージが インポートする。
Intl.message() でそれらを読み込んで返している。
という流れ。 メッセージカタログは、後述する intl のツールで作成できる。

多言語対応(メッセージカタログの作成)

intl のツールを利用する。

arb ファイル作成

 flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart

main.dart 内にある Intl.message() ごとに定義を作成できる。
lib/l10n の下に intl_messages.arb という JSON ファイルが出力される。
複数言語対応するときは、この arb ファイルをベースに intl_ja.arb や intl_en.arb を作成する。

dart ファイル作成

 flutter pub run intl_translation:generate_from_arb \
    --output-dir=lib/l10n --no-use-deferred-loading \
    lib/main.dart lib/l10n/intl_*.arb

上記で作成した arb ファイルごとに、 intl_XXX_all.dart が作成される。
この dart ファイルの中身がロケールに応じて使われる。

使ってみる

print(DemoLocalizations.of(context).hello);

みたいにするだけ。
デフォルトロケールが日本と想定して、

こんにちは

ロケールを変更したい場合は、 DemoLocalizations.load(Locale('en')); としてやる。

DemoLocalizations.load(Locale('en'));
print(DemoLocalizations.of(context).hello);
hello

その他

とりあえず公式ページにあるコードをサンプルとして掲載。
後日 git にサンプルあげる。

Flutter の pop による戻り値

Flutter のルーティングで push / pop する時の扱い

スタックでのルーティング

概略

  • push 時に return で受け取りたい型を指定
  • pop 時に指定された型を return
  • pop の引数を省略すると null が返る
  • 戻るボタンでも null が返るので、必ず考慮が必要

ページ遷移(進む)

push で積む。
Navigator.of(context).push
を使う。

return で受け取りたい型を指定してやればいいので、 int を指定してみる。

int ret = await Navigator.of(context)
    .push(MaterialPageRoute<int>(builder: (BuildContext context) {
  return SecondPage();
}));

ページ遷移(戻る)

pop でスタックから取り除く。
Navigator.of(context).pop
を使う。

この時、 push 側で受け取りたい戻り値を、 pop() の引数で渡す。

int _counter;
~~ 中略 ~~
Navigator.of(context).pop(_counter)

引数を省略すると null が返される。

デフォルトの戻る機能

OS の戻る機能を使うと、引数を省略した時と同じで null が返される。

back button in Android
back_button

なのでそこは考慮しておく必要がある。逆に言えば、戻る機能と同じ挙動をさせたければ、引数を省略して null を返せばいい。

コードサンプル

全体のコード

simple push and pop demo with return