diff --git a/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xlf b/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xlf new file mode 100644 index 0000000000..8ed5cbf868 --- /dev/null +++ b/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xlf @@ -0,0 +1,17 @@ + + + + + + translate me + käännä teksti + desc + meaning + + + Welcome + tervetuloa + + + + \ No newline at end of file diff --git a/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xtb b/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xtb index 7b3b157e47..5c24884c84 100644 --- a/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xtb +++ b/modules/@angular/compiler-cli/integrationtest/src/messages.fi.xtb @@ -1,3 +1,11 @@ + + + + + + + +]> käännä teksti tervetuloa diff --git a/modules/@angular/compiler-cli/integrationtest/test/basic_spec.ts b/modules/@angular/compiler-cli/integrationtest/test/basic_spec.ts index c4b2dcf5b8..45a3952e28 100644 --- a/modules/@angular/compiler-cli/integrationtest/test/basic_spec.ts +++ b/modules/@angular/compiler-cli/integrationtest/test/basic_spec.ts @@ -73,7 +73,7 @@ describe('template codegen output', () => { it('should inject the translations format into the component', () => { const compFixture = createComponent(BasicComp); - expect(compFixture.componentInstance.translationsFormat).toEqual('xtb'); + expect(compFixture.componentInstance.translationsFormat).toEqual('xlf'); }); it('should support i18n for content tags', () => { diff --git a/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts b/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts index f382332f46..c4fdabd964 100644 --- a/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts +++ b/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts @@ -11,11 +11,7 @@ import './init'; import * as fs from 'fs'; import * as path from 'path'; -describe('template i18n extraction output', () => { - const outDir = ''; - - it('should extract i18n messages', () => { - const EXPECTED = ` +const EXPECTED_XMB = ` @@ -42,9 +38,39 @@ describe('template i18n extraction output', () => { Welcome `; +const EXPECTED_XLIFF = ` + + + + + translate me + + desc + meaning + + + Welcome + + + + +`; + +describe('template i18n extraction output', () => { + const outDir = ''; + + it('should extract i18n messages as xmb', () => { const xmbOutput = path.join(outDir, 'messages.xmb'); expect(fs.existsSync(xmbOutput)).toBeTruthy(); const xmb = fs.readFileSync(xmbOutput, {encoding: 'utf-8'}); - expect(xmb).toEqual(EXPECTED); + expect(xmb).toEqual(EXPECTED_XMB); }); + + it('should extract i18n messages as xliff', () => { + const xlfOutput = path.join(outDir, 'messages.xlf'); + expect(fs.existsSync(xlfOutput)).toBeTruthy(); + const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'}); + expect(xlf).toEqual(EXPECTED_XLIFF); + }); + }); diff --git a/modules/@angular/compiler-cli/src/codegen.ts b/modules/@angular/compiler-cli/src/codegen.ts index 5f79f7ea1d..47667b0162 100644 --- a/modules/@angular/compiler-cli/src/codegen.ts +++ b/modules/@angular/compiler-cli/src/codegen.ts @@ -144,7 +144,8 @@ export class CodeGenerator { const reflectorHost = new ReflectorHost(program, compilerHost, options, reflectorHostContext); const staticReflector = new StaticReflector(reflectorHost); StaticAndDynamicReflectionCapabilities.install(staticReflector); - const htmlParser = new compiler.i18n.HtmlParser(new HtmlParser(), transContent); + const htmlParser = + new compiler.i18n.HtmlParser(new HtmlParser(), transContent, cliOptions.i18nFormat); const config = new compiler.CompilerConfig({ genDebugInfo: options.debug === true, defaultEncapsulation: ViewEncapsulation.Emulated, @@ -161,6 +162,7 @@ export class CodeGenerator { new compiler.NgModuleResolver(staticReflector), new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector), config, console, elementSchemaRegistry, staticReflector); + // TODO(vicb): do not pass cliOptions.i18nFormat here const offlineCompiler = new compiler.OfflineCompiler( resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config), new NgModuleCompiler(), new TypeScriptEmitter(reflectorHost), cliOptions.locale, diff --git a/modules/@angular/compiler-cli/src/extract_i18n.ts b/modules/@angular/compiler-cli/src/extract_i18n.ts index 75676aef2f..a67f555f9d 100644 --- a/modules/@angular/compiler-cli/src/extract_i18n.ts +++ b/modules/@angular/compiler-cli/src/extract_i18n.ts @@ -30,12 +30,29 @@ import {StaticReflector, StaticSymbol} from './static_reflector'; function extract( ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.I18nExtractionCliOptions, program: ts.Program, host: ts.CompilerHost) { - const extractor = Extractor.create(ngOptions, cliOptions.i18nFormat, program, host); + const htmlParser = new compiler.i18n.HtmlParser(new HtmlParser()); + const extractor = Extractor.create(ngOptions, cliOptions.i18nFormat, program, host, htmlParser); const bundlePromise: Promise = extractor.extract(); return (bundlePromise).then(messageBundle => { - const serializer = new compiler.i18n.Xmb(); - const dstPath = path.join(ngOptions.genDir, 'messages.xmb'); + let ext: string; + let serializer: compiler.i18n.Serializer; + const format = (cliOptions.i18nFormat || 'xlf').toLowerCase(); + + switch (format) { + case 'xmb': + ext = 'xmb'; + serializer = new compiler.i18n.Xmb(); + break; + case 'xliff': + case 'xlf': + default: + ext = 'xlf'; + serializer = new compiler.i18n.Xliff(htmlParser, compiler.DEFAULT_INTERPOLATION_CONFIG); + break; + } + + const dstPath = path.join(ngOptions.genDir, `messages.${ext}`); host.writeFile(dstPath, messageBundle.write(serializer), false); }); } @@ -128,7 +145,8 @@ export class Extractor { static create( options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program, - compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext): Extractor { + compilerHost: ts.CompilerHost, htmlParser: compiler.i18n.HtmlParser, + reflectorHostContext?: ReflectorHostContext): Extractor { const xhr: compiler.XHR = { get: (s: string) => { if (!compilerHost.fileExists(s)) { @@ -143,7 +161,6 @@ export class Extractor { const reflectorHost = new ReflectorHost(program, compilerHost, options, reflectorHostContext); const staticReflector = new StaticReflector(reflectorHost); StaticAndDynamicReflectionCapabilities.install(staticReflector); - const htmlParser = new compiler.i18n.HtmlParser(new HtmlParser()); const config = new compiler.CompilerConfig({ genDebugInfo: options.debug === true, diff --git a/modules/@angular/compiler/index.ts b/modules/@angular/compiler/index.ts index 1dc751de3a..1b7ba3a397 100644 --- a/modules/@angular/compiler/index.ts +++ b/modules/@angular/compiler/index.ts @@ -14,7 +14,7 @@ import * as i18n from './src/i18n/index'; export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NgModuleResolver, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, XHR, analyzeAppProvidersForDeprecatedConfiguration, createOfflineCompileUrlResolver, platformCoreDynamic} from './src/compiler'; -export {InterpolationConfig} from './src/ml_parser/interpolation_config'; +export {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './src/ml_parser/interpolation_config'; export {ElementSchemaRegistry} from './src/schema/element_schema_registry'; export {i18n}; diff --git a/modules/@angular/compiler/src/compiler.ts b/modules/@angular/compiler/src/compiler.ts index f96e6fe505..8637217dcc 100644 --- a/modules/@angular/compiler/src/compiler.ts +++ b/modules/@angular/compiler/src/compiler.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Component, Inject, Injectable, OptionalMetadata, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core'; +import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Component, Inject, Injectable, OptionalMetadata, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core'; export * from './template_parser/template_ast'; export {TEMPLATE_TRANSFORMS} from './template_parser/template_parser'; @@ -63,9 +63,13 @@ export const COMPILER_PROVIDERS: Array|{[k: string]: any}|any[]> = HtmlParser, { provide: i18n.HtmlParser, - useFactory: (parser: HtmlParser, translations: string) => - new i18n.HtmlParser(parser, translations), - deps: [HtmlParser, [new OptionalMetadata(), new Inject(TRANSLATIONS)]] + useFactory: (parser: HtmlParser, translations: string, format: string) => + new i18n.HtmlParser(parser, translations, format), + deps: [ + HtmlParser, + [new OptionalMetadata(), new Inject(TRANSLATIONS)], + [new OptionalMetadata(), new Inject(TRANSLATIONS_FORMAT)], + ] }, TemplateParser, DirectiveNormalizer, diff --git a/modules/@angular/compiler/src/i18n/html_parser.ts b/modules/@angular/compiler/src/i18n/html_parser.ts index 5672d29014..2a436aa630 100644 --- a/modules/@angular/compiler/src/i18n/html_parser.ts +++ b/modules/@angular/compiler/src/i18n/html_parser.ts @@ -12,17 +12,22 @@ import {ParseTreeResult} from '../ml_parser/parser'; import {mergeTranslations} from './extractor_merger'; import {MessageBundle} from './message_bundle'; +import {Serializer} from './serializers/serializer'; +import {Xliff} from './serializers/xliff'; +import {Xmb} from './serializers/xmb'; import {Xtb} from './serializers/xtb'; import {TranslationBundle} from './translation_bundle'; export class HtmlParser implements BaseHtmlParser { // @override - public getTagDefinition: any; + getTagDefinition: any; // TODO(vicb): transB.load() should not need a msgB & add transB.resolve(msgB, // interpolationConfig) // TODO(vicb): remove the interpolationConfig from the Xtb serializer - constructor(private _htmlParser: BaseHtmlParser, private _translations?: string) {} + constructor( + private _htmlParser: BaseHtmlParser, private _translations?: string, + private _translationsFormat?: string) {} parse( source: string, url: string, parseExpansionForms: boolean = false, @@ -43,9 +48,25 @@ export class HtmlParser implements BaseHtmlParser { return new ParseTreeResult(parseResult.rootNodes, parseResult.errors.concat(errors)); } - const xtb = new Xtb(this._htmlParser, interpolationConfig); - const translationBundle = TranslationBundle.load(this._translations, url, messageBundle, xtb); + const serializer = this._createSerializer(interpolationConfig); + const translationBundle = + TranslationBundle.load(this._translations, url, messageBundle, serializer); return mergeTranslations(parseResult.rootNodes, translationBundle, interpolationConfig, [], {}); } + + private _createSerializer(interpolationConfig: InterpolationConfig): Serializer { + const format = (this._translationsFormat || 'xlf').toLowerCase(); + + switch (format) { + case 'xmb': + return new Xmb(); + case 'xtb': + return new Xtb(this._htmlParser, interpolationConfig); + case 'xliff': + case 'xlf': + default: + return new Xliff(this._htmlParser, interpolationConfig); + } + } } \ No newline at end of file diff --git a/modules/@angular/compiler/src/i18n/index.ts b/modules/@angular/compiler/src/i18n/index.ts index 6c43336835..b7e136de49 100644 --- a/modules/@angular/compiler/src/i18n/index.ts +++ b/modules/@angular/compiler/src/i18n/index.ts @@ -9,5 +9,6 @@ export {HtmlParser} from './html_parser'; export {MessageBundle} from './message_bundle'; export {Serializer} from './serializers/serializer'; +export {Xliff} from './serializers/xliff'; export {Xmb} from './serializers/xmb'; export {Xtb} from './serializers/xtb'; diff --git a/modules/@angular/compiler/test/i18n/integration_spec.ts b/modules/@angular/compiler/test/i18n/integration_spec.ts index 362f3ff5ff..b81f47a27e 100644 --- a/modules/@angular/compiler/test/i18n/integration_spec.ts +++ b/modules/@angular/compiler/test/i18n/integration_spec.ts @@ -8,10 +8,9 @@ import {DirectiveResolver, XHR, i18n} from '@angular/compiler'; import {MockDirectiveResolver} from '@angular/compiler/testing'; -import {Compiler, Component, DebugElement, Injector, TRANSLATIONS} from '@angular/core'; +import {Compiler, Component, DebugElement, Injector, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core'; import {TestBed, fakeAsync} from '@angular/core/testing'; - -import {beforeEach, TestComponentBuilder, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit,} from '@angular/core/testing/testing_internal'; +import {beforeEach, TestComponentBuilder, ddescribe, describe, iit, inject, it, xdescribe, xit,} from '@angular/core/testing/testing_internal'; import {expect} from '@angular/platform-browser/testing/matchers'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {SpyXHR} from '../spies'; @@ -32,6 +31,7 @@ export function main() { {provide: XHR, useClass: SpyXHR}, {provide: NgLocalization, useClass: FrLocalization}, {provide: TRANSLATIONS, useValue: XTB}, + {provide: TRANSLATIONS_FORMAT, useValue: 'xtb'}, ] }); }); diff --git a/scripts/ci-lite/offline_compiler_test.sh b/scripts/ci-lite/offline_compiler_test.sh index 0bfc6ac4ae..cf956fa539 100755 --- a/scripts/ci-lite/offline_compiler_test.sh +++ b/scripts/ci-lite/offline_compiler_test.sh @@ -33,8 +33,11 @@ cp -v package.json $TMP ./node_modules/.bin/tsc --version # Compile the compiler-cli integration tests - ./node_modules/.bin/ngc --i18nFile=src/messages.fi.xtb --locale=fi --i18nFormat=xtb - ./node_modules/.bin/ng-xi18n + # TODO(vicb): restore the test for .xtb + #./node_modules/.bin/ngc --i18nFile=src/messages.fi.xtb --locale=fi --i18nFormat=xtb + ./node_modules/.bin/ngc --i18nFile=src/messages.fi.xlf --locale=fi --i18nFormat=xlf + ./node_modules/.bin/ng-xi18n --i18nFormat=xlf + ./node_modules/.bin/ng-xi18n --i18nFormat=xmb ./node_modules/.bin/jasmine init # Run compiler-cli integration tests in node