Skip to content

Commit

Permalink
Changed options to language and additionalLanguages.
Browse files Browse the repository at this point in the history
  • Loading branch information
ma2ciek committed Nov 24, 2017
1 parent e4b2c59 commit 772d6bd
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@ const { EventEmitter } = require( 'events' );
*/
module.exports = class MultipleLanguageTranslationService extends EventEmitter {
/**
* @param {Array.<String>} languages Target languages.
* @param {String} language Main language.
* @param {Object} options
* @param {Boolean} [options.compileAllLanguages=false] Flag indicates whether the languages are specified
* or should be found at runtime.
* @param {Boolean} [options.defaultLanguage] Default language that will be added to the main bundle (if possible).
* @param {Array.<String>} options.additionalLanguages Additional languages. Build is optimized for this option is not set.
* When option is set to 'all' then script will be looking for all languages and according translations during the compilation.
*/
constructor( languages, { compileAllLanguages = false, defaultLanguage } = {} ) {
constructor( language, { additionalLanguages, compileAllLanguages = false } = {} ) {
super();

this._languages = new Set( languages );
this._mainLanguage = language;

this._defaultLanguage = defaultLanguage;
this._languages = new Set( [ language, ...additionalLanguages ] );

this._compileAllLanguages = compileAllLanguages;

Expand Down Expand Up @@ -130,8 +131,8 @@ module.exports = class MultipleLanguageTranslationService extends EventEmitter {

if ( compilationAssetNames.length > 1 ) {
this.emit( 'warning', [
'Because of the many found bundles, none bundle will contain the default language.',
`You should add it directly to the application from the '${ outputDirectory }${ path.sep }${ this._defaultLanguage }.js'.`
'Because of the many found bundles, none of the bundles will contain the main language.',
`You should add it directly to the application from the '${ outputDirectory }${ path.sep }${ this._mainLanguage }.js'.`
].join( '\n' ) );

return this._getTranslationAssets( outputDirectory, this._languages );
Expand All @@ -140,15 +141,15 @@ module.exports = class MultipleLanguageTranslationService extends EventEmitter {
const mainAssetName = compilationAssetNames[ 0 ];
const mainCompilationAsset = compilationAssets[ mainAssetName ];

const mainTranslationAsset = this._getTranslationAssets( outputDirectory, [ this._defaultLanguage ] )[ 0 ];
const mainTranslationAsset = this._getTranslationAssets( outputDirectory, [ this._mainLanguage ] )[ 0 ];

const mergedCompilationAsset = {
outputBody: mainCompilationAsset.source() + '\n;' + mainTranslationAsset.outputBody,
outputPath: mainAssetName
};

const otherLanguages = Array.from( this._languages )
.filter( lang => lang !== this._defaultLanguage );
.filter( lang => lang !== this._mainLanguage );

return [
mergedCompilationAsset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ describe( 'translations', () => {

describe( 'constructor()', () => {
it( 'should initialize `SingleLanguageTranslationService`', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'en', { additionalLanguages: [ 'pl', 'de' ] } );

expect( translationService ).to.be.instanceof( MultipleLanguageTranslationService );
} );
} );

describe( 'loadPackage()', () => {
it( 'should load PO file from the package and load translations', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const pathToTranslationsDirectory = path.join( 'pathToPackage', 'lang', 'translations' );
const pathToPlTranslations = path.join( 'pathToPackage', 'lang', 'translations', 'pl.po' );
const pathToDeTranslations = path.join( 'pathToPackage', 'lang', 'translations', 'de.po' );
Expand Down Expand Up @@ -82,15 +82,15 @@ describe( 'translations', () => {
} );

it( 'should do nothing if the PO file does not exist', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );

translationService.loadPackage( 'pathToPackage' );

expect( translationService._dictionary ).to.deep.equal( {} );
} );

it( 'should load PO file from the package only once per language', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const loadPoFileSpy = sandbox.stub( translationService, '_loadPoFile' );

const pathToTranslationsDirectory = path.join( 'pathToPackage', 'lang', 'translations' );
Expand All @@ -105,7 +105,9 @@ describe( 'translations', () => {
} );

it( 'should load all PO files for the current package and add languages to the language list', () => {
const translationService = new MultipleLanguageTranslationService( [], { compileAllLanguages: true } );
const translationService = new MultipleLanguageTranslationService( 'pl', {
compileAllLanguages: true, additionalLanguages: []
} );

const pathToTranslations = path.join( 'pathToPackage', 'lang', 'translations' );
const pathToPlTranslations = path.join( pathToTranslations, 'pl.po' );
Expand Down Expand Up @@ -149,7 +151,7 @@ describe( 'translations', () => {

describe( 'translateSource()', () => {
it( 'should replace t() call params with the translation key, starting with `a`', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const source = 't( \'Cancel\' ), t( \'Save\' );';

const result = translationService.translateSource( source, 'file.js' );
Expand All @@ -162,7 +164,7 @@ describe( 'translations', () => {
} );

it( 'should not create new id for the same translation key', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const source = 't( \'Cancel\' ), t( \'Cancel\' );';

const result = translationService.translateSource( source, 'file.js' );
Expand All @@ -174,7 +176,7 @@ describe( 'translations', () => {
} );

it( 'should return original source if there is no t() calls in the code', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ] );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const source = 'translate( \'Cancel\' )';

const result = translationService.translateSource( source, 'file.js' );
Expand All @@ -187,7 +189,7 @@ describe( 'translations', () => {

describe( 'getAssets()', () => {
it( 'should return an array of assets', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'en' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'en' ] } );

translationService._translationIdsDictionary = {
Cancel: 'a',
Expand Down Expand Up @@ -224,7 +226,7 @@ describe( 'translations', () => {
} );

it( 'should emit an error if the language is not present in language list', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'xxx' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'xxx' ] } );
const spy = sandbox.spy();

translationService.on( 'error', spy );
Expand Down Expand Up @@ -254,7 +256,7 @@ describe( 'translations', () => {
} );

it( 'should feed missing translation with the translation key if the translated string is missing', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'xxx' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'xxx' ] } );
const spy = sandbox.spy();

translationService.on( 'error', spy );
Expand Down Expand Up @@ -290,7 +292,7 @@ describe( 'translations', () => {
} );

it( 'should emit an error if the main translation is missing', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl' ], { defaultLanguage: 'xxx' } );
const translationService = new MultipleLanguageTranslationService( 'xxx', { additionalLanguages: [ 'pl' ] } );
const spy = sandbox.spy();

translationService.on( 'error', spy );
Expand Down Expand Up @@ -320,7 +322,7 @@ describe( 'translations', () => {
} );

it( 'should bound to assets only used translations', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [] } );

translationService._translationIdsDictionary = {
Cancel: 'a',
Expand Down Expand Up @@ -351,7 +353,7 @@ describe( 'translations', () => {
} );

it( 'should emit warning when many assets will be emitted by compilator and return only translation assets', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [] } );
const spy = sandbox.spy();

translationService.on( 'warning', spy );
Expand All @@ -377,7 +379,7 @@ describe( 'translations', () => {

sinon.assert.calledOnce( spy );
sinon.assert.alwaysCalledWithExactly( spy, [
'Because of the many found bundles, none of the bundles will contain the default language.',
'Because of the many found bundles, none of the bundles will contain the main language.',
`You should add it directly to the application from the 'lang${ path.sep }pl.js'.`
].join( '\n' ) );

Expand All @@ -398,7 +400,7 @@ describe( 'translations', () => {
}
}

const translationService = new CustomTranslationService( [ 'en' ], { defaultLanguage: 'en' } );
const translationService = new CustomTranslationService( 'en', { additionalLanguages: [] } );

const pathToPlTranslations = path.join( 'custom', 'path', 'to', 'pathToPackage', 'en.po' );
const pathToTranslationDirectory = path.join( 'custom', 'path', 'to', 'pathToPackage' );
Expand Down Expand Up @@ -426,7 +428,7 @@ describe( 'translations', () => {

describe( 'integration test', () => {
it( 'test #1', () => {
const translationService = new MultipleLanguageTranslationService( [ 'pl', 'de' ], { defaultLanguage: 'pl' } );
const translationService = new MultipleLanguageTranslationService( 'pl', { additionalLanguages: [ 'de' ] } );
const pathToPlTranslations = path.join( 'pathToPackage', 'lang', 'translations', 'pl.po' );
const pathToDeTranslations = path.join( 'pathToPackage', 'lang', 'translations', 'de.po' );
const pathToTranslationsDirectory = path.join( 'pathToPackage', 'lang', 'translations' );
Expand Down
46 changes: 20 additions & 26 deletions packages/ckeditor5-dev-webpack-plugin/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,24 @@ const ckeditor5EnvUtils = require( './ckeditor5-env-utils' );
* Workflow:
*
* One entry point (or to be precise one output JS file):
* - one language in `languages` -> build optimized version
* - many languages in `languages` –> get first or `defaultLanguage` as the main language that will be built into the main bundle
* (e.g. `ckeditor.js`) (`languages` must support `all` option, that's why the `defaultLanguage` option is needed)
* - `additinalLanguages` not set -> build optimized version
* - `additinalLanguages` set –> `language` will be built into the main bundle (e.g. `ckeditor.js`).
* Translation files will be emitted in the `outputDirectory` or 'lang' directory.
*
* Multiple output JS files
* - one language in `languages` -> build optimized version
* - many languages in `languages` –> emit all translation files separately and warn user,
* that he needs to load translation file manually to get editor working
* - `additinalLanguages` not set -> build optimized version
* - `additinalLanguages` set –> emit all translation files separately and warn user,
* that he needs to load at least one translation file manually to get editor working
*/
module.exports = class CKEditorWebpackPlugin {
/**
* @param {Object} [options] Plugin options.
* @param {Array.<String>|'all'} [options.languages] Target languages. Build is optimized if only one language is provided.
* When option is set to 'all' then script will be looking for all languages and according translations during the compilation.
* @param {String} options.language Main language of the build that will be added to the bundle.
* @param {Array.<String>|'all'} [options.additinalLanguages] Additiional languages. Build is optimized when this option is not set.
* When `additinalLanguages` is set to 'all' then script will be looking for all languages and according translations during
* the compilation.
* @param {String} [options.outputDirectory='lang'] Output directory for the emitted translation files,
* should be relative to the webpack context.
* @param {String} [options.defaultLanguage] Default language for the build. If not set, the first language will be used.
* @param {Boolean} [options.throwErrorOnMissingTranslation] Option that make the plugin throw when the translation is missing.
* By default original (english translation keys) are used when the target translation is missing.
*/
Expand All @@ -42,41 +43,34 @@ module.exports = class CKEditorWebpackPlugin {
}

apply( compiler ) {
if ( !this.options.languages ) {
if ( !this.options.language ) {
return;
}

const language = this.options.language;
let translationService;
let compileAllLanguages = false;
let languages = this.options.languages;
let additinalLanguages = this.options.additinalLanguages;

if ( typeof languages == 'string' ) {
if ( languages !== 'all' ) {
throw new Error( '`languages` option should be an array of language codes or `all`.' );
if ( typeof additinalLanguages == 'string' ) {
if ( additinalLanguages !== 'all' ) {
throw new Error( '`additinalLanguages` option should be an array of language codes or `all`.' );
}

compileAllLanguages = true;
languages = []; // They will be searched in runtime.
additinalLanguages = []; // They will be searched in runtime.
}

const defaultLanguage = this.options.defaultLanguage || languages[ 0 ];

if ( languages.length === 0 && !compileAllLanguages ) {
throw new Error( chalk.red(
'At least one target language should be specified.'
) );
}

if ( languages.length === 1 ) {
if ( !additinalLanguages ) {
if ( this.options.outputDirectory ) {
console.warn( chalk.red(
'`outputDirectory` option does not work for one language because zero files will be emitted. It will be ignored.'
) );
}

translationService = new SingleLanguageTranslationService( languages[ 0 ] );
translationService = new SingleLanguageTranslationService( language );
} else {
translationService = new MultipleLanguageTranslationService( languages, { compileAllLanguages, defaultLanguage } );
translationService = new MultipleLanguageTranslationService( language, { compileAllLanguages, additinalLanguages } );
}

serveTranslations( compiler, this.options, translationService, ckeditor5EnvUtils );
Expand Down
Loading

0 comments on commit 772d6bd

Please sign in to comment.