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

Side by Side Diff: packages/intl/lib/generate_localized.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 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
« no previous file with comments | « packages/intl/lib/extract_messages.dart ('k') | packages/intl/lib/intl.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 * This provides utilities for generating localized versions of
7 * messages. It does not stand alone, but expects to be given
8 * TranslatedMessage objects and generate code for a particular locale
9 * based on them.
10 *
11 * An example of usage can be found
12 * in test/message_extract/generate_from_json.dart
13 */
14 library generate_localized;
15
16 import 'intl.dart';
17 import 'src/intl_message.dart';
18 import 'dart:io';
19 import 'package:path/path.dart' as path;
20
21 /**
22 * If the import path following package: is something else, modify the
23 * [intlImportPath] variable to change the import directives in the generated
24 * code.
25 */
26 var intlImportPath = 'intl';
27
28 /**
29 * If the path to the generated files is something other than the current
30 * directory, update the [generatedImportPath] variable to change the import
31 * directives in the generated code.
32 */
33 var generatedImportPath = '';
34
35 /**
36 * Given a base file, return the file prefixed with the path to import it.
37 * By default, that is in the current directory, but if [generatedImportPath]
38 * has been set, then use that as a prefix.
39 */
40 String importForGeneratedFile(String file) =>
41 generatedImportPath.isEmpty ? file : "$generatedImportPath/$file";
42
43 /**
44 * A list of all the locales for which we have translations. Code that does
45 * the reading of translations should add to this.
46 */
47 List<String> allLocales = [];
48
49 /**
50 * If we have more than one set of messages to generate in a particular
51 * directory we may want to prefix some to distinguish them.
52 */
53 String generatedFilePrefix = '';
54
55 /**
56 * Should we use deferred loading for the generated libraries.
57 */
58 bool useDeferredLoading = true;
59
60 /**
61 * This represents a message and its translation. We assume that the translation
62 * has some identifier that allows us to figure out the original message it
63 * corresponds to, and that it may want to transform the translated text in
64 * some way, e.g. to turn whatever format the translation uses for variables
65 * into a Dart string interpolation. Specific translation
66 * mechanisms are expected to subclass this.
67 */
68 abstract class TranslatedMessage {
69 /**
70 * The identifier for this message. In the simplest case, this is the name
71 * parameter from the Intl.message call,
72 * but it can be any identifier that this program and the output of the
73 * translation can agree on as identifying a message.
74 */
75 final String id;
76
77 /** Our translated version of all the [originalMessages]. */
78 final Message translated;
79
80 /**
81 * The original messages that we are a translation of. There can
82 * be more than one original message for the same translation.
83 */
84 List<MainMessage> originalMessages;
85
86 /**
87 * For backward compatibility, we still have the originalMessage API.
88 */
89 MainMessage get originalMessage => originalMessages.first;
90 set originalMessage(MainMessage m) => originalMessages = [m];
91
92 TranslatedMessage(this.id, this.translated);
93
94 Message get message => translated;
95
96 toString() => id.toString();
97 }
98
99 /**
100 * We can't use a hyphen in a Dart library name, so convert the locale
101 * separator to an underscore.
102 */
103 String _libraryName(String x) => 'messages_' + x.replaceAll('-', '_');
104
105 /**
106 * Generate a file <[generated_file_prefix]>_messages_<[locale]>.dart
107 * for the [translations] in [locale] and put it in [targetDir].
108 */
109 void generateIndividualMessageFile(String basicLocale,
110 Iterable<TranslatedMessage> translations, String targetDir) {
111 var result = new StringBuffer();
112 var locale = new MainMessage()
113 .escapeAndValidateString(Intl.canonicalizedLocale(basicLocale));
114 result.write(prologue(locale));
115 // Exclude messages with no translation and translations with no matching
116 // original message (e.g. if we're using some messages from a larger catalog)
117 var usableTranslations = translations
118 .where((each) => each.originalMessages != null && each.message != null)
119 .toList();
120 for (var each in usableTranslations) {
121 for (var original in each.originalMessages) {
122 original.addTranslation(locale, each.message);
123 }
124 }
125 usableTranslations.sort((a, b) =>
126 a.originalMessages.first.name.compareTo(b.originalMessages.first.name));
127 for (var translation in usableTranslations) {
128 for (var original in translation.originalMessages) {
129 result
130 ..write(" ")
131 ..write(original.toCodeForLocale(locale))
132 ..write("\n\n");
133 }
134 }
135 result.write("\n final messages = const {\n");
136 var entries = usableTranslations
137 .expand((translation) => translation.originalMessages)
138 .map((original) => original.name)
139 .map((name) => " \"$name\" : $name");
140 result
141 ..write(entries.join(",\n"))
142 ..write("\n };\n}");
143
144 // To preserve compatibility, we don't use the canonical version of the locale
145 // in the file name.
146 var filename =
147 path.join(targetDir, "${generatedFilePrefix}messages_$basicLocale.dart");
148 new File(filename).writeAsStringSync(result.toString());
149 }
150
151 /**
152 * This returns the mostly constant string used in
153 * [generateIndividualMessageFile] for the beginning of the file,
154 * parameterized by [locale].
155 */
156 String prologue(String locale) => """
157 /**
158 * DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
159 * This is a library that provides messages for a $locale locale. All the
160 * messages from the main program should be duplicated here with the same
161 * function name.
162 */
163
164 library ${_libraryName(locale)};
165 import 'package:$intlImportPath/intl.dart';
166 import 'package:$intlImportPath/message_lookup_by_library.dart';
167
168 final messages = new MessageLookup();
169
170 class MessageLookup extends MessageLookupByLibrary {
171
172 get localeName => '$locale';
173 """;
174
175 /**
176 * This section generates the messages_all.dart file based on the list of
177 * [allLocales].
178 */
179 String generateMainImportFile() {
180 var output = new StringBuffer();
181 output.write(mainPrologue);
182 for (var locale in allLocales) {
183 var baseFile = '${generatedFilePrefix}messages_$locale.dart';
184 var file = importForGeneratedFile(baseFile);
185 output.write("import '$file' ");
186 if (useDeferredLoading) output.write("deferred ");
187 output.write("as ${_libraryName(locale)};\n");
188 }
189 output.write("\n");
190 output.write("\nMap<String, Function> _deferredLibraries = {\n");
191 for (var rawLocale in allLocales) {
192 var locale = Intl.canonicalizedLocale(rawLocale);
193 var loadOperation = (useDeferredLoading)
194 ? " '$locale' : () => ${_libraryName(locale)}.loadLibrary(),\n"
195 : " '$locale' : () => new Future.value(null),\n";
196 output.write(loadOperation);
197 }
198 output.write("};\n");
199 output.write("\nMessageLookupByLibrary _findExact(localeName) {\n"
200 " switch (localeName) {\n");
201 for (var rawLocale in allLocales) {
202 var locale = Intl.canonicalizedLocale(rawLocale);
203 output.write(
204 " case '$locale' : return ${_libraryName(locale)}.messages;\n");
205 }
206 output.write(closing);
207 return output.toString();
208 }
209
210 /**
211 * Constant string used in [generateMainImportFile] for the beginning of the
212 * file.
213 */
214 var mainPrologue = """
215 /**
216 * DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
217 * This is a library that looks up messages for specific locales by
218 * delegating to the appropriate library.
219 */
220
221 library messages_all;
222
223 import 'dart:async';
224 import 'package:$intlImportPath/message_lookup_by_library.dart';
225 import 'package:$intlImportPath/src/intl_helpers.dart';
226 import 'package:$intlImportPath/intl.dart';
227
228 """;
229
230 /**
231 * Constant string used in [generateMainImportFile] as the end of the file.
232 */
233 const closing = """
234 default: return null;
235 }
236 }
237
238 /** User programs should call this before using [localeName] for messages.*/
239 Future initializeMessages(String localeName) {
240 initializeInternalMessageLookup(() => new CompositeMessageLookup());
241 var lib = _deferredLibraries[Intl.canonicalizedLocale(localeName)];
242 var load = lib == null ? new Future.value(false) : lib();
243 return load.then((_) =>
244 messageLookup.addLocale(localeName, _findGeneratedMessagesFor));
245 }
246
247 MessageLookupByLibrary _findGeneratedMessagesFor(locale) {
248 var actualLocale = Intl.verifiedLocale(locale, (x) => _findExact(x) != null,
249 onFailure: (_) => null);
250 if (actualLocale == null) return null;
251 return _findExact(actualLocale);
252 }
253 """;
OLDNEW
« no previous file with comments | « packages/intl/lib/extract_messages.dart ('k') | packages/intl/lib/intl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698