Allow Dart enums in Intl.select calls

PiperOrigin-RevId: 234825234
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c84b7d6..a8c78d6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@
    explicit) to Object. In particular, the examples and args parameters on
    Intl.message, Intl.plural, Intl.gender, and Intl.select, as well as the args
    parameter on MessageLookup.
+ * Allow Dart enums in an Intl.select call. The map of cases can either take
+   enums directly, or the short string name of the enum. Requires
+   intl_translation 0.17.4 to take advantage of this.
 
 ## 0.15.7
  * Upate to require Dart 2.0. Remove deprecated calls,
diff --git a/lib/intl.dart b/lib/intl.dart
index b8abcfa..7928559 100644
--- a/lib/intl.dart
+++ b/lib/intl.dart
@@ -447,11 +447,19 @@
     }
   }
 
-  /// Format a message differently depending on [choice]. We look up the value
+  /// Format a message differently depending on [choice].
+  ///
+  /// We look up the value
   /// of [choice] in [cases] and return the result, or an empty string if
   /// it is not found. Normally used as part
   /// of an Intl.message message that is to be translated.
-  static String select(Object choice, Map<String, String> cases,
+  ///
+  /// It is possible to use a Dart enum as the choice and as the
+  /// key in cases, but note that we will process this by truncating
+  /// toString() of the enum and using just the name part. We will
+  /// do this for any class or strings that are passed, since we
+  /// can't actually identify if something is an enum or not.
+  static String select(Object choice, Map<Object, String> cases,
       {String desc,
       Map<String, Object> examples,
       String locale,
@@ -463,11 +471,14 @@
         locale: locale, name: name, args: args, meaning: meaning);
   }
 
-  static String _select(Object choice, Map<String, String> cases,
+  static String _select(Object choice, Map<Object, String> cases,
       {String locale, String name, List<Object> args, String meaning}) {
     // Look up our translation, but pass in a null message so we don't have to
     // eagerly evaluate calls that may not be necessary.
-    var translated = _message(null, locale, name, args, meaning);
+    var stringChoice = choice is String ? choice : "$choice".split('.').last;
+    var modifiedArgs =
+        args == null ? null : (<Object>[stringChoice]..addAll(args.skip(1)));
+    var translated = _message(null, locale, name, modifiedArgs, meaning);
 
     /// If there's a translation, return it, otherwise evaluate with our
     /// original text.
@@ -476,11 +487,18 @@
 
   /// Internal: Implements the logic for select - use [select] for
   /// normal messages.
-  static selectLogic(Object choice, Map<String, dynamic> cases) {
-    // Allow passing non-strings, e.g. enums to a select.
-    choice = "$choice";
+  static selectLogic(Object choice, Map<Object, dynamic> cases) {
+    // This will work if choice is a string, or if it's e.g. an
+    // enum and the map uses the enum values as choices.
     var exact = cases[choice];
     if (exact != null) return exact;
+    // If it didn't match exactly, take the toString and
+    // take the part after the period. We need to do this
+    // because enums print as 'EnumType.enumName' and periods
+    // aren't acceptable in ICU select choices.
+    var stringChoice = "$choice".split('.').last;
+    var stringMatch = cases[stringChoice];
+    if (stringMatch != null) return stringMatch;
     var other = cases["other"];
     if (other == null)
       throw new ArgumentError("The 'other' case must be specified");