X Tutup
Skip to content

Commit 8326ab3

Browse files
vsavkinjelbourn
authored andcommitted
feat(i18n): add a simple dart script extracting all i18n messages from a package
Closes #7620
1 parent a7fe983 commit 8326ab3

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed

modules/angular2/pubspec.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ dependencies:
2020
protobuf: '^0.5.0'
2121
source_span: '^1.0.0'
2222
stack_trace: '^1.1.1'
23-
build:
24-
git: git@github.com:dart-lang/build.git
23+
build: '>=0.0.1'
2524
dev_dependencies:
2625
transformer_test: '^0.2.0'
2726
guinness: '^0.1.18'

modules/benchmarks_external/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: benchmarks_external
22
environment:
33
sdk: '>=1.4.0'
44
dependencies:
5-
angular: '>=1.0.0 <2.0.0'
5+
angular: '>=1.1.2+2 <2.0.0'
66
browser: '>=0.10.0 <0.11.0'
77
dev_dependencies:
88
angular2:
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import 'package:build/build.dart';
2+
import 'package:analyzer/src/generated/element.dart';
3+
import 'src/transform/common/url_resolver.dart';
4+
import 'dart:async';
5+
import 'package:angular2/i18n.dart';
6+
import 'package:angular2/src/core/change_detection/parser/parser.dart';
7+
import 'package:angular2/src/core/change_detection/parser/lexer.dart';
8+
import 'package:angular2/src/core/reflection/reflector.dart';
9+
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
10+
import 'package:angular2/src/compiler/html_parser.dart';
11+
12+
/**
13+
* An command-line utility extracting i18n messages from an application.
14+
*
15+
* For instance, the following command will extract all the messages from the 'my-app-package' package, where
16+
* index.dart is the entry point, and will serialize them into i18n-messages.xml.
17+
*
18+
* pub run packages/angular2/extract_messages.dart 'my-app-package' 'web/src/index.dart' 'i18n-messages.xml'
19+
*/
20+
main(List<String> args) async {
21+
final input = new InputSet(args[0], [args[1]]);
22+
final output = new AssetId(args[0], args[2]);
23+
24+
await build(new PhaseGroup.singleAction(new I18nMessageExtractorBuilder(output), input));
25+
}
26+
27+
class I18nMessageExtractorBuilder implements Builder {
28+
final AssetId outputAssetId;
29+
30+
I18nMessageExtractorBuilder(this.outputAssetId);
31+
32+
Future build(BuildStep buildStep) async {
33+
final resolver = await buildStep.resolve(buildStep.input.id);
34+
final entryLib = resolver.getLibrary(buildStep.input.id);
35+
36+
final extractor = new I18nMessageExtractor((path) => buildStep.readAsString(path));
37+
await extractor.processLibrary(entryLib);
38+
resolver.release();
39+
40+
if (extractor.errors.length > 0) {
41+
print("Errors:");
42+
extractor.errors.forEach(print);
43+
throw "Failed to extract messages";
44+
45+
} else {
46+
await buildStep.writeAsString(new Asset(outputAssetId, extractor.output));
47+
}
48+
}
49+
50+
List<AssetId> declareOutputs(AssetId inputId) => [outputAssetId];
51+
}
52+
53+
class I18nMessageExtractor {
54+
final TransformerUrlResolver urlResovler = new TransformerUrlResolver();
55+
final List<Message> messages = [];
56+
final List errors = [];
57+
final HtmlParser htmlParser = new HtmlParser();
58+
final Parser parser = new Parser(new Lexer(), new Reflector(new ReflectionCapabilities()));
59+
60+
final Function readInput;
61+
62+
I18nMessageExtractor(this.readInput);
63+
64+
String get output => serialize(removeDuplicates(messages));
65+
66+
Future processLibrary(LibraryElement el) async {
67+
return Future.wait(el.units.map(processCompilationUnit));
68+
}
69+
70+
Future processCompilationUnit(CompilationUnitElement el) async {
71+
return Future.wait(el.types.map(processClass));
72+
}
73+
74+
Future processClass(ClassElement el) async {
75+
final baseUrl = (el.source as dynamic).assetId;
76+
final filtered = el.metadata.where((m) {
77+
if (m.element is ConstructorElement) {
78+
final isComponent = m.element.enclosingElement.name == "Component" &&
79+
m.element.library.displayName == "angular2.src.core.metadata";
80+
81+
final isView = m.element.enclosingElement.name == "View" &&
82+
m.element.library.displayName == "angular2.src.core.metadata";
83+
84+
return isComponent || isView;
85+
} else {
86+
return false;
87+
}
88+
});
89+
90+
return Future.wait(filtered.map((m) => processAnnotation(el, m, baseUrl)));
91+
}
92+
93+
Future processAnnotation(ClassElement el, ElementAnnotation m, baseUrl) async {
94+
final fields = (m.constantValue as dynamic).fields["(super)"].fields;
95+
final template = fields["template"];
96+
final templateUrl = fields["templateUrl"];
97+
98+
if (template != null && !template.isNull) {
99+
processTemplate(template.toStringValue(), baseUrl.toString());
100+
}
101+
102+
if (templateUrl != null && !templateUrl.isNull) {
103+
final value = templateUrl.toStringValue();
104+
final resolvedPath = urlResovler.resolve(toAssetUri(baseUrl), value);
105+
final template = await readInput(fromUri(resolvedPath));
106+
processTemplate(template.toStringValue(), baseUrl.toString());
107+
}
108+
}
109+
110+
void processTemplate(String template, String sourceUrl) {
111+
final m = new MessageExtractor(htmlParser, parser);
112+
final res = m.extract(template, sourceUrl);
113+
if (res.errors.isNotEmpty) {
114+
errors.addAll(res.errors);
115+
} else {
116+
messages.addAll(res.messages);
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)
X Tutup