Localizations for Material (#11832)

diff --git a/dev/tools/gen_localizations.dart b/dev/tools/gen_localizations.dart
new file mode 100644
index 0000000..0a7a838
--- /dev/null
+++ b/dev/tools/gen_localizations.dart
@@ -0,0 +1,127 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Given a directory that contains localized ".arb" (application resource
+// bundle) files, generates a Dart "localizations" Map definition that combines
+// the contents of the arb files. The map can be used to lookup a localized
+// string: localizations[localeString][resourceId].
+//
+// See *.arb and localizations.dart in packages/flutter/lib/src/material/i18n/.
+//
+// The arb (JSON) format files must contain a single map indexed by locale.
+// Each map value is itself a map with resource identifier keys and localized
+// resource string values.
+//
+// The arb filenames are assumed to end in "prefix_lc.arb" or "prefix_lc_cc.arb",
+// where prefix is the 2nd command line argument, lc is a language code and cc
+// is the country code. In most cases both codes are just two characters. A typical
+// filename would be "material_en.arb".
+//
+// This app is typically run by hand when a module's .arb files have been
+// updated.
+//
+// Usage: dart gen_localizations.dart directory prefix
+
+import 'dart:convert' show JSON;
+import 'dart:io';
+
+const String outputHeader = '''
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been automatically generated.  Please do not edit it manually.
+// To regenerate the file, use:
+// @(regenerate)
+''';
+
+final Map<String, Map<String, String>> localeToResources = <String, Map<String, String>>{};
+
+// Return s as a Dart-parseable raw string in double quotes. Expand double quotes:
+// foo => r"foo"
+// foo "bar" => r"foo " '"' r"bar" '"'
+String generateString(String s) {
+  if (!s.contains('"'))
+    return 'r"$s"';
+
+  final StringBuffer output = new StringBuffer();
+  bool started = false; // Have we started writing a raw string.
+  for (int i = 0; i < s.length; i++) {
+    if (s[i] == '"') {
+      if (started)
+        output.write('"');
+      output.write(' \'"\' ');
+      started = false;
+    } else if (!started) {
+      output.write('r"${s[i]}');
+      started = true;
+    } else {
+      output.write(s[i]);
+    }
+  }
+  if (started)
+    output.write('"');
+  return output.toString();
+}
+
+String generateLocalizationsMap() {
+  final StringBuffer output = new StringBuffer();
+
+  output.writeln('const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {');
+
+  final String lastLocale = localeToResources.keys.last;
+  for (String locale in localeToResources.keys) {
+    output.writeln('  "$locale": const <String, String>{');
+
+    final Map<String, String> resources = localeToResources[locale];
+    final String lastName = resources.keys.last;
+    for (String name in resources.keys) {
+      final String comma = name == lastName ? "" : ",";
+      final String value = generateString(resources[name]);
+      output.writeln('    "$name": $value$comma');
+    }
+    final String comma = locale == lastLocale ? "" : ",";
+    output.writeln('  }$comma');
+  }
+
+  output.writeln('};');
+  return output.toString();
+}
+
+void processBundle(File file, String locale) {
+  localeToResources[locale] ??= <String, String>{};
+  final Map<String, String> resources = localeToResources[locale];
+  final Map<String, dynamic> bundle = JSON.decode(file.readAsStringSync());
+  for (String key in bundle.keys) {
+    // The ARB file resource "attributes" for foo are called @foo.
+    if (key.startsWith('@'))
+      continue;
+    resources[key] = bundle[key];
+  }
+}
+
+void main(List<String> args) {
+  if (args.length != 2)
+    stderr.writeln('Usage: dart gen_localizations.dart directory prefix');
+
+  // filenames are assumed to end in "prefix_lc.arb" or "prefix_lc_cc.arb", where prefix
+  // is the 2nd command line argument, lc is a language code and cc is the country
+  // code. In most cases both codes are just two characters.
+
+  final Directory directory = new Directory(args[0]);
+  final String prefix = args[1];
+  final RegExp filenameRE = new RegExp('${prefix}_(\\w+)\\.arb\$');
+
+  for (FileSystemEntity entity in directory.listSync()) {
+    final String path = entity.path;
+    if (FileSystemEntity.isFileSync(path) && filenameRE.hasMatch(path)) {
+      final String locale = filenameRE.firstMatch(path)[1];
+      processBundle(new File(path), locale);
+    }
+  }
+
+  final String regenerate = 'dart gen_localizations ${directory.path} ${args[1]}';
+  print(outputHeader.replaceFirst('@(regenerate)', regenerate));
+  print(generateLocalizationsMap());
+}
diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart
index a114622..4d06360 100644
--- a/packages/flutter/lib/src/material/app.dart
+++ b/packages/flutter/lib/src/material/app.dart
@@ -26,19 +26,17 @@
   decorationStyle: TextDecorationStyle.double
 );
 
-// Delegate that fetches the default (English) strings.
 class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
   const _MaterialLocalizationsDelegate();
 
   @override
-  Future<MaterialLocalizations> load(Locale locale) {
-    return new SynchronousFuture<MaterialLocalizations>(const MaterialLocalizations());
-  }
+  Future<MaterialLocalizations> load(Locale locale) => DefaultMaterialLocalizations.load(locale);
 
   @override
   bool shouldReload(_MaterialLocalizationsDelegate old) => false;
 }
 
