Skip to content
This repository was archived by the owner on Jul 13, 2023. It is now read-only.

Commit f09b5d8

Browse files
committed
Move message extraction, code generation, and transformer into a separate package from intl
1 parent cc8e8b0 commit f09b5d8

38 files changed

+3513
-1
lines changed

AUTHORS

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Names should be added to this file with this pattern:
2+
#
3+
# For individuals:
4+
# Name <email address>
5+
#
6+
# For organizations:
7+
# Organization <fnmatch pattern>
8+
#
9+
Google Inc. <*@google.com>

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.14.0
2+
* Split message extraction and code generation out into a separate
3+
package. Versioned to match the corresponding Intl version.

LICENSE

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright 2013, the Dart project authors. All rights reserved.
2+
Redistribution and use in source and binary forms, with or without
3+
modification, are permitted provided that the following conditions are
4+
met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

PATENTS

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Additional IP Rights Grant (Patents)
2+
3+
"This implementation" means the copyrightable works distributed by
4+
Google as part of the Dart Project.
5+
6+
Google hereby grants to you a perpetual, worldwide, non-exclusive,
7+
no-charge, royalty-free, irrevocable (except as stated in this
8+
section) patent license to make, have made, use, offer to sell, sell,
9+
import, transfer, and otherwise run, modify and propagate the contents
10+
of this implementation of Dart, where such license applies only to
11+
those patent claims, both currently owned by Google and acquired in
12+
the future, licensable by Google that are necessarily infringed by
13+
this implementation of Dart. This grant does not include claims that
14+
would be infringed only as a consequence of further modification of
15+
this implementation. If you or your agent or exclusive licensee
16+
institute or order or agree to the institution of patent litigation
17+
against any entity (including a cross-claim or counterclaim in a
18+
lawsuit) alleging that this implementation of Dart or any code
19+
incorporated within this implementation of Dart constitutes direct or
20+
contributory patent infringement, or inducement of patent
21+
infringement, then any patent rights granted to you under this License
22+
for this implementation of Dart shall terminate as of the date such
23+
litigation is filed.

README.md

