OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /// This defines a class for loading locale data incrementally from |
6 * This defines a class for loading locale data incrementally from | 6 /// an external source as JSON. The external sources expected are either |
7 * an external source as JSON. The external sources expected are either | 7 /// local files or via HTTP request. |
8 * local files or via HTTP request. | |
9 */ | |
10 | 8 |
11 library lazy_locale_data; | 9 library lazy_locale_data; |
12 | 10 |
13 import 'dart:async'; | 11 import 'dart:async'; |
14 import 'dart:convert'; | 12 import 'dart:convert'; |
15 import 'intl_helpers.dart'; | 13 import 'intl_helpers.dart'; |
16 | 14 |
17 /** | 15 /// This implements the very basic map-type operations which are used |
18 * This implements the very basic map-type operations which are used | 16 /// in locale lookup, and looks them up based on a URL that defines |
19 * in locale lookup, and looks them up based on a URL that defines | 17 /// the external source. |
20 * the external source. | |
21 */ | |
22 class LazyLocaleData { | 18 class LazyLocaleData { |
23 /// This holds the data we have loaded. | 19 /// This holds the data we have loaded. |
24 Map map; | 20 Map map; |
25 | 21 |
26 /// The object that actually does the data reading. | 22 /// The object that actually does the data reading. |
27 LocaleDataReader _reader; | 23 LocaleDataReader _reader; |
28 | 24 |
29 /** | 25 /// In order to avoid a potentially remote call to see if a locale |
30 * In order to avoid a potentially remote call to see if a locale | 26 /// is available, we hold a complete list of all the available |
31 * is available, we hold a complete list of all the available | 27 /// locales. |
32 * locales. | |
33 */ | |
34 List availableLocales; | 28 List availableLocales; |
35 | 29 |
36 /** | 30 /// Given a piece of remote data, apply [_creationFunction] to it to |
37 * Given a piece of remote data, apply [_creationFunction] to it to | 31 /// convert it into the right form. Typically this means converting it |
38 * convert it into the right form. Typically this means converting it | 32 /// from a Map into an object form. |
39 * from a Map into an object form. | |
40 */ | |
41 Function _creationFunction; | 33 Function _creationFunction; |
42 | 34 |
43 /** | 35 /// The set of available locales. |
44 * The set of available locales. | |
45 */ | |
46 Set availableLocaleSet; | 36 Set availableLocaleSet; |
47 | 37 |
48 /** | 38 /// The constructor. The [_reader] specifies where the data comes |
49 * The constructor. The [_reader] specifies where the data comes | 39 /// from. The [_creationFunction] creates the appropriate data type |
50 * from. The [_creationFunction] creates the appropriate data type | 40 /// from the remote data (which typically comes in as a Map). The |
51 * from the remote data (which typically comes in as a Map). The | 41 /// [keys] lists the set of remotely available locale names so we know which |
52 * [keys] lists the set of remotely available locale names so we know which | 42 /// things can be fetched without having to check remotely. |
53 * things can be fetched without having to check remotely. | |
54 */ | |
55 LazyLocaleData(this._reader, this._creationFunction, List keys) { | 43 LazyLocaleData(this._reader, this._creationFunction, List keys) { |
56 map = new Map(); | 44 map = new Map(); |
57 availableLocales = keys; | 45 availableLocales = keys; |
58 availableLocaleSet = new Set.from(availableLocales); | 46 availableLocaleSet = new Set.from(availableLocales); |
59 } | 47 } |
60 | 48 |
61 /** | 49 /// Tests if we have data for the locale available. Note that this returns |
62 * Tests if we have data for the locale available. Note that this returns | 50 /// true even if the data is known to be available remotely but not yet |
63 * true even if the data is known to be available remotely but not yet loaded. | 51 /// loaded. |
64 */ | |
65 bool containsKey(String locale) => availableLocaleSet.contains(locale); | 52 bool containsKey(String locale) => availableLocaleSet.contains(locale); |
66 | 53 |
67 /** Returns the list of keys/locale names. */ | 54 /// Returns the list of keys/locale names. |
68 List get keys => availableLocales; | 55 List get keys => availableLocales; |
69 | 56 |
70 /** | 57 /// Returns the data stored for [localeName]. If no data has been loaded |
71 * Returns the data stored for [localeName]. If no data has been loaded | 58 /// for [localeName], throws an exception. If no data is available for |
72 * for [localeName], throws an exception. If no data is available for | 59 /// [localeName] then throw an exception with a different message. |
73 * [localeName] then throw an exception with a different message. | |
74 */ | |
75 operator [](String localeName) { | 60 operator [](String localeName) { |
76 if (containsKey(localeName)) { | 61 if (containsKey(localeName)) { |
77 var data = map[localeName]; | 62 var data = map[localeName]; |
78 if (data == null) { | 63 if (data == null) { |
79 throw new LocaleDataException( | 64 throw new LocaleDataException( |
80 "Locale $localeName has not been initialized." | 65 "Locale $localeName has not been initialized." |
81 " Call initializeDateFormatting($localeName, <data url>) first"); | 66 " Call initializeDateFormatting($localeName, <data url>) first"); |
82 } else { | 67 } else { |
83 return data; | 68 return data; |
84 } | 69 } |
85 } else { | 70 } else { |
86 unsupportedLocale(localeName); | 71 unsupportedLocale(localeName); |
87 } | 72 } |
88 } | 73 } |
89 | 74 |
90 /** | 75 /// Throw an exception indicating that the locale has no data available, |
91 * Throw an exception indicating that the locale has no data available, | 76 /// either locally or remotely. |
92 * either locally or remotely. | |
93 */ | |
94 unsupportedLocale(localeName) { | 77 unsupportedLocale(localeName) { |
95 throw new LocaleDataException('Locale $localeName has no data available'); | 78 throw new LocaleDataException('Locale $localeName has no data available'); |
96 } | 79 } |
97 | 80 |
98 /** | 81 /// Initialize for locale. Internal use only. As a user, call |
99 * Initialize for locale. Internal use only. As a user, call | 82 /// initializeDateFormatting instead. |
100 * initializeDateFormatting instead. | |
101 */ | |
102 Future initLocale(String localeName) { | 83 Future initLocale(String localeName) { |
103 var data = _reader.read(localeName); | 84 var data = _reader.read(localeName); |
104 return jsonData(data).then((input) { | 85 return jsonData(data).then((input) { |
105 map[localeName] = _creationFunction(input); | 86 map[localeName] = _creationFunction(input); |
106 }); | 87 }); |
107 } | 88 } |
108 | 89 |
109 /** | 90 /// Given a Future [input] whose value is expected to be a string in JSON |
110 * Given a Future [input] whose value is expected to be a string in JSON form, | 91 /// form, return another future that parses the JSON into a usable format. |
111 * return another future that parses the JSON into a usable format. | |
112 */ | |
113 Future jsonData(Future input) { | 92 Future jsonData(Future input) { |
114 return input.then((response) => JSON.decode(response)); | 93 return input.then((response) => JSON.decode(response)); |
115 } | 94 } |
116 } | 95 } |
OLD | NEW |