| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * Message/plural format library with locale support. This can have different | |
| 7 * implementations based on the mechanism for finding the localized versions | |
| 8 * of messages. This version expects them to be in a library named e.g. | |
| 9 * 'messages_en_US'. The prefix is set in the [initializeMessages] call, which | |
| 10 * must be made for a locale before any lookups can be done. | |
| 11 * | |
| 12 * See Intl class comment or `tests/message_format_test.dart` for more examples. | |
| 13 */ | |
| 14 //TODO(efortuna): documentation example involving the offset parameter? | |
| 15 | |
| 16 library message_lookup_local; | |
| 17 | |
| 18 import 'dart:async'; | |
| 19 import 'intl.dart'; | |
| 20 import 'src/intl_helpers.dart'; | |
| 21 import 'dart:mirrors'; | |
| 22 | |
| 23 /** | |
| 24 * Initialize the user messages for [localeName]. Note that this is an ASYNC | |
| 25 * operation. This must be called before attempting to use messages in | |
| 26 * [localeName]. | |
| 27 */ | |
| 28 Future initializeMessages(localeName, [String source = 'messages_']) { | |
| 29 initializeInternalMessageLookup( | |
| 30 () => new MessageLookupLocal(localeName, source)); | |
| 31 _initializeMessagesForLocale(localeName); | |
| 32 return new Future.immediate(null); | |
| 33 } | |
| 34 | |
| 35 void _initializeMessagesForLocale(String localeName) {} | |
| 36 | |
| 37 class MessageLookupLocal { | |
| 38 /** Prevent infinite recursion when looking up the message. */ | |
| 39 bool _lookupInProgress = false; | |
| 40 | |
| 41 /** The libraries we can look in for internationalization messages. */ | |
| 42 Map<String, LibraryMirror> _libraries; | |
| 43 | |
| 44 /** The prefix used to find libraries that contain localized messages. | |
| 45 * So, if this is 'messages_' we would look for messages for the locale | |
| 46 * 'pt_BR' in a library named 'messages_pt_BR'. | |
| 47 */ | |
| 48 String _sourcePrefix; | |
| 49 | |
| 50 /** | |
| 51 * Constructor. The [localeName] is of the form 'en' or 'en_US'. | |
| 52 *The [source] parameter defines the prefix that is used to find | |
| 53 * libraries that contain localized messages. So with the default value of | |
| 54 * 'messages_', we would look for messages for the locale 'pt_BR' in a library | |
| 55 * named 'messages_pt_BR'. | |
| 56 */ | |
| 57 MessageLookupLocal(String localeName, this._sourcePrefix) { | |
| 58 _libraries = currentMirrorSystem().libraries; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Return true if the locale exists, or if it is null. The null case | |
| 63 * is interpreted to mean that we use the default locale. | |
| 64 */ | |
| 65 bool localeExists(localeName) { | |
| 66 if (localeName == null) return false; | |
| 67 return _libraries['$_sourcePrefix$localeName'] != null; | |
| 68 } | |
| 69 | |
| 70 /** | |
| 71 * Return the localized version of a message. We are passed the original | |
| 72 * version of the message, which consists of a | |
| 73 * [message_str] that will be translated, and which may be interpolated | |
| 74 * based on one or more variables, a [desc] providing a description of usage | |
| 75 * for the [message_str], and a map of [examples] for each data element to be | |
| 76 * substituted into the message. | |
| 77 * | |
| 78 * For example, if message="Hello, $name", then | |
| 79 * examples = {'name': 'Sparky'}. If not using the user's default locale, or | |
| 80 * if the locale is not easily detectable, explicitly pass [locale]. | |
| 81 * | |
| 82 * The values of [desc] and [examples] are not used at run-time but are only | |
| 83 * made available to the translators, so they MUST be simple Strings available | |
| 84 * at compile time: no String interpolation or concatenation. | |
| 85 * The expected usage of this is inside a function that takes as parameters | |
| 86 * the variables used in the interpolated string. | |
| 87 * | |
| 88 * Ultimately, the information about the enclosing function and its arguments | |
| 89 * will be extracted automatically but for the time being it must be passed | |
| 90 * explicitly in the [name] and [args] arguments. | |
| 91 */ | |
| 92 Future<String> lookupMessage(String message_str, [final String desc='', | |
| 93 final Map examples=const {}, String locale, | |
| 94 String name, List<String> args]) { | |
| 95 if (name == null) return new Future.immediate(message_str); | |
| 96 // The translations also make use of Intl.message, so we need to not | |
| 97 // recurse and just stop when we find the first substitution. | |
| 98 if (_lookupInProgress) return new Future.immediate(message_str); | |
| 99 _lookupInProgress = true; | |
| 100 var result; | |
| 101 try { | |
| 102 var actualLocale = (locale == null) ? Intl.getCurrentLocale() : locale; | |
| 103 // For this usage, if the locale doesn't exist for messages, just return | |
| 104 // it and we'll fall back to the original version. | |
| 105 var verifiedLocale = | |
| 106 Intl.verifiedLocale( | |
| 107 actualLocale, | |
| 108 localeExists, | |
| 109 onFailure: (locale)=>locale); | |
| 110 LibraryMirror messagesForThisLocale = | |
| 111 _libraries['$_sourcePrefix$verifiedLocale']; | |
| 112 if (messagesForThisLocale == null) { | |
| 113 return new Future.immediate(message_str); | |
| 114 } | |
| 115 MethodMirror localized = messagesForThisLocale.functions[name]; | |
| 116 if (localized == null) return new Future.immediate(message_str); | |
| 117 result = messagesForThisLocale.invoke(localized.simpleName, args); | |
| 118 } finally { | |
| 119 _lookupInProgress = false; | |
| 120 } | |
| 121 return result.then((value) => value.reflectee); | |
| 122 } | |
| 123 } | |
| OLD | NEW |