| 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 * Message/plural format library with locale support. | 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. |
| 7 * | 11 * |
| 8 * | 12 * |
| 9 * _message example: | 13 * _message example: |
| 10 * '''I see ${Intl.plural(num_people, | 14 * '''I see ${Intl.plural(num_people, |
| 11 * {'0': 'no one at all', | 15 * {'0': 'no one at all', |
| 12 * '1': 'one other person', | 16 * '1': 'one other person', |
| 13 * 'other': '$num_people other people'})} in $place.'''' | 17 * 'other': '$num_people other people'})} in $place.'''' |
| 14 * | 18 * |
| 15 * Usage examples: | 19 * Usage examples: |
| 16 * today(date) => intl.message( | 20 * today(date) => intl.message( |
| (...skipping 10 matching lines...) Expand all Loading... |
| 27 * desc: 'Description of how many people are seen as program start.', | 31 * desc: 'Description of how many people are seen as program start.', |
| 28 * examples: {'num_people': 3, 'place': 'London'}); | 32 * examples: {'num_people': 3, 'place': 'London'}); |
| 29 * | 33 * |
| 30 * Calling `msg({'num_people': 2, 'place': 'Athens'});` would | 34 * Calling `msg({'num_people': 2, 'place': 'Athens'});` would |
| 31 * produce "I see 2 other people in Athens." as output. | 35 * produce "I see 2 other people in Athens." as output. |
| 32 * | 36 * |
| 33 * See tests/message_format_test.dart for more examples. | 37 * See tests/message_format_test.dart for more examples. |
| 34 */ | 38 */ |
| 35 //TODO(efortuna): documentation example involving the offset parameter? | 39 //TODO(efortuna): documentation example involving the offset parameter? |
| 36 | 40 |
| 37 class IntlMessage { | 41 #library('message_lookup_local'); |
| 38 | 42 |
| 39 /** String describing the use case for this message. */ | 43 #import('intl.dart'); |
| 40 String _messageDescription; | 44 #import('dart:mirrors'); |
| 45 |
| 46 /** |
| 47 * Initialize the user messages for [localeName]. Note that this is an ASYNC |
| 48 * operation. This must be called before attempting to use messages in |
| 49 * [localeName]. |
| 50 */ |
| 51 Future initializeMessages(localeName, [String source = 'messages_']) { |
| 52 initializeInternalMessageLookup( |
| 53 () => new MessageLookupLocal(localeName, source)); |
| 54 _initializeMessagesForLocale(localeName); |
| 55 return new Future.immediate(null); |
| 56 } |
| 57 |
| 58 void _initializeMessagesForLocale(String localeName) {} |
| 59 |
| 60 class MessageLookupLocal { |
| 61 /** Prevent infinite recursion when looking up the message. */ |
| 62 bool _lookupInProgress = false; |
| 63 |
| 64 /** The libraries we can look in for internationalization messages. */ |
| 65 Map<String, LibraryMirror> _libraries; |
| 66 |
| 67 /** The prefix used to find libraries that contain localized messages. |
| 68 * So, if this is 'messages_' we would look for messages for the locale |
| 69 * 'pt_BR' in a library named 'messages_pt_BR'. |
| 70 */ |
| 71 String _sourcePrefix; |
| 41 | 72 |
| 42 /** | 73 /** |
| 43 * String that contains the message to be displayed. It may contain | 74 * Constructor. The [localeName] is of the form 'en' or 'en_US'. |
| 44 * placeholders in the form of string interpolated items (ie 'hello$foo') that | 75 *The [source] parameter defines the prefix that is used to find |
| 45 * will be substituted in to complete the message. | 76 * libraries that contain localized messages. So with the default value of |
| 46 * See tests/message_format_test.dart for more examples. | 77 * 'messages_', we would look for messages for the locale 'pt_BR' in a library |
| 78 * named 'messages_pt_BR'. |
| 47 */ | 79 */ |
| 48 String _message; | 80 MessageLookupLocal(String localeName, this._sourcePrefix) { |
| 81 _libraries = currentMirrorSystem().libraries; |
| 82 } |
| 49 | 83 |
| 50 /** | 84 /** |
| 51 * String indicating the locale code with which the message is to be | 85 * Return the localized version of a message. We are passed the original |
| 52 * formatted (such as en-CA). | 86 * version of the message, which consists of a |
| 87 * [message_str] that will be translated, and which may be interpolated |
| 88 * based on one or more variables, a [desc] providing a description of usage |
| 89 * for the [message_str], and a map of [examples] for each data element to be |
| 90 * substituted into the message. |
| 91 * |
| 92 * For example, if message="Hello, $name", then |
| 93 * examples = {'name': 'Sparky'}. If not using the user's default locale, or |
| 94 * if the locale is not easily detectable, explicitly pass [locale]. |
| 95 * |
| 96 * The values of [desc] and [examples] are not used at run-time but are only |
| 97 * made available to the translators, so they MUST be simple Strings available |
| 98 * at compile time: no String interpolation or concatenation. |
| 99 * The expected usage of this is inside a function that takes as parameters |
| 100 * the variables used in the interpolated string. |
| 101 * |
| 102 * Ultimately, the information about the enclosing function and its arguments |
| 103 * will be extracted automatically but for the time being it must be passed |
| 104 * explicitly in the [name] and [args] arguments. |
| 53 */ | 105 */ |
| 54 String _languageCode; | 106 String lookupMessage(String message_str, [final String desc='', |
| 55 | 107 final Map examples=const {}, String locale, |
| 56 /** Examples of the placeholders used in the message string. */ | 108 String name, List<String> args]) { |
| 57 Map _messageExamples; | 109 if (name == null) return message_str; |
| 58 | 110 // The translations also make use of Intl.message, so we need to not |
| 59 /** | 111 // recurse and just stop when we find the first substitution. |
| 60 * Accepts a String [_message] that contains the message (that | 112 if (_lookupInProgress) return message_str; |
| 61 * will be internationalized). A String [_messageDescription] describes the | 113 _lookupInProgress = true; |
| 62 * use case for this string in the program, and [examples] provides a map of | 114 var result; |
| 63 * examples for the items (if any) to be subsituted into [_message]. | 115 try { |
| 64 * It also optionally accepts a [_languageCode] to specify the particular | 116 // TODO(alanknight): Look up alternate forms, e.g. en for en_US |
| 65 * language to return content in (necessary if the Dart code is not running in | 117 var actualLocale = (locale == null) ? Intl.getCurrentLocale() : locale; |
| 66 * a browser). The values of [desc] and [examples] *must* be | 118 LibraryMirror messagesForThisLocale = |
| 67 * simple Strings available at compile time: no String interpolation or | 119 _libraries['$_sourcePrefix$actualLocale']; |
| 68 * concatenation. | 120 if (messagesForThisLocale == null) return message_str; |
| 69 */ | 121 MethodMirror localized = messagesForThisLocale.functions[name]; |
| 70 IntlMessage(this._message, [final String desc='', final Map examples=const {}, | 122 if (localized == null) return message_str; |
| 71 final String locale='']) { | 123 result = messagesForThisLocale.invoke(localized.simpleName, args); |
| 72 this._messageDescription = desc; | 124 } |
| 73 this._messageExamples = examples; | 125 finally { |
| 74 this._languageCode = locale; | 126 _lookupInProgress = false; |
| 127 } |
| 128 return result.value.reflectee; |
| 75 } | 129 } |
| 76 } | 130 } |
| OLD | NEW |