0
0

Widgetbook+SlangでLocaleを変更

Posted at

はじめに

仕事でFlutterにローカリゼーションとWidgetbookの両方を導入することになりました。
それぞれは問題なく導入できて、よっしゃー!と思っていたのですがWidgetbookのAddonに存在するLocaleを変更しても言語が変更されませんでした。調べたところ、WidgetのデフォルトのLocalizationAddonはFlutterネイティブでLocaleを変更する方式であればうまく動くようですが、今回はslangを使ってるので動いてないっぽい。じゃあ直すか!ということで色々調べ、問題を解決したので共有です。

対象者

  • Flutterで開発をしている人
  • アプリの多言語化にslangを使用している人
  • widgetbookを導入してページやWidgetをカタログ化したい人

前提条件

// widgetbook.dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;

// Import the generated directories variable
import 'widgetbook.directories.g.dart';

void main() {
  runApp(const WidgetbookApp());
}

@widgetbook.App()
class WidgetbookApp extends StatelessWidget {
  const WidgetbookApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Widgetbook.material(
      // Use the generated directories variable
      appBuilder: (context, child) {
        return ProviderScope(child: child);
      },
      directories: directories,
      addons: <WidgetbookAddon>[
        MaterialThemeAddon(themes: [
          WidgetbookTheme(name: "Light", data: ThemeData.light()),
          WidgetbookTheme(name: "Dark", data: ThemeData.dark()),
        ]),
        DeviceFrameAddon(devices: [
          Devices.ios.iPhoneSE,
          Devices.ios.iPhone13,
          Devices.ios.iPhone13Mini,
          Devices.ios.iPhone13ProMax,
        ]),
        TextScaleAddon(
          scales: <double>[1.0, 2.0],
        ),
        LocalizationAddon(
          locales: <Locale>[
            const Locale('en', 'US'),
          ],
          localizationsDelegates: <LocalizationsDelegate<dynamic>>[
            DefaultWidgetsLocalizations.delegate,
            DefaultMaterialLocalizations.delegate,
          ],
        ),
      ],
      integrations: const [],
    );
  }
}

いくつかカスタマイズしてますが、基本的にはデフォルトに近いです。

では本題に入ります。

Localization入ってない?

そう、上記のコードを見るとそもそもLocaleのコードが入ってるんです。
しかしこれは動きません
上記のローカリゼーションはwidgetbookが用意しているAddonで、これはFlutterのネイティブのローカリゼーション機能を使用しています。slangを使ってる場合、このネイティブのローカリゼーションは行っていないので機能しません。(少なくとも自分は機能させられなかった)

じゃあどうしたら良いのか?

そこで色々試行錯誤し、「自分でAddon作れば良いんじゃね?」という結論になりました。
wdigetbookのAddonは自分でカスタムのものが作れるので、これとslangが用意してる手動で言語を切り替える機能を使って、独自のLocalizationAddonを作成します。

class CustomLocaleAddon extends WidgetbookAddon<String> {
  String initialCustomLocale = "ja";

  CustomLocaleAddon()
      : super(
          name: "Locale",
        );

  @override
  Widget buildUseCase(BuildContext context, Widget child, String setting) {
    LocaleSettings.setLocaleRaw(setting);
    return child;
  }

  @override
  List<Field<String>> get fields {
    return [
      ListField<String>(
          name: "locale",
          initialValue: initialCustomLocale,
          values: [
            "ja",
            "en",
          ])
    ];
  }

  @override
  String valueFromQueryGroup(Map<String, String> group) {
    return valueOf<String>("locale", group)!;
  }
}

基本的なコードはwidgetbookの公式にあるカスタムAddonの項目を参考にしています。

fieldsがAddonで選択できる内容を管理しています。
これが選択された時、valueFromQueryGroupが実行されるのでここで値の変更を行います。
上記の例ではそのまま文字列を返せばいいので特別な処理は入れません。

これが実行されたあと、buildUseCaseが実行され、valueFromQueryGroupのreturn値がbuildUseCasesetting引数に渡されます。
つまり、この時点でユーザーが選択した言語文字列がsettingsに入ってくるということです。
あとは、slangLocaleSettings.setLocaleRaw(言語文字列)を使って、slangの選択されている言語を変更します。

そしたら、これをwidgetbookのAddonに追加します。

// widgetbook.dart

import 'package:comolu_app/i18n/i18n.g.dart';
import 'package:comolu_app/services/firebase.dart';
import 'package:comolu_app/services/get_it.dart';
import 'package:comolu_app/utils/theme.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;

// Import the generated directories variable
import 'widgetbook.directories.g.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  LocaleSettings.useDeviceLocale();

  // NOTE: 各種コンフィグの設定
  await setupFirebase();
  await setupGetIt();

  runApp(const WidgetbookApp());
}

@widgetbook.App()
class WidgetbookApp extends StatelessWidget {
  const WidgetbookApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Widgetbook.material(
      // Use the generated directories variable
      appBuilder: (context, child) {
        return ProviderScope(child: child);
      },
      directories: directories,
      addons: <WidgetbookAddon>[
        MaterialThemeAddon(themes: [
          WidgetbookTheme(name: "Light", data: defaultTheme),
          WidgetbookTheme(name: "Dark", data: defaultTheme),
        ]),
        DeviceFrameAddon(devices: [
          Devices.ios.iPhoneSE,
          Devices.ios.iPhone13,
          Devices.ios.iPhone13Mini,
          Devices.ios.iPhone13ProMax,
        ]),
        TextScaleAddon(
          scales: <double>[1.0, 2.0],
        ),
        CustomLocaleAddon(), <- 追加
      ],
      integrations: const [],
    );
  }
}

これで、widgetbook+slangで言語の変更できます。

slang_switch.gif

あとがき

Storybookに慣れてるので最初は設定などに手こずりましたが、やり方がわかってくるとやっぱりページやWidgetのカタログ化は便利ですね。

Reference

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0