| Index: packages/intl/lib/src/intl_message.dart
|
| diff --git a/packages/intl/lib/src/intl_message.dart b/packages/intl/lib/src/intl_message.dart
|
| deleted file mode 100644
|
| index 3df4a6194965cd19377aa7175b27d36793a8c97d..0000000000000000000000000000000000000000
|
| --- a/packages/intl/lib/src/intl_message.dart
|
| +++ /dev/null
|
| @@ -1,767 +0,0 @@
|
| -// Copyright (c) 2013, 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.
|
| -
|
| -/**
|
| - * This provides classes to represent the internal structure of the
|
| - * arguments to `Intl.message`. It is used when parsing sources to extract
|
| - * messages or to generate code for message substitution. Normal programs
|
| - * using Intl would not import this library.
|
| - *
|
| - * While it's written
|
| - * in a somewhat abstract way, it has some assumptions about ICU-style
|
| - * message syntax for parameter substitutions, choices, selects, etc.
|
| - *
|
| - * For example, if we have the message
|
| - * plurals(num) => Intl.message("""${Intl.plural(num,
|
| - * zero : 'Is zero plural?',
|
| - * one : 'This is singular.',
|
| - * other : 'This is plural ($num).')
|
| - * }""",
|
| - * name: "plurals", args: [num], desc: "Basic plurals");
|
| - * That is represented as a MainMessage which has only one message component, a
|
| - * Plural, but also has a name, list of arguments, and a description.
|
| - * The Plural has three different clauses. The `zero` clause is
|
| - * a LiteralString containing 'Is zero plural?'. The `other` clause is a
|
| - * CompositeMessage containing three pieces, a LiteralString for
|
| - * 'This is plural (', a VariableSubstitution for `num`. amd a LiteralString
|
| - * for '.)'.
|
| - *
|
| - * This representation isn't used at runtime. Rather, we read some format
|
| - * from a translation file, parse it into these objects, and they are then
|
| - * used to generate the code representation above.
|
| - */
|
| -library intl_message;
|
| -
|
| -import 'package:analyzer/analyzer.dart';
|
| -
|
| -/** A default function for the [Message.expanded] method. */
|
| -_nullTransform(msg, chunk) => chunk;
|
| -
|
| -/**
|
| - * An abstract superclass for Intl.message/plural/gender calls in the
|
| - * program's source text. We
|
| - * assemble these into objects that can be used to write out some translation
|
| - * format and can also print themselves into code.
|
| - */
|
| -abstract class Message {
|
| -
|
| - /**
|
| - * All [Message]s except a [MainMessage] are contained inside some parent,
|
| - * terminating at an Intl.message call which supplies the arguments we
|
| - * use for variable substitutions.
|
| - */
|
| - Message parent;
|
| -
|
| - Message(this.parent);
|
| -
|
| - /**
|
| - * We find the arguments from the top-level [MainMessage] and use those to
|
| - * do variable substitutions. [MainMessage] overrides this to return
|
| - * the actual arguments.
|
| - */
|
| - get arguments => parent == null ? const [] : parent.arguments;
|
| -
|
| - /**
|
| - * We find the examples from the top-level [MainMessage] and use those
|
| - * when writing out variables. [MainMessage] overrides this to return
|
| - * the actual examples.
|
| - */
|
| - get examples => parent == null ? const [] : parent.examples;
|
| -
|
| - /**
|
| - * The name of the top-level [MainMessage].
|
| - */
|
| - String get name => parent == null ? '<unnamed>' : parent.name;
|
| -
|
| - String checkValidity(MethodInvocation node, List arguments, String outerName,
|
| - FormalParameterList outerArgs) {
|
| - var hasArgs = arguments.any(
|
| - (each) => each is NamedExpression && each.name.label.name == 'args');
|
| - var hasParameters = !outerArgs.parameters.isEmpty;
|
| - if (!hasArgs && hasParameters) {
|
| - return "The 'args' argument for Intl.message must be specified";
|
| - }
|
| -
|
| - var messageName = arguments.firstWhere((eachArg) =>
|
| - eachArg is NamedExpression && eachArg.name.label.name == 'name',
|
| - orElse: () => null);
|
| - if (messageName == null) {
|
| - return "The 'name' argument for Intl.message must be specified";
|
| - }
|
| - if (messageName.expression is! SimpleStringLiteral) {
|
| - return "The 'name' argument for Intl.message must be a simple string "
|
| - "literal.";
|
| - }
|
| - var hasOuterName = outerName != null;
|
| - var givenName = messageName.expression.value;
|
| - var simpleMatch = outerName == givenName;
|
| - ClassDeclaration classNode(n) {
|
| - if (n == null) return null;
|
| - if (n is ClassDeclaration) return n;
|
| - return classNode(n.parent);
|
| - }
|
| - var classDeclaration = classNode(node);
|
| - var classPlusMethod = classDeclaration == null
|
| - ? null
|
| - : "${classDeclaration.name.token.toString()}_$outerName";
|
| - var classMatch = classPlusMethod != null && (givenName == classPlusMethod);
|
| - if (!(hasOuterName && (simpleMatch || classMatch))) {
|
| - return "The 'name' argument for Intl.message must match either"
|
| - "the name of the containing function or <className>_<methodName> ("
|
| - "'$givenName' vs. '$outerName')";
|
| - }
|
| - var simpleArguments = arguments.where((each) => each is NamedExpression &&
|
| - ["desc", "name"].contains(each.name.label.name));
|
| - var values = simpleArguments.map((each) => each.expression).toList();
|
| - for (var arg in values) {
|
| - if (arg is! StringLiteral) {
|
| - return ("Intl.message arguments must be string literals: $arg");
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Turn a value, typically read from a translation file or created out of an
|
| - * AST for a source program, into the appropriate
|
| - * subclass. We expect to get literal Strings, variable substitutions
|
| - * represented by integers, things that are already MessageChunks and
|
| - * lists of the same.
|
| - */
|
| - static Message from(value, Message parent) {
|
| - if (value is String) return new LiteralString(value, parent);
|
| - if (value is int) return new VariableSubstitution(value, parent);
|
| - if (value is Iterable) {
|
| - if (value.length == 1) return Message.from(value[0], parent);
|
| - var result = new CompositeMessage([], parent);
|
| - var items = value.map((x) => from(x, result)).toList();
|
| - result.pieces.addAll(items);
|
| - return result;
|
| - }
|
| - // We assume this is already a Message.
|
| - value.parent = parent;
|
| - return value;
|
| - }
|
| -
|
| - /**
|
| - * Return a string representation of this message for use in generated Dart
|
| - * code.
|
| - */
|
| - String toCode();
|
| -
|
| - /**
|
| - * Escape the string for use in generated Dart code and validate that it
|
| - * doesn't doesn't contain any illegal interpolations. We only allow
|
| - * simple variables ("$foo", but not "${foo}") and Intl.gender/plural
|
| - * calls.
|
| - */
|
| - String escapeAndValidateString(String value) {
|
| - const escapes = const {
|
| - r"\": r"\\",
|
| - '"': r'\"',
|
| - "\b": r"\b",
|
| - "\f": r"\f",
|
| - "\n": r"\n",
|
| - "\r": r"\r",
|
| - "\t": r"\t",
|
| - "\v": r"\v",
|
| - "'": r"\'",
|
| - };
|
| -
|
| - _escape(String s) => (escapes[s] == null) ? s : escapes[s];
|
| -
|
| - var escaped = value.splitMapJoin("", onNonMatch: _escape);
|
| -
|
| - // We don't allow any ${} expressions, only $variable to avoid malicious
|
| - // code. Disallow any usage of "${". If that makes a false positive
|
| - // on a translation that legitimately contains "\\${" or other variations,
|
| - // we'll live with that rather than risk a false negative.
|
| - var validInterpolations = new RegExp(r"(\$\w+)|(\${\w+})");
|
| - var validMatches = validInterpolations.allMatches(escaped);
|
| - escapeInvalidMatches(Match m) {
|
| - var valid = validMatches.any((x) => x.start == m.start);
|
| - if (valid) {
|
| - return m.group(0);
|
| - } else {
|
| - return "\\${m.group(0)}";
|
| - }
|
| - }
|
| - return escaped.replaceAllMapped("\$", escapeInvalidMatches);
|
| - }
|
| -
|
| - /**
|
| - * Expand this string out into a printed form. The function [f] will be
|
| - * applied to any sub-messages, allowing this to be used to generate a form
|
| - * suitable for a wide variety of translation file formats.
|
| - */
|
| - String expanded([Function f]);
|
| -}
|
| -
|
| -/**
|
| - * Abstract class for messages with internal structure, representing the
|
| - * main Intl.message call, plurals, and genders.
|
| - */
|
| -abstract class ComplexMessage extends Message {
|
| - ComplexMessage(parent) : super(parent);
|
| -
|
| - /**
|
| - * When we create these from strings or from AST nodes, we want to look up and
|
| - * set their attributes by string names, so we override the indexing operators
|
| - * so that they behave like maps with respect to those attribute names.
|
| - */
|
| - operator [](x);
|
| -
|
| - /**
|
| - * When we create these from strings or from AST nodes, we want to look up and
|
| - * set their attributes by string names, so we override the indexing operators
|
| - * so that they behave like maps with respect to those attribute names.
|
| - */
|
| - operator []=(x, y);
|
| -
|
| - List<String> get attributeNames;
|
| -
|
| - /**
|
| - * Return the name of the message type, as it will be generated into an
|
| - * ICU-type format. e.g. choice, select
|
| - */
|
| - String get icuMessageName;
|
| -
|
| - /**
|
| - * Return the message name we would use for this when doing Dart code
|
| - * generation, e.g. "Intl.plural".
|
| - */
|
| - String get dartMessageName;
|
| -}
|
| -
|
| -/**
|
| - * This represents a message chunk that is a list of multiple sub-pieces,
|
| - * each of which is in turn a [Message].
|
| - */
|
| -class CompositeMessage extends Message {
|
| - List<Message> pieces;
|
| -
|
| - CompositeMessage.withParent(parent) : super(parent);
|
| - CompositeMessage(this.pieces, ComplexMessage parent) : super(parent) {
|
| - pieces.forEach((x) => x.parent = this);
|
| - }
|
| - toCode() => pieces.map((each) => each.toCode()).join('');
|
| - toString() => "CompositeMessage(" + pieces.toString() + ")";
|
| - String expanded([Function f = _nullTransform]) =>
|
| - pieces.map((chunk) => f(this, chunk)).join("");
|
| -}
|
| -
|
| -/** Represents a simple constant string with no dynamic elements. */
|
| -class LiteralString extends Message {
|
| - String string;
|
| - LiteralString(this.string, Message parent) : super(parent);
|
| - toCode() => escapeAndValidateString(string);
|
| - toString() => "Literal($string)";
|
| - String expanded([Function f = _nullTransform]) => f(this, string);
|
| -}
|
| -
|
| -/**
|
| - * Represents an interpolation of a variable value in a message. We expect
|
| - * this to be specified as an [index] into the list of variables, or else
|
| - * as the name of a variable that exists in [arguments] and we will
|
| - * compute the variable name or the index based on the value of the other.
|
| - */
|
| -class VariableSubstitution extends Message {
|
| - VariableSubstitution(this._index, Message parent) : super(parent);
|
| -
|
| - /**
|
| - * Create a substitution based on the name rather than the index. The name
|
| - * may have been used as all upper-case in the translation tool, so we
|
| - * save it separately and look it up case-insensitively once the parent
|
| - * (and its arguments) are definitely available.
|
| - */
|
| - VariableSubstitution.named(String name, Message parent) : super(parent) {
|
| - _variableNameUpper = name.toUpperCase();
|
| - }
|
| -
|
| - /** The index in the list of parameters of the containing function. */
|
| - int _index;
|
| - int get index {
|
| - if (_index != null) return _index;
|
| - if (arguments.isEmpty) return null;
|
| - // We may have been given an all-uppercase version of the name, so compare
|
| - // case-insensitive.
|
| - _index = arguments
|
| - .map((x) => x.toUpperCase())
|
| - .toList()
|
| - .indexOf(_variableNameUpper);
|
| - if (_index == -1) {
|
| - throw new ArgumentError(
|
| - "Cannot find parameter named '$_variableNameUpper' in "
|
| - "message named '$name'. Available "
|
| - "parameters are $arguments");
|
| - }
|
| - return _index;
|
| - }
|
| -
|
| - /**
|
| - * The variable name we get from parsing. This may be an all uppercase version
|
| - * of the Dart argument name.
|
| - */
|
| - String _variableNameUpper;
|
| -
|
| - /**
|
| - * The name of the variable in the parameter list of the containing function.
|
| - * Used when generating code for the interpolation.
|
| - */
|
| - String get variableName =>
|
| - _variableName == null ? _variableName = arguments[index] : _variableName;
|
| - String _variableName;
|
| - // Although we only allow simple variable references, we always enclose them
|
| - // in curly braces so that there's no possibility of ambiguity with
|
| - // surrounding text.
|
| - toCode() => "\${${variableName}}";
|
| - toString() => "VariableSubstitution($index)";
|
| - String expanded([Function f = _nullTransform]) => f(this, index);
|
| -}
|
| -
|
| -class MainMessage extends ComplexMessage {
|
| - MainMessage() : super(null);
|
| -
|
| - /**
|
| - * All the pieces of the message. When we go to print, these will
|
| - * all be expanded appropriately. The exact form depends on what we're
|
| - * printing it for See [expanded], [toCode].
|
| - */
|
| - List<Message> messagePieces = [];
|
| -
|
| - /** Verify that this looks like a correct Intl.message invocation. */
|
| - String checkValidity(MethodInvocation node, List arguments, String outerName,
|
| - FormalParameterList outerArgs) {
|
| - if (arguments.first is! StringLiteral) {
|
| - return "Intl.message messages must be string literals";
|
| - }
|
| -
|
| - return super.checkValidity(node, arguments, outerName, outerArgs);
|
| - }
|
| -
|
| - void addPieces(List<Message> messages) {
|
| - for (var each in messages) {
|
| - messagePieces.add(Message.from(each, this));
|
| - }
|
| - }
|
| -
|
| - /** The description provided in the Intl.message call. */
|
| - String description;
|
| -
|
| - /** The examples from the Intl.message call */
|
| - Map<String, dynamic> examples;
|
| -
|
| - /**
|
| - * A field to disambiguate two messages that might have exactly the
|
| - * same text. The two messages will also need different names, but
|
| - * this can be used by machine translation tools to distinguish them.
|
| - */
|
| - String meaning;
|
| -
|
| - /**
|
| - * The name, which may come from the function name, from the arguments
|
| - * to Intl.message, or we may just re-use the message.
|
| - */
|
| - String _name;
|
| -
|
| - /**
|
| - * A placeholder for any other identifier that the translation format
|
| - * may want to use.
|
| - */
|
| - String id;
|
| -
|
| - /** The arguments list from the Intl.message call. */
|
| - List arguments;
|
| -
|
| - /**
|
| - * When generating code, we store translations for each locale
|
| - * associated with the original message.
|
| - */
|
| - Map<String, String> translations = new Map();
|
| -
|
| - /**
|
| - * If the message was not given a name, we use the entire message string as
|
| - * the name.
|
| - */
|
| - String get name => _name == null ? computeName() : _name;
|
| - set name(String newName) {
|
| - _name = newName;
|
| - }
|
| -
|
| - String computeName() => name = expanded((msg, chunk) => "");
|
| -
|
| - /**
|
| - * Return the full message, with any interpolation expressions transformed
|
| - * by [f] and all the results concatenated. The chunk argument to [f] may be
|
| - * either a String, an int or an object representing a more complex
|
| - * message entity.
|
| - * See [messagePieces].
|
| - */
|
| - String expanded([Function f = _nullTransform]) =>
|
| - messagePieces.map((chunk) => f(this, chunk)).join("");
|
| -
|
| - /**
|
| - * Record the translation for this message in the given locale, after
|
| - * suitably escaping it.
|
| - */
|
| - void addTranslation(String locale, Message translated) {
|
| - translated.parent = this;
|
| - translations[locale] = translated.toCode();
|
| - }
|
| -
|
| - toCode() =>
|
| - throw new UnsupportedError("MainMessage.toCode requires a locale");
|
| -
|
| - /**
|
| - * Generate code for this message, expecting it to be part of a map
|
| - * keyed by name with values the function that calls Intl.message.
|
| - */
|
| - String toCodeForLocale(String locale) {
|
| - var out = new StringBuffer()
|
| - ..write('static $name(')
|
| - ..write(arguments.join(", "))
|
| - ..write(') => "')
|
| - ..write(translations[locale])
|
| - ..write('";');
|
| - return out.toString();
|
| - }
|
| -
|
| - /**
|
| - * The AST node will have the attribute names as strings, so we translate
|
| - * between those and the fields of the class.
|
| - */
|
| - void operator []=(attributeName, value) {
|
| - switch (attributeName) {
|
| - case "desc":
|
| - description = value;
|
| - return;
|
| - case "examples":
|
| - examples = value;
|
| - return;
|
| - case "name":
|
| - name = value;
|
| - return;
|
| - // We use the actual args from the parser rather than what's given in the
|
| - // arguments to Intl.message.
|
| - case "args":
|
| - return;
|
| - case "meaning":
|
| - meaning = value;
|
| - return;
|
| - default:
|
| - return;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * The AST node will have the attribute names as strings, so we translate
|
| - * between those and the fields of the class.
|
| - */
|
| - operator [](attributeName) {
|
| - switch (attributeName) {
|
| - case "desc":
|
| - return description;
|
| - case "examples":
|
| - return examples;
|
| - case "name":
|
| - return name;
|
| - // We use the actual args from the parser rather than what's given in the
|
| - // arguments to Intl.message.
|
| - case "args":
|
| - return [];
|
| - case "meaning":
|
| - return meaning;
|
| - default:
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - // This is the top-level construct, so there's no meaningful ICU name.
|
| - get icuMessageName => '';
|
| -
|
| - get dartMessageName => "message";
|
| -
|
| - /** The parameters that the Intl.message call may provide. */
|
| - get attributeNames => const ["name", "desc", "examples", "args", "meaning"];
|
| -
|
| - String toString() =>
|
| - "Intl.message(${expanded()}, $name, $description, $examples, $arguments)";
|
| -}
|
| -
|
| -/**
|
| - * An abstract class to represent sub-sections of a message, primarily
|
| - * plurals and genders.
|
| - */
|
| -abstract class SubMessage extends ComplexMessage {
|
| - SubMessage() : super(null);
|
| -
|
| - /**
|
| - * Creates the sub-message, given a list of [clauses] in the sort of form
|
| - * that we're likely to get them from parsing a translation file format,
|
| - * as a list of [key, value] where value may in turn be a list.
|
| - */
|
| - SubMessage.from(this.mainArgument, List clauses, parent) : super(parent) {
|
| - for (var clause in clauses) {
|
| - this[clause.first] = (clause.last is List) ? clause.last : [clause.last];
|
| - }
|
| - }
|
| -
|
| - toString() => expanded();
|
| -
|
| - /**
|
| - * The name of the main argument, which is expected to have the value
|
| - * which is one of [attributeNames] and is used to decide which clause to use.
|
| - */
|
| - String mainArgument;
|
| -
|
| - /**
|
| - * Return the arguments that affect this SubMessage as a map of
|
| - * argument names and values.
|
| - */
|
| - Map argumentsOfInterestFor(MethodInvocation node) {
|
| - var basicArguments = node.argumentList.arguments;
|
| - var others = basicArguments.where((each) => each is NamedExpression);
|
| - return new Map.fromIterable(others,
|
| - key: (node) => node.name.label.token.value(),
|
| - value: (node) => node.expression);
|
| - }
|
| -
|
| - /**
|
| - * Return the list of attribute names to use when generating code. This
|
| - * may be different from [attributeNames] if there are multiple aliases
|
| - * that map to the same clause.
|
| - */
|
| - List<String> get codeAttributeNames;
|
| -
|
| - String expanded([Function transform = _nullTransform]) {
|
| - fullMessageForClause(key) =>
|
| - key + '{' + transform(parent, this[key]).toString() + '}';
|
| - var clauses = attributeNames
|
| - .where((key) => this[key] != null)
|
| - .map(fullMessageForClause)
|
| - .toList();
|
| - return "{$mainArgument,$icuMessageName, ${clauses.join("")}}";
|
| - }
|
| -
|
| - String toCode() {
|
| - var out = new StringBuffer();
|
| - out.write('\${');
|
| - out.write(dartMessageName);
|
| - out.write('(');
|
| - out.write(mainArgument);
|
| - var args = codeAttributeNames.where((attribute) => this[attribute] != null);
|
| - args.fold(
|
| - out, (buffer, arg) => buffer..write(", $arg: '${this[arg].toCode()}'"));
|
| - out.write(")}");
|
| - return out.toString();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Represents a message send of [Intl.gender] inside a message that is to
|
| - * be internationalized. This corresponds to an ICU message syntax "select"
|
| - * with "male", "female", and "other" as the possible options.
|
| - */
|
| -class Gender extends SubMessage {
|
| - Gender();
|
| - /**
|
| - * Create a new Gender providing [mainArgument] and the list of possible
|
| - * clauses. Each clause is expected to be a list whose first element is a
|
| - * variable name and whose second element is either a [String] or
|
| - * a list of strings and [Message] or [VariableSubstitution].
|
| - */
|
| - Gender.from(String mainArgument, List clauses, Message parent)
|
| - : super.from(mainArgument, clauses, parent);
|
| -
|
| - Message female;
|
| - Message male;
|
| - Message other;
|
| -
|
| - String get icuMessageName => "select";
|
| - String get dartMessageName => 'Intl.gender';
|
| -
|
| - get attributeNames => ["female", "male", "other"];
|
| - get codeAttributeNames => attributeNames;
|
| -
|
| - /**
|
| - * The node will have the attribute names as strings, so we translate
|
| - * between those and the fields of the class.
|
| - */
|
| - void operator []=(attributeName, rawValue) {
|
| - var value = Message.from(rawValue, this);
|
| - switch (attributeName) {
|
| - case "female":
|
| - female = value;
|
| - return;
|
| - case "male":
|
| - male = value;
|
| - return;
|
| - case "other":
|
| - other = value;
|
| - return;
|
| - default:
|
| - return;
|
| - }
|
| - }
|
| - Message operator [](String attributeName) {
|
| - switch (attributeName) {
|
| - case "female":
|
| - return female;
|
| - case "male":
|
| - return male;
|
| - case "other":
|
| - return other;
|
| - default:
|
| - return other;
|
| - }
|
| - }
|
| -}
|
| -
|
| -class Plural extends SubMessage {
|
| - Plural();
|
| - Plural.from(String mainArgument, List clauses, Message parent)
|
| - : super.from(mainArgument, clauses, parent);
|
| -
|
| - Message zero;
|
| - Message one;
|
| - Message two;
|
| - Message few;
|
| - Message many;
|
| - Message other;
|
| -
|
| - String get icuMessageName => "plural";
|
| - String get dartMessageName => "Intl.plural";
|
| -
|
| - get attributeNames => ["=0", "=1", "=2", "few", "many", "other"];
|
| - get codeAttributeNames => ["zero", "one", "two", "few", "many", "other"];
|
| -
|
| - /**
|
| - * The node will have the attribute names as strings, so we translate
|
| - * between those and the fields of the class.
|
| - */
|
| - void operator []=(String attributeName, rawValue) {
|
| - var value = Message.from(rawValue, this);
|
| - switch (attributeName) {
|
| - case "zero":
|
| - zero = value;
|
| - return;
|
| - case "=0":
|
| - zero = value;
|
| - return;
|
| - case "one":
|
| - one = value;
|
| - return;
|
| - case "=1":
|
| - one = value;
|
| - return;
|
| - case "two":
|
| - two = value;
|
| - return;
|
| - case "=2":
|
| - two = value;
|
| - return;
|
| - case "few":
|
| - few = value;
|
| - return;
|
| - case "many":
|
| - many = value;
|
| - return;
|
| - case "other":
|
| - other = value;
|
| - return;
|
| - default:
|
| - return;
|
| - }
|
| - }
|
| -
|
| - Message operator [](String attributeName) {
|
| - switch (attributeName) {
|
| - case "zero":
|
| - return zero;
|
| - case "=0":
|
| - return zero;
|
| - case "one":
|
| - return one;
|
| - case "=1":
|
| - return one;
|
| - case "two":
|
| - return two;
|
| - case "=2":
|
| - return two;
|
| - case "few":
|
| - return few;
|
| - case "many":
|
| - return many;
|
| - case "other":
|
| - return other;
|
| - default:
|
| - return other;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Represents a message send of [Intl.select] inside a message that is to
|
| - * be internationalized. This corresponds to an ICU message syntax "select"
|
| - * with arbitrary options.
|
| - */
|
| -class Select extends SubMessage {
|
| - Select();
|
| - /**
|
| - * Create a new [Select] providing [mainArgument] and the list of possible
|
| - * clauses. Each clause is expected to be a list whose first element is a
|
| - * variable name and whose second element is either a String or
|
| - * a list of strings and [Message]s or [VariableSubstitution]s.
|
| - */
|
| - Select.from(String mainArgument, List clauses, Message parent)
|
| - : super.from(mainArgument, clauses, parent);
|
| -
|
| - Map<String, Message> cases = new Map<String, Message>();
|
| -
|
| - String get icuMessageName => "select";
|
| - String get dartMessageName => 'Intl.select';
|
| -
|
| - get attributeNames => cases.keys;
|
| - get codeAttributeNames => attributeNames;
|
| -
|
| - void operator []=(attributeName, rawValue) {
|
| - var value = Message.from(rawValue, this);
|
| - cases[attributeName] = value;
|
| - }
|
| -
|
| - Message operator [](String attributeName) {
|
| - var exact = cases[attributeName];
|
| - return exact == null ? cases["other"] : exact;
|
| - }
|
| -
|
| - /**
|
| - * Return the arguments that we care about for the select. In this
|
| - * case they will all be passed in as a Map rather than as the named
|
| - * arguments used in Plural/Gender.
|
| - */
|
| - Map argumentsOfInterestFor(MethodInvocation node) {
|
| - var casesArgument = node.argumentList.arguments[1];
|
| - return new Map.fromIterable(casesArgument.entries,
|
| - key: (node) => node.key.value, value: (node) => node.value);
|
| - }
|
| -
|
| - /**
|
| - * Write out the generated representation of this message. This differs
|
| - * from Plural/Gender in that it prints a literal map rather than
|
| - * named arguments.
|
| - */
|
| - String toCode() {
|
| - var out = new StringBuffer();
|
| - out.write('\${');
|
| - out.write(dartMessageName);
|
| - out.write('(');
|
| - out.write(mainArgument);
|
| - var args = codeAttributeNames;
|
| - out.write(", {");
|
| - args.fold(out,
|
| - (buffer, arg) => buffer..write("'$arg': '${this[arg].toCode()}', "));
|
| - out.write("})}");
|
| - return out.toString();
|
| - }
|
| -}
|
|
|