Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(436)

Unified Diff: pkg/intl/lib/src/intl_message.dart

Issue 22286013: Add support for Intl.select (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/intl/lib/src/intl_message.dart
diff --git a/pkg/intl/lib/src/intl_message.dart b/pkg/intl/lib/src/intl_message.dart
index ae3179876010680b4b27812bccdf12990b783417..8619eeb8cf60ba73c051822a61b487fd5f496386 100644
--- a/pkg/intl/lib/src/intl_message.dart
+++ b/pkg/intl/lib/src/intl_message.dart
@@ -33,6 +33,8 @@
*/
library intl_message;
+import 'package:analyzer_experimental/analyzer.dart';
+
/** A default function for the [Message.expanded] method. */
_nullTransform(msg, chunk) => chunk;
@@ -59,6 +61,39 @@ abstract class Message {
*/
get arguments => parent == null ? const [] : parent.arguments;
+ 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)
+ || messageName.expression.value != outerName) {
+ return "The 'name' argument for Intl.message must be a simple string "
+ "literal and match the containing function name.";
+ }
+ var simpleArguments = arguments.where(
+ (each) => each is NamedExpression
+ && ["desc", "locale", "name"].contains(each.name.label.name));
+ var values = simpleArguments.map((each) => each.expression).toList();
+ for (var arg in values) {
+ if (arg is! SimpleStringLiteral) {
+ return "Intl.message argument '${arg.name.label.name}' must be "
+ "a simple string literal";
+ }
+ }
+ }
+
/**
* Turn a value, typically read from a translation file or created out of an
* AST for a source program, into the appropriate
@@ -234,6 +269,16 @@ class MainMessage extends ComplexMessage {
*/
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));
@@ -384,6 +429,18 @@ abstract class SubMessage extends ComplexMessage {
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.elements;
+ 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.
@@ -423,10 +480,10 @@ class Gender extends SubMessage {
Gender();
/**
- * Create a new IntlGender providing [mainArgument] and the list of possible
+ * 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 IntlMessageSends or IntlVariableSubstitution.
+ * variable name and whose second element is either a [String] or
+ * a list of strings and [Message] or [VariableSubstitution].
*/
Gender.from(mainArgument, List clauses, parent) :
super.from(mainArgument, clauses, parent);
@@ -519,3 +576,69 @@ class Plural extends SubMessage {
}
}
+/**
+ * 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
Emily Fortuna 2013/08/08 23:49:55 what types can mainArgument be since it's not type
Alan Knight 2013/08/09 17:09:16 It's a String. On the superclass it's typed as a f
+ * 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(mainArgument, List clauses, 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) {
Emily Fortuna 2013/08/08 23:49:55 should this actually be private? It seems more lik
Alan Knight 2013/08/09 17:09:16 It's somewhat of a helper, but it's a helper for t
+ var casesArgument = node.argumentList.arguments.elements[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();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698