Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use multiple LocalizationsDelegates in Flutter

I'm facing an issue where I'm trying to use multiple LocalizationsDelegates in a MaterialApp.

I'm using the Dart intl tools to provide translations to my labels. When I have multiple LocalizationsDelegates only the one that is specified the first gets the translated values. The labels of the next delegate, get the default value provided in the Intl.message() function.

Short, self contained, correct example

I've set up a minimal project as an example of this issue on GitHub.

Code snippets

In the MaterialApp, I define a bunch of localizationsDelegates, including two app specific ones: DogLocalizationsDelegate and CatLocalizationsDelegate.

MaterialApp(
  // other properties
  locale: Locale("en"),
  localizationsDelegates: [
    CatLocalizationsDelegate(),
    DogLocalizationsDelegate(),
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    const Locale('en'),
    const Locale('nl'),
  ],
);

The delegates have the same boilerplate code, but provide different labels. Here's how the DogLocalizations and its DogLocalizationsDelegate look like.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'messages_all.dart';

class DogLocalizations {
  static Future<DogLocalizations> load(Locale locale) {
    final String name = locale.languageCode;
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      return DogLocalizations();
    });
  }

  static DogLocalizations of(BuildContext context) {
    return Localizations.of<DogLocalizations>(context, DogLocalizations);
  }

  String get bark {
    return Intl.message(
      '<insert dog sound>',
      name: 'bark',
    );
  }
}

class DogLocalizationsDelegate extends LocalizationsDelegate<DogLocalizations> {
  const DogLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) => ['en', 'nl'].contains(locale.languageCode);

  @override
  Future<DogLocalizations> load(Locale locale) => DogLocalizations.load(locale);

  @override
  bool shouldReload(DogLocalizationsDelegate old) => false;
}

The CatLocalizations are the same, but with a meow String getter. Full example in the GitHub project.

Commands used to generate translations files

I'm using multiple extraction and generation commands instead of having multiple files in one command. This is because I'm actually having this problem with a library (with its own labels) and a consumer of that library (that also has its own labels).

  1. Extract labels of both cats and dogs

flutter pub run intl_translation:extract_to_arb --output-dir=lib/cat_labels/gen lib/cat_labels/CatLabels.dart

flutter pub run intl_translation:extract_to_arb --output-dir=lib/dog_labels/gen lib/dog_labels/DogLabels.dart

  1. Translate the generated intl_messages.arb to have two language files

    • intl_en.arb
    • intl_nl.arb And then add the correct translated values to these files.
  2. Generate the dart files from ARB

flutter pub run intl_translation:generate_from_arb --output-dir=lib/cat_labels lib/cat_labels/CatLabels.dart lib/cat_labels/gen/intl_*.arb

flutter pub run intl_translation:generate_from_arb --output-dir=lib/dog_labels lib/dog_labels/DogLabels.dart lib/dog_labels/gen/intl_*.arb

Issue

In this demo project, having the following order of delegates:

// main.dart (line 20)
DogLocalizationsDelegate(),
CatLocalizationsDelegate(),

will give the translation for the bark label, but not for the meow label.

When switching it:

// main.dart (line 20)
CatLocalizationsDelegate(),
DogLocalizationsDelegate(),

will give the translation for the meow label, but not for the bark label.

Why multiple localization delegates

In case you're wondering why: I'm using labels in a library and in the consumer apps of that library. Important to know is that it's not (really) possible to specify both localization files in the same generator command because of this.

like image 210
dumazy Avatar asked Jul 30 '19 08:07

dumazy


1 Answers

From what I learned, no, you can’t use multiple localizations delegates like this. That is because intl’s initializeMessages can only be called once per locale.

So in your example, once your CatLocalizationsDelegate runs initializeMessages, the one for DogLocalizationsDelegate has no effect. That’s why you are only seeing the translation Meow! but not Dog’s, or whichever one gets to run it first.

For additional reading, check out https://phrase.com/blog/posts/how-to-internationalize-a-flutter-app/ and please share feedback at https://github.com/flutter/flutter/issues/41437.

like image 133
TWL Avatar answered Oct 13 '22 14:10

TWL