blob: a2e4a0a0e31817ad633d413b6c1fa8220f4e0200 [file] [log] [blame] [edit]
// 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 'icu_message_parser.dart';
import 'message_parser.dart';
Map<String, int> numbers = {'zero': 0, 'one': 1, 'two': 2};
class PluralParser {
MapEntry<T, Message>? getPluralCaseFrom<T>(
T id,
Node node,
List<String> arguments,
) {
final childMessage = node.children.firstWhere((e) => e.type == ST.message);
final parsedMessage = MessageParser.parseNode(childMessage, arguments);
if (parsedMessage != null) {
return MapEntry(id, parsedMessage);
} else {
return null;
}
}
Message? getNamed(
List<Node> parts,
String id,
List<String> arguments,
) {
final messages = parts
.where((e) =>
e.children[0].type == ST.identifier && e.children[0].value == id)
.map((e) => e.children.firstWhere((e) => e.type == ST.message))
.map((e) => MessageParser.parseNode(e, arguments))
.whereType<Message>();
if (messages.isNotEmpty) {
return messages.first;
}
return null;
}
PluralMessage parse(Node node, List<String> arguments,
[bool addId = false, String? name]) {
final identifier = node.children
.firstWhere((element) => element.type == ST.identifier)
.value!;
if (!arguments.contains(identifier)) arguments.add(identifier);
final parts = node.children
.firstWhere((element) => element.type == ST.pluralParts)
.children;
final numberCases = getNumberCases(parts, arguments);
final wordCases = getWordCases(parts, arguments);
return PluralMessage(
numberCases: numberCases,
wordCases: wordCases,
few: getNamed(parts, 'few', arguments),
many: getNamed(parts, 'many', arguments),
other: getOther(parts, arguments)!,
argIndex: arguments.indexOf(identifier),
id: addId ? name : null,
);
}
Map<int, Message> getNumberCases(List<Node> parts, List<String> arguments) {
final numberCases = parts
.where((node) =>
node.children[0].type == ST.equalSign &&
node.children[1].type == ST.number)
.map((node) => getPluralCaseFrom(
int.parse(node.children[1].value ?? ''),
node,
arguments,
))
.whereType<MapEntry<int, Message>>();
return Map.fromEntries(numberCases);
}
Map<int, Message> getWordCases(List<Node> parts, List<String> arguments) {
final wordCases = parts
.where((node) => node.children[0].type == ST.identifier)
.where((node) => numbers.containsKey(node.children[0].value))
.map((node) => getPluralCaseFrom(
numbers[node.children[0].value!]!,
node,
arguments,
))
.whereType<MapEntry<int, Message>>();
return Map.fromEntries(wordCases);
}
Message? getOther(List<Node> parts, List<String> arguments) {
final other = parts
.where((e) => e.children[0].type == ST.other)
.map((e) => e.children.firstWhere((e) => e.type == ST.message))
.map((e) => MessageParser.parseNode(e, arguments))
.whereType<Message>();
return other.isNotEmpty ? other.first : null;
}
}