【Flutter】Amplify UIログイン画面の日本語化対応

# 概要
本記事では、Amplify UIのログイン画面の日本語化対応について記します。

[前回の記事](https://qiita.com/ko-izumi/items/c4ab3ab443f9983d3693)でFlutterでAmplify UIを用いてログイン機能を実装しました。ただし、そのままだと英語表記となり、日本人には優しくないUIになってしまいます。今回は日本語化するにあたり、Amplify UIのLabel & text対応について整理しました。参考にした記事は[こちら](https://ui.docs.amplify.aws/components/authenticator?platform=flutter#labels--text)になります。

# 環境
flutter, Amplify CLIのインストールは別記事を参照お願いします。

```shell
$ flutter --version
Flutter 2.10.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 7e9793dee1 (3 weeks ago) • 2022-03-02 11:23:12 -0600
Engine • revision bd539267b4
Tools • Dart 2.16.1 • DevTools 2.9.2

$ amplify -v
8.0.2
```
# 事前準備
[前回の記事](https://qiita.com/ko-izumi/items/c4ab3ab443f9983d3693)を参考にしていただき、Flutter上で、Amplify UIのログインを実装お願いします。

# 実装
英語で表現されているクラス(xxResolver)を日本語に上書きします。
[公式ドキュメント](https://ui.docs.amplify.aws/components/authenticator?platform=flutter#labels--text)だと、signinメソッドをoverrideすると記載ありますが、それは間違いで、実際にはsignInメソッドですのでご注意を。なかなか気づけず10数分ハマってしまいました(公式なのでちゃんと確認して書いて欲しい...)。
※確認画面の日本語化までは冗長なので割愛。同様に変更していただければと(決して面倒だったわけじゃ...)


```dart:main.dart
class CustomButtonResolver extends ButtonResolver {
  const CustomButtonResolver();

  @override
  String signIn(BuildContext context) {
    //the text of the signin button can be customized
    return 'ログイン';
  }

  @override
  String signUp(BuildContext context) {
    return 'アカウント作成';
  }

  @override
  String forgotPassword(BuildContext context) {
    return "パスワードを忘れましたか？";
  }

  @override
  String submit(BuildContext context) {
    return "送信";
  }

  @override
  String backTo(BuildContext context, AuthenticatorStep previousStep) {
    return "サインイン画面に戻る";
  }
}

/// Instantiate an InputResolver
class CustomInputResolver extends InputResolver {
  const CustomInputResolver();

  @override
  String title(BuildContext context, InputField field) {
    switch (field) {
      case InputField.username:
        return 'ユーザー名';
      case InputField.email:
        return 'メールアドレス';
      case InputField.password:
        return 'パスワード';
      case InputField.passwordConfirmation:
        return 'パスワード再入力';
      default:
        return super.title(context, field);
    }
  }

  @override
  String hint(BuildContext context, InputField field) {
    final fieldName = title(context, field);
    return '$fieldNameを入力してください';
  }

  @override
  String confirmHint(BuildContext context, InputField field) {
    final fieldName = title(context, field);
    return '$fieldNameしてください';
  }

  @override
  String empty(BuildContext context, InputField field) {
    return 'パスワードを空にしたまま登録できません';
  }

  @override
  String resolve(BuildContext context, InputResolverKey key) {
    switch (key.type) {
      case InputResolverKeyType.title:
        return title(context, key.field);
      case InputResolverKeyType.hint:
        return hint(context, key.field);
      case InputResolverKeyType.confirmHint:
        return confirmHint(context, key.field);
      case InputResolverKeyType.empty:
        return empty(context, key.field);
      case InputResolverKeyType.passwordRequirements:
        return passwordRequires(context, key.unmetPasswordRequirements!);

      /// 本当はpasswordRequiresの中身相当の実装が必要だが、簡単のため以下のように記載。
      // return "パスワードは最低8文字以上必要です";
      case InputResolverKeyType.mismatch:

        /// こちらは関数化されていなかったので、直接resolveメソッドを変更
        // return AuthenticatorLocalizations.inputsOf(context).passwordsDoNotMatch;
        return "パスワードが一致しませんでした";
      case InputResolverKeyType.format:
        return format(context, key.field);
    }
  }
}

class CustomTitleResolver extends TitleResolver {
  const CustomTitleResolver();

  @override
  String signIn(BuildContext context) {
    return "サインイン";
  }

  @override
  String signUp(BuildContext context) {
    return "アカウント作成";
  }

  @override
  String resetPassword(BuildContext context) {
    return "コード送信";
  }
}

class CustomMessageResolver extends MessageResolver {
  const CustomMessageResolver();

  @override
  String codeSent(BuildContext context, String destination) {
    // ↓✨✨スナックバーの文言を変更
    return "登録用コードを次のメールアドレスに送信しました。$destination";
  }
}
```

上記クラスをAuthStringResolverでまとめます。
```dart:main.dart
/// Instantiate an AuthStringResolver with your two custom resolvers
const stringResolver = AuthStringResolver(
  buttons: CustomButtonResolver(),
  inputs: CustomInputResolver(),
  titles: CustomTitleResolver(),
  messages: CustomMessageResolver(),
);
```

続いて、buildメソッドのAuthenticatorのstringResolverオプションに先ほど作成したインスタンスを設定する。
これにより、日本語化されます。

```dart:main.dart
  @override
  Widget build(BuildContext context) {
    return Authenticator(
      /// ↓✨✨stringResolverオプションを追加
      stringResolver: stringResolver,
      child: MaterialApp(
        builder: Authenticator.builder(),
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(title: 'Flutter Demo Home Page'),
      ),
    );
  }
```

# メールで送信されるパスコードの日本語対応について
パスコードをメールで送信した際、デフォルトは、
- メールタイトル: [Your verification code]
- メール内容: [Your verification code is xxxxxx]

となります。
こちらは、クライアント側でなくバックエンド側の変更が必要です。
AWSのコンソールから実施できるので、以下のように実施ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1424230/4861a127-01b4-2d73-49a2-eb9ca7149e37.png)

# おまけ
[Github](https://github.com/ko-izumi/flutter_amplifyui_ja)に今回のコードを置いておきました。全文見たい方は、リンクください。