[Flutter] 比較的ラクに多言語化できるパッケージ

# まとめ
「言語ごとに必要なファイル（`arb`ファイル）を１つのファイルにまとめたい（重複部分が多いため）」
　　↓
[fast_i18n](https://pub.dev/packages/fast_i18n)が良さげ

### 2023/2/25 追記
パッケージ名が変わって、 [slang](https://pub.dev/packages/slang) となったようです。

https://pub.dev/packages/slang

## fast_i18nの良いところ
* yaml、json、csvなど使い慣れたフォーマットに対応している
* 複数の言語ファイルを1つのファイルにまとめることができる（csvのみ。Compact CSV機能)
* 言語ごとだけでなく、機能やWidgetごとにファイルを分割できる（Namespaces機能)
* Compact CSVとNamespacesを組み合わせることで、言語ごとにファイルを作る必要がなくなるうえ機能やWidget単位で分割できる。

#### ソースコード
https://github.com/popy1017/flutter_fast_i18n_samples

# 背景
Flutter公式で紹介されている方法では、言語ごとに`arb`ファイルが必要になる。それはわかった。

```app_en.arb
{
    "helloWorld": "Hello World!",
    "@helloWorld": {
      "description": "The conventional newborn programmer greeting"
    }
}
```

https://docs.flutter.dev/development/accessibility-and-localization/internationalization

しかし、サンプルのようにごく少数の部分だけであれば問題ないが、英語・日本語の`arb`ファイルをそれぞれ１００行くらい書いていて「あれ、、、ファイル内容的にはめちゃくちゃ重複してないかこれ・・・・？１つにまとめられないの・・・？」という疑問が生じた。（`arb`ファイルはjsonのようにKey-Value形式で記載するが、ファイルごとにKeyは同じなので１つにまとめられるのではないかという思い）

# 調査結果
※ 2021/12/28時点

|パッケージ名|概要|最終リリース|LIKE|PUB POINTS|POPULARITY|
|:----|:----|:----|:----|:----|:----|
|[fast_i18n](https://pub.dev/packages/fast_i18n) |jsonやyaml,csvからl10nクラスを生成してくれる。**csvの場合は複数の言語を１つにまとめられる。**| 2021/12/18 | 60 | 130 | 88% |
|[flappy_translator](https://pub.dev/packages/flappy_translator/versions/2.0.0-nullsafety.2)| 複数の言語をまとめたcsvやExcelファイルからl10nクラスを生成してくれる。 | 2021/05/26 | 22 | 110 | 70% |
|[arb_generator](https://pub.dev/packages/arb_generator)|複数の言語をまとめたcsvファイルから各言語のarbファイルを生成する。[flappy_translator](https://pub.dev/packages/flappy_translator/versions/2.0.0-nullsafety.2)に依存している。| 2021/04/10 | 4 | 110 | 22% |

→ Popularityと更新頻度の観点から、[fast_i18n](https://pub.dev/packages/fast_i18n) を使ってみることに。

# 特徴
初期設定などについては、以下を参照してください。
https://pub.dev/packages/fast_i18n

## 設定ファイル
パッケージ公開サイトに詳しく書かれているので、注意点のみ記載。

|パラメータ|デフォルト|備考|
|:----|:----|:----|
|base_locale| en | デフォルトでは英語が優先されるため日本語を優先にしたい場合は注意。 | 
|input_directory| - | 入力となる言語ファイルがあるディレクトリ名を指定する。 |
|input_file_pattern|.i18.json|入力となる言語ファイルにjson以外のファイルを使いたい場合はここで指定する。(`.yaml`, `.l10n.csv`など)|
| output_directory| - |出力ディレクトリ。指定したディレクトリが存在しないとエラーになるため作成しておくこと。|
| output_file_name | - | 出力ファイル名。指定しない場合、`***.g.dart`となるっぽい。|
| namespaces | false | **デフォルトではOFFになっているため注意！** 後述するNamespaces機能の使用有無。使う場合はtrueにする。|
| translate_var | t | 多言語設定した文字列にアクセスする際の変数名。(`t.hoge.label`のようにアクセスできる) |
| flat_map | true | t['hoge.label']のようにアクセスできるようになる。**静的解析の設定によってはエラーになるため、使わないならfalseにする。** | 
| pluralization/auto | cardinal | 複数形への自動変換有無の設定？（1 apple, 2nd floorとか)。日本語は対応しておらず独自で変換ルールを定義しないといけないため'off'にしたほうがいい。 |

#### 設定ファイルサンプル
```build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          input_directory: i18n
          input_file_pattern: .i18n.csv
          output_directory: lib/i18n
          output_file_name: i18n.g.dart
          output_format: single_file
          namespaces: true # 機能やWidget単位で言語設定ファイルを分ける場合はtrueに設定
          pluralization:
            auto: off
          translate_var: i18n # 個人的にtだとわかりづらいためi18nとした。お好みでOK
```

## Compact CSV
言語ごとにファイルを分ける場合と書き方が異なるため注意。
1行目は、`key`、`対応言語`、`対応言語`、・・・というふうにする。（**最低３列必要**）
今回はファイルをWidgetごとに分割し、以下のようにした。

※ **入力となるcsvファイルの改行コードは`CRLF`でないと変換コマンドを実行した際にエラーが出るため注意**

```home.i18n.csv:csv
key,en,ja
appBarTitle,Internationalization,多言語化
homeLabel,Home,ホーム
searchLabel,Search,検索
```

```page1.i18n.csv
key,en,ja
header.recently,Recently,最近
header.favorites,Favorites,お気に入り
header.all,All,すべて
```

```page2.i18n.csv
key,en,ja
hintText.search,"Shop, Genre, etc.",お店、ジャンル、…
result,Result: $number,検索結果: $number
item.name,Hogehoge $index,ほげほげ $index
```

## 変換

```shell
flutter pub run fast_i18n
```

## 各文言へのアクセス例
```dart
// home.dart
AppBar(
  title: Text(t.home.appBarTitle),
),

// page1.dart
t.page1.header.recently

// page2.dart
t.page2.result(number: 20)
```

## おまけ
csvファイルを直に編集するのはさすがに大変なので、VSCodeなどの拡張機能を使って編集しやすくするとさらに便利。