+
 /// An application that uses material design.
 ///
 /// A convenience widget that wraps a number of widgets that are commonly
diff --git a/packages/flutter/lib/src/material/i18n/localizations.dart b/packages/flutter/lib/src/material/i18n/localizations.dart
new file mode 100644
index 0000000..1808dbc
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/localizations.dart
@@ -0,0 +1,80 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been automatically generated.  Please do not edit it manually.
+// To regenerate the file, use:
+// dart gen_localizations packages/flutter/lib/src/material/i18n material
+
+const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {
+  "ar": const <String, String>{
+    "openAppDrawerTooltip": r"افتح قائمة التنقل",
+    "backButtonTooltip": r"الى الخلف",
+    "closeButtonTooltip": r"إغلا",
+    "nextMonthTooltip": r"الشهر القادم",
+    "previousMonthTooltip": r"الشهر الماضى"
+  },
+  "it": const <String, String>{
+    "openAppDrawerTooltip": r"Apri il menu di navigazione",
+    "backButtonTooltip": r"Indietro",
+    "closeButtonTooltip": r"Chiudi",
+    "nextMonthTooltip": r"Il prossimo mese",
+    "previousMonthTooltip": r"Il mese scorso"
+  },
+  "pt": const <String, String>{
+    "openAppDrawerTooltip": r"Abrir menu de navegação",
+    "backButtonTooltip": r"Costas",
+    "closeButtonTooltip": r"Fechar",
+    "nextMonthTooltip": r"Próximo mês",
+    "previousMonthTooltip": r"Mês anterior"
+  },
+  "es": const <String, String>{
+    "openAppDrawerTooltip": r"Abrir el menú de navegación",
+    "backButtonTooltip": r"Espalda",
+    "closeButtonTooltip": r"Cerrar",
+    "nextMonthTooltip": r"Próximo mes",
+    "previousMonthTooltip": r"mes anterior"
+  },
+  "fr": const <String, String>{
+    "openAppDrawerTooltip": r"Ouvrir le menu de navigation",
+    "backButtonTooltip": r"Arrière",
+    "closeButtonTooltip": r"Fermer",
+    "nextMonthTooltip": r"Mois Suivant",
+    "previousMonthTooltip": r"Le mois précédent"
+  },
+  "zh": const <String, String>{
+    "openAppDrawerTooltip": r"打开导航菜单",
+    "backButtonTooltip": r"背部",
+    "closeButtonTooltip": r"关",
+    "nextMonthTooltip": r"-下月就29了。",
+    "previousMonthTooltip": r"前一个月"
+  },
+  "en": const <String, String>{
+    "openAppDrawerTooltip": r"Open navigation menu",
+    "backButtonTooltip": r"Back",
+    "closeButtonTooltip": r"Close",
+    "nextMonthTooltip": r"Next month",
+    "previousMonthTooltip": r"Previous month"
+  },
+  "de": const <String, String>{
+    "openAppDrawerTooltip": r"Navigationsmenü öffnen",
+    "backButtonTooltip": r"Zurück",
+    "closeButtonTooltip": r"Schließen ",
+    "nextMonthTooltip": r"Nächster Monat",
+    "previousMonthTooltip": r"Letzter Monat"
+  },
+  "ja": const <String, String>{
+    "openAppDrawerTooltip": r"ナビゲーションメニューを開く",
+    "backButtonTooltip": r"バック",
+    "closeButtonTooltip": r"閉じる",
+    "nextMonthTooltip": r"来月",
+    "previousMonthTooltip": r"前の月"
+  },
+  "ru": const <String, String>{
+    "openAppDrawerTooltip": r"Открыть меню навигации",
+    "backButtonTooltip": r"назад",
+    "closeButtonTooltip": r"Закрыть",
+    "nextMonthTooltip": r"В следующем месяце",
+    "previousMonthTooltip": r"Предыдущий месяц"
+  }
+};
diff --git a/packages/flutter/lib/src/material/i18n/material_ar.arb b/packages/flutter/lib/src/material/i18n/material_ar.arb
new file mode 100644
index 0000000..16745bf
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_ar.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "افتح قائمة التنقل",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "الى الخلف",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "إغلا",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "الشهر القادم",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "الشهر الماضى",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_de.arb b/packages/flutter/lib/src/material/i18n/material_de.arb
new file mode 100644
index 0000000..e36bec6
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_de.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Navigationsmenü öffnen",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "Zurück",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Schließen ",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "Nächster Monat",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "Letzter Monat",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_en.arb b/packages/flutter/lib/src/material/i18n/material_en.arb
new file mode 100644
index 0000000..784ad6a
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_en.arb
@@ -0,0 +1,31 @@
+{
+  "openAppDrawerTooltip": "Open navigation menu",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+
+  "backButtonTooltip": "Back",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+
+  "closeButtonTooltip": "Close",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+
+  "nextMonthTooltip": "Next month",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+
+  "previousMonthTooltip": "Previous month",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_es.arb b/packages/flutter/lib/src/material/i18n/material_es.arb
new file mode 100644
index 0000000..ddb3053
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_es.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Abrir el menú de navegación",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "Espalda",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Cerrar",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "Próximo mes",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "mes anterior",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_fr.arb b/packages/flutter/lib/src/material/i18n/material_fr.arb
new file mode 100644
index 0000000..4ff5670
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_fr.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Ouvrir le menu de navigation",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "Arrière",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Fermer",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "Mois Suivant",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "Le mois précédent",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_it.arb b/packages/flutter/lib/src/material/i18n/material_it.arb
new file mode 100644
index 0000000..80030ea
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_it.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Apri il menu di navigazione",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "Indietro",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Chiudi",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "Il prossimo mese",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "Il mese scorso",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_ja.arb b/packages/flutter/lib/src/material/i18n/material_ja.arb
new file mode 100644
index 0000000..4205c64
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_ja.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "ナビゲーションメニューを開く",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "バック",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "閉じる",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "来月",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "前の月",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_pt.arb b/packages/flutter/lib/src/material/i18n/material_pt.arb
new file mode 100644
index 0000000..a346b4b
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_pt.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Abrir menu de navegação",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "Costas",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Fechar",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "Próximo mês",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "Mês anterior",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_ru.arb b/packages/flutter/lib/src/material/i18n/material_ru.arb
new file mode 100644
index 0000000..c12a616
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_ru.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "Открыть меню навигации",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "назад",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "Закрыть",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "В следующем месяце",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "Предыдущий месяц",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/i18n/material_zh.arb b/packages/flutter/lib/src/material/i18n/material_zh.arb
new file mode 100644
index 0000000..c194874
--- /dev/null
+++ b/packages/flutter/lib/src/material/i18n/material_zh.arb
@@ -0,0 +1,27 @@
+{
+  "openAppDrawerTooltip": "打开导航菜单",
+  "@openAppDrawerTooltip": {
+    "description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
+    "type": "text"
+  },
+  "backButtonTooltip": "背部",
+  "@backButtonTooltip": {
+    "description": "The BackButton's tooltip",
+    "type": "text"
+  },
+  "closeButtonTooltip": "关",
+  "@closeButtonTooltip": {
+    "description": "The CloseButton's tooltip",
+    "type": "text"
+  },
+  "nextMonthTooltip": "-下月就29了。",
+  "@nextMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'next month' button.",
+    "type": "text"
+  },
+  "previousMonthTooltip": "前一个月",
+  "@previousMonthTooltip": {
+    "description": "The tooltip for the MonthPicker's 'previous month' button.",
+    "type": "text"
+  }
+}
diff --git a/packages/flutter/lib/src/material/material_localizations.dart b/packages/flutter/lib/src/material/material_localizations.dart
index b13adce..6289bf4 100644
--- a/packages/flutter/lib/src/material/material_localizations.dart
+++ b/packages/flutter/lib/src/material/material_localizations.dart
@@ -2,35 +2,34 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
 import 'package:flutter/widgets.dart';
 
