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