Updates to messages (#762)
* Updates to messages
* Format
* Change carbs name
* Regenerate example
* Rev versions
* Changes as per review
* Remove unused file
diff --git a/pkgs/intl4x/CHANGELOG.md b/pkgs/intl4x/CHANGELOG.md
index 9e5e4f8..e41644a 100644
--- a/pkgs/intl4x/CHANGELOG.md
+++ b/pkgs/intl4x/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.1
+
+- Export plural rules.
+
## 0.7.0
- Add conformance testing workflow.
diff --git a/pkgs/intl4x/lib/intl4x.dart b/pkgs/intl4x/lib/intl4x.dart
index 3496255..aba21c3 100644
--- a/pkgs/intl4x/lib/intl4x.dart
+++ b/pkgs/intl4x/lib/intl4x.dart
@@ -24,6 +24,7 @@
import 'src/plural_rules/plural_rules_options.dart';
export 'src/locale/locale.dart';
+export 'src/plural_rules/plural_rules.dart';
typedef Icu4xKey = String;
diff --git a/pkgs/intl4x/pubspec.yaml b/pkgs/intl4x/pubspec.yaml
index 5a80045..2ceab4a 100644
--- a/pkgs/intl4x/pubspec.yaml
+++ b/pkgs/intl4x/pubspec.yaml
@@ -1,7 +1,7 @@
name: intl4x
description: >-
A lightweight modular library for internationalization (i18n) functionality.
-version: 0.7.0
+version: 0.7.1
repository: https://github.com/dart-lang/i18n/tree/main/pkgs/intl4x
platforms: ## TODO: Add native platforms once ICU4X is integrated.
web:
diff --git a/pkgs/messages/CHANGELOG.md b/pkgs/messages/CHANGELOG.md
index 822f95b..6903662 100644
--- a/pkgs/messages/CHANGELOG.md
+++ b/pkgs/messages/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.2.0
+
+- Remove `IntlObject` interface.
+- Introduce `PluralRules` to retrieve the correct message for plurals.
+
## 0.1.1
- Update README.
diff --git a/pkgs/messages/example_json/bin/example.dart b/pkgs/messages/example_json/bin/example.dart
index 5721893..f53bce4 100644
--- a/pkgs/messages/example_json/bin/example.dart
+++ b/pkgs/messages/example_json/bin/example.dart
@@ -7,13 +7,10 @@
import 'dart:io';
import 'package:example_json/testarbctx2.g.dart';
-import 'package:messages/package_intl_object.dart';
Future<void> main(List<String> arguments) async {
- final messages = AboutPageMessages(
- (String id) async => File(id).readAsString(),
- const OldIntlObject(),
- );
+ final messages =
+ AboutPageMessages((String id) async => File(id).readAsString());
// final index = AboutPageMessagesEnum.aboutMessage;
await messages.loadLocale('en');
diff --git a/pkgs/messages/example_json/lib/testarb.g.dart b/pkgs/messages/example_json/lib/testarb.g.dart
index 03b7516..f35050f 100644
--- a/pkgs/messages/example_json/lib/testarb.g.dart
+++ b/pkgs/messages/example_json/lib/testarb.g.dart
@@ -1,12 +1,10 @@
-// Generated by package:messages_builder
+// Generated by package:messages_builder.
+import 'package:intl4x/intl4x.dart';
import 'package:messages/messages_json.dart';
class HomePageMessages {
- HomePageMessages(
- this._fileLoader,
- this.intlObject,
- );
+ HomePageMessages(this._fileLoader);
final Future<String> Function(String id) _fileLoader;
@@ -14,28 +12,26 @@
final Map<String, MessageList> _messages = {};
- static const carbs = {
+ static const _dataFiles = {
'de': ('lib/testarb_de.json', 'hbDN1MhX'),
'en': ('lib/testarb.json', 'dr9Md951')
};
- IntlObject intlObject;
-
String get currentLocale => _currentLocale;
MessageList get _currentMessages => _messages[currentLocale]!;
- static Iterable<String> get knownLocales => carbs.keys;
+ static Iterable<String> get knownLocales => _dataFiles.keys;
Future<void> loadLocale(String locale) async {
if (!_messages.containsKey(locale)) {
- final info = carbs[locale];
+ final info = _dataFiles[locale];
final carb = info?.$1;
if (carb == null) {
throw ArgumentError('Locale $locale is not in $knownLocales');
}
final data = await _fileLoader(carb);
- final messageList = MessageListJson.fromString(data, intlObject);
+ final messageList = MessageListJson.fromString(data, pluralSelector);
if (messageList.preamble.hash != info?.$2) {
throw ArgumentError('''
Messages file for locale $locale has different hash "${messageList.preamble.hash}" than generated code "${info?.$2}".''');
@@ -46,11 +42,31 @@
}
void loadAllLocales() {
- for (var locale in knownLocales) {
+ for (final locale in knownLocales) {
loadLocale(locale);
}
}
+ Message pluralSelector(
+ num howMany, {
+ required Message other,
+ Message? few,
+ Message? many,
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ }) {
+ Message getCase(int i) => numberCases?[i] ?? wordCases?[i] ?? other;
+ return switch (
+ Intl(locale: Locale.parse(currentLocale)).plural().select(howMany)) {
+ PluralCategory.zero => getCase(0),
+ PluralCategory.one => getCase(1),
+ PluralCategory.two => getCase(2),
+ PluralCategory.few => few ?? other,
+ PluralCategory.many => many ?? other,
+ PluralCategory.other => other,
+ };
+ }
+
String helloAndWelcome(
String firstName,
String lastName,
diff --git a/pkgs/messages/example_json/lib/testarb.json b/pkgs/messages/example_json/lib/testarb.json
index eb1082f..d46d15a 100644
--- a/pkgs/messages/example_json/lib/testarb.json
+++ b/pkgs/messages/example_json/lib/testarb.json
@@ -1 +1 @@
-[0,"en","dr9Md951",0,null,["Welcome von !",[8,0],[13,1]],["Welcome von !",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[2,"No new messages",4,"One new message",5,"Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]]]
\ No newline at end of file
+[0,"en","dr9Md951",0,null,["Welcome von !",[8,0],[13,1]],["Welcome von !",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]]]
\ No newline at end of file
diff --git a/pkgs/messages/example_json/lib/testarb_de.json b/pkgs/messages/example_json/lib/testarb_de.json
index f77a4e5..8480d16 100644
--- a/pkgs/messages/example_json/lib/testarb_de.json
+++ b/pkgs/messages/example_json/lib/testarb_de.json
@@ -1 +1 @@
-[0,"de","hbDN1MhX",0,null,["Willkommen von ",[11,0],[16,1]],["Willkommen von 2",[11,0],[16,1]],[6,"testde ",[3,0,["test new messages",[5,0]],[2,"No new messages",4,"One new message",5,"Two new Messages"]]],"testdse is just a simple message"]
\ No newline at end of file
+[0,"de","hbDN1MhX",0,null,["Willkommen von ",[11,0],[16,1]],["Willkommen von 2",[11,0],[16,1]],[6,"testde ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],"testdse is just a simple message"]
\ No newline at end of file
diff --git a/pkgs/messages/example_json/lib/testarbctx2.g.dart b/pkgs/messages/example_json/lib/testarbctx2.g.dart
index 0a7c6d8..55aa20f 100644
--- a/pkgs/messages/example_json/lib/testarbctx2.g.dart
+++ b/pkgs/messages/example_json/lib/testarbctx2.g.dart
@@ -1,12 +1,10 @@
-// Generated by package:messages_builder
+// Generated by package:messages_builder.
+import 'package:intl4x/intl4x.dart';
import 'package:messages/messages_json.dart';
class AboutPageMessages {
- AboutPageMessages(
- this._fileLoader,
- this.intlObject,
- );
+ AboutPageMessages(this._fileLoader);
final Future<String> Function(String id) _fileLoader;
@@ -14,28 +12,26 @@
final Map<String, MessageList> _messages = {};
- static const carbs = {
+ static const _dataFiles = {
'fr': ('lib/testarbctx2_fr.json', 'EyPjEJJU'),
'en': ('lib/testarbctx2.json', 'QrwRSsOy')
};
- IntlObject intlObject;
-
String get currentLocale => _currentLocale;
MessageList get _currentMessages => _messages[currentLocale]!;
- static Iterable<String> get knownLocales => carbs.keys;
+ static Iterable<String> get knownLocales => _dataFiles.keys;
Future<void> loadLocale(String locale) async {
if (!_messages.containsKey(locale)) {
- final info = carbs[locale];
+ final info = _dataFiles[locale];
final carb = info?.$1;
if (carb == null) {
throw ArgumentError('Locale $locale is not in $knownLocales');
}
final data = await _fileLoader(carb);
- final messageList = MessageListJson.fromString(data, intlObject);
+ final messageList = MessageListJson.fromString(data, pluralSelector);
if (messageList.preamble.hash != info?.$2) {
throw ArgumentError('''
Messages file for locale $locale has different hash "${messageList.preamble.hash}" than generated code "${info?.$2}".''');
@@ -46,11 +42,31 @@
}
void loadAllLocales() {
- for (var locale in knownLocales) {
+ for (final locale in knownLocales) {
loadLocale(locale);
}
}
+ Message pluralSelector(
+ num howMany, {
+ required Message other,
+ Message? few,
+ Message? many,
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ }) {
+ Message getCase(int i) => numberCases?[i] ?? wordCases?[i] ?? other;
+ return switch (
+ Intl(locale: Locale.parse(currentLocale)).plural().select(howMany)) {
+ PluralCategory.zero => getCase(0),
+ PluralCategory.one => getCase(1),
+ PluralCategory.two => getCase(2),
+ PluralCategory.few => few ?? other,
+ PluralCategory.many => many ?? other,
+ PluralCategory.other => other,
+ };
+ }
+
String aboutMessage(String websitename) =>
_currentMessages.generateStringAtIndex(0, [websitename]);
diff --git a/pkgs/messages/example_json/lib/testarbctx2.json b/pkgs/messages/example_json/lib/testarbctx2.json
index f59abb6..a56c79c 100644
--- a/pkgs/messages/example_json/lib/testarbctx2.json
+++ b/pkgs/messages/example_json/lib/testarbctx2.json
@@ -1 +1 @@
-[0,"en","QrwRSsOy",0,null,["About ",[6,0]],["Welcome von <",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[2,"No new messages",4,"One new message",5,"Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],"other"]
\ No newline at end of file
+[0,"en","QrwRSsOy",0,null,["About ",[6,0]],["Welcome von <",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],"other"]
\ No newline at end of file
diff --git a/pkgs/messages/example_json/lib/testarbctx2_fr.json b/pkgs/messages/example_json/lib/testarbctx2_fr.json
index a1c89f3..61b6c08 100644
--- a/pkgs/messages/example_json/lib/testarbctx2_fr.json
+++ b/pkgs/messages/example_json/lib/testarbctx2_fr.json
@@ -1 +1 @@
-[0,"fr","EyPjEJJU",0,null,["Sur ",[4,0]],["Welcome von <",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[2,"No new messages",4,"One new message",5,"Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],"other"]
\ No newline at end of file
+[0,"fr","EyPjEJJU",0,null,["Sur ",[4,0]],["Welcome von <",[8,0],[13,1]],[6,"test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],"other"]
\ No newline at end of file
diff --git a/pkgs/messages/example_json/pubspec.yaml b/pkgs/messages/example_json/pubspec.yaml
index 348628f..6807cce 100644
--- a/pkgs/messages/example_json/pubspec.yaml
+++ b/pkgs/messages/example_json/pubspec.yaml
@@ -6,6 +6,7 @@
sdk: ^3.0.0
dependencies:
+ intl4x: ^0.7.0
messages:
path: ../
@@ -25,3 +26,4 @@
generateMethods: true
generateFindById: false
generateFindBy: integer
+ pluralSelector: intl4x
diff --git a/pkgs/messages/example_json/pubspec_overrides.yaml b/pkgs/messages/example_json/pubspec_overrides.yaml
index 4477e4d..54623dd 100644
--- a/pkgs/messages/example_json/pubspec_overrides.yaml
+++ b/pkgs/messages/example_json/pubspec_overrides.yaml
@@ -3,3 +3,5 @@
path: ../
messages_serializer:
path: ../../messages_serializer
+ intl4x:
+ path: ../../intl4x
diff --git a/pkgs/messages/lib/messages.dart b/pkgs/messages/lib/messages.dart
index 9926f34..6544241 100644
--- a/pkgs/messages/lib/messages.dart
+++ b/pkgs/messages/lib/messages.dart
@@ -3,6 +3,4 @@
// BSD-style license that can be found in the LICENSE file.
export 'src/deserializer/deserializer.dart';
-export 'src/intl_object.dart' show IntlObject;
-export 'src/intl_style_lookup.dart' show Intl;
export 'src/message_format.dart';
diff --git a/pkgs/messages/lib/package_intl_object.dart b/pkgs/messages/lib/package_intl_object.dart
deleted file mode 100644
index 42ae38e..0000000
--- a/pkgs/messages/lib/package_intl_object.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-//TODO: Move OldIntlObject to package:intl
-export 'src/old_intl_object.dart' show OldIntlObject;
diff --git a/pkgs/messages/lib/src/deserializer/deserializer.dart b/pkgs/messages/lib/src/deserializer/deserializer.dart
index 7888ddc..1bc6120 100644
--- a/pkgs/messages/lib/src/deserializer/deserializer.dart
+++ b/pkgs/messages/lib/src/deserializer/deserializer.dart
@@ -2,9 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import '../intl_object.dart';
import '../message_format.dart';
+import '../plural_selector.dart';
abstract class Deserializer<T extends MessageList> {
- T deserialize(IntlObject intl);
+ T deserialize(PluralSelector selector);
}
diff --git a/pkgs/messages/lib/src/deserializer/deserializer_json.dart b/pkgs/messages/lib/src/deserializer/deserializer_json.dart
index a6aa509..98a56ed 100644
--- a/pkgs/messages/lib/src/deserializer/deserializer_json.dart
+++ b/pkgs/messages/lib/src/deserializer/deserializer_json.dart
@@ -4,9 +4,9 @@
import 'dart:convert';
-import '../intl_object.dart';
import '../message_format.dart';
import '../message_list_json.dart';
+import '../plural_selector.dart';
import 'deserializer.dart';
class JsonDeserializer extends Deserializer<MessageListJson> {
@@ -20,7 +20,7 @@
}
@override
- MessageListJson deserialize(IntlObject intl) {
+ MessageListJson deserialize(PluralSelector selector) {
if (preamble.version != serializationVersion) {
throw ArgumentError(
'''This message has version ${preamble.version}, while the deserializer has version $serializationVersion''');
@@ -32,7 +32,7 @@
return MessageListJson(
preamble,
_messages,
- intl,
+ selector,
mapping?.map((key, value) => MapEntry(
int.parse(key, radix: serializationRadix),
int.parse(value as String, radix: serializationRadix),
@@ -55,8 +55,6 @@
return _forPlural(message, start, id);
} else if (typeOrId == SelectMessage.type) {
return _forSelect(message, start, id);
- } else if (typeOrId == GenderMessage.type) {
- return _forGender(message, start, id);
} else if (typeOrId == CombinedMessage.type) {
return _forCombined(message, start, id);
} else if (typeOrId is String) {
@@ -83,51 +81,29 @@
PluralMessage _forPlural(List<dynamic> message, int start, String? id) {
final argIndex = message[start] as int;
final otherMessage = getMessage(message[start + 1]);
- Message? zeroWordMessage;
- Message? zeroNumberMessage;
- Message? oneWordMessage;
- Message? oneNumberMessage;
- Message? twoWordMessage;
- Message? twoNumberMessage;
Message? fewMessage;
Message? manyMessage;
+ final numberCases = <int, Message>{};
+ final wordCases = <int, Message>{};
final submessages = message[start + 2] as List;
for (var i = 0; i < submessages.length - 1; i += 2) {
final msg = getMessage(submessages[i + 1]);
- switch (submessages[i]) {
- case Plural.zeroWord:
- zeroWordMessage = msg;
- break;
- case Plural.zeroNumber:
- zeroNumberMessage = msg;
- break;
- case Plural.oneWord:
- oneWordMessage = msg;
- break;
- case Plural.oneNumber:
- oneNumberMessage = msg;
- break;
- case Plural.twoWord:
- twoWordMessage = msg;
- break;
- case Plural.twoNumber:
- twoNumberMessage = msg;
- break;
- case Plural.few:
- fewMessage = msg;
- break;
- case Plural.many:
- manyMessage = msg;
- break;
+ final messageMarker = submessages[i];
+ if (messageMarker case PluralMarker.few) {
+ fewMessage = msg;
+ } else if (messageMarker case PluralMarker.many) {
+ manyMessage = msg;
+ } else if (messageMarker case final int digit) {
+ numberCases[digit] = msg;
+ } else if (messageMarker is String &&
+ messageMarker.startsWith(PluralMarker.wordCase)) {
+ final digit = int.parse(messageMarker.substring(1));
+ wordCases[digit] = msg;
}
}
return PluralMessage(
- zeroNumber: zeroNumberMessage,
- zeroWord: zeroWordMessage,
- oneNumber: oneNumberMessage,
- oneWord: oneWordMessage,
- twoNumber: twoNumberMessage,
- twoWord: twoWordMessage,
+ numberCases: numberCases,
+ wordCases: wordCases,
few: fewMessage,
many: manyMessage,
argIndex: argIndex,
@@ -153,30 +129,4 @@
message.skip(start).map(getMessage).toList(),
);
}
-
- GenderMessage _forGender(List<dynamic> message, int start, String? id) {
- final argIndex = message[start] as int;
- final otherMessage = getMessage(message[start + 1]);
- final submessages = message[start + 2] as List;
- Message? femaleMessage;
- Message? maleMessage;
- for (var i = 0; i < submessages.length - 1; i += 2) {
- final msg = getMessage(submessages[i + 1]);
- switch (submessages[i]) {
- case Gender.female:
- femaleMessage = msg;
- break;
- case Gender.male:
- maleMessage = msg;
- break;
- }
- }
- return GenderMessage(
- female: femaleMessage,
- male: maleMessage,
- other: otherMessage,
- argIndex: argIndex,
- id: id,
- );
- }
}
diff --git a/pkgs/messages/lib/src/intl_object.dart b/pkgs/messages/lib/src/intl_object.dart
deleted file mode 100644
index 0638121..0000000
--- a/pkgs/messages/lib/src/intl_object.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'message.dart';
-
-abstract class IntlObject {
- const IntlObject();
-
- Message gender(
- GenderEnum gender,
- Message? female,
- Message? male,
- Message other,
- );
-
- Message plural(
- num howMany, {
- Message? zero,
- Message? one,
- Message? two,
- Message? few,
- Message? many,
- required Message other,
- String? locale,
- });
-
- Message select(Object arg, Map<Object, Message> cases);
-}
diff --git a/pkgs/messages/lib/src/intl_style_lookup.dart b/pkgs/messages/lib/src/intl_style_lookup.dart
deleted file mode 100644
index 5a5d4a6..0000000
--- a/pkgs/messages/lib/src/intl_style_lookup.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-class Intl {
- static MessageLookup? l;
-
- static String message(
- String s, {
- required List<String> args,
- required String id,
- }) {
- if (l != null) return l!.getById(id, args);
- for (var i = 0; i < args.length; i++) {
- s = s.replaceAll('#$i', args[i]);
- }
- return s;
- }
-}
-
-abstract class MessageLookup {
- String getById(String id, List<dynamic> args);
-}
diff --git a/pkgs/messages/lib/src/message.dart b/pkgs/messages/lib/src/message.dart
index 63da1fe..54adec1 100644
--- a/pkgs/messages/lib/src/message.dart
+++ b/pkgs/messages/lib/src/message.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'intl_object.dart';
+import 'plural_selector.dart';
sealed class Message {
final String? id;
@@ -11,7 +11,7 @@
String generateString(
List allArgs, {
- required IntlObject intl,
+ required PluralSelector pluralSelector,
String? locale,
String Function(String p1)? cleaner,
});
@@ -25,14 +25,14 @@
@override
String generateString(
List allArgs, {
- required IntlObject intl,
+ required PluralSelector pluralSelector,
String Function(String p1)? cleaner,
String? locale,
}) =>
messages
.map((e) => e.generateString(
allArgs,
- intl: intl,
+ pluralSelector: pluralSelector,
cleaner: cleaner,
locale: locale,
))
@@ -57,7 +57,7 @@
@override
String generateString(
List allArgs, {
- required IntlObject intl,
+ required PluralSelector pluralSelector,
String Function(String p1)? cleaner,
String? locale,
}) {
@@ -81,73 +81,20 @@
}
}
-final class GenderMessage extends Message {
- final Message? male;
- final Message? female;
- final Message other;
- final int argIndex;
-
- GenderMessage({
- this.male,
- this.female,
- required this.other,
- required this.argIndex,
- String? id,
- }) : super(id);
-
- static const int type = 5;
-
- @override
- String generateString(
- List allArgs, {
- required IntlObject intl,
- String Function(String p1)? cleaner,
- String? locale,
- }) {
- return intl
- .gender(
- allArgs[argIndex] as GenderEnum,
- female,
- male,
- other,
- )
- .generateString(
- allArgs,
- intl: intl,
- cleaner: cleaner,
- locale: locale,
- );
- }
-}
-
-enum GenderEnum {
- female,
- male,
- other;
-}
-
final class PluralMessage extends Message {
- final Message? zeroWord;
- final Message? zeroNumber;
- final Message? oneWord;
- final Message? oneNumber;
- final Message? twoWord;
- final Message? twoNumber;
+ final Map<int, Message> numberCases;
+ final Map<int, Message> wordCases;
final Message? few;
final Message? many;
final Message other;
final int argIndex;
PluralMessage({
+ this.numberCases = const {},
+ this.wordCases = const {},
this.few,
this.many,
required this.other,
- this.zeroWord,
- this.zeroNumber,
- this.oneWord,
- this.oneNumber,
- this.twoWord,
- this.twoNumber,
required this.argIndex,
String? id,
}) : super(id);
@@ -157,22 +104,19 @@
@override
String generateString(
List allArgs, {
- required IntlObject intl,
+ required PluralSelector pluralSelector,
String Function(String p1)? cleaner,
String? locale,
}) {
- return intl
- .plural(
- allArgs[argIndex] as num,
- few: few,
- many: many,
- zero: zeroNumber ?? zeroWord,
- one: oneNumber ?? oneWord,
- two: twoNumber ?? twoWord,
- other: other,
- locale: locale,
- )
- .generateString(allArgs, intl: intl, cleaner: cleaner, locale: locale);
+ return pluralSelector(
+ allArgs[argIndex] as num,
+ numberCases: numberCases,
+ wordCases: wordCases,
+ few: few,
+ many: many,
+ other: other,
+ ).generateString(allArgs,
+ pluralSelector: pluralSelector, cleaner: cleaner, locale: locale);
}
}
@@ -192,14 +136,13 @@
@override
String generateString(
List allArgs, {
- required IntlObject intl,
+ required PluralSelector pluralSelector,
String Function(String p1)? cleaner,
String? locale,
}) {
- final selected =
- intl.select(allArgs[argIndex] as Object, {...cases, 'other': other});
+ final selected = cases[allArgs[argIndex]!] ?? other;
return selected.generateString(
- intl: intl,
+ pluralSelector: pluralSelector,
allArgs,
cleaner: cleaner,
locale: locale,
diff --git a/pkgs/messages/lib/src/message_format.dart b/pkgs/messages/lib/src/message_format.dart
index c8e881e..909d7a4 100644
--- a/pkgs/messages/lib/src/message_format.dart
+++ b/pkgs/messages/lib/src/message_format.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// ignore_for_file: non_constant_identifier_names
-import 'intl_object.dart';
+import 'plural_selector.dart';
export 'message.dart';
@@ -30,36 +30,15 @@
abstract class MessageList {
Preamble get preamble;
- IntlObject get intl;
+ PluralSelector get pluralSelector;
String generateStringAtIndex(int index, List args);
String generateStringAtId(String id, List args);
}
-enum PluralEnum {
- zeroWord,
- zeroNumber,
- oneWord,
- oneNumber,
- twoWord,
- twoNumber,
- few,
- many,
-}
-
-class Plural {
- static const int zeroWord = 1;
- static const int zeroNumber = 2;
- static const int oneWord = 3;
- static const int oneNumber = 4;
- static const int twoWord = 5;
- static const int twoNumber = 6;
- static const int few = 7;
- static const int many = 8;
-}
-
-class Gender {
- static const int female = 1;
- static const int male = 2;
+sealed class PluralMarker {
+ static const String wordCase = 'w';
+ static const String few = 'f';
+ static const String many = 'm';
}
diff --git a/pkgs/messages/lib/src/message_list_json.dart b/pkgs/messages/lib/src/message_list_json.dart
index 773e4a3..bb0eb1c 100644
--- a/pkgs/messages/lib/src/message_list_json.dart
+++ b/pkgs/messages/lib/src/message_list_json.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'deserializer/deserializer_json.dart';
-import 'intl_object.dart';
import 'message_format.dart';
+import 'plural_selector.dart';
class JsonPreamble extends Preamble {
final List _data;
@@ -40,12 +40,12 @@
class MessageListJson extends MessageList {
final List<Message> messages;
- final IntlObject _intl;
+ final PluralSelector _selector;
final JsonPreamble _preamble;
final Map<int, int>? messageIndices;
@override
- IntlObject get intl => _intl;
+ PluralSelector get pluralSelector => _selector;
@override
Preamble get preamble => _preamble;
@@ -53,22 +53,22 @@
MessageListJson(
this._preamble,
this.messages,
- this._intl,
+ this._selector,
this.messageIndices,
);
- factory MessageListJson.fromString(String string, IntlObject intl) =>
+ factory MessageListJson.fromString(String string, PluralSelector intl) =>
JsonDeserializer(string).deserialize(intl);
@override
String generateStringAtId(String id, List args) => messages
.where((element) => element.id == id)
.first
- .generateString(args, intl: _intl);
+ .generateString(args, pluralSelector: _selector);
@override
String generateStringAtIndex(int index, List args) =>
- messages[getIndex(index)].generateString(args, intl: _intl);
+ messages[getIndex(index)].generateString(args, pluralSelector: _selector);
int getIndex(int index) => messageIndices?[index] ?? index;
}
diff --git a/pkgs/messages/lib/src/old_intl_object.dart b/pkgs/messages/lib/src/old_intl_object.dart
deleted file mode 100644
index a217376..0000000
--- a/pkgs/messages/lib/src/old_intl_object.dart
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:intl/intl.dart' as old_intl;
-
-import 'intl_object.dart';
-import 'message.dart';
-
-class OldIntlObject extends IntlObject {
- const OldIntlObject();
- @override
- Message gender(
- GenderEnum gender,
- Message? female,
- Message? male,
- Message other,
- ) =>
- old_intl.Intl.genderLogic<Message>(
- gender.name,
- female: female,
- male: male,
- other: other,
- );
-
- @override
- Message plural(
- num howMany, {
- Message? zero,
- Message? one,
- Message? two,
- Message? few,
- Message? many,
- required Message other,
- String? locale,
- }) {
- return old_intl.Intl.pluralLogic(
- howMany,
- few: few,
- many: many,
- zero: zero,
- one: one,
- two: two,
- other: other,
- locale: locale,
- );
- }
-
- @override
- Message select(Object arg, Map<Object, Message> cases) {
- return old_intl.Intl.selectLogic(
- arg,
- cases,
- );
- }
-}
diff --git a/pkgs/messages/lib/src/plural_selector.dart b/pkgs/messages/lib/src/plural_selector.dart
new file mode 100644
index 0000000..5d6899b
--- /dev/null
+++ b/pkgs/messages/lib/src/plural_selector.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'message.dart';
+
+typedef PluralSelector = Message Function(
+ num howMany, {
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ Message? few,
+ Message? many,
+ required Message other,
+});
diff --git a/pkgs/messages/pubspec.yaml b/pkgs/messages/pubspec.yaml
index 7ccaf86..82e3b90 100644
--- a/pkgs/messages/pubspec.yaml
+++ b/pkgs/messages/pubspec.yaml
@@ -1,6 +1,6 @@
name: messages
description: A lightweight modular library for localization (l10n) functionality.
-version: 0.1.1
+version: 0.2.0
repository: https://github.com/dart-lang/i18n/tree/main/pkgs/messages
environment:
diff --git a/pkgs/messages/test/messagelist_json_test.dart b/pkgs/messages/test/messagelist_json_test.dart
index 2c90587..ab29145 100644
--- a/pkgs/messages/test/messagelist_json_test.dart
+++ b/pkgs/messages/test/messagelist_json_test.dart
@@ -2,10 +2,31 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:intl/intl.dart' as old_intl;
import 'package:messages/messages_json.dart';
-import 'package:messages/package_intl_object.dart';
import 'package:test/test.dart';
+Message intlPluralSelector(
+ num howMany, {
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ Message? few,
+ Message? many,
+ required Message other,
+ String? locale,
+}) {
+ return old_intl.Intl.pluralLogic(
+ howMany,
+ few: few,
+ many: many,
+ zero: numberCases?[0] ?? wordCases?[0],
+ one: numberCases?[1] ?? wordCases?[1],
+ two: numberCases?[2] ?? wordCases?[2],
+ other: other,
+ locale: locale,
+ );
+}
+
void main() {
test('JSON MessageList', () {
final MessageList messageList = MessageListJson(
@@ -27,17 +48,19 @@
'case2': StringMessage('Case 2'),
'case3': PluralMessage(
other: StringMessage('other nested'),
- twoNumber: StringMessage(': ', argPositions: [
- (stringIndex: 0, argIndex: 0),
- (stringIndex: 2, argIndex: 1),
- ]),
+ numberCases: {
+ 2: StringMessage(': ', argPositions: [
+ (stringIndex: 0, argIndex: 0),
+ (stringIndex: 2, argIndex: 1),
+ ])
+ },
argIndex: 1,
),
},
0,
)
],
- const OldIntlObject(),
+ intlPluralSelector,
null,
);
diff --git a/pkgs/messages_builder/CHANGELOG.md b/pkgs/messages_builder/CHANGELOG.md
index 9ee6d8d..e17f754 100644
--- a/pkgs/messages_builder/CHANGELOG.md
+++ b/pkgs/messages_builder/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.2.0
+
+- Remove `IntlObject` interface.
+- Introduce `PluralRules` to retrieve the correct message for plurals.
+
## 0.1.1
- Add `header` to `GenerationOptions`.
diff --git a/pkgs/messages_builder/lib/code_generation/constructor_generation.dart b/pkgs/messages_builder/lib/code_generation/constructor_generation.dart
index 468c2d2..936ef66 100644
--- a/pkgs/messages_builder/lib/code_generation/constructor_generation.dart
+++ b/pkgs/messages_builder/lib/code_generation/constructor_generation.dart
@@ -21,9 +21,10 @@
..name = '_fileLoader'
..toThis = true,
),
- Parameter((pb) => pb
- ..name = 'intlObject'
- ..toThis = true),
+ if (options.pluralSelector == PluralSelectorType.custom)
+ Parameter((pb) => pb
+ ..name = 'pluralSelector'
+ ..toThis = true),
]));
return [nativeConstructor];
}
diff --git a/pkgs/messages_builder/lib/code_generation/field_generation.dart b/pkgs/messages_builder/lib/code_generation/field_generation.dart
index 7c667fb..a6d28f6 100644
--- a/pkgs/messages_builder/lib/code_generation/field_generation.dart
+++ b/pkgs/messages_builder/lib/code_generation/field_generation.dart
@@ -42,29 +42,30 @@
..name = '_messages'
..assignment = const Code('{}'),
);
- final carbs = Field(
+ final dataFiles = Field(
(fb) {
final paths = localeToResourceInfo.entries
.map((e) => "'${e.key}' : ('${e.value.path}', '${e.value.hasch}')")
.join(',');
fb
- ..name = 'carbs'
+ ..name = '_dataFiles'
..modifier = FieldModifier.constant
..static = true
..assignment = Code('{$paths}');
},
);
- final intlObject = Field(
+ final pluralSelector = Field(
(fb) => fb
- ..name = 'intlObject'
- ..type = const Reference('IntlObject'),
+ ..name = 'pluralSelector'
+ ..type = const Reference(
+ '''Message Function(num howMany, {Map<int, Message>? numberCases, Map<int, Message>? wordCases, Message? few, Message? many, Message other, String? locale})'''),
);
final fields = [
loadingStrategy,
currentLocale,
messages,
- carbs,
- intlObject,
+ dataFiles,
+ if (options.pluralSelector == PluralSelectorType.custom) pluralSelector,
];
return fields;
}
diff --git a/pkgs/messages_builder/lib/code_generation/import_generation.dart b/pkgs/messages_builder/lib/code_generation/import_generation.dart
index 66a4b7f..79ee4e5 100644
--- a/pkgs/messages_builder/lib/code_generation/import_generation.dart
+++ b/pkgs/messages_builder/lib/code_generation/import_generation.dart
@@ -19,6 +19,13 @@
Directive.import('package:messages/messages_json.dart')
],
};
- return serializationImports;
+ final pluralImports = switch (options.pluralSelector) {
+ PluralSelectorType.intl => [Directive.import('package:intl/intl.dart')],
+ PluralSelectorType.intl4x => [
+ Directive.import('package:intl4x/intl4x.dart')
+ ],
+ PluralSelectorType.custom => <Directive>[],
+ };
+ return [...serializationImports, ...pluralImports];
}
}
diff --git a/pkgs/messages_builder/lib/code_generation/method_generation.dart b/pkgs/messages_builder/lib/code_generation/method_generation.dart
index 39f684d..c2438f7 100644
--- a/pkgs/messages_builder/lib/code_generation/method_generation.dart
+++ b/pkgs/messages_builder/lib/code_generation/method_generation.dart
@@ -63,7 +63,7 @@
final loading = switch (options.deserialization) {
DeserializationType.web => '''
final data = await _fileLoader(carb);
- final messageList = MessageListJson.fromString(data, intlObject);''',
+ final messageList = MessageListJson.fromString(data, pluralSelector);''',
};
mb
..name = 'loadLocale'
@@ -75,7 +75,7 @@
..modifier = MethodModifier.async
..body = Code('''
if (!_messages.containsKey(locale)) {
- final info = carbs[locale];
+ final info = _dataFiles[locale];
final carb = info?.\$1;
if (carb == null) {
throw ArgumentError('Locale \$locale is not in \$knownLocales');
@@ -98,7 +98,7 @@
..name = 'loadAllLocales'
..returns = const Reference('void')
..body = const Code('''
- for (var locale in knownLocales) {
+ for (final locale in knownLocales) {
loadLocale(locale);
}
''');
@@ -110,7 +110,7 @@
..type = MethodType.getter
..lambda = true
..static = true
- ..body = const Code('carbs.keys')
+ ..body = const Code('_dataFiles.keys')
..returns = const Reference('Iterable<String>'),
);
final getCurrentMessages = Method(
@@ -166,6 +166,60 @@
const Code('_currentMessages.generateStringAtIndex(val.index, args)')
..lambda = true
..returns = const Reference('String'));
+ // Message Function(num,
+ // {Message? few,
+ // String? locale,
+ // Message? many,
+ // Map<int, Message>? numberCases,
+ // required Message other,
+ // Map<int, Message>? wordCases}) intl;
+ Method pluralSelector() => Method(
+ (mb) => mb
+ ..name = 'pluralSelector'
+ ..returns = const Reference('Message')
+ ..requiredParameters.addAll([
+ Parameter(
+ (pb) => pb
+ ..name = 'howMany'
+ ..type = const Reference('num')
+ ..named = false,
+ ),
+ ])
+ ..optionalParameters.addAll([
+ Parameter(
+ (pb) => pb
+ ..name = 'other'
+ ..type = const Reference('Message')
+ ..required = true
+ ..named = true,
+ ),
+ Parameter(
+ (pb) => pb
+ ..name = 'few'
+ ..type = const Reference('Message?')
+ ..named = true,
+ ),
+ Parameter(
+ (pb) => pb
+ ..name = 'many'
+ ..type = const Reference('Message?')
+ ..named = true,
+ ),
+ Parameter(
+ (pb) => pb
+ ..name = 'numberCases'
+ ..type = const Reference('Map<int, Message>?')
+ ..named = true,
+ ),
+ Parameter(
+ (pb) => pb
+ ..name = 'wordCases'
+ ..type = const Reference('Map<int, Message>?')
+ ..named = true,
+ ),
+ ])
+ ..body = pluralSelectorBody(),
+ );
return [
getCurrentLocale,
@@ -175,7 +229,37 @@
getKnownLocales,
loadLocale,
loadAllLocales,
+ if (options.pluralSelector != PluralSelectorType.custom) pluralSelector(),
...messageCalls,
];
}
+
+ Code pluralSelectorBody() {
+ return switch (options.pluralSelector) {
+ PluralSelectorType.intl => const Code('''
+return Intl.pluralLogic(
+ howMany,
+ few: few,
+ many: many,
+ zero: numberCases?[0] ?? wordCases?[0],
+ one: numberCases?[1] ?? wordCases?[1],
+ two: numberCases?[2] ?? wordCases?[2],
+ other: other,
+ locale: currentLocale,
+ );
+ '''),
+ PluralSelectorType.intl4x => const Code('''
+Message getCase(int i) => numberCases?[i] ?? wordCases?[i] ?? other;
+ return switch (Intl(locale: Locale.parse(currentLocale)).plural().select(howMany)) {
+ PluralCategory.zero => getCase(0),
+ PluralCategory.one => getCase(1),
+ PluralCategory.two => getCase(2),
+ PluralCategory.few => few ?? other,
+ PluralCategory.many => many ?? other,
+ PluralCategory.other => other,
+ };
+ '''),
+ PluralSelectorType.custom => throw ArgumentError(),
+ };
+ }
}
diff --git a/pkgs/messages_builder/lib/generation_options.dart b/pkgs/messages_builder/lib/generation_options.dart
index e9e2616..6573b3f 100644
--- a/pkgs/messages_builder/lib/generation_options.dart
+++ b/pkgs/messages_builder/lib/generation_options.dart
@@ -36,8 +36,12 @@
/// dart native code.
final DeserializationType deserialization;
+ /// The header to add to all generated files, for example for licensing.
final String header;
+ /// The origin of the algorithm for determining which plural case to use.
+ final PluralSelectorType pluralSelector;
+
GenerationOptions({
required this.serialization,
required this.deserialization,
@@ -45,6 +49,7 @@
required this.findById,
required this.indexType,
required this.header,
+ required this.pluralSelector,
});
static Future<GenerationOptions> fromPubspec(BuildStep buildStep) async {
@@ -58,16 +63,31 @@
deserialization: DeserializationType.web,
messageCalls: (messagesOptions?['generateMethods'] as bool?) ?? true,
findById: (messagesOptions?['generateFindById'] as bool?) ?? false,
- indexType: IndexType.values
- .where((type) =>
- type.name == messagesOptions?['generateFindBy'] as String?)
- .firstOrNull ??
- IndexType.integer,
+ indexType: _indexType(messagesOptions),
header: messagesOptions?['header'] as String? ??
'Generated by package:messages_builder.',
+ pluralSelector: _pluralSelector(messagesOptions),
);
return generationOptions;
}
+
+ static IndexType _indexType(YamlMap? messagesOptions) {
+ final generateFindString = messagesOptions?['generateFindBy'] as String?;
+ return generateFindString != null
+ ? IndexType.values
+ .where((type) => type.name == generateFindString)
+ .first
+ : IndexType.integer;
+ }
+
+ static PluralSelectorType _pluralSelector(YamlMap? messagesOptions) {
+ final pluralSelectorString = messagesOptions?['pluralSelector'] as String?;
+ return pluralSelectorString != null
+ ? PluralSelectorType.values
+ .where((type) => type.name == pluralSelectorString)
+ .first
+ : PluralSelectorType.intl;
+ }
}
enum SerializationType {
@@ -78,8 +98,27 @@
web;
}
+/// How the indexing of the messages should be implemented.
enum IndexType {
+ /// No indexing.
none,
+
+ /// Indexing via a collection of `static int`s.
integer,
+
+ /// Indexing via an enum.
enumerate;
}
+
+/// The origin of the algorithm for determining which plural case to use.
+enum PluralSelectorType {
+ /// From `package:intl`.
+ intl,
+
+ /// From `package:intl4x`.
+
+ intl4x,
+
+ /// A user-specified algorithm.
+ custom;
+}
diff --git a/pkgs/messages_builder/lib/message_parser/plural_parser.dart b/pkgs/messages_builder/lib/message_parser/plural_parser.dart
index 92fd340..77ec654 100644
--- a/pkgs/messages_builder/lib/message_parser/plural_parser.dart
+++ b/pkgs/messages_builder/lib/message_parser/plural_parser.dart
@@ -56,12 +56,8 @@
final numberCases = getNumberCases(parts, arguments);
final wordCases = getWordCases(parts, arguments);
return PluralMessage(
- zeroNumber: numberCases[0],
- zeroWord: wordCases[0],
- oneNumber: numberCases[1],
- oneWord: wordCases[1],
- twoNumber: numberCases[2],
- twoWord: wordCases[2],
+ numberCases: numberCases,
+ wordCases: wordCases,
few: getNamed(parts, 'few', arguments),
many: getNamed(parts, 'many', arguments),
other: getOther(parts, arguments)!,
diff --git a/pkgs/messages_builder/pubspec.yaml b/pkgs/messages_builder/pubspec.yaml
index 962f923..1cf7124 100644
--- a/pkgs/messages_builder/pubspec.yaml
+++ b/pkgs/messages_builder/pubspec.yaml
@@ -1,6 +1,6 @@
name: messages_builder
description: Build the messages for consumption by package:messages
-version: 0.1.1
+version: 0.2.0
repository: https://github.com/dart-lang/i18n/pkgs/messages_builder
environment:
diff --git a/pkgs/messages_builder/test/web_deserializer_native_test.dart b/pkgs/messages_builder/test/web_deserializer_native_test.dart
index 0761683..e93fa82 100644
--- a/pkgs/messages_builder/test/web_deserializer_native_test.dart
+++ b/pkgs/messages_builder/test/web_deserializer_native_test.dart
@@ -5,8 +5,8 @@
import 'dart:convert';
import 'package:build/src/asset/id.dart';
+import 'package:intl/intl.dart' as old_intl;
import 'package:messages/messages_json.dart';
-import 'package:messages/package_intl_object.dart';
import 'package:messages_builder/arb_parser.dart';
import 'package:messages_builder/message_with_metadata.dart';
import 'package:messages_serializer/messages_serializer.dart';
@@ -14,6 +14,27 @@
import 'testarb.arb.dart';
+Message intlPluralSelector(
+ num howMany, {
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ Message? few,
+ Message? many,
+ required Message other,
+ String? locale,
+}) {
+ return old_intl.Intl.pluralLogic(
+ howMany,
+ few: few,
+ many: many,
+ zero: numberCases?[0] ?? wordCases?[0],
+ one: numberCases?[1] ?? wordCases?[1],
+ two: numberCases?[2] ?? wordCases?[2],
+ other: other,
+ locale: locale,
+ );
+}
+
void main() {
final uniqueKey = AssetId('package', 'path');
test('generateMessageFile from Object json', () {
@@ -24,7 +45,7 @@
.serialize('', '', messageList.map((e) => e.message).toList())
.data;
final messages =
- JsonDeserializer(buffer).deserialize(const OldIntlObject()).messages;
+ JsonDeserializer(buffer).deserialize(intlPluralSelector).messages;
expect((messages[0] as StringMessage).value, message.value);
});
@@ -38,7 +59,7 @@
.serialize('', '', parsed.messages.map((e) => e.message).toList())
.data;
final messages =
- JsonDeserializer(buffer).deserialize(const OldIntlObject()).messages;
+ JsonDeserializer(buffer).deserialize(intlPluralSelector).messages;
expect((messages[0] as StringMessage).value, 'Hello World');
});
test('generateMessageFile from simple arb JSON with placeholder', () {
@@ -51,7 +72,7 @@
.serialize('', '', parsed.messages.map((e) => e.message).toList())
.data;
final messages =
- JsonDeserializer(buffer).deserialize(const OldIntlObject()).messages;
+ JsonDeserializer(buffer).deserialize(intlPluralSelector).messages;
expect((messages[0] as StringMessage).value, 'Hello ');
expect(
(messages[0] as StringMessage).argPositions,
@@ -68,7 +89,7 @@
.serialize('', '', parsed.messages.map((e) => e.message).toList())
.data;
final messages =
- JsonDeserializer(buffer).deserialize(const OldIntlObject()).messages;
+ JsonDeserializer(buffer).deserialize(intlPluralSelector).messages;
expect((messages[0] as StringMessage).value, '');
expect(
(messages[0] as StringMessage).argPositions,
@@ -87,11 +108,11 @@
.serialize('', '', parsed.messages.map((e) => e.message).toList())
.data;
final messages =
- JsonDeserializer(buffer).deserialize(const OldIntlObject()).messages;
+ JsonDeserializer(buffer).deserialize(intlPluralSelector).messages;
expect(
messages[2].generateString(
['female', 'b'],
- intl: const OldIntlObject(),
+ pluralSelector: intlPluralSelector,
),
'test One new message');
});
diff --git a/pkgs/messages_serializer/CHANGELOG.md b/pkgs/messages_serializer/CHANGELOG.md
index a0712a7..47f0d5d 100644
--- a/pkgs/messages_serializer/CHANGELOG.md
+++ b/pkgs/messages_serializer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.0
+
+- Switch plural encoding to map.
+
## 0.1.0
- Initial version.
diff --git a/pkgs/messages_serializer/lib/src/serializer_json.dart b/pkgs/messages_serializer/lib/src/serializer_json.dart
index 2b468af..a1bb1a5 100644
--- a/pkgs/messages_serializer/lib/src/serializer_json.dart
+++ b/pkgs/messages_serializer/lib/src/serializer_json.dart
@@ -59,8 +59,6 @@
messageIndex = encodePlural(message, isVisible);
} else if (message is CombinedMessage) {
messageIndex = encodeCombined(message, isVisible);
- } else if (message is GenderMessage) {
- messageIndex = encodeGender(message, isVisible);
} else {
throw ArgumentError('Unknown message type');
}
@@ -136,36 +134,21 @@
m.add(encodeMessage(message.other));
final caseIndices = <Object>[];
if (message.few != null) {
- caseIndices.add(Plural.few);
+ caseIndices.add(PluralMarker.few);
caseIndices.add(encodeMessage(message.few!));
}
if (message.many != null) {
- caseIndices.add(Plural.many);
+ caseIndices.add(PluralMarker.many);
caseIndices.add(encodeMessage(message.many!));
}
- if (message.zeroNumber != null) {
- caseIndices.add(Plural.zeroNumber);
- caseIndices.add(encodeMessage(message.zeroNumber!));
+ for (final MapEntry(key: caseIndex, value: messageIndex)
+ in message.numberCases.entries) {
+ caseIndices.add(caseIndex);
+ caseIndices.add(encodeMessage(messageIndex));
}
- if (message.zeroWord != null) {
- caseIndices.add(Plural.zeroWord);
- caseIndices.add(encodeMessage(message.zeroWord!));
- }
- if (message.oneNumber != null) {
- caseIndices.add(Plural.oneNumber);
- caseIndices.add(encodeMessage(message.oneNumber!));
- }
- if (message.oneWord != null) {
- caseIndices.add(Plural.oneWord);
- caseIndices.add(encodeMessage(message.oneWord!));
- }
- if (message.twoNumber != null) {
- caseIndices.add(Plural.twoNumber);
- caseIndices.add(encodeMessage(message.twoNumber!));
- }
- if (message.twoWord != null) {
- caseIndices.add(Plural.twoWord);
- caseIndices.add(encodeMessage(message.twoWord!));
+ for (final entry in message.wordCases.entries) {
+ caseIndices.add(PluralMarker.wordCase + entry.key.toString());
+ caseIndices.add(encodeMessage(entry.value));
}
m.add(caseIndices);
return m;
@@ -187,34 +170,6 @@
return m;
}
- /// Encodes a gender message as follows:
- ///
- /// * int | the GenderMessage type
- /// * if we write IDs: String | the message id
- /// * int | the argument index on which the gender switches
- /// * int | the index of the other case message, which must be present
- /// * List\<int\> | the cases, which are added in pairs of two:
- /// * int | the case index as encoded by the constants in `Gender`
- /// * int | the message index of the case
- List encodeGender(GenderMessage message, bool isVisible) {
- final m = <Object>[];
- m.add(GenderMessage.type);
- addId(message, m, isVisible);
- m.add(message.argIndex);
- m.add(encodeMessage(message.other));
- final caseIndices = <Object>[];
- if (message.female != null) {
- caseIndices.add(Gender.female);
- caseIndices.add(encodeMessage(message.female!));
- }
- if (message.male != null) {
- caseIndices.add(Gender.male);
- caseIndices.add(encodeMessage(message.male!));
- }
- m.add(caseIndices);
- return m;
- }
-
/// Add a non-null ID iff `writeIds` is enabled
void addId(Message message, List<dynamic> m, bool isVisible) {
if (writeIds && message.id != null && isVisible) m.add(message.id!);
diff --git a/pkgs/messages_serializer/pubspec.yaml b/pkgs/messages_serializer/pubspec.yaml
index 0fbb33d..0653fd1 100644
--- a/pkgs/messages_serializer/pubspec.yaml
+++ b/pkgs/messages_serializer/pubspec.yaml
@@ -1,6 +1,6 @@
name: messages_serializer
description: Serialization of messages for package:messages.
-version: 0.1.0
+version: 0.2.0
repository: https://github.com/dart-lang/i18n/tree/main/pkgs/messages_serializer
environment:
@@ -12,4 +12,5 @@
dev_dependencies:
dart_flutter_team_lints: ^2.1.1
+ intl: ^0.18.1
test: ^1.21.0
diff --git a/pkgs/messages_serializer/test/messages_serializer_test.dart b/pkgs/messages_serializer/test/messages_serializer_test.dart
index a53e43b..b9ebee9 100644
--- a/pkgs/messages_serializer/test/messages_serializer_test.dart
+++ b/pkgs/messages_serializer/test/messages_serializer_test.dart
@@ -4,11 +4,32 @@
import 'dart:math';
+import 'package:intl/intl.dart' as old_intl;
import 'package:messages/messages_json.dart';
-import 'package:messages/package_intl_object.dart';
import 'package:messages_serializer/messages_serializer.dart';
import 'package:test/test.dart';
+Message intlPluralSelector(
+ num howMany, {
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ Message? few,
+ Message? many,
+ required Message other,
+ String? locale,
+}) {
+ return old_intl.Intl.pluralLogic(
+ howMany,
+ few: few,
+ many: many,
+ zero: numberCases?[0] ?? wordCases?[0],
+ one: numberCases?[1] ?? wordCases?[1],
+ two: numberCases?[2] ?? wordCases?[2],
+ other: other,
+ locale: locale,
+ );
+}
+
StringMessage stringMessage = StringMessage('Hello World', id: 'hello_world');
CombinedMessage combinedMessage = CombinedMessage('combined', [
@@ -20,8 +41,8 @@
id: 'pluralMes',
few: StringMessage('few case'),
many: StringMessage('many case'),
- oneNumber: StringMessage('oneNumber case'),
- twoWord: StringMessage('twoWord case'),
+ numberCases: {1: StringMessage('oneNumber case')},
+ wordCases: {2: StringMessage('twoWord case')},
other: StringMessage('Other case'),
argIndex: 0,
);
@@ -36,14 +57,6 @@
'selectMes',
);
-GenderMessage genderMessage = GenderMessage(
- female: StringMessage('Female'),
- male: StringMessage('Male'),
- argIndex: 0,
- other: StringMessage('other'),
- id: 'genderMes',
-);
-
void main() {
test('Serialize with IDs', () {
final messages = [
@@ -51,12 +64,11 @@
combinedMessage,
pluralMessage,
selectMessage,
- genderMessage
];
final serialized =
JsonSerializer(true).serialize('hash', 'locale', messages);
final deserialize =
- JsonDeserializer(serialized.data).deserialize(const OldIntlObject());
+ JsonDeserializer(serialized.data).deserialize(intlPluralSelector);
expect(
deserialize.messages.map((e) => e.id),
orderedEquals(messages.map((e) => e.id)),
@@ -69,15 +81,14 @@
combinedMessage,
pluralMessage,
selectMessage,
- genderMessage
];
final serialized =
- JsonSerializer(true).serialize('hash', 'locale', messages, [1, 4]);
+ JsonSerializer(true).serialize('hash', 'locale', messages, [1, 3]);
final deserialize =
- JsonDeserializer(serialized.data).deserialize(const OldIntlObject());
+ JsonDeserializer(serialized.data).deserialize(intlPluralSelector);
expect(
deserialize.messages.map((e) => e.id),
- orderedEquals([messages[1], messages[4]].map((e) => e.id)),
+ orderedEquals([messages[1], messages[3]].map((e) => e.id)),
);
});
@@ -89,7 +100,6 @@
combinedMessage,
pluralMessage,
selectMessage,
- genderMessage
]
];
final params = [
@@ -116,7 +126,7 @@
final serialized = serializer.serialize(hash, locale, messages);
final deserializer = deserializerBuilder(serialized.data);
- final deserialized = deserializer.deserialize(const OldIntlObject());
+ final deserialized = deserializer.deserialize(intlPluralSelector);
expect(deserialized.preamble.hash, hash);
expect(deserialized.preamble.locale, locale);
@@ -139,12 +149,19 @@
if (original is StringMessage) {
expect((deserialized as StringMessage).value, original.value);
} else if (original is PluralMessage) {
- compareMessage((deserialized as PluralMessage).zeroWord, original.zeroWord);
- compareMessage(deserialized.zeroNumber, original.zeroNumber);
- compareMessage(deserialized.oneWord, original.oneWord);
- compareMessage(deserialized.oneNumber, original.oneNumber);
- compareMessage(deserialized.twoWord, original.twoWord);
- compareMessage(deserialized.twoNumber, original.twoNumber);
+ final deserialized2 = deserialized as PluralMessage;
+ for (final key in original.wordCases.keys) {
+ compareMessage(
+ deserialized2.wordCases[key],
+ original.wordCases[key],
+ );
+ }
+ for (final key in original.numberCases.keys) {
+ compareMessage(
+ deserialized.numberCases[key],
+ original.numberCases[key],
+ );
+ }
compareMessage(deserialized.few, original.few);
compareMessage(deserialized.many, original.many);
compareMessage(deserialized.other, original.other);
diff --git a/pkgs/messages_shrinker/CHANGELOG.md b/pkgs/messages_shrinker/CHANGELOG.md
index a0712a7..19e1dfe 100644
--- a/pkgs/messages_shrinker/CHANGELOG.md
+++ b/pkgs/messages_shrinker/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.0
+
+- Adapt to `PluralRules` interface to retrieve the correct message for plurals.
+
## 0.1.0
- Initial version.
diff --git a/pkgs/messages_shrinker/lib/messages_shrinker.dart b/pkgs/messages_shrinker/lib/messages_shrinker.dart
index 5703fd7..2099b3e 100644
--- a/pkgs/messages_shrinker/lib/messages_shrinker.dart
+++ b/pkgs/messages_shrinker/lib/messages_shrinker.dart
@@ -6,7 +6,6 @@
import 'dart:io';
import 'package:messages/messages_json.dart';
-import 'package:messages/package_intl_object.dart';
import 'package:messages_serializer/messages_serializer.dart';
class MessageShrinker {
@@ -33,7 +32,12 @@
/// message indices in [messagesToKeep].
String shrinkJson(String buffer, List<int> messagesToKeep) {
final sizeBefore = buffer.length;
- final json = JsonDeserializer(buffer).deserialize(const OldIntlObject());
+ final json = JsonDeserializer(buffer).deserialize(
+ (howMany, {few, locale, many, numberCases, required other, wordCases}) {
+ throw StateError('As the deserialized MessageList is not used, but '
+ 'just immediately reserialized, this selector will not be called.');
+ },
+ );
final data = JsonSerializer(json.preamble.hasIds)
.serialize(
json.preamble.hash,
diff --git a/pkgs/messages_shrinker/pubspec.yaml b/pkgs/messages_shrinker/pubspec.yaml
index cfb73ad..088558e 100644
--- a/pkgs/messages_shrinker/pubspec.yaml
+++ b/pkgs/messages_shrinker/pubspec.yaml
@@ -1,6 +1,6 @@
name: messages_shrinker
description: A starting point for Dart libraries or applications.
-version: 0.1.0
+version: 0.2.0
repository: https://github.com/dart-lang/i18n/pkgs/messages_shrinker
environment:
@@ -17,4 +17,5 @@
dev_dependencies:
dart_flutter_team_lints: ^2.0.0
+ intl: ^0.18.1
test: ^1.21.0
diff --git a/pkgs/messages_shrinker/test/message_shrinker_test.dart b/pkgs/messages_shrinker/test/message_shrinker_test.dart
index 276ddb5..5c8f76f 100644
--- a/pkgs/messages_shrinker/test/message_shrinker_test.dart
+++ b/pkgs/messages_shrinker/test/message_shrinker_test.dart
@@ -9,15 +9,36 @@
import 'dart:io';
import 'package:build/build.dart';
+import 'package:intl/intl.dart' as old_intl;
import 'package:messages/messages_json.dart';
-import 'package:messages/package_intl_object.dart';
import 'package:messages_builder/arb_parser.dart';
import 'package:messages_serializer/messages_serializer.dart';
import 'package:messages_shrinker/messages_shrinker.dart';
import 'package:test/test.dart';
+Message intlPluralSelector(
+ num howMany, {
+ Map<int, Message>? numberCases,
+ Map<int, Message>? wordCases,
+ Message? few,
+ Message? many,
+ required Message other,
+ String? locale,
+}) {
+ return old_intl.Intl.pluralLogic(
+ howMany,
+ few: few,
+ many: many,
+ zero: numberCases?[0] ?? wordCases?[0],
+ one: numberCases?[1] ?? wordCases?[1],
+ two: numberCases?[2] ?? wordCases?[2],
+ other: other,
+ locale: locale,
+ );
+}
+
void main() {
- final intl = const OldIntlObject();
+ final intl = intlPluralSelector;
late String dataFileContents;
late String dataFile;