-/// Interface for localized resource values for the material widgets.
+import 'i18n/localizations.dart';
+
+/// Defines the localized resource values used by the Material widgts.
 ///
-/// This class provides a default placeholder implementation that returns
-/// hard-coded American English values.
-class MaterialLocalizations {
-  /// Create a placeholder object for the localized resources of material widgets
-  /// which only provides American English strings.
-  const MaterialLocalizations();
-
-  /// The locale for which the values of this class's localized resources
-  /// have been translated.
-  Locale get locale => const Locale('en', 'US');
-
+/// See also:
+///
+///  * [DefaultMaterialLocalizations], which implements this interface and
+///    and supports a variety of locales.
+abstract class MaterialLocalizations {
   /// The tooltip for the leading [AppBar] menu (aka 'hamburger') button
-  String get openAppDrawerTooltip => 'Open navigation menu';
+  String get openAppDrawerTooltip;
 
   /// The [BackButton]'s tooltip.
-  String get backButtonTooltip => 'Back';
+  String get backButtonTooltip;
 
   /// The [CloseButton]'s tooltip.
-  String get closeButtonTooltip => 'Close';
+  String get closeButtonTooltip;
 
   /// The tooltip for the [MonthPicker]'s "next month" button.
-  String get nextMonthTooltip => 'Next month';
+  String get nextMonthTooltip;
 
   /// The tooltip for the [MonthPicker]'s "previous month" button.
-  String get previousMonthTooltip => 'Previous month';
+  String get previousMonthTooltip;
 
   /// The `MaterialLocalizations` from the closest [Localizations] instance
   /// that encloses the given context.
@@ -48,3 +47,46 @@
     return Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
   }
 }
