| // 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: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( |
| String debugString, |
| String fileContents, |
| String name, { |
| bool addId = false, |
| }) { |
| final node = Parser(name, debugString, fileContents).parse(); |
| final arguments = <String>[]; |
| final message = |
| parseNode(node, arguments, name, addId) ?? StringMessage(''); |
| final placeholders = arguments.map(Placeholder.new).toList(); |
| return ParameterizedMessage(message, name, placeholders); |
| } |
| |
| static Message? parseNode( |
| Node node, |
| List<String> arguments, [ |
| String? name, |
| bool addId = false, |
| ]) { |
| final id = addId ? name : null; |
| final submessages = <Message>[]; |
| final placeholders = <({int argIndex, int afterStringMessage})>[]; |
| for (var child in node.children) { |
| switch (child.type) { |
| case ST.string: |
| submessages.add(StringMessage(child.value!, id: id)); |
| break; |
| case ST.pluralExpr: |
| submessages.add(PluralParser().parse(child, arguments, addId, name)); |
| break; |
| case ST.placeholderExpr: |
| final identifier = child.children |
| .firstWhere((element) => element.type == ST.identifier) |
| .value!; |
| if (!arguments.contains(identifier)) { |
| arguments.add(identifier); |
| } |
| placeholders.add(( |
| argIndex: arguments.indexOf(identifier), |
| afterStringMessage: submessages.length, |
| )); |
| break; |
| case ST.selectExpr: |
| submessages.add(SelectParser().parse(child, arguments, addId, name)); |
| break; |
| default: |
| break; |
| } |
| } |
| if (submessages.isEmpty && placeholders.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<StringMessage>().toList(), |
| id, |
| placeholders, |
| ); |
| } else { |
| return CombinedMessage(id, submessages); |
| } |
| } |
| |
| static StringMessage combineStringsAndPlaceholders( |
| List<StringMessage> submessages, |
| String? id, |
| 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); |
| } |
| } |
| return StringMessage(s.toString(), argPositions: argPositions, id: id); |
| } |
| } |