feat(i18n): add a simple dart script extracting all i18n messages from a package
Closes #7620
This commit is contained in:
parent
a7fe983be2
commit
8326ab3240
@ -20,8 +20,7 @@ dependencies:
|
||||
protobuf: '^0.5.0'
|
||||
source_span: '^1.0.0'
|
||||
stack_trace: '^1.1.1'
|
||||
build:
|
||||
git: git@github.com:dart-lang/build.git
|
||||
build: '>=0.0.1'
|
||||
dev_dependencies:
|
||||
transformer_test: '^0.2.0'
|
||||
guinness: '^0.1.18'
|
||||
|
@ -2,7 +2,7 @@ name: benchmarks_external
|
||||
environment:
|
||||
sdk: '>=1.4.0'
|
||||
dependencies:
|
||||
angular: '>=1.0.0 <2.0.0'
|
||||
angular: '>=1.1.2+2 <2.0.0'
|
||||
browser: '>=0.10.0 <0.11.0'
|
||||
dev_dependencies:
|
||||
angular2:
|
||||
|
119
modules_dart/transform/lib/extract_messages.dart
Normal file
119
modules_dart/transform/lib/extract_messages.dart
Normal file
@ -0,0 +1,119 @@
|
||||
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);
|
||||
|
||||
String get output => serialize(removeDuplicates(messages));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user