diff --git a/packages/@ngtools/webpack/src/plugin.ts b/packages/@ngtools/webpack/src/plugin.ts index 4ac9b891de69..bedf13c604b6 100644 --- a/packages/@ngtools/webpack/src/plugin.ts +++ b/packages/@ngtools/webpack/src/plugin.ts @@ -25,8 +25,10 @@ export interface AotPluginOptions { entryModule?: string; mainPath?: string; typeChecking?: boolean; - skipCodeGeneration?: boolean; + i18nFile?: string; + i18nFormat?: string; + locale?: string; } @@ -78,6 +80,9 @@ export class AotPlugin implements Tapable { private _basePath: string; private _genDir: string; + private _i18nFile: string; + private _i18nFormat: string; + private _locale: string; constructor(options: AotPluginOptions) { this._setupOptions(options); @@ -93,6 +98,9 @@ export class AotPlugin implements Tapable { get program() { return this._program; } get skipCodeGeneration() { return this._skipCodeGeneration; } get typeCheck() { return this._typeCheck; } + get i18nFile() { return this._i18nFile; } + get i18nFormat() { return this._i18nFormat; } + get locale() { return this._locale; } private _setupOptions(options: AotPluginOptions) { // Fill in the missing options. @@ -153,6 +161,16 @@ export class AotPlugin implements Tapable { this._reflectorHost = new ngCompiler.ReflectorHost( this._program, this._compilerHost, this._angularCompilerOptions); this._reflector = new ngCompiler.StaticReflector(this._reflectorHost); + + if (options.hasOwnProperty('i18nFile')) { + this._i18nFile = options.i18nFile; + } + if (options.hasOwnProperty('i18nFormat')) { + this._i18nFormat = options.i18nFormat; + } + if (options.hasOwnProperty('locale')) { + this._locale = options.locale; + } } // registration hook for webpack plugin @@ -222,9 +240,9 @@ export class AotPlugin implements Tapable { this._resourceLoader = new WebpackResourceLoader(compilation); const i18nOptions: ngCompiler.NgcCliOptions = { - i18nFile: undefined, - i18nFormat: undefined, - locale: undefined, + i18nFile: this.i18nFile, + i18nFormat: this.i18nFormat, + locale: this.locale, basePath: this.basePath }; diff --git a/packages/angular-cli/commands/build.ts b/packages/angular-cli/commands/build.ts index 97ba333527cf..821b74e10d81 100644 --- a/packages/angular-cli/commands/build.ts +++ b/packages/angular-cli/commands/build.ts @@ -15,6 +15,9 @@ export interface BuildOptions { vendorChunk?: boolean; verbose?: boolean; progress?: boolean; + i18nFile?: string; + i18nFormat?: string; + locale?: string; } const BuildCommand = Command.extend({ @@ -39,7 +42,10 @@ const BuildCommand = Command.extend({ { name: 'sourcemap', type: Boolean, default: true, aliases: ['sm'] }, { name: 'vendor-chunk', type: Boolean, default: true }, { name: 'verbose', type: Boolean, default: false }, - { name: 'progress', type: Boolean, default: true } + { name: 'progress', type: Boolean, default: true }, + { name: 'i18n-file', type: String, default: null }, + { name: 'i18n-format', type: String, default: null }, + { name: 'locale', type: String, default: null } ], run: function (commandOptions: BuildOptions) { diff --git a/packages/angular-cli/commands/serve.ts b/packages/angular-cli/commands/serve.ts index e22c91c71030..38836cf50e46 100644 --- a/packages/angular-cli/commands/serve.ts +++ b/packages/angular-cli/commands/serve.ts @@ -32,6 +32,9 @@ export interface ServeTaskOptions { open?: boolean; vendorChunk?: boolean; hmr?: boolean; + i18nFile?: string; + i18nFormat?: string; + locale?: string; } const ServeCommand = Command.extend({ @@ -103,6 +106,9 @@ const ServeCommand = Command.extend({ default: false, description: 'Enable hot module replacement', }, + { name: 'i18n-file', type: String, default: null }, + { name: 'i18n-format', type: String, default: null }, + { name: 'locale', type: String, default: null } ], run: function(commandOptions: ServeTaskOptions) { diff --git a/packages/angular-cli/models/webpack-build-typescript.ts b/packages/angular-cli/models/webpack-build-typescript.ts index 8371e79c9364..40de6bb09dd9 100644 --- a/packages/angular-cli/models/webpack-build-typescript.ts +++ b/packages/angular-cli/models/webpack-build-typescript.ts @@ -29,7 +29,8 @@ export const getWebpackNonAotConfigPartial = function(projectRoot: string, appCo }; }; -export const getWebpackAotConfigPartial = function(projectRoot: string, appConfig: any) { +export const getWebpackAotConfigPartial = function(projectRoot: string, appConfig: any, + i18nFile: string, i18nFormat: string, locale: string) { return { module: { rules: [ @@ -43,7 +44,10 @@ export const getWebpackAotConfigPartial = function(projectRoot: string, appConfi plugins: [ new AotPlugin({ tsConfigPath: path.resolve(projectRoot, appConfig.root, appConfig.tsconfig), - mainPath: path.join(projectRoot, appConfig.root, appConfig.main) + mainPath: path.join(projectRoot, appConfig.root, appConfig.main), + i18nFile: i18nFile, + i18nFormat: i18nFormat, + locale: locale }), ] }; diff --git a/packages/angular-cli/models/webpack-config.ts b/packages/angular-cli/models/webpack-config.ts index 439e8e7e88e6..b93a3bc24a37 100644 --- a/packages/angular-cli/models/webpack-config.ts +++ b/packages/angular-cli/models/webpack-config.ts @@ -24,6 +24,9 @@ export class NgCliWebpackConfig { public environment: string, outputDir?: string, baseHref?: string, + i18nFile?: string, + i18nFormat?: string, + locale?: string, isAoT = false, sourcemap = true, vendorChunk = false, @@ -49,7 +52,7 @@ export class NgCliWebpackConfig { this.ngCliProject.root, appConfig, sourcemap, verbose ); const typescriptConfigPartial = isAoT - ? getWebpackAotConfigPartial(this.ngCliProject.root, appConfig) + ? getWebpackAotConfigPartial(this.ngCliProject.root, appConfig, i18nFile, i18nFormat, locale) : getWebpackNonAotConfigPartial(this.ngCliProject.root, appConfig); if (appConfig.mobile) { diff --git a/packages/angular-cli/tasks/build-webpack-watch.ts b/packages/angular-cli/tasks/build-webpack-watch.ts index 7e6958a90fbe..4a793dc5d9bd 100644 --- a/packages/angular-cli/tasks/build-webpack-watch.ts +++ b/packages/angular-cli/tasks/build-webpack-watch.ts @@ -23,6 +23,9 @@ export default Task.extend({ runTaskOptions.environment, outputDir, runTaskOptions.baseHref, + runTaskOptions.i18nFile, + runTaskOptions.i18nFormat, + runTaskOptions.locale, runTaskOptions.aot, runTaskOptions.sourcemap, runTaskOptions.vendorChunk, diff --git a/packages/angular-cli/tasks/build-webpack.ts b/packages/angular-cli/tasks/build-webpack.ts index d17af6c72964..5e76299c55dc 100644 --- a/packages/angular-cli/tasks/build-webpack.ts +++ b/packages/angular-cli/tasks/build-webpack.ts @@ -24,6 +24,9 @@ export default Task.extend({ runTaskOptions.environment, outputDir, runTaskOptions.baseHref, + runTaskOptions.i18nFile, + runTaskOptions.i18nFormat, + runTaskOptions.locale, runTaskOptions.aot, runTaskOptions.sourcemap, runTaskOptions.vendorChunk, diff --git a/packages/angular-cli/tasks/serve-webpack.ts b/packages/angular-cli/tasks/serve-webpack.ts index c5d8ff615bd0..4aedab2b0800 100644 --- a/packages/angular-cli/tasks/serve-webpack.ts +++ b/packages/angular-cli/tasks/serve-webpack.ts @@ -25,6 +25,9 @@ export default Task.extend({ serveTaskOptions.environment, undefined, undefined, + serveTaskOptions.i18nFile, + serveTaskOptions.i18nFormat, + serveTaskOptions.locale, serveTaskOptions.aot, serveTaskOptions.sourcemap, serveTaskOptions.vendorChunk, diff --git a/packages/angular-cli/utilities/completion.sh b/packages/angular-cli/utilities/completion.sh index f1af947e61fb..3b867977d059 100644 --- a/packages/angular-cli/utilities/completion.sh +++ b/packages/angular-cli/utilities/completion.sh @@ -8,13 +8,13 @@ ng_opts='b build completion doc e2e g generate get github-pages:deploy gh-pages:deploy h help i init install lint make-this-awesome new s serve server set t test v version' -build_opts='--aot --base-href --environment --output-path --progress --sourcemap --suppress-sizes --target --vendor-chunk --verbose --watch --watcher -bh -dev -e -o -prod -sm -t -w' +build_opts='--aot --base-href --environment --i18n-file --i18n-format --locale --output-path --progress --sourcemap --suppress-sizes --target --vendor-chunk --verbose --watch --watcher -bh -dev -e -o -prod -sm -t -w' generate_opts='class component directive enum module pipe route service c cl d e m p r s --help' github_pages_deploy_opts='--base-href --environment --gh-token --gh-username --message --skip-build --target --user-page -bh -e -t' help_opts='--json --verbose -v' init_opts='--dry-run inline-style inline-template --link-cli --mobile --name --prefix --routing --skip-bower --skip-npm --source-dir --style --verbose -d -is -it -lc -n -p -sb -sd -sn -v' new_opts='--directory --dry-run inline-style inline-template --link-cli --mobile --prefix --routing --skip-bower --skip-git --skip-npm --source-dir --style --verbose -d -dir -is -it -lc -p -sb -sd -sg -sn -v' -serve_opts='--aot --environment --hmr --host --live-reload --live-reload-base-url --live-reload-host --live-reload-live-css --live-reload-port --open --port --proxy-config --sourcemap --ssl --ssl-cert --ssl-key --target --watcher -H -e -lr -lrbu -lrh -lrp -o -p -pc -sm -t -w' +serve_opts='--aot --environment --hmr --host --i18n-file --i18n-format --live-reload --live-reload-base-url --live-reload-host --live-reload-live-css --live-reload-port --locale --open --port --proxy-config --sourcemap --ssl --ssl-cert --ssl-key --target --watcher -H -e -lr -lrbu -lrh -lrp -o -p -pc -sm -t -w' set_opts='--global -g' test_opts='--browsers --build --code-coverage --colors --lint --log-level --port --reporters --single-run --sourcemap --watch -cc -l -sm -sr -w' diff --git a/tests/e2e/tests/build/aot-i18n.ts b/tests/e2e/tests/build/aot-i18n.ts new file mode 100644 index 000000000000..a4479ba7bb4d --- /dev/null +++ b/tests/e2e/tests/build/aot-i18n.ts @@ -0,0 +1,29 @@ +import {ng} from '../../utils/process'; +import {expectFileToMatch, writeFile, createDir, appendToFile} from '../../utils/fs'; +import {expectToFail} from '../../utils/utils'; + +export default function() { + return Promise.resolve() + .then(() => createDir('src/locale')) + .then(() => writeFile('src/locale/messages.fr.xlf', ` + + + + + + Hello i18n! + Bonjour i18n! + An introduction header for this sample + + + + `)) + .then(() => appendToFile('src/app/app.component.html', + '

Hello i18n!

')) + .then(() => ng('build', '--aot', '--i18n-file', 'src/locale/messages.fr.xlf', '--i18n-format', + 'xlf', '--locale', 'fr')) + .then(() => expectFileToMatch('dist/main.bundle.js', /Bonjour i18n!/)) + .then(() => ng('build', '--aot')) + .then(() => expectToFail(() => expectFileToMatch('dist/main.bundle.js', /Bonjour i18n!/))) + .then(() => expectFileToMatch('dist/main.bundle.js', /Hello i18n!/)); +}