+
+/// Localized strings for the material widgets.
+class DefaultMaterialLocalizations implements MaterialLocalizations {
+  /// Construct an object that defines the material widgets' localized strings
+  /// for the given `locale`.
+  DefaultMaterialLocalizations(this.locale) {
+    assert(locale != null);
+    _nameToValue = localizations[locale.toString()]
+      ?? localizations[locale.languageCode]
+      ?? localizations['en']
+      ?? <String, String>{};
+  }
+
+  Map<String, String> _nameToValue;
+
+  /// The locale for which the values of this class's localized resources
+  /// have been translated.
+  final Locale locale;
+
+  @override
+  String get openAppDrawerTooltip => _nameToValue["openAppDrawerTooltip"];
+
+  @override
+  String get backButtonTooltip => _nameToValue["backButtonTooltip"];
+
+  @override
+  String get closeButtonTooltip => _nameToValue["closeButtonTooltip"];
+
+  @override
+  String get nextMonthTooltip => _nameToValue["nextMonthTooltip"];
+
+  @override
+  String get previousMonthTooltip => _nameToValue["previousMonthTooltip"];
+
+  /// Creates an object that provides localized resource values for the
+  /// for the widgets of the material library.
+  ///
+  /// This method is typically used to create a [LocalizationsDelegate].
+  /// The [MaterialApp] does so by default.
+  static Future<MaterialLocalizations> load(Locale locale) {
+    return new SynchronousFuture<MaterialLocalizations>(new DefaultMaterialLocalizations(locale));
+  }
+}
diff --git a/packages/flutter/lib/src/widgets/localizations.dart b/packages/flutter/lib/src/widgets/localizations.dart
index 961fbc6..5ed7d60 100644
--- a/packages/flutter/lib/src/widgets/localizations.dart
+++ b/packages/flutter/lib/src/widgets/localizations.dart
@@ -16,10 +16,17 @@
 // class Intl { static String message(String s, { String name, String locale }) => ''; }
 // Future<Null> initializeMessages(String locale) => null;
 
+// Used by loadAll() to record LocalizationsDelegate.load() futures we're
+// waiting for.
+class _Pending {
+  _Pending(this.delegate, this.futureValue);
+  final LocalizationsDelegate<dynamic> delegate;
+  final Future<dynamic> futureValue;
+}
+
 // A utility function used by Localizations to generate one future
 // that completes when all of the LocalizationsDelegate.load() futures
-// complete. The returned map is indexed by the type of each input
-// future's value.
+// complete. The returned map is indexed by each delegate's type.
 //
 // The input future values must have distinct types.
 //
@@ -31,38 +38,41 @@
 // This is more complicated than just applying Future.wait to input
 // because some of the input.values may be SynchronousFutures. We don't want
 // to Future.wait for the synchronous futures.
