| 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 * Internationalization object providing access to message formatting objects, | 6 * Internationalization object providing access to message formatting objects, |
| 7 * date formatting, parsing, bidirectional text relative to a specific locale. | 7 * date formatting, parsing, bidirectional text relative to a specific locale. |
| 8 */ | 8 */ |
| 9 #library('intl'); | 9 #library('intl'); |
| 10 | 10 |
| 11 // TODO(rnystrom): Use "package:" import when test.dart supports it (#4968). | 11 // TODO(rnystrom): Use "package:" import when test.dart supports it (#4968). |
| 12 #import('../../pkg/htmlescape/lib/htmlescape.dart'); | 12 #import('../htmlescape/lib/htmlescape.dart'); |
| 13 | 13 |
| 14 #import('date_format.dart'); | 14 #import('date_format.dart'); |
| 15 #source('intl_message.dart'); | 15 #import('lib/intl_helpers.dart'); |
| 16 |
| 16 #source('bidi_formatter.dart'); | 17 #source('bidi_formatter.dart'); |
| 17 #source('bidi_utils.dart'); | 18 #source('bidi_utils.dart'); |
| 18 | 19 |
| 19 class Intl { | 20 class Intl { |
| 20 /** | 21 /** |
| 21 * String indicating the locale code with which the message is to be | 22 * String indicating the locale code with which the message is to be |
| 22 * formatted (such as en-CA). | 23 * formatted (such as en-CA). |
| 23 */ | 24 */ |
| 24 static String _locale; | 25 String _locale; |
| 25 | 26 |
| 26 IntlMessage intlMsg; | 27 /** The default locale, which normally will be obtained from the browser. */ |
| 28 static String _defaultLocale; |
| 27 | 29 |
| 28 /** | 30 /** |
| 29 * Return a new date format using the specified [pattern]. | 31 * Return a new date format using the specified [pattern]. |
| 30 * If [desiredLocale] is not specified, then we default to [locale]. | 32 * If [desiredLocale] is not specified, then we default to [locale]. |
| 31 */ | 33 */ |
| 32 DateFormat date(String pattern, [String desiredLocale]) { | 34 DateFormat date([String pattern, String desiredLocale]) { |
| 33 var actualLocale = (desiredLocale == null) ? _locale : desiredLocale; | 35 var actualLocale = (desiredLocale == null) ? locale : desiredLocale; |
| 34 return new DateFormat(pattern, actualLocale); | 36 return new DateFormat(pattern, actualLocale); |
| 35 } | 37 } |
| 36 | 38 |
| 37 /** | 39 /** |
| 38 * Constructor optionally [_locale] for specifics of the language | 40 * Constructor optionally [aLocale] for specifics of the language |
| 39 * locale to be used, otherwise, we will attempt to infer it (acceptable if | 41 * locale to be used, otherwise, we will attempt to infer it (acceptable if |
| 40 * Dart is running on the client, we can infer from the browser/client | 42 * Dart is running on the client, we can infer from the browser/client |
| 41 * preferences). | 43 * preferences). |
| 42 */ | 44 */ |
| 43 Intl([a_locale]) { | 45 Intl([String aLocale]) { |
| 44 if (a_locale == null) { | 46 if (aLocale != null) { |
| 45 _locale = _getDefaultLocale(); | 47 _locale = aLocale; |
| 46 } else { | 48 } else { |
| 47 _locale = verifiedLocale(a_locale); | 49 _locale = getCurrentLocale(); |
| 48 } | 50 } |
| 49 intlMsg = new IntlMessage(_locale); | |
| 50 } | 51 } |
| 51 | 52 |
| 52 /** | 53 /** |
| 53 * Create a message that can be internationalized. It takes a | 54 * Returns a message that can be internationalized. It takes a |
| 54 * [message_str] that will be translated, which may be interpolated | 55 * [message_str] that will be translated, which may be interpolated |
| 55 * based on one or more variables, a [desc] providing a description of usage | 56 * based on one or more variables, a [desc] providing a description of usage |
| 56 * for the [message_str], and a map of [examples] for each data element to be | 57 * for the [message_str], and a map of [examples] for each data element to be |
| 57 * substituted into the message. For example, if message="Hello, $name", then | 58 * substituted into the message. For example, if message="Hello, $name", then |
| 58 * examples = {'name': 'Sparky'}. If not using the user's default locale, or | 59 * examples = {'name': 'Sparky'}. If not using the user's default locale, or |
| 59 * if the locale is not easily detectable, explicitly pass [locale]. | 60 * if the locale is not easily detectable, explicitly pass [locale]. |
| 60 * The values of [desc] and [examples] are not used at run-time but are only | 61 * The values of [desc] and [examples] are not used at run-time but are only |
| 61 * made available to the translators, so they MUST be simple Strings available | 62 * made available to the translators, so they MUST be simple Strings available |
| 62 * at compile time: no String interpolation or concatenation. | 63 * at compile time: no String interpolation or concatenation. |
| 63 * The expected usage of this is inside a function that takes as parameters | 64 * The expected usage of this is inside a function that takes as parameters |
| 64 * the variables used in the interpolated string, and additionally also a | 65 * the variables used in the interpolated string, and additionally also a |
| 65 * locale (optional). | 66 * locale (optional). |
| 67 * Ultimately, the information about the enclosing function and its arguments |
| 68 * will be extracted automatically but for the time being it must be passed |
| 69 * explicitly in the [name] and [args] arguments. |
| 66 */ | 70 */ |
| 67 static String message(String message_str, [final String desc='', | 71 static String message(String message_str, [final String desc='', |
| 68 final Map examples=const {}, String locale='']) { | 72 final Map examples=const {}, String locale, String name, |
| 69 return message_str; | 73 List<String> args]) { |
| 74 return _messageLookup.lookupMessage( |
| 75 message_str, desc, examples, locale, name, args); |
| 70 } | 76 } |
| 71 | 77 |
| 72 /** | 78 /** |
| 73 * Return the locale for this instance. If none was set, the locale will | 79 * Return the locale for this instance. If none was set, the locale will |
| 74 * be the default. | 80 * be the default. |
| 75 */ | 81 */ |
| 76 String get locale => _locale; | 82 String get locale => _locale; |
| 77 | 83 |
| 78 /** | 84 /** |
| 79 * Return true if the locale exists, or if it is null. The null case | 85 * Return true if the locale exists, or if it is null. The null case |
| 80 * is interpreted to mean that we use the default locale. | 86 * is interpreted to mean that we use the default locale. |
| 81 */ | 87 */ |
| 82 static bool _localeExists(localeName) { | 88 static bool _localeExists(localeName) { |
| 83 return DateFormat.localeExists(localeName); | 89 return DateFormat.localeExists(localeName); |
| 84 } | 90 } |
| 85 | 91 |
| 86 /** | 92 /** |
| 87 * Given [newLocale] return a locale that we have data for that is similar | 93 * Given [newLocale] return a locale that we have data for that is similar |
| 88 * to it, if possible. | 94 * to it, if possible. |
| 89 * If [newLocale] is found directly, return it. If it can't be found, look up | 95 * If [newLocale] is found directly, return it. If it can't be found, look up |
| 90 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' | 96 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' |
| 91 * as a separator and changes it into '_' for lookup, and changes the | 97 * as a separator and changes it into '_' for lookup, and changes the |
| 92 * country to uppercase. | 98 * country to uppercase. |
| 93 * Note that null is interpreted as meaning the default locale, so if | 99 * Note that null is interpreted as meaning the default locale, so if |
| 94 * [newLocale] is null it will be returned. | 100 * [newLocale] is null it will be returned. |
| 95 */ | 101 */ |
| 96 static String verifiedLocale(String newLocale) { | 102 static String verifiedLocale(String newLocale) { |
| 103 // TODO(alanknight): This is specific to DateFormat, and only used there |
| 104 // now. This should be moved, renamed, or generalized. |
| 97 if (newLocale == null) return _getDefaultLocale(); | 105 if (newLocale == null) return _getDefaultLocale(); |
| 98 if (_localeExists(newLocale)) { | 106 if (_localeExists(newLocale)) { |
| 99 return newLocale; | 107 return newLocale; |
| 100 } | 108 } |
| 101 for (var each in [_canonicalized(newLocale), _shortLocale(newLocale)]) { | 109 for (var each in [_canonicalized(newLocale), _shortLocale(newLocale)]) { |
| 102 if (_localeExists(each)) { | 110 if (_localeExists(each)) { |
| 103 return each; | 111 return each; |
| 104 } | 112 } |
| 105 } | 113 } |
| 106 throw new IllegalArgumentException("Invalid locale '$newLocale'"); | 114 throw new IllegalArgumentException("Invalid locale '$newLocale'"); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 137 | 145 |
| 138 /** | 146 /** |
| 139 * Format the given function with a specific [locale], given a | 147 * Format the given function with a specific [locale], given a |
| 140 * [msg_function] that takes no parameters and returns a String. We | 148 * [msg_function] that takes no parameters and returns a String. We |
| 141 * basically delay calling the message function proper until after the proper | 149 * basically delay calling the message function proper until after the proper |
| 142 * locale has been set. | 150 * locale has been set. |
| 143 */ | 151 */ |
| 144 static String withLocale(String locale, Function msg_function) { | 152 static String withLocale(String locale, Function msg_function) { |
| 145 // We have to do this silliness because Locale is not known at compile time, | 153 // We have to do this silliness because Locale is not known at compile time, |
| 146 // but must be a static variable. | 154 // but must be a static variable. |
| 147 if (_locale == null) _locale = _getDefaultLocale(); | 155 if (_defaultLocale == null) _defaultLocale = _getDefaultLocale(); |
| 148 var oldLocale = _locale; | 156 var oldLocale = _defaultLocale; |
| 149 _locale = locale; | 157 _defaultLocale = locale; |
| 150 var result = msg_function(); | 158 var result = msg_function(); |
| 151 _locale = oldLocale; | 159 _defaultLocale = oldLocale; |
| 152 return result; | 160 return result; |
| 153 } | 161 } |
| 154 | 162 |
| 155 /** | 163 /** |
| 156 * Support method for message formatting. Select the correct exact (gender, | 164 * Support method for message formatting. Select the correct exact (gender, |
| 157 * usually) form from [cases] given the user [choice]. | 165 * usually) form from [cases] given the user [choice]. |
| 158 */ | 166 */ |
| 159 static String select(String choice, Map cases) { | 167 static String select(String choice, Map cases) { |
| 160 if (cases.containsKey(choice)) { | 168 if (cases.containsKey(choice)) { |
| 161 return cases[choice]; | 169 return cases[choice]; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 176 // Yay, hard-coding for now! | 184 // Yay, hard-coding for now! |
| 177 return 'en_US'; | 185 return 'en_US'; |
| 178 } | 186 } |
| 179 | 187 |
| 180 /** | 188 /** |
| 181 * Accessor for the current locale. This should always == the default locale, | 189 * Accessor for the current locale. This should always == the default locale, |
| 182 * unless for some reason this gets called inside a message that resets the | 190 * unless for some reason this gets called inside a message that resets the |
| 183 * locale. | 191 * locale. |
| 184 */ | 192 */ |
| 185 static String getCurrentLocale() { | 193 static String getCurrentLocale() { |
| 186 return _locale; | 194 if (_defaultLocale == null) _defaultLocale = _getDefaultLocale(); |
| 195 return _defaultLocale; |
| 187 } | 196 } |
| 188 } | 197 } |
| 198 |
| 199 /** |
| 200 * The internal mechanism for looking up messages. We expect this to be set |
| 201 * by the implementing package so that we're not dependent on its |
| 202 * implementation. |
| 203 */ |
| 204 var _messageLookup = const |
| 205 UninitializedLocaleData('initializeMessages(<locale>)'); |
| 206 |
| 207 /** |
| 208 * Initialize the message lookup mechanism. This is for internal use only. |
| 209 * User applications should import message_lookup_local.dart and call |
| 210 * initializeMessages |
| 211 */ |
| 212 void initializeInternalMessageLookup(Function lookupFunction) { |
| 213 if (_messageLookup is UninitializedLocaleData) { |
| 214 _messageLookup = lookupFunction(); |
| 215 } |
| 216 } |
| OLD | NEW |