Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1795)

Side by Side Diff: pkg/intl/lib/message_lookup_by_library.dart

Issue 12733003: Adds facilities for extracting Intl.message calls and generating code from translations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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. This can have different 6 * Message/plural format library with locale support. This can have different
7 * implementations based on the mechanism for finding the localized versions 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. 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 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. 10 * must be made for a locale before any lookups can be done.
11 * 11 *
12 * See Intl class comment or `tests/message_format_test.dart` for more examples. 12 * See Intl class comment or `tests/message_format_test.dart` for more examples.
13 */ 13 */
14 //TODO(efortuna): documentation example involving the offset parameter? 14 library message_lookup_by_library;
15
16 library message_lookup_local;
17 15
18 import 'dart:async'; 16 import 'dart:async';
19 import 'intl.dart'; 17 import 'intl.dart';
20 import 'src/intl_helpers.dart'; 18 import 'src/intl_helpers.dart';
21 import 'dart:mirrors'; 19
20 class CompositeMessageLookup {
Emily Fortuna 2013/03/13 18:54:43 some documentation explaining this class, please?
Alan Knight 2013/03/14 17:49:05 Done.
21 Map<String,MessageLookupByLibrary> availableMessages = new Map();
22
23 bool localeExists(localeName) => availableMessages.containsKey(localeName);
24
25 lookupMessage(String message_str, [final String desc='',
26 final Map examples=const {}, String locale,
27 String name, List<String> args]) {
28 var actualLocale = (locale == null) ? Intl.getCurrentLocale() : locale;
29 // For this usage, if the locale doesn't exist for messages, just return
Emily Fortuna 2013/03/13 18:54:43 random indentation?
Alan Knight 2013/03/14 17:49:05 Not random, I put each argument to the function on
Emily Fortuna 2013/03/14 19:45:00 No, that's totally fine. I was complaining that li
Alan Knight 2013/03/14 20:50:04 Doh! Done.
30 // it and we'll fall back to the original version.
31 var verifiedLocale =
32 Intl.verifiedLocale(
33 actualLocale,
34 localeExists,
35 onFailure: (locale)=>locale);
36 var messages = availableMessages[verifiedLocale];
37 if (messages == null) return message_str;
38 return messages.
39 lookupMessage(message_str, desc, examples, locale, name, args);
40 }
41
42 addLocale(String localeName, Function findLocale) {
43 if (localeExists(localeName)) return;
44 var newLocale = findLocale(localeName);
45 if (newLocale != null) {
46 availableMessages[localeName] = newLocale;
47 }
48 }
49 }
22 50
23 /** 51 /**
24 * Initialize the user messages for [localeName]. Note that this is an ASYNC 52 * This provides an abstract class for messages looked up in generated code.
25 * operation. This must be called before attempting to use messages in 53 * Each locale will have a separate subclass of this class with its set of
26 * [localeName]. 54 * messages. See generate_localized.dart.
27 */ 55 */
28 Future initializeMessages(localeName, [String source = 'messages_']) { 56 abstract class MessageLookupByLibrary {
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. */ 57 /** Prevent infinite recursion when looking up the message. */
39 bool _lookupInProgress = false; 58 bool _lookupInProgress = false;
40 59
41 /** The libraries we can look in for internationalization messages. */ 60 /**
42 Map<String, LibraryMirror> _libraries; 61 * Return true if the locale exists, or if it is null. Null is treated
43 62 * as meaning that we use the default locale.
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 */ 63 */
48 String _sourcePrefix; 64 bool localeExists(localeName);
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 65
70 /** 66 /**
71 * Return the localized version of a message. We are passed the original 67 * Return the localized version of a message. We are passed the original
72 * version of the message, which consists of a 68 * version of the message, which consists of a
73 * [message_str] that will be translated, and which may be interpolated 69 * [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 70 * 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 71 * for the [message_str], and a map of [examples] for each data element to be
76 * substituted into the message. 72 * substituted into the message.
77 * 73 *
78 * For example, if message="Hello, $name", then 74 * For example, if message="Hello, $name", then
79 * examples = {'name': 'Sparky'}. If not using the user's default locale, or 75 * examples = {'name': 'Sparky'}. If not using the user's default locale, or
80 * if the locale is not easily detectable, explicitly pass [locale]. 76 * if the locale is not easily detectable, explicitly pass [locale].
81 * 77 *
82 * The values of [desc] and [examples] are not used at run-time but are only 78 * 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 79 * made available to the translators, so they MUST be simple Strings available
84 * at compile time: no String interpolation or concatenation. 80 * at compile time: no String interpolation or concatenation.
85 * The expected usage of this is inside a function that takes as parameters 81 * The expected usage of this is inside a function that takes as parameters
86 * the variables used in the interpolated string. 82 * the variables used in the interpolated string.
87 * 83 *
88 * Ultimately, the information about the enclosing function and its arguments 84 * Ultimately, the information about the enclosing function and its arguments
89 * will be extracted automatically but for the time being it must be passed 85 * will be extracted automatically but for the time being it must be passed
90 * explicitly in the [name] and [args] arguments. 86 * explicitly in the [name] and [args] arguments.
91 */ 87 */
92 Future<String> lookupMessage(String message_str, [final String desc='', 88 lookupMessage(String message_str, [final String desc='',
Emily Fortuna 2013/03/13 18:54:43 list return type? String?
Alan Knight 2013/03/14 17:49:05 Done.
93 final Map examples=const {}, String locale, 89 final Map examples=const {}, String locale,
94 String name, List<String> args]) { 90 String name, List<String> args]) {
95 if (name == null) return new Future.immediate(message_str); 91 if (name == null) return message_str;
96 // The translations also make use of Intl.message, so we need to not 92 // The translations also make use of Intl.message, so we need to not
97 // recurse and just stop when we find the first substitution. 93 // recurse and just stop when we find the first substitution.
98 if (_lookupInProgress) return new Future.immediate(message_str); 94 if (_lookupInProgress) return message_str;
Emily Fortuna 2013/03/13 18:54:43 can we combine this branch with line 91, so we hav
Alan Knight 2013/03/14 17:49:05 Done.
99 _lookupInProgress = true; 95 _lookupInProgress = true;
100 var result; 96 var result;
101 try { 97 try {
102 var actualLocale = (locale == null) ? Intl.getCurrentLocale() : locale; 98 var function = this[name];
103 // For this usage, if the locale doesn't exist for messages, just return 99 if (function == null) return message_str;
Emily Fortuna 2013/03/13 18:54:43 suggestion: instead of eagerly returning here, run
Alan Knight 2013/03/14 17:49:05 Re-organized a bit more than even that so now ther
104 // it and we'll fall back to the original version. 100 result = Function.apply(function, args);
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 { 101 } finally {
119 _lookupInProgress = false; 102 _lookupInProgress = false;
120 } 103 }
121 return result.then((value) => value.reflectee); 104 return result == null ? message_str : result;
122 } 105 }
123 } 106
107 operator [](x) => messages[x];
108
109 get messages;
Emily Fortuna 2013/03/13 18:54:43 don't these need implementation? Return types? doc
Alan Knight 2013/03/14 17:49:05 They are to be implemented by the generated subcla
Emily Fortuna 2013/03/14 19:45:00 sgtm.
110
111 get localeName;
112
113 toString() => localeName;
114 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698