OLD | NEW |
1 #!/usr/bin/env dart | 1 #!/usr/bin/env dart |
2 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 /** | 6 /** |
7 * This simulates a translation process, reading the messages generated | 7 * This simulates a translation process, reading the messages generated |
8 * from extract_message.dart for the files sample_with_messages.dart and | 8 * from extract_message.dart for the files sample_with_messages.dart and |
9 * part_of_sample_with_messages.dart and writing out hard-coded translations for | 9 * part_of_sample_with_messages.dart and writing out hard-coded translations for |
10 * German and French locales. | 10 * German and French locales. |
11 */ | 11 */ |
12 | 12 |
13 import 'dart:io'; | 13 import 'dart:io'; |
14 import 'dart:json' as json; | 14 import 'dart:json' as json; |
15 import 'package:pathos/path.dart' as path; | 15 import 'package:pathos/path.dart' as path; |
16 import 'package:args/args.dart'; | 16 import 'package:args/args.dart'; |
| 17 import 'package:intl/src/intl_message.dart'; |
| 18 import 'package:serialization/serialization.dart'; |
| 19 |
| 20 /** |
| 21 * A serialization so that we can write out the more complex plural and |
| 22 * gender examples to JSON easily. This is a stopgap and should be replaced |
| 23 * with a commonly used translation file format. |
| 24 */ |
| 25 get serialization => new Serialization() |
| 26 ..addRuleFor(new VariableSubstitution(0, null), |
| 27 constructorFields: ["index", "parent"]) |
| 28 ..addRuleFor(new LiteralString("a", null), |
| 29 constructorFields: ["string", "parent"]) |
| 30 ..addRuleFor(new CompositeMessage([], null), constructor: "parent", |
| 31 constructorFields: ["parent"]); |
| 32 var format = const SimpleFlatFormat(); |
| 33 get writer => serialization.newWriter(format); |
17 | 34 |
18 /** A list of the French translations that we will produce. */ | 35 /** A list of the French translations that we will produce. */ |
19 var french = { | 36 var french = { |
20 "types" : r"$a, $b, $c", | 37 "types" : r"$a, $b, $c", |
21 "multiLine" : "Cette message prend plusiers lignes.", | 38 "multiLine" : "Cette message prend plusiers lignes.", |
22 "message2" : r"Un autre message avec un seul paramètre $x", | 39 "message2" : r"Un autre message avec un seul paramètre $x", |
23 "alwaysTranslated" : "Cette chaîne est toujours traduit", | 40 "alwaysTranslated" : "Cette chaîne est toujours traduit", |
24 "message1" : "Il s'agit d'un message", | 41 "message1" : "Il s'agit d'un message", |
25 "leadingQuotes" : "\"Soi-disant\"", | 42 "leadingQuotes" : "\"Soi-disant\"", |
26 "trickyInterpolation" : r"L'interpolation est délicate " | 43 "trickyInterpolation" : r"L'interpolation est délicate " |
27 r"quand elle se termine une phrase comme ${s}.", | 44 r"quand elle se termine une phrase comme ${s}.", |
28 "message3" : "Caractères qui doivent être échapper, par exemple barres \\ " | 45 "message3" : "Caractères qui doivent être échapper, par exemple barres \\ " |
29 "dollars \${ (les accolades sont ok), et xml/html réservés <& et " | 46 "dollars \${ (les accolades sont ok), et xml/html réservés <& et " |
30 "des citations \" " | 47 "des citations \" " |
31 "avec quelques paramètres ainsi \$a, \$b, et \$c", | 48 "avec quelques paramètres ainsi \$a, \$b, et \$c", |
32 "method" : "Cela vient d'une méthode", | 49 "method" : "Cela vient d'une méthode", |
33 "nonLambda" : "Cette méthode n'est pas un lambda", | 50 "nonLambda" : "Cette méthode n'est pas un lambda", |
34 "staticMessage" : "Cela vient d'une méthode statique", | 51 "staticMessage" : "Cela vient d'une méthode statique", |
35 "notAlwaysTranslated" : "Ce manque certaines traductions", | 52 "notAlwaysTranslated" : "Ce manque certaines traductions", |
36 "thisNameIsNotInTheOriginal" : "Could this lead to something malicious?", | 53 "thisNameIsNotInTheOriginal" : "Could this lead to something malicious?", |
37 "originalNotInBMP" : "Anciens caractères grecs jeux du pendu: 𐅆𐅇.", | 54 "originalNotInBMP" : "Anciens caractères grecs jeux du pendu: 𐅆𐅇.", |
38 "plural" : """Une des choses difficiles est \${Intl.plural(num, | 55 "escapable" : "Escapes: \n\r\f\b\t\v.", |
39 { | 56 "plurals" : writer.write(new Plural.from("num", |
40 '0' : 'la forme plurielle', | 57 [ |
41 '1' : 'la forme plurielle', | 58 ["zero", "Est-ce que nulle est pluriel?"], |
42 'other' : 'des formes plurielles'})}""", | 59 ["one", "C'est singulier"], |
43 "namedArgs" : "La chose est, \$thing", | 60 ["other", "C'est pluriel (\$num)."] |
44 "escapable" : "Escapes: \n\r\f\b\t\v." | 61 ], null)), |
| 62 // TODO(alanknight): These are pretty horrible to write out manually. Provide |
| 63 // a better way of reading/writing translations. A real format would be good. |
| 64 "whereTheyWent" : writer.write(new Gender.from("gender", |
| 65 [ |
| 66 ["male", [0, " est allé à sa ", 2]], |
| 67 ["female", [0, " est allée à sa ", 2]], |
| 68 ["other", [0, " est allé à sa ", 2]] |
| 69 ], null)), |
| 70 // Gratuitously different translation for testing. Ignoring gender of place. |
| 71 "nestedMessage" : writer.write(new Gender.from("combinedGender", |
| 72 [ |
| 73 ["other", new Plural.from("number", |
| 74 [ |
| 75 ["zero", "Personne n'avait allé à la \$place"], |
| 76 ["one", "\${names} était allé à la \$place"], |
| 77 ["other", "\${names} étaient allés à la \$place"], |
| 78 ], null) |
| 79 ], |
| 80 ["female", new Plural.from("number", |
| 81 [ |
| 82 ["one", "\$names était allée à la \$place"], |
| 83 ["other", "\$names étaient allées à la \$place"], |
| 84 ], null) |
| 85 ] |
| 86 ], null |
| 87 )) |
45 }; | 88 }; |
46 | 89 |
47 /** A list of the German translations that we will produce. */ | 90 /** A list of the German translations that we will produce. */ |
48 var german = { | 91 var german = { |
49 "types" : r"$a, $b, $c", | 92 "types" : r"$a, $b, $c", |
50 "multiLine" : "Dieser String erstreckt sich über mehrere Zeilen erstrecken.", | 93 "multiLine" : "Dieser String erstreckt sich über mehrere Zeilen erstrecken.", |
51 "message2" : r"Eine weitere Meldung mit dem Parameter $x", | 94 "message2" : r"Eine weitere Meldung mit dem Parameter $x", |
52 "alwaysTranslated" : "Diese Zeichenkette wird immer übersetzt", | 95 "alwaysTranslated" : "Diese Zeichenkette wird immer übersetzt", |
53 "message1" : "Dies ist eine Nachricht", | 96 "message1" : "Dies ist eine Nachricht", |
54 "leadingQuotes" : "\"Sogenannt\"", | 97 "leadingQuotes" : "\"Sogenannt\"", |
55 "trickyInterpolation" : | 98 "trickyInterpolation" : |
56 r"Interpolation ist schwierig, wenn es einen Satz wie dieser endet ${s}.", | 99 r"Interpolation ist schwierig, wenn es einen Satz wie dieser endet ${s}.", |
57 "message3" : "Zeichen, die Flucht benötigen, zB Schrägstriche \\ Dollar " | 100 "message3" : "Zeichen, die Flucht benötigen, zB Schrägstriche \\ Dollar " |
58 "\${ (geschweiften Klammern sind ok) und xml reservierte Zeichen <& und " | 101 "\${ (geschweiften Klammern sind ok) und xml reservierte Zeichen <& und " |
59 "Zitate \" Parameter \$a, \$b und \$c", | 102 "Zitate \" Parameter \$a, \$b und \$c", |
60 "method" : "Dies ergibt sich aus einer Methode", | 103 "method" : "Dies ergibt sich aus einer Methode", |
61 "nonLambda" : "Diese Methode ist nicht eine Lambda", | 104 "nonLambda" : "Diese Methode ist nicht eine Lambda", |
62 "staticMessage" : "Dies ergibt sich aus einer statischen Methode", | 105 "staticMessage" : "Dies ergibt sich aus einer statischen Methode", |
63 "originalNotInBMP" : "Antike griechische Galgenmännchen Zeichen: 𐅆𐅇", | 106 "originalNotInBMP" : "Antike griechische Galgenmännchen Zeichen: 𐅆𐅇", |
64 "plurals" : """\${Intl.plural(num, | 107 "escapable" : "Escapes: \n\r\f\b\t\v.", |
65 { | 108 "plurals" : writer.write(new Plural.from("num", |
66 '0' : 'Einer der knifflige Dinge ist der Plural', | 109 [ |
67 '1' : 'Einer der knifflige Dinge ist der Plural', | 110 ["zero", "Ist Null Plural?"], |
68 'other' : 'Zu den kniffligen Dinge Pluralformen' | 111 ["one", "Dies ist einmalig"], |
69 })}""", | 112 ["other", "Dies ist Plural (\$num)."] |
70 "namedArgs" : "Die Sache ist, \$thing", | 113 ], null)), |
71 "escapable" : "Escapes: \n\r\f\b\t\v." | 114 // TODO(alanknight): These are pretty horrible to write out manually. Provide |
| 115 // a better way of reading/writing translations. A real format would be good. |
| 116 "whereTheyWent" : writer.write(new Gender.from("gender", |
| 117 [ |
| 118 ["male", [0, " ging zu seinem ", 2]], |
| 119 ["female", [0, " ging zu ihrem ", 2]], |
| 120 ["other", [0, " ging zu seinem ", 2]] |
| 121 ], null)), |
| 122 //Note that we're only using the gender of the people. The gender of the |
| 123 //place also matters, but we're not dealing with that here. |
| 124 "nestedMessage" : writer.write(new Gender.from("combinedGender", |
| 125 [ |
| 126 ["other", new Plural.from("number", |
| 127 [ |
| 128 ["zero", "Niemand ging zu \$place"], |
| 129 ["one", "\${names} ging zum \$place"], |
| 130 ["other", "\${names} gingen zum \$place"], |
| 131 ], null) |
| 132 ], |
| 133 ["female", new Plural.from("number", |
| 134 [ |
| 135 ["one", "\$names ging in dem \$place"], |
| 136 ["other", "\$names gingen zum \$place"], |
| 137 ], null) |
| 138 ] |
| 139 ], null |
| 140 )) |
72 }; | 141 }; |
73 | 142 |
74 /** The output directory for translated files. */ | 143 /** The output directory for translated files. */ |
75 String targetDir; | 144 String targetDir; |
76 | 145 |
77 /** | 146 /** |
78 * Generate a translated json version from [originals] in [locale] looking | 147 * Generate a translated json version from [originals] in [locale] looking |
79 * up the translations in [translations]. | 148 * up the translations in [translations]. |
80 */ | 149 */ |
81 void translate(List originals, String locale, Map translations) { | 150 void translate(List originals, String locale, Map translations) { |
82 var translated = {"_locale" : locale}; | 151 var translated = {"_locale" : locale}; |
83 for (var each in originals) { | 152 for (var each in originals) { |
84 var name = each["name"]; | 153 var name = each["name"]; |
85 translated[name] = translations[name]; | 154 translated[name] = translations[name]; |
86 } | 155 } |
87 var file = new File(path.join(targetDir, 'translation_$locale.json')); | 156 var file = new File(path.join(targetDir, 'translation_$locale.json')); |
88 file.writeAsStringSync(json.stringify(translated)); | 157 file.writeAsStringSync(json.stringify(translated)); |
89 } | 158 } |
90 | 159 |
91 main() { | 160 main() { |
92 var args = new Options().arguments; | 161 var args = new Options().arguments; |
93 if (args.length == 0) { | 162 if (args.length == 0) { |
94 print('Usage: generate_hardcoded_translation [--output-dir=<dir>] ' | 163 print('Usage: generate_hardcoded_translation [--output-dir=<dir>] ' |
95 '[originalFile.dart]'); | 164 '[originalFile.json]'); |
96 exit(0); | 165 exit(0); |
97 } | 166 } |
98 var parser = new ArgParser(); | 167 var parser = new ArgParser(); |
99 parser.addOption("output-dir", defaultsTo: '.', | 168 parser.addOption("output-dir", defaultsTo: '.', |
100 callback: (value) => targetDir = value); | 169 callback: (value) => targetDir = value); |
101 parser.parse(args); | 170 parser.parse(args); |
102 | 171 |
103 var fileArgs = args.where((x) => x.contains('.json')); | 172 var fileArgs = args.where((x) => x.contains('.json')); |
104 | 173 |
105 var messages = json.parse(new File(fileArgs.first).readAsStringSync()); | 174 var messages = json.parse(new File(fileArgs.first).readAsStringSync()); |
106 translate(messages, "fr", french); | 175 translate(messages, "fr", french); |
107 translate(messages, "de_DE", german); | 176 translate(messages, "de_DE", german); |
108 } | 177 } |
OLD | NEW |