i18n
i18n copied to clipboard
Multiple Translations
If in your application you import a package, which is translated and in your application create a translation, you get:
Duplicated library name 'messages_all'. library messages_all;
when using the generate_from_arb functionality. This applies also to the library in the translated files, e.g. messages_es
The cause is that in generate_localized.dart, the library name(s) are hardcoded.
generate_from_arb.dart allows to specify a file prefix, e.g. --generated-file-prefix=base-
I suggest to use the file prefix also for the library names.
Right now the intl package only supports a single set of translations within an app. Are you saying that it actually works to have multiple translations, and you're just getting warnings about the library name?
On Thu, Jun 4, 2015 at 8:40 PM Jorg Janke [email protected] wrote:
If in your application you import a package, which is translated and in your application create a translation, you get:
Duplicated library name 'messages_all'. library messages_all;
when using the generate_from_arb functionality. This applies also to the library in the translated files, e.g. messages_es
The cause is that in generate_localized.dart, the library name(s) are hardcoded.
generate_from_arb.dart allows to specify a file prefix, e.g. --generated-file-prefix=base-
I suggest to use the file prefix also for the library names.
— Reply to this email directly or view it on GitHub https://github.com/dart-lang/i18n/issues/358.
One translation per library. When I import a library which has a translation into an application which has a translation, I get the Warning: Duplicated library name 'messages_all'. .. etc. messages - What are the options to deal with this (not unusual) situation?
Duplicated library names are only a warning, which can be ignored. But if you actually try to use it I suspect that it will fail for other reasons.
The objective was to create an enhancement request - and if it is accepted, I might attempt to fix it by adding the prefix to avoid the name clash.
The enhancement request is reasonable. Changing the name to reflect that. However, the problem is not the duplicated library name. That should probably be fixed to match the file name. But it's probably more important that the program will not run correctly if it has two different sets of translated messages in it. In particular, only the first one that gets initialized for a particular locale will be used, and message in the other will either fail or will use the translation from the first catalog. I thought there was already an open issue for that, but I don't see one, so we can use this one.
I have this problem as well. My app has some of its functionality implemented as an independent package that should be providing its own localized strings; I had to resort to the following dirty hack on the package side to allow its lookup table to coexist with the application's:
import 'dart:async';
import 'dart:ui';
import 'package:flutter/widgets.dart';
import 'package:my_package/l10n/messages_all.dart';
import 'package:intl/intl.dart' as RealIntl; // HORRIBLE HACK! (see below)
import 'package:intl/src/intl_helpers.dart';
class MyPackageLocalizationsDelegate
extends LocalizationsDelegate<MyPackageLocalizations> {
const MyPackageLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ... ;
@override
Future<MyPackageLocalizations> load(Locale locale) =>
MyPackageLocalizations.load(locale);
@override
bool shouldReload(LocalizationsDelegate<MyPackageLocalizations> old) => false;
}
/// HORRIBLE HACK!
///
/// The intl package only supports loading one global message table, which is
/// held at [messageLookup] in intl_helpers.dart. This prevents us from
/// providing localized strings in this plugin for consumption in a parent
/// application, as only one message table will be used.
///
/// The travesty below works around this. It is so horrible because we are
/// trying to have our cake and eat it too:
///
/// - We want to manage strings in this package with the intl_translation
/// extraction and merging tools, so message lookup calls must (appear) to be
/// made to [Intl]
/// - We don't want to edit generated files (messages_all.dart, etc.) by hand
///
/// How it works:
///
/// 1. We define our own [Intl] class that calls into our own lookup,
/// [myMessageLookup]. The lookup is initially "empty".
/// 2. We import the real intl class under an alias and delegate to it where
/// appropriate.
/// 3. We call the default generated [initializeMessages], then immediately swap
/// out the real [messageLookup] and [myMessageLookup] objects. This
/// returns the real lookup to an uninitialized state for the application's
/// localizations to load. (Yes, all this relies on localization delegate
/// init happening sequentially.)
/// 4. We exhort the consuming application to load our localization delegate
/// before the application's.
class Intl {
// copied from the real intl package
static String message(String message_str,
{String desc: '',
Map<String, dynamic> examples: const {},
String locale,
String name,
List args,
String meaning,
bool skip}) =>
_message(message_str, locale, name, args, meaning);
// copied from the real intl package
static _message(String message_str, String locale, String name, List args,
String meaning) {
return myMessageLookup.lookupMessage(
message_str, locale, name, args, meaning);
}
}
MessageLookup myMessageLookup =
UninitializedLocaleData('initializeMessages(<locale>)', null);
class MyPackageLocalizations {
static Future<MyPackageLocalizations> load(Locale locale) {
final name =
locale.countryCode == null ? locale.languageCode : locale.toString();
final localeName = RealIntl.Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
// HORRIBLE HACK! (see above)
// Steal the just-initialized lookup and keep it for ourselves.
// Then un-initialize the real lookup so the next localizations can load.
final uninitialized = myMessageLookup;
myMessageLookup = messageLookup;
messageLookup = uninitialized;
RealIntl.Intl.defaultLocale = localeName;
return MyPackageLocalizations();
});
}
⋮
}
This is pretty unexpected and dangerously hidden limitation to allow only one translation set per app. I would not have expected to face this kind of limitation when developing 3 "totally independent" packages each having their own translation set. It took 3 months until I realized this issue... mainly because the default language works normally. You will see the issue only after changing the language.
My workaround no longer functions, it seems due to changes in the timing of when localization delegates are initialized by the framework.
I've managed to hack it again, but I'm not sure if it only works by coincidence since it relies on a specific order of execution: https://github.com/amake/flutter_l10n_test/commit/6ff8fc632ae728e299e76b38f947f6f2d687ce7e
To have localizations in my packages I'm using a patch that I explain in this article. https://medium.com/@gerrel/flutter-package-with-intl-localization-394e9da1164a?source=friends_link&sk=48169f60f86aef7eb38bf0fe43041574
Is there a better solution?
I use https://github.com/Innim/flutter_multiple_localization to load and override messages
It’s been 9 years and this problem still exists 😭
It’s been 9 years and this problem still exists 😭
Which is why we are working on it in package:messages! :)
It’s been 9 years and this problem still exists 😭
Which is why we are working on it in package:messages! :)
I found the code that caused the current bug in the source code of intl package
Since the messageLookup used by multiple packages is the same object, it causes other packages to return when they are initialized.