| 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 /** |
| 6 * This library provides internationalization and localization. This includes | 6 * This library provides internationalization and localization. This includes |
| 7 * message formatting and replacement, date and number formatting and parsing, | 7 * message formatting and replacement, date and number formatting and parsing, |
| 8 * and utilities for working with Bidirectional text. | 8 * and utilities for working with Bidirectional text. |
| 9 * | 9 * |
| 10 * For things that require locale or other data, there are multiple different | 10 * For things that require locale or other data, there are multiple different |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 * and used to create a date format via `anIntl.date()`. Static methods | 33 * and used to create a date format via `anIntl.date()`. Static methods |
| 34 * on this class are also used in message formatting. | 34 * on this class are also used in message formatting. |
| 35 * | 35 * |
| 36 * Message example: | 36 * Message example: |
| 37 * '''I see ${Intl.plural(num_people, | 37 * '''I see ${Intl.plural(num_people, |
| 38 * {'0': 'no one at all', | 38 * {'0': 'no one at all', |
| 39 * '1': 'one other person', | 39 * '1': 'one other person', |
| 40 * 'other': '$num_people other people'})} in $place.'''' | 40 * 'other': '$num_people other people'})} in $place.'''' |
| 41 * | 41 * |
| 42 * Usage examples: | 42 * Usage examples: |
| 43 * today(date) => intl.message( | 43 * today(date) => Intl.message( |
| 44 * "Today's date is $date", | 44 * "Today's date is $date", |
| 45 * desc: 'Indicate the current date', | 45 * desc: 'Indicate the current date', |
| 46 * examples: {'date' : 'June 8, 2012'}); | 46 * examples: {'date' : 'June 8, 2012'}); |
| 47 * print(today(new Date.now()); | 47 * print(today(new Date.now()); |
| 48 * | 48 * |
| 49 * msg(num_people, place) => intl.message( | 49 * msg({num_people, place}) => Intl.message( |
| 50 * '''I see ${Intl.plural(num_people, | 50 * '''I see ${Intl.plural(num_people, |
| 51 * {'0': 'no one at all', | 51 * {'0': 'no one at all', |
| 52 * '1': 'one other person', | 52 * '1': 'one other person', |
| 53 * 'other': '$num_people other people'})} in $place.'''', | 53 * 'other': '$num_people other people'})} in $place.'''', |
| 54 * desc: 'Description of how many people are seen as program start.', | 54 * desc: 'Description of how many people are seen as program start.', |
| 55 * examples: {'num_people': 3, 'place': 'London'}); | 55 * examples: {'num_people': 3, 'place': 'London'}); |
| 56 * | 56 * |
| 57 * Calling `msg({'num_people': 2, 'place': 'Athens'});` would | 57 * Calling `msg({'num_people': 2, 'place': 'Athens'});` would |
| 58 * produce "I see 2 other people in Athens." as output. | 58 * produce "I see 2 other people in Athens." as output in the default locale. |
| 59 * |
| 60 * To use a locale other than the default, use the `withLocale` function. |
| 61 * var todayString = new DateFormat("pt_BR").format(new Date.now()); |
| 62 * print(withLocale("pt_BR", () => today(todayString)); |
| 59 * | 63 * |
| 60 * See `tests/message_format_test.dart` for more examples. | 64 * See `tests/message_format_test.dart` for more examples. |
| 61 */ | 65 */ |
| 62 //TODO(efortuna): documentation example involving the offset parameter? | 66 //TODO(efortuna): documentation example involving the offset parameter? |
| 63 | 67 |
| 64 class Intl { | 68 class Intl { |
| 65 /** | 69 /** |
| 66 * String indicating the locale code with which the message is to be | 70 * String indicating the locale code with which the message is to be |
| 67 * formatted (such as en-CA). | 71 * formatted (such as en-CA). |
| 68 */ | 72 */ |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 /** | 151 /** |
| 148 * Given [newLocale] return a locale that we have data for that is similar | 152 * Given [newLocale] return a locale that we have data for that is similar |
| 149 * to it, if possible. | 153 * to it, if possible. |
| 150 * If [newLocale] is found directly, return it. If it can't be found, look up | 154 * If [newLocale] is found directly, return it. If it can't be found, look up |
| 151 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' | 155 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' |
| 152 * as a separator and changes it into '_' for lookup, and changes the | 156 * as a separator and changes it into '_' for lookup, and changes the |
| 153 * country to uppercase. | 157 * country to uppercase. |
| 154 * Note that null is interpreted as meaning the default locale, so if | 158 * Note that null is interpreted as meaning the default locale, so if |
| 155 * [newLocale] is null it will be returned. | 159 * [newLocale] is null it will be returned. |
| 156 */ | 160 */ |
| 157 static String verifiedLocale(String newLocale) { | 161 static String verifiedLocale(String newLocale, bool localeExists(String), |
| 158 // TODO(alanknight): This is specific to DateFormat, and only used there | 162 [Function onFailure = _throwLocaleError]) { |
| 159 // now. This should be moved, renamed, or generalized. | 163 // TODO(alanknight): Previously we kept a single verified locale on the Intl |
| 164 // object, but with different verification for different uses, that's more |
| 165 // difficult. As a result, we call this more often. Consider keeping |
| 166 // verified locales for each purpose if it turns out to be a performance |
| 167 // issue. |
| 160 if (newLocale == null) return systemLocale; | 168 if (newLocale == null) return systemLocale; |
| 161 if (_localeExists(newLocale)) { | 169 if (localeExists(newLocale)) { |
| 162 return newLocale; | 170 return newLocale; |
| 163 } | 171 } |
| 164 for (var each in [canonicalizedLocale(newLocale), _shortLocale(newLocale)])
{ | 172 for (var each in |
| 165 if (_localeExists(each)) { | 173 [canonicalizedLocale(newLocale), _shortLocale(newLocale)]) { |
| 174 if (localeExists(each)) { |
| 166 return each; | 175 return each; |
| 167 } | 176 } |
| 168 } | 177 } |
| 169 throw new ArgumentError("Invalid locale '$newLocale'"); | 178 return onFailure(newLocale); |
| 179 } |
| 180 |
| 181 /** |
| 182 * The default action if a locale isn't found in verifiedLocale. Throw |
| 183 * an exception indicating the locale isn't correct. |
| 184 */ |
| 185 static String _throwLocaleError(String localeName) { |
| 186 throw new ArgumentError("Invalid locale '$localeName'"); |
| 170 } | 187 } |
| 171 | 188 |
| 172 /** Return the short version of a locale name, e.g. 'en_US' => 'en' */ | 189 /** Return the short version of a locale name, e.g. 'en_US' => 'en' */ |
| 173 static String _shortLocale(String aLocale) { | 190 static String _shortLocale(String aLocale) { |
| 174 if (aLocale.length < 2) return aLocale; | 191 if (aLocale.length < 2) return aLocale; |
| 175 return aLocale.substring(0, 2).toLowerCase(); | 192 return aLocale.substring(0, 2).toLowerCase(); |
| 176 } | 193 } |
| 177 | 194 |
| 178 /** | 195 /** |
| 179 * Return a locale name turned into xx_YY where it might possibly be | 196 * Return a locale name turned into xx_YY where it might possibly be |
| (...skipping 18 matching lines...) Expand all Loading... |
| 198 * Support method for message formatting. Select the correct plural form from | 215 * Support method for message formatting. Select the correct plural form from |
| 199 * [cases] given [howMany]. | 216 * [cases] given [howMany]. |
| 200 */ | 217 */ |
| 201 static String plural(var howMany, Map cases, [num offset=0]) { | 218 static String plural(var howMany, Map cases, [num offset=0]) { |
| 202 // TODO(efortuna): Deal with "few" and "many" cases, offset, and others! | 219 // TODO(efortuna): Deal with "few" and "many" cases, offset, and others! |
| 203 return select(howMany.toString(), cases); | 220 return select(howMany.toString(), cases); |
| 204 } | 221 } |
| 205 | 222 |
| 206 /** | 223 /** |
| 207 * Format the given function with a specific [locale], given a | 224 * Format the given function with a specific [locale], given a |
| 208 * [msg_function] that takes no parameters and returns a String. We | 225 * [message_function] that takes no parameters. The [message_function] can be |
| 209 * basically delay calling the message function proper until after the proper | 226 * a simple message function that just returns the result of `Intl.message()` |
| 210 * locale has been set. | 227 * it can be a wrapper around a message function that takes arguments, or it |
| 228 * can be something more complex that manipulates multiple message |
| 229 * functions. |
| 230 * |
| 231 * In either case, the purpose of this is to delay calling [message_function] |
| 232 * until the proper locale has been set. This returns the result of calling |
| 233 * [msg_function], which could be of an arbitrary type. |
| 211 */ | 234 */ |
| 212 static String withLocale(String locale, Function msg_function) { | 235 static dynamic withLocale(String locale, message_function()) { |
| 213 // We have to do this silliness because Locale is not known at compile time, | 236 // We have to do this silliness because Locale is not known at compile time, |
| 214 // but must be a static variable. | 237 // but must be a static variable in order to be visible to the Intl.message |
| 238 // invocation. |
| 215 if (_defaultLocale == null) _defaultLocale = systemLocale; | 239 if (_defaultLocale == null) _defaultLocale = systemLocale; |
| 216 var oldLocale = _defaultLocale; | 240 var oldLocale = _defaultLocale; |
| 217 _defaultLocale = locale; | 241 _defaultLocale = locale; |
| 218 var result = msg_function(); | 242 var result = message_function(); |
| 219 _defaultLocale = oldLocale; | 243 _defaultLocale = oldLocale; |
| 220 return result; | 244 return result; |
| 221 } | 245 } |
| 222 | 246 |
| 223 /** | 247 /** |
| 224 * Support method for message formatting. Select the correct exact (gender, | 248 * Support method for message formatting. Select the correct exact (gender, |
| 225 * usually) form from [cases] given the user [choice]. | 249 * usually) form from [cases] given the user [choice]. |
| 226 */ | 250 */ |
| 227 static String select(String choice, Map cases) { | 251 static String select(String choice, Map cases) { |
| 228 if (cases.containsKey(choice)) { | 252 if (cases.containsKey(choice)) { |
| 229 return cases[choice]; | 253 return cases[choice]; |
| 230 } else if (cases.containsKey('other')){ | 254 } else if (cases.containsKey('other')){ |
| 231 return cases['other']; | 255 return cases['other']; |
| 232 } else { | 256 } else { |
| 233 return ''; | 257 return ''; |
| 234 } | 258 } |
| 235 } | 259 } |
| 236 | 260 |
| 237 /** | 261 /** |
| 238 * Accessor for the current locale. This should always == the default locale, | 262 * Accessor for the current locale. This should always == the default locale, |
| 239 * unless for some reason this gets called inside a message that resets the | 263 * unless for some reason this gets called inside a message that resets the |
| 240 * locale. | 264 * locale. |
| 241 */ | 265 */ |
| 242 static String getCurrentLocale() { | 266 static String getCurrentLocale() { |
| 243 if (_defaultLocale == null) _defaultLocale = systemLocale; | 267 if (_defaultLocale == null) _defaultLocale = systemLocale; |
| 244 return _defaultLocale; | 268 return _defaultLocale; |
| 245 } | 269 } |
| 246 } | 270 } |
| OLD | NEW |