diff --git a/pkgs/messages_builder/lib/arb_parser.dart b/pkgs/messages_builder/lib/arb_parser.dart index 43904a1f..4ed5e9cf 100644 --- a/pkgs/messages_builder/lib/arb_parser.dart +++ b/pkgs/messages_builder/lib/arb_parser.dart @@ -19,12 +19,14 @@ class ArbParser { final context = arb['@@context'] as String?; final messages = arb.keys .where((key) => !key.startsWith('@')) - .map((key) => parseMessage( - arb[key] as String, - arb['@$key'] as Map?, - key, - '${context}_$locale', - )) + .map( + (key) => parseMessage( + arb[key] as String, + arb['@$key'] as Map?, + key, + '${context}_$locale', + ), + ) .toList(); messages.sort((a, b) => a.name.compareTo(b.name)); return MessageFile( @@ -47,23 +49,32 @@ class ArbParser { String name, String debugString, ) { - final message = MessageParser.parse( + final (message, arguments) = MessageParser.parse( debugString, messageContent, name, ); + final meaning = metadata?['meaning'] as String?; + final description = metadata?['description'] as String?; + final placeholdersMap = metadata?['placeholders'] as Map?; - final placeholdersWithMetadata = placeholdersMap?.map( - (name, metadata) { - final type = (metadata as Map)['type'] as String?; - return MapEntry(name, Placeholder(name, type ?? 'String')); - }, - ) ?? + final placeholdersWithMetadata = placeholdersMap?.map((name, metadata) { + final type = (metadata as Map)['type'] as String?; + final example = metadata['example'] as String?; + return MapEntry(name, Placeholder(name, type ?? 'String', example)); + }) ?? {}; - final placeholders = message.placeholders - .map((p) => placeholdersWithMetadata[p.name] ?? p) - .toList(); - return ParameterizedMessage(message.message, message.name, placeholders); + return ParameterizedMessage( + message: message, + name: name, + meaning: meaning, + description: description, + placeholders: arguments + .map( + (name) => placeholdersWithMetadata[name] ?? Placeholder(name), + ) + .toList(), + ); } } diff --git a/pkgs/messages_builder/lib/message_parser/message_parser.dart b/pkgs/messages_builder/lib/message_parser/message_parser.dart index a1162e83..ca40d454 100644 --- a/pkgs/messages_builder/lib/message_parser/message_parser.dart +++ b/pkgs/messages_builder/lib/message_parser/message_parser.dart @@ -4,14 +4,12 @@ import 'package:messages/messages.dart'; -import '../parameterized_message.dart'; -import '../placeholder.dart'; import 'icu_message_parser.dart'; import 'plural_parser.dart'; import 'select_parser.dart'; class MessageParser { - static ParameterizedMessage parse( + static (Message, List) parse( String debugString, String fileContents, String name, @@ -19,17 +17,11 @@ class MessageParser { final node = Parser(name, debugString, fileContents).parse(); final arguments = []; final message = parseNode(node, arguments, name) ?? StringMessage(''); - final placeholders = arguments.map(Placeholder.new).toList(); - return ParameterizedMessage(message, name, placeholders); + return (message, arguments); } - static Message? parseNode( - Node node, - List arguments, [ - String? name, - ]) { + static Message? parseNode(Node node, List arguments, [String? name]) { final submessages = []; - final placeholders = <({int argIndex, int afterStringMessage})>[]; for (var child in node.children) { switch (child.type) { case ST.string: @@ -45,10 +37,14 @@ class MessageParser { if (!arguments.contains(identifier)) { arguments.add(identifier); } - placeholders.add(( - argIndex: arguments.indexOf(identifier), - afterStringMessage: submessages.length, - )); + submessages.add( + StringMessage( + '', + argPositions: [ + (argIndex: arguments.indexOf(identifier), stringIndex: 0), + ], + ), + ); break; case ST.selectExpr: submessages.add(SelectParser().parse(child, arguments)); @@ -57,37 +53,40 @@ class MessageParser { break; } } - if (submessages.isEmpty && placeholders.isEmpty) { + if (submessages.isEmpty) { return null; - } else if (submessages.length == 1 && placeholders.isEmpty) { - return submessages.first; - } else if (submessages.every((message) => message is StringMessage)) { - return combineStringsAndPlaceholders( - submessages.whereType().toList(), - placeholders, - ); - } else { - return CombinedMessage(submessages); } - } - - static StringMessage combineStringsAndPlaceholders( - List submessages, - List<({int afterStringMessage, int argIndex})> placeholders, - ) { - final argPositions = <({int argIndex, int stringIndex})>[]; - final s = StringBuffer(); - for (var i = 0; i < submessages.length + 1; i++) { - placeholders - .where((element) => element.afterStringMessage == i) - .forEach((element) { - argPositions.add((argIndex: element.argIndex, stringIndex: s.length)); - }); - if (i < submessages.length) { - final submessage = submessages[i]; - s.write(submessage.value); + final fold = submessages.fold([], (messages, message) { + if (messages.isNotEmpty && + message is StringMessage && + messages.last is StringMessage) { + final last = messages.removeLast() as StringMessage; + return [...messages, combineStringMessages(last, message)]; + } else { + return [...messages, message]; } + }); + if (fold.length == 1) { + return fold.first; + } else { + return CombinedMessage(fold); } - return StringMessage(s.toString(), argPositions: argPositions); } + + static StringMessage combineStringMessages( + StringMessage message1, + StringMessage message2, + ) => + StringMessage( + message1.value + message2.value, + argPositions: [ + ...message1.argPositions, + ...message2.argPositions.map( + (e) => ( + argIndex: e.argIndex, + stringIndex: e.stringIndex + message1.value.length, + ), + ), + ], + ); } diff --git a/pkgs/messages_builder/lib/parameterized_message.dart b/pkgs/messages_builder/lib/parameterized_message.dart index 659aff2e..f4b63751 100644 --- a/pkgs/messages_builder/lib/parameterized_message.dart +++ b/pkgs/messages_builder/lib/parameterized_message.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:messages/messages.dart'; + import 'placeholder.dart'; /// A wrapper class around a [Message], adding its [placeholders] and a [name]. @@ -26,11 +27,19 @@ import 'placeholder.dart'; class ParameterizedMessage { final Message message; final String name; + final String? meaning; + final String? description; final List placeholders; static final RegExp _dartName = RegExp(r'^[a-zA-Z][a-zA-Z_0-9]*$'); - ParameterizedMessage(this.message, this.name, this.placeholders); + ParameterizedMessage({ + required this.message, + required this.name, + this.meaning, + this.description, + this.placeholders = const [], + }); bool get nameIsDartConform => _dartName.hasMatch(name); } diff --git a/pkgs/messages_builder/lib/placeholder.dart b/pkgs/messages_builder/lib/placeholder.dart index 0d5d1bbf..0ab93267 100644 --- a/pkgs/messages_builder/lib/placeholder.dart +++ b/pkgs/messages_builder/lib/placeholder.dart @@ -29,8 +29,9 @@ class Placeholder { final String name; final String? type; + final String? example; - Placeholder(this.name, [this.type]); + Placeholder(this.name, [this.type, this.example]); @override String toString() { diff --git a/pkgs/messages_builder/test/web_deserializer_native_test.dart b/pkgs/messages_builder/test/web_deserializer_native_test.dart index 461f36e3..8f51fc0c 100644 --- a/pkgs/messages_builder/test/web_deserializer_native_test.dart +++ b/pkgs/messages_builder/test/web_deserializer_native_test.dart @@ -37,7 +37,7 @@ Message intlPluralSelector( void main() { test('generateMessageFile from Object json', () { final message = StringMessage('Hello World'); - final message1 = ParameterizedMessage(message, 'helloWorld', []); + final message1 = ParameterizedMessage(message: message, name: 'helloWorld'); final messageList = [message1]; final buffer = JsonSerializer() .serialize('', '', messageList.map((e) => e.message).toList())