Dart/Flutterで日付と数値を多言語化する

# はじめに
* 日時や数値を多言語化をする際は、各国の表記に合わせることが必要な時がある
* Dartで日時・数値を多言語化すると、どのような変換となるかコードで確認する

# 日付
* `DateFormat`形式で任意のフォーマットに変換した上で表示が可能
* コード中の`Hm`や`yMd`で表示スタイルを指定可能
    * [date_time_patterns.dart](https://github.com/dart-archive/intl/blob/master/lib/date_time_patterns.dart)の中で、各国の表示スタイルに合わせた定義がある

## コード
```dart
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';

void main() {
  final date = DateTime(2024, DateTime.june, 6, 15, 13, 30);
  final languageList = [
    null, // default
    'ja', // Japan
    'da', // Denmark
    'fi', // Finland
    'fr', // France
    'de', // Germany
    'it', // Italy
    'no', // Norway
    'es', // Spain
    'sv', // Sweden
    'th', // Thailand
  ];

  for (final lang in languageList) {
    initializeDateFormatting(lang);

    print('Language: $lang');
    print(DateFormat.Hm(lang).format(date));
    print(DateFormat.yMd(lang).format(date));
  }
}

```
## 出力まとめ
* `Hm`表示は分かるが、`yMd`表示は何でこんなバラつくねん！という感想
    * 調べた範囲では、タイ語の`น.`は正式な文書とかだと書くよう
    * アラビア人にとっては`15:13`といった表記でも伝わるらしいが、アラビア語としては表中のように書くよう
* Dartのパッケージで国ごとにスタイルが定義されているので、基本的にはそれを使うのが良さそう。一方で、多言語のUXとしてどんな表示にするかを確認した上で多言語化を行う必要あり

| 言語 | Hm表示 | yMd表示 |
|--|--|--|
| デフォルト | 15:13 | 6/6/2024 |
| 日本 | 15:13 | 2024/6/6 |
| デンマーク | 15.13 | 6.6.2024 |
| フィンランド | 15.13 | 6.6.2024 |
| フランス | 15:13 | 06/06/2024 |
| ドイツ | 15:13 | 6.6.2024 |
| イタリア | 15:13 | 06/06/2024 |
| ノルウェー | 15:13 | 6.6.2024 |
| スペイン | 15:13 | 6/6/2024 |
| スウェーデン | 15:13 | 2024-6-6 |
| タイ | 15:13 น. | 6/6/2024 |
| アラビア | ١٥:١٣ | ٦‏/٦‏/٢٠٢٤ |


# 数字
* 数字は`NumberFormat`で、`DateFormat`と同様に多言語化が可能
* [number_symbols_data.dart](https://github.com/dart-archive/intl/blob/master/lib/number_symbols_data.dart)の中で、各国の表示スタイルに合わせた定義がある


## コード
```dart
import 'package:intl/intl.dart';

void main() {
  final num = 1234567.1234567;
  final languageList = [
    null, // default
    'ja', // Japan
    'da', // Denmark
    'fi', // Finland
    'fr', // France
    'de', // Germany
    'it', // Italy
    'no', // Norway
    'es', // Spain
    'sv', // Sweden
    'th', // Thailand
    'ar', // Arabia
  ];

  for (final lang in languageList) {
    final formatter = NumberFormat(null, lang);

    // 通貨
    print(NumberFormat.simpleCurrency(locale: lang).currencySymbol);

    // 数値
    formatter.maximumFractionDigits = 7;
    print(formatter.format(num));
  }
}
```

## 出力まとめ
* 小数点はどの言語も書き方が同じであるが、整数部は国によりけり
* **カンマ区切りがない場合**は、数字の意味自体が変わることは無いが、読みやすさに影響はありそう
* **カンマ区切りがある場合**は、意味が変わる可能性あり。例えば日本ではカンマ`,`が桁数の区切りに使われるが、ヨーロッパではドット`.`が桁数の区切りに使われている
* `DateFormat`と同様にパッケージの定義を使い回すのがベターそう

| 言語 | 通貨 | 数値 |
|--|--|--|
| デフォルト | $ | 1,234,567.1234567 |
| 日本 | ¥ | 1,234,567.1234567 |
| デンマーク | kr | 1.234.567,1234567 |
| フィンランド | € | 1 234 567,1234567 |
| フランス | € | 1 234 567,1234567 |
| ドイツ | € | 1.234.567,1234567 |
| イタリア | € | 1.234.567,1234567 |
| ノルウェー | kr | 1 234 567,1234567 |
| スペイン | € | 1.234.567,1234567 |
| スウェーデン | kr | 1 234 567,1234567 |
| タイ | ฿ | 1,234,567.1234567 |
| アラビア | E£ | 1,234,567.1234567 |

# まとめ
* 日付、数値などの多言語化を行う時は、パッケージの定義を使うと楽
* ただし各国の表示に合わせることがUXとして良いかは要確認
    * 例えば、想像よりテキストが長くなって枠に入らず、文字切れなんてことも起こり得る
* 多言語は深い

# 参考文献
* [Dart/Flutterでの多言語対応あれこれ](https://medium.com/flutter-jp/intl-beb5b9e8ee73)
* [国際化対応言語環境の利用ガイド](https://docs.oracle.com/cd/E19683-01/816-3979/overview-46/index.html)