| 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('../htmlescape/lib/htmlescape.dart'); | 12 #import('../htmlescape/lib/htmlescape.dart'); |
| 13 | 13 |
| 14 #import('date_format.dart'); | 14 #import('date_format.dart'); |
| 15 #import('lib/intl_helpers.dart'); | 15 #import('lib/intl_helpers.dart'); |
| 16 | 16 |
| 17 #source('bidi_formatter.dart'); | 17 #source('bidi_formatter.dart'); |
| 18 #source('bidi_utils.dart'); | 18 #source('bidi_utils.dart'); |
| 19 | 19 |
| 20 class Intl { | 20 class Intl { |
| 21 /** | 21 /** |
| 22 * 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 |
| 23 * formatted (such as en-CA). | 23 * formatted (such as en-CA). |
| 24 */ | 24 */ |
| 25 String _locale; | 25 String _locale; |
| 26 | 26 |
| 27 /** The default locale, which normally will be obtained from the browser. */ | 27 /** The default locale. This defaults to being set from systemLocale, but |
| 28 * can also be set explicitly, and will then apply to any new instances where |
| 29 * the locale isn't specified. |
| 30 */ |
| 28 static String _defaultLocale; | 31 static String _defaultLocale; |
| 29 | 32 |
| 30 /** | 33 /** |
| 34 * The system's locale, as obtained from the window.navigator.language |
| 35 * or other operating system mechanism. Note that due to system limitations |
| 36 * this is not automatically set, and must be set by importing one of |
| 37 * intl_browser.dart or intl_standalone.dart and calling findSystemLocale(). |
| 38 */ |
| 39 // TODO(alanknight): Detect this without forcing the jump through hoops. |
| 40 // Issue 5171. |
| 41 static String systemLocale = 'en_US'; |
| 42 |
| 43 /** |
| 31 * Return a new date format using the specified [pattern]. | 44 * Return a new date format using the specified [pattern]. |
| 32 * If [desiredLocale] is not specified, then we default to [locale]. | 45 * If [desiredLocale] is not specified, then we default to [locale]. |
| 33 */ | 46 */ |
| 34 DateFormat date([String pattern, String desiredLocale]) { | 47 DateFormat date([String pattern, String desiredLocale]) { |
| 35 var actualLocale = (desiredLocale == null) ? locale : desiredLocale; | 48 var actualLocale = (desiredLocale == null) ? locale : desiredLocale; |
| 36 return new DateFormat(pattern, actualLocale); | 49 return new DateFormat(pattern, actualLocale); |
| 37 } | 50 } |
| 38 | 51 |
| 39 /** | 52 /** |
| 40 * Constructor optionally [aLocale] for specifics of the language | 53 * Constructor optionally [aLocale] for specifics of the language |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 * If [newLocale] is found directly, return it. If it can't be found, look up | 108 * If [newLocale] is found directly, return it. If it can't be found, look up |
| 96 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' | 109 * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-' |
| 97 * as a separator and changes it into '_' for lookup, and changes the | 110 * as a separator and changes it into '_' for lookup, and changes the |
| 98 * country to uppercase. | 111 * country to uppercase. |
| 99 * Note that null is interpreted as meaning the default locale, so if | 112 * Note that null is interpreted as meaning the default locale, so if |
| 100 * [newLocale] is null it will be returned. | 113 * [newLocale] is null it will be returned. |
| 101 */ | 114 */ |
| 102 static String verifiedLocale(String newLocale) { | 115 static String verifiedLocale(String newLocale) { |
| 103 // TODO(alanknight): This is specific to DateFormat, and only used there | 116 // TODO(alanknight): This is specific to DateFormat, and only used there |
| 104 // now. This should be moved, renamed, or generalized. | 117 // now. This should be moved, renamed, or generalized. |
| 105 if (newLocale == null) return _getDefaultLocale(); | 118 if (newLocale == null) return systemLocale; |
| 106 if (_localeExists(newLocale)) { | 119 if (_localeExists(newLocale)) { |
| 107 return newLocale; | 120 return newLocale; |
| 108 } | 121 } |
| 109 for (var each in [_canonicalized(newLocale), _shortLocale(newLocale)]) { | 122 for (var each in [canonicalizedLocale(newLocale), _shortLocale(newLocale)])
{ |
| 110 if (_localeExists(each)) { | 123 if (_localeExists(each)) { |
| 111 return each; | 124 return each; |
| 112 } | 125 } |
| 113 } | 126 } |
| 114 throw new IllegalArgumentException("Invalid locale '$newLocale'"); | 127 throw new IllegalArgumentException("Invalid locale '$newLocale'"); |
| 115 } | 128 } |
| 116 | 129 |
| 117 /** Return the short version of a locale name, e.g. 'en_US' => 'en' */ | 130 /** Return the short version of a locale name, e.g. 'en_US' => 'en' */ |
| 118 static String _shortLocale(String aLocale) { | 131 static String _shortLocale(String aLocale) { |
| 119 if (aLocale.length < 2) return aLocale; | 132 if (aLocale.length < 2) return aLocale; |
| 120 return aLocale.substring(0, 2).toLowerCase(); | 133 return aLocale.substring(0, 2).toLowerCase(); |
| 121 } | 134 } |
| 122 | 135 |
| 123 /** | 136 /** |
| 124 * Return a locale name turned into xx_YY where it might possibly be | 137 * Return a locale name turned into xx_YY where it might possibly be |
| 125 * in the wrong case or with a hyphen instead of an underscore. | 138 * in the wrong case or with a hyphen instead of an underscore. |
| 126 */ | 139 */ |
| 127 static String _canonicalized(String aLocale) { | 140 static String canonicalizedLocale(String aLocale) { |
| 128 // Locales of length < 5 are presumably two-letter forms, or else malformed. | 141 // Locales of length < 5 are presumably two-letter forms, or else malformed. |
| 129 // Locales of length > 6 are likely to be malformed. In either case we | 142 // Locales of length > 6 are likely to be malformed. In either case we |
| 130 // return them unmodified and if correct they will be found. | 143 // return them unmodified and if correct they will be found. |
| 131 if ((aLocale.length < 5) || (aLocale.length > 6)) return aLocale; | 144 if ((aLocale.length < 5) || (aLocale.length > 6)) return aLocale; |
| 132 if (aLocale[2] != '-' && (aLocale[2] != '_')) return aLocale; | 145 if (aLocale[2] != '-' && (aLocale[2] != '_')) return aLocale; |
| 133 return '${aLocale[0]}${aLocale[1]}_${aLocale[3].toUpperCase()}' | 146 return '${aLocale[0]}${aLocale[1]}_${aLocale[3].toUpperCase()}' |
| 134 '${aLocale[4].toUpperCase()}'; | 147 '${aLocale[4].toUpperCase()}'; |
| 135 } | 148 } |
| 136 | 149 |
| 137 /** | 150 /** |
| 138 * Support method for message formatting. Select the correct plural form from | 151 * Support method for message formatting. Select the correct plural form from |
| 139 * [cases] given [howMany]. | 152 * [cases] given [howMany]. |
| 140 */ | 153 */ |
| 141 static String plural(var howMany, Map cases, [num offset=0]) { | 154 static String plural(var howMany, Map cases, [num offset=0]) { |
| 142 // TODO(efortuna): Deal with "few" and "many" cases, offset, and others! | 155 // TODO(efortuna): Deal with "few" and "many" cases, offset, and others! |
| 143 return select(howMany.toString(), cases); | 156 return select(howMany.toString(), cases); |
| 144 } | 157 } |
| 145 | 158 |
| 146 /** | 159 /** |
| 147 * Format the given function with a specific [locale], given a | 160 * Format the given function with a specific [locale], given a |
| 148 * [msg_function] that takes no parameters and returns a String. We | 161 * [msg_function] that takes no parameters and returns a String. We |
| 149 * basically delay calling the message function proper until after the proper | 162 * basically delay calling the message function proper until after the proper |
| 150 * locale has been set. | 163 * locale has been set. |
| 151 */ | 164 */ |
| 152 static String withLocale(String locale, Function msg_function) { | 165 static String withLocale(String locale, Function msg_function) { |
| 153 // We have to do this silliness because Locale is not known at compile time, | 166 // We have to do this silliness because Locale is not known at compile time, |
| 154 // but must be a static variable. | 167 // but must be a static variable. |
| 155 if (_defaultLocale == null) _defaultLocale = _getDefaultLocale(); | 168 if (_defaultLocale == null) _defaultLocale = systemLocale; |
| 156 var oldLocale = _defaultLocale; | 169 var oldLocale = _defaultLocale; |
| 157 _defaultLocale = locale; | 170 _defaultLocale = locale; |
| 158 var result = msg_function(); | 171 var result = msg_function(); |
| 159 _defaultLocale = oldLocale; | 172 _defaultLocale = oldLocale; |
| 160 return result; | 173 return result; |
| 161 } | 174 } |
| 162 | 175 |
| 163 /** | 176 /** |
| 164 * Support method for message formatting. Select the correct exact (gender, | 177 * Support method for message formatting. Select the correct exact (gender, |
| 165 * usually) form from [cases] given the user [choice]. | 178 * usually) form from [cases] given the user [choice]. |
| 166 */ | 179 */ |
| 167 static String select(String choice, Map cases) { | 180 static String select(String choice, Map cases) { |
| 168 if (cases.containsKey(choice)) { | 181 if (cases.containsKey(choice)) { |
| 169 return cases[choice]; | 182 return cases[choice]; |
| 170 } else if (cases.containsKey('other')){ | 183 } else if (cases.containsKey('other')){ |
| 171 return cases['other']; | 184 return cases['other']; |
| 172 } else { | 185 } else { |
| 173 return ''; | 186 return ''; |
| 174 } | 187 } |
| 175 } | 188 } |
| 176 | 189 |
| 177 /** | 190 /** |
| 178 * Helper to detect the locale as defined at runtime. | |
| 179 */ | |
| 180 static String _getDefaultLocale() { | |
| 181 // TODO(efortuna): Detect the default locale given the user preferences. | |
| 182 // That would mean using window.navigator.language in a browser or | |
| 183 // an environment variable or other OS mechanism for the standalone VM. | |
| 184 // Yay, hard-coding for now! | |
| 185 return 'en_US'; | |
| 186 } | |
| 187 | |
| 188 /** | |
| 189 * Accessor for the current locale. This should always == the default locale, | 191 * Accessor for the current locale. This should always == the default locale, |
| 190 * unless for some reason this gets called inside a message that resets the | 192 * unless for some reason this gets called inside a message that resets the |
| 191 * locale. | 193 * locale. |
| 192 */ | 194 */ |
| 193 static String getCurrentLocale() { | 195 static String getCurrentLocale() { |
| 194 if (_defaultLocale == null) _defaultLocale = _getDefaultLocale(); | 196 if (_defaultLocale == null) _defaultLocale = systemLocale; |
| 195 return _defaultLocale; | 197 return _defaultLocale; |
| 196 } | 198 } |
| 197 } | 199 } |
| 198 | 200 |
| 199 /** | 201 /** |
| 200 * The internal mechanism for looking up messages. We expect this to be set | 202 * 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 | 203 * by the implementing package so that we're not dependent on its |
| 202 * implementation. | 204 * implementation. |
| 203 */ | 205 */ |
| 204 var _messageLookup = const | 206 var _messageLookup = const |
| 205 UninitializedLocaleData('initializeMessages(<locale>)'); | 207 UninitializedLocaleData('initializeMessages(<locale>)'); |
| 206 | 208 |
| 207 /** | 209 /** |
| 208 * Initialize the message lookup mechanism. This is for internal use only. | 210 * Initialize the message lookup mechanism. This is for internal use only. |
| 209 * User applications should import message_lookup_local.dart and call | 211 * User applications should import message_lookup_local.dart and call |
| 210 * initializeMessages | 212 * initializeMessages |
| 211 */ | 213 */ |
| 212 void initializeInternalMessageLookup(Function lookupFunction) { | 214 void initializeInternalMessageLookup(Function lookupFunction) { |
| 213 if (_messageLookup is UninitializedLocaleData) { | 215 if (_messageLookup is UninitializedLocaleData) { |
| 214 _messageLookup = lookupFunction(); | 216 _messageLookup = lookupFunction(); |
| 215 } | 217 } |
| 216 } | 218 } |
| OLD | NEW |