При разработке пакета может возникнуть потребность добавить локализацию. Если вы используете для локализации пакет Intl, то вас ждёт неприятный сюрприз.
Проблема
Для того, чтобы реализовать Intl локализацию стандартным образом вы должны:
- создать класс, содержащий строки для локализации, получаемые через Intl.message();
- сгенерировать arb файлы на основе этого класса;
- выполнить перевод и разместить arb файл для каждого языка;
- сгенерировать код ( messages_*.dart файлы) на основе arb файлов;
- объявить делегат локализации (который будет зарегистрирован в приложении) и реализовать функцию загрузки, которая выполнит initializeMessages() из сгенерированного кода и вернёт экземпляр класса реализации.
Этот способ отлично работает в приложении, но имеет одно существенное ограничение: правильно обработан будет только первый вызов initializeMessages(). Все последующие вызовы не добавят строк в локализацию, если для указанной локали уже есть записи.
Таким образом, если у меня есть несколько arb файлов (и сгенерированных для них messages_*.dart) с разным набором строк для одной локали, то добавлены будут только строки от первого вызова.
Такое поведение вполне подходит в большинстве случаев — нам незачем иметь несколько файлов со строками локализации, даже если строки объявлены в разных классах, мы можем сгенерировать общий arb для них. Но при локализации пакета я хочу, чтобы переводы поставлялись вместе с ним, а не приходилось переводить строки внутри каждого приложения снова и снова.
Выходом из ситуации может служить генерация отдельных классов локализации для каждой локали, и создание нужного экземпляра по загрузке, в обход механизма с initializeMessages(). Так, например, реализована локализация в стандартном пакете flutter_localization. Но я не нашёл удобного способа автоматической генерации таких классов в рамках Intl?. Если вы знаете как работать с такой локализацией — буду благодарен за информацию в комментариях.
Таким образом, мне бы хотелось:
- делать локализацию пакета привычным, стандартным способом, как и локализацию приложения;
- иметь возможность подключать локализацию пакета наравне с локализацией приложения.
Решение
Для решения этой проблемы был разработан пакет multiple_localization.
Чтобы получить нужное поведение, требуется изменить реализацию функции загрузки делегата локализации, избавившись от прямого вызова initializeMessages().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class _AppLocalizationsDelegate extends LocalizationsDelegate { const _AppLocalizationsDelegate(); @override Future load(Locale locale) { // Implement load() with multiple_localization package return MultipleLocalizations.load( initializeMessages, locale, (l) => AppLocalizations(l), setDefaultLocale: true); } @override bool isSupported(Locale locale) => ['en'].contains(locale.languageCode); @override bool shouldReload(LocalizationsDelegate old) => false; } |
Вот и всё. Теперь вы можете добавлять несколько таких делегатов — переводы будут загружены из всех них.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@override Widget build(BuildContext context) { return MaterialApp( supportedLocales: ['en'], localizationsDelegates: [ // Main app delegate AppLocalizations.delegate, // Another delegate from package MyPackageLocalizations.delegate, // Default delegates DefaultCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate ], ); } |
Также вы можете переопределять перевод для делегата из пакета, определив аналогичный геттер с тем же именем в файле локализации приложения (делегат приложения должен быть выше в списке).
⚠️ Важно. Способ будет работать корректно только если первой будет вызвана загрузка, реализованная с помощью multiple_localization. Для этого достаточно реализовать загрузку в делегате локализации приложения описанным выше способом и добавить этот делегат первым в списке.
На этом все. Надеюсь статья была вам полезна. Если у вас есть какие-то вопросы, корректировки или дополнения — оставляйте свои комментарии, я буду благодарен любому фидбэку. ?
Пакет multiple_localization на pub.dev https://pub.dev/packages/multiple_localization
English version on Medium https://medium.com/@greymag/localization-for-dart-package-8ca2f56ea971