-Future<Map<Type, dynamic>> _loadAll(Iterable<Future<dynamic>> inputValues) {
+Future<Map<Type, dynamic>> _loadAll(Locale locale, Iterable<LocalizationsDelegate<dynamic>> delegates) {
   final Map<Type, dynamic> output = <Type, dynamic>{};
-  List<Future<dynamic>> outputFutures;
+  List<_Pending> pendingList;
 
-  for (Future<dynamic> inputValue in inputValues) {
+  for (LocalizationsDelegate<dynamic> delegate in delegates) {
+    final Future<dynamic> inputValue = delegate.load(locale);
     dynamic completedValue;
     final Future<dynamic> futureValue = inputValue.then<dynamic>((dynamic value) {
       return completedValue = value;
     });
     if (completedValue != null) { // inputValue was a SynchronousFuture
-      final Type type = completedValue.runtimeType;
+      final Type type = delegate.type;
       assert(!output.containsKey(type));
       output[type] = completedValue;
     } else {
-      outputFutures ??= <Future<dynamic>>[];
-      outputFutures.add(futureValue);
+      pendingList ??= <_Pending>[];
+      pendingList.add(new _Pending(delegate, futureValue));
     }
   }
 
-  // All of the input.values were synchronous futures, we're done.
-  if (outputFutures == null)
+  // All of the delegate.load() values were synchronous futures, we're done.
+  if (pendingList == null)
     return new SynchronousFuture<Map<Type, dynamic>>(output);
 
-  // Some of input.values were asynchronous futures. Wait for them.
-  return Future.wait<dynamic>(outputFutures).then<Map<Type, dynamic>>((List<dynamic> values) {
-    for (dynamic value in values) {
-      final Type type = value.runtimeType;
-      assert(!output.containsKey(type));
-      output[type] = value;
-     }
-    return output;
-  });
+  // Some of delegate.load() values were asynchronous futures. Wait for them.
+  return Future.wait<dynamic>(pendingList.map((_Pending p) => p.futureValue))
+    .then<Map<Type, dynamic>>((List<dynamic> values) {
+      assert(values.length == pendingList.length);
+      for (int i = 0; i < values.length; i += 1) {
+        final Type type = pendingList[i].delegate.type;
+        assert(!output.containsKey(type));
+        output[type] = values[i];
+      }
+      return output;
+    });
 }
 
 /// A factory for a set of localized resources of type `T`, to be loaded by a
@@ -92,8 +102,10 @@
   /// after [load] has completed.
   bool shouldReload(covariant LocalizationsDelegate<T> old);
 
+  Type get type => T;
+
   @override
-  String toString() => '$runtimeType';
+  String toString() => '$runtimeType[$type]';
 }
 
 /// Interface for localized resource values for the lowest levels of the Flutter
@@ -346,12 +358,8 @@
       return;
     }
 
-    final Iterable<Future<dynamic>> allResources = delegates.map((LocalizationsDelegate<dynamic> delegate) {
-      return delegate.load(locale);
-    });
-
     Map<Type, dynamic> typeToResources;
-    final Future<Map<Type, dynamic>> typeToResourcesFuture = _loadAll(allResources)
+    final Future<Map<Type, dynamic>> typeToResourcesFuture = _loadAll(locale, delegates)
       .then((Map<Type, dynamic> value) {
         return typeToResources = value;
       });
@@ -383,7 +391,6 @@
   T resourcesFor<T>(Type type) {
     assert(type != null);
     final T resources = _typeToResources[type];
-    assert(resources.runtimeType == type);
     return resources;
   }
 
diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart
new file mode 100644
index 0000000..d6ed0d8
--- /dev/null
+++ b/packages/flutter/test/material/localizations_test.dart
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. 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:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+Widget buildFrame({
+  Locale locale,
+  WidgetBuilder buildContent,
+}) {
+  return new MaterialApp(
+    color: const Color(0xFFFFFFFF),
+    locale: locale,
+    onGenerateRoute: (RouteSettings settings) {
+      return new MaterialPageRoute<Null>(
+        builder: (BuildContext context) {
+          return buildContent(context);
+        }
+      );
+    },
+  );
+}
+
+void main() {
+  final Key textKey = new UniqueKey();
+
+  testWidgets('sanity check', (WidgetTester tester) async {
+    await tester.pumpWidget(
+      buildFrame(
+        buildContent: (BuildContext context) {
+          return new Text(
+            MaterialLocalizations.of(context).backButtonTooltip,
+            key: textKey,
+          );
+        }
+      )
+    );
+
+    expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
+
+    // Spanish Bolivia locale, falls back to just 'es'
+    await tester.binding.setLocale('es', 'bo');
+    await tester.pump();
+    expect(tester.widget<Text>(find.byKey(textKey)).data, 'Espalda');
+
+    // Unrecognized locale falls back to 'en'
+    await tester.binding.setLocale('foo', 'bar');
+    await tester.pump();
+    expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
+  });
+}