+51-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,51 @@
1-
Initial commit placeholder.
1+
Intl_translation
2+
====
3+
4+
This package provides message extraction and code generation from translated
5+
messages for the [Intl][Intl] package. It's a separate package so as to not
6+
require a dependency on analyzer for all users.
7+
8+
## Extracting And Using Translated Messages
9+
10+
When your program contains messages that need translation, these must
11+
be extracted from the program source, sent to human translators, and the
12+
results need to be incorporated.
13+
14+
To extract messages, run the `extract_to_arb.dart` program.
15+
16+
pub run intl_translation:extract_to_arb --output-dir=target/directory
17+
my_program.dart more_of_my_program.dart
18+
19+
This will produce a file `intl_messages.arb` with the messages from
20+
all of these programs. an [ARB]
21+
(https://code.google.com/p/arb/wiki/ApplicationResourceBundleSpecification)
22+
format file which can be used for input to translation tools like
23+
[Google Translator Toolkit](https://translate.google.com/toolkit/)
24+
The resulting translations can be used to generate a set of libraries
25+
using the `generate_from_arb.dart` program.
26+
27+
This expects to receive a series of files, one per
28+
locale.
29+
30+
```
31+
pub run intl_translation:generate_from_arb --generated_file_prefix=<prefix>
32+
<my_dart_files> <translated_ARB_files>
33+
```
34+
35+
This will generate Dart libraries, one per locale, which contain the
36+
translated versions. Your Dart libraries can import the primary file,
37+
named `<prefix>messages_all.dart`, and then call the initialization
38+
for a specific locale. Once that's done, any
39+
[Intl.message][Intl.message] calls made in the context of that locale
40+
will automatically print the translated version instead of the
41+
original.
42+
43+
import "my_prefix_messages_all.dart";
44+
...
45+
initializeMessages("dk").then(printSomeMessages);
46+
47+
Once the future returned from the initialization call returns, the
48+
message data is available.
49+
50+
[Intl]: https://www.dartdocs.org/documentation/intl/latest
51+
[Intl.message]: https://www.dartdocs.org/documentation/intl/latest/intl/Intl/message.html

bin/extract_to_arb.dart

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env dart
2+
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
5+
6+
/// This script uses the extract_messages.dart library to find the Intl.message
7+
/// calls in the target dart files and produces ARB format output. See
8+
/// https://code.google.com/p/arb/wiki/ApplicationResourceBundleSpecification
9+
library extract_to_arb;
10+
11+
import 'dart:convert';
12+
import 'dart:io';
13+
14+
import 'package:args/args.dart';
15+
import 'package:path/path.dart' as path;
16+
17+
import 'package:intl_translation/extract_messages.dart';
18+
import 'package:intl_translation/src/intl_message.dart';
19+
20+
var outputFilename = 'intl_messages.arb';
21+
22+
main(List<String> args) {
23+
var targetDir;
24+
bool transformer;
25+
var parser = new ArgParser();
26+
var extraction = new MessageExtraction();
27+
parser.addFlag("suppress-warnings",
28+
defaultsTo: false,
29+
callback: (x) => extraction.suppressWarnings = x,
30+
help: 'Suppress printing of warnings.');
31+
parser.addFlag("warnings-are-errors",
32+
defaultsTo: false,
33+
callback: (x) => extraction.warningsAreErrors = x,
34+
help: 'Treat all warnings as errors, stop processing ');
35+
parser.addFlag("embedded-plurals",
36+
defaultsTo: true,
37+
callback: (x) => extraction.allowEmbeddedPluralsAndGenders = x,
38+
help: 'Allow plurals and genders to be embedded as part of a larger '
39+
'string, otherwise they must be at the top level.');
40+
parser.addFlag("transformer",
41+
defaultsTo: false,
42+
callback: (x) => transformer = x,
43+
help: "Assume that the transformer is in use, so name and args "
44+
"don't need to be specified for messages.");
45+
46+
parser.addOption("output-dir",
47+
defaultsTo: '.',
48+
callback: (value) => targetDir = value,
49+
help: 'Specify the output directory.');
50+
parser.parse(args);
51+
if (args.length == 0) {
52+
print('Accepts Dart files and produces $outputFilename');
53+
print('Usage: extract_to_arb [options] [files.dart]');
54+
print(parser.usage);
55+
exit(0);
56+
}
57+
var allMessages = {};
58+
for (var arg in args.where((x) => x.contains(".dart"))) {
59+
var messages = extraction.parseFile(new File(arg), transformer);
60+
messages.forEach((k, v) => allMessages.addAll(toARB(v)));
61+
}
62+
var file = new File(path.join(targetDir, outputFilename));
63+
file.writeAsStringSync(JSON.encode(allMessages));
64+
if (extraction.hasWarnings && extraction.warningsAreErrors) {
65+
exit(1);
66+
}
67+
}
68+
69+
/// This is a placeholder for transforming a parameter substitution from
70+
/// the translation file format into a Dart interpolation. In our case we
71+
/// store it to the file in Dart interpolation syntax, so the transformation
72+
/// is trivial.
73+
String leaveTheInterpolationsInDartForm(MainMessage msg, chunk) {
74+
if (chunk is String) return chunk;
75+
if (chunk is int) return "\$${msg.arguments[chunk]}";
76+
return chunk.toCode();
77+
}
78+
79+
/// Convert the [MainMessage] to a trivial JSON format.
80+
Map toARB(MainMessage message) {
81+
if (message.messagePieces.isEmpty) return null;
82+
var out = {};
83+
out[message.name] = icuForm(message);
84+
out["@${message.name}"] = arbMetadata(message);
85+
return out;
86+
}
87+
88+
Map arbMetadata(MainMessage message) {
89+
var out = {};
90+
var desc = message.description;
91+
if (desc != null) {
92+
out["description"] = desc;
93+
}
94+
out["type"] = "text";
95+
var placeholders = {};
96+
for (var arg in message.arguments) {
97+
addArgumentFor(message, arg, placeholders);
98+
}
99+
out["placeholders"] = placeholders;
100+
return out;
101+
}
102+
103+
void addArgumentFor(MainMessage message, String arg, Map result) {
104+
var extraInfo = {};
105+
if (message.examples != null && message.examples[arg] != null) {
106+
extraInfo["example"] = message.examples[arg];
107+
}
108+
result[arg] = extraInfo;
109+
}
110+
111+
/// Return a version of the message string with with ICU parameters "{variable}"
112+
/// rather than Dart interpolations "$variable".
113+
String icuForm(MainMessage message) =>
114+
message.expanded(turnInterpolationIntoICUForm);
115+
116+
String turnInterpolationIntoICUForm(Message message, chunk,
117+
{bool shouldEscapeICU: false}) {
118+
if (chunk is String) {
119+
return shouldEscapeICU ? escape(chunk) : chunk;
120+
}
121+
if (chunk is int && chunk >= 0 && chunk < message.arguments.length) {
122+
return "{${message.arguments[chunk]}}";
123+
}
124+
if (chunk is SubMessage) {
125+
return chunk.expanded((message, chunk) =>
126+
turnInterpolationIntoICUForm(message, chunk, shouldEscapeICU: true));
127+
}
128+
if (chunk is Message) {
129+
return chunk.expanded((message, chunk) => turnInterpolationIntoICUForm(
130+
message, chunk,
131+
shouldEscapeICU: shouldEscapeICU));
132+
}
133+
throw new FormatException("Illegal interpolation: $chunk");
134+
}
135+
136+
String escape(String s) {
137+
return s.replaceAll("'", "''").replaceAll("{", "'{'").replaceAll("}", "'}'");
138+
}

0 commit comments

Comments
 (0)