| 
									
										
										
										
											2016-03-16 11:58:43 -07:00
										 |  |  | import 'package:build/build.dart'; | 
					
						
							|  |  |  | import 'package:analyzer/src/generated/element.dart'; | 
					
						
							|  |  |  | import 'src/transform/common/url_resolver.dart'; | 
					
						
							|  |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'package:angular2/i18n.dart'; | 
					
						
							|  |  |  | import 'package:angular2/src/core/change_detection/parser/parser.dart'; | 
					
						
							|  |  |  | import 'package:angular2/src/core/change_detection/parser/lexer.dart'; | 
					
						
							|  |  |  | import 'package:angular2/src/core/reflection/reflector.dart'; | 
					
						
							|  |  |  | import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; | 
					
						
							|  |  |  | import 'package:angular2/src/compiler/html_parser.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * An command-line utility extracting i18n messages from an application. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For instance, the following command will extract all the messages from the 'my-app-package' package, where | 
					
						
							|  |  |  |  * index.dart is the entry point, and will serialize them into i18n-messages.xml. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * pub run packages/angular2/extract_messages.dart 'my-app-package' 'web/src/index.dart' 'i18n-messages.xml' | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | main(List<String> args) async { | 
					
						
							|  |  |  |   final input = new InputSet(args[0], [args[1]]); | 
					
						
							|  |  |  |   final output = new AssetId(args[0], args[2]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await build(new PhaseGroup.singleAction(new I18nMessageExtractorBuilder(output), input)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class I18nMessageExtractorBuilder implements Builder { | 
					
						
							|  |  |  |   final AssetId outputAssetId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   I18nMessageExtractorBuilder(this.outputAssetId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future build(BuildStep buildStep) async { | 
					
						
							|  |  |  |     final resolver = await buildStep.resolve(buildStep.input.id); | 
					
						
							|  |  |  |     final entryLib = resolver.getLibrary(buildStep.input.id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     final extractor = new I18nMessageExtractor((path) => buildStep.readAsString(path)); | 
					
						
							|  |  |  |     await extractor.processLibrary(entryLib); | 
					
						
							|  |  |  |     resolver.release(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (extractor.errors.length > 0) { | 
					
						
							|  |  |  |       print("Errors:"); | 
					
						
							|  |  |  |       extractor.errors.forEach(print); | 
					
						
							|  |  |  |       throw "Failed to extract messages"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       await buildStep.writeAsString(new Asset(outputAssetId, extractor.output)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   List<AssetId> declareOutputs(AssetId inputId) => [outputAssetId]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class I18nMessageExtractor { | 
					
						
							|  |  |  |   final TransformerUrlResolver urlResovler = new TransformerUrlResolver(); | 
					
						
							|  |  |  |   final List<Message> messages = []; | 
					
						
							|  |  |  |   final List errors = []; | 
					
						
							|  |  |  |   final HtmlParser htmlParser = new HtmlParser(); | 
					
						
							|  |  |  |   final Parser parser = new Parser(new Lexer(), new Reflector(new ReflectionCapabilities())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final Function readInput; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   I18nMessageExtractor(this.readInput); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-27 11:12:48 -07:00
										 |  |  |   String get output => serializeXmb(removeDuplicates(messages)); | 
					
						
							| 
									
										
										
										
											2016-03-16 11:58:43 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Future processLibrary(LibraryElement el) async  { | 
					
						
							|  |  |  |     return Future.wait(el.units.map(processCompilationUnit)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future processCompilationUnit(CompilationUnitElement el) async { | 
					
						
							|  |  |  |     return Future.wait(el.types.map(processClass)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future processClass(ClassElement el) async { | 
					
						
							|  |  |  |     final baseUrl = (el.source as dynamic).assetId; | 
					
						
							|  |  |  |     final filtered = el.metadata.where((m) { | 
					
						
							|  |  |  |       if (m.element is ConstructorElement) { | 
					
						
							|  |  |  |         final isComponent = m.element.enclosingElement.name == "Component" && | 
					
						
							|  |  |  |             m.element.library.displayName == "angular2.src.core.metadata"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         final isView = m.element.enclosingElement.name == "View" && | 
					
						
							|  |  |  |             m.element.library.displayName == "angular2.src.core.metadata"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return isComponent || isView; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Future.wait(filtered.map((m) => processAnnotation(el, m, baseUrl))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future processAnnotation(ClassElement el, ElementAnnotation m, baseUrl) async { | 
					
						
							|  |  |  |     final fields = (m.constantValue as dynamic).fields["(super)"].fields; | 
					
						
							|  |  |  |     final template = fields["template"]; | 
					
						
							|  |  |  |     final templateUrl = fields["templateUrl"]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (template != null && !template.isNull) { | 
					
						
							|  |  |  |       processTemplate(template.toStringValue(), baseUrl.toString()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (templateUrl != null && !templateUrl.isNull) { | 
					
						
							|  |  |  |       final value = templateUrl.toStringValue(); | 
					
						
							|  |  |  |       final resolvedPath = urlResovler.resolve(toAssetUri(baseUrl), value); | 
					
						
							|  |  |  |       final template = await readInput(fromUri(resolvedPath)); | 
					
						
							|  |  |  |       processTemplate(template.toStringValue(), baseUrl.toString()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void processTemplate(String template, String sourceUrl) { | 
					
						
							|  |  |  |     final m = new MessageExtractor(htmlParser, parser); | 
					
						
							|  |  |  |     final res = m.extract(template, sourceUrl); | 
					
						
							|  |  |  |     if (res.errors.isNotEmpty) { | 
					
						
							|  |  |  |       errors.addAll(res.errors); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       messages.addAll(res.messages); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |