Przeglądaj źródła

Added support for the shorthand `t` call signature: `t( message, value )`, Added an error when the value used to determine the plural form is not a number.

Maciej Bukowski 5 lat temu
rodzic
commit
4125b47c65

+ 25 - 13
packages/ckeditor5-utils/src/locale.js

@@ -86,21 +86,25 @@ export default class Locale {
 		 *
 		 *
 		 * The message can be either a string or an object implementing the {@link module:utils/translation-service~Message} interface.
 		 * The message can be either a string or an object implementing the {@link module:utils/translation-service~Message} interface.
 		 *
 		 *
-		 * The message may contain placeholders (`%<index>`) for values that are passed as the second argument.
-		 * `<index>` is the index in the `values` array.
+		 * The message may contain placeholders (`%<index>`) for value(s) that are passed as the second argument.
+		 * For an array of values the `<index>` will be the index in that array.
 		 *
 		 *
 		 *		t( 'Created file "%0" in %1ms.', [ fileName, timeTaken ] );
 		 *		t( 'Created file "%0" in %1ms.', [ fileName, timeTaken ] );
 		 *
 		 *
+		 * For only one argument that should be interpolated there's a shorthand:
+		 *
+		 * 		t( 'Created file "%0", fileName );
+		 *
 		 * The message supports plural forms. To specify a plural form, use the `plural` property. Single or plural form
 		 * The message supports plural forms. To specify a plural form, use the `plural` property. Single or plural form
 		 * will be chosen depending on the first value from the passed `values`. The value of this property is used
 		 * will be chosen depending on the first value from the passed `values`. The value of this property is used
-		 * as a default plural translation when the translation for the target language is missing.
+		 * as a default plural translation when the translation for the target language is missing. Therefor, it should be a number.
 		 *
 		 *
-		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, [ 1 ] ); // 'Add a space' for the English language.
-		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, [ 5 ] ); // 'Add 5 spaces' for the English language.
+		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Add a space' for the English language.
+		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Add 5 spaces' for the English language.
 		 *		t( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Add 2 spaces' for the English language.
 		 *		t( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Add 2 spaces' for the English language.
 		 *
 		 *
-		 * 		t( { string: 'Add a space', plural: 'Add %0 spaces' }, [ 1 ] ); // 'Dodaj spację' for the Polish language.
-		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, [ 5 ] ); // 'Dodaj 5 spacji' for the Polish language.
+		 * 		t( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Dodaj spację' for the Polish language.
+		 *		t( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Dodaj 5 spacji' for the Polish language.
 		 *		t( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Dodaj 2 spacje' for the Polish language.
 		 *		t( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Dodaj 2 spacje' for the Polish language.
 		 *
 		 *
 		 * The message can provide a context using the `context` property when the message ids created from message strings
 		 * The message can provide a context using the `context` property when the message ids created from message strings
@@ -112,7 +116,7 @@ export default class Locale {
 		 *
 		 *
 		 * @method #t
 		 * @method #t
 		 * @param {String|module:utils/translation-service~Message} message A message that will be localized (translated).
 		 * @param {String|module:utils/translation-service~Message} message A message that will be localized (translated).
-		 * @param {Array.<String>} [values] An array of values that will fill message placeholders.
+		 * @param {String|Number|Array.<String|Number>} [values] A value or an array of values that will fill message placeholders.
 		 * For messages supporting plural forms the first value will determine the plural form.
 		 * For messages supporting plural forms the first value will determine the plural form.
 		 * @returns {String}
 		 * @returns {String}
 		 */
 		 */
@@ -148,10 +152,14 @@ export default class Locale {
 	 *
 	 *
 	 * @private
 	 * @private
 	 * @param {String|module:utils/translation-service~Message} message
 	 * @param {String|module:utils/translation-service~Message} message
-	 * @param {Array.<String>} [values]
+	 * @param {Number|String|Array.<Number|String>} [values]
 	 * @returns {String}
 	 * @returns {String}
 	 */
 	 */
 	_t( message, values = [] ) {
 	_t( message, values = [] ) {
+		if ( !Array.isArray( values ) ) {
+			values = [ values ];
+		}
+
 		if ( typeof message === 'string' ) {
 		if ( typeof message === 'string' ) {
 			message = { string: message };
 			message = { string: message };
 		}
 		}
@@ -161,13 +169,17 @@ export default class Locale {
 
 
 		const translatedString = _translate( this.uiLanguage, message, amount );
 		const translatedString = _translate( this.uiLanguage, message, amount );
 
 
-		return translatedString
-			.replace( /%(\d+)/g, ( match, index ) => {
-				return ( index < values.length ) ? values[ index ] : match;
-			} );
+		return interpolateString( translatedString, values );
 	}
 	}
 }
 }
 
 
+// Fills the `%0, %1, ...` string placeholders with values.
+function interpolateString( string, values ) {
+	return string.replace( /%(\d+)/g, ( match, index ) => {
+		return ( index < values.length ) ? values[ index ] : match;
+	} );
+}
+
 // Helps determine whether a language is LTR or RTL.
 // Helps determine whether a language is LTR or RTL.
 //
 //
 // @param {String} language The ISO 639-1 language code.
 // @param {String} language The ISO 639-1 language code.

+ 13 - 0
packages/ckeditor5-utils/src/translation-service.js

@@ -9,6 +9,8 @@
  * @module utils/translation-service
  * @module utils/translation-service
  */
  */
 
 
+import CKEditorError from './ckeditorerror';
+
 /* istanbul ignore else */
 /* istanbul ignore else */
 if ( !window.CKEDITOR_TRANSLATIONS ) {
 if ( !window.CKEDITOR_TRANSLATIONS ) {
 	window.CKEDITOR_TRANSLATIONS = {};
 	window.CKEDITOR_TRANSLATIONS = {};
@@ -107,6 +109,17 @@ export function add( language, translations, getPluralForm ) {
  * @returns {String} Translated sentence.
  * @returns {String} Translated sentence.
  */
  */
 export function _translate( language, message, amount = 1 ) {
 export function _translate( language, message, amount = 1 ) {
+	if ( typeof amount !== 'number' ) {
+		/**
+		 * The incorrect value has been passed to the `translation` function. This probably was caused
+		 * by the incorrect message interpolation of a plural form. Note that for messages supporting plural forms
+		 * the second argument of the `t()` function should always be a number or an array with number as the first element.
+		 *
+		 * @error translation-service-amount-not-a-number
+		 */
+		throw new CKEditorError( 'translation-service-amount-not-a-number: Expecting `amount` to be a number.', null, { amount } );
+	}
+
 	const numberOfLanguages = getNumberOfLanguages();
 	const numberOfLanguages = getNumberOfLanguages();
 
 
 	if ( numberOfLanguages === 1 ) {
 	if ( numberOfLanguages === 1 ) {

+ 32 - 2
packages/ckeditor5-utils/tests/locale.js

@@ -10,6 +10,7 @@ import {
 	add as addTranslations,
 	add as addTranslations,
 	_clear as clearTranslations
 	_clear as clearTranslations
 } from '../src/translation-service';
 } from '../src/translation-service';
+import { expectToThrowCKEditorError } from './_utils/utils';
 
 
 describe( 'Locale', () => {
 describe( 'Locale', () => {
 	afterEach( () => {
 	afterEach( () => {
@@ -152,7 +153,7 @@ describe( 'Locale', () => {
 			expect( t( { string: 'foo', context: 'bar' } ) ).to.equal( 'foo_bar_pl' );
 			expect( t( { string: 'foo', context: 'bar' } ) ).to.equal( 'foo_bar_pl' );
 		} );
 		} );
 
 
-		it( 'should translate a plural form to the target ui language based on the first value and interpolate the string', () => {
+		it( 'should translate a message supporting plural forms', () => {
 			const t = locale.t;
 			const t = locale.t;
 
 
 			expect( t( { string: 'bar', plural: '%0 bars' }, [ 1 ] ), 1 ).to.equal( 'bar_pl_0' );
 			expect( t( { string: 'bar', plural: '%0 bars' }, [ 1 ] ), 1 ).to.equal( 'bar_pl_0' );
@@ -160,7 +161,7 @@ describe( 'Locale', () => {
 			expect( t( { string: 'bar', plural: '%0 bars' }, [ 5 ] ), 3 ).to.equal( '5 bar_pl_2' );
 			expect( t( { string: 'bar', plural: '%0 bars' }, [ 5 ] ), 3 ).to.equal( '5 bar_pl_2' );
 		} );
 		} );
 
 
-		it( 'should translate a message supporting plural form with a context', () => {
+		it( 'should translate a message supporting plural forms with a context', () => {
 			const t = locale.t;
 			const t = locale.t;
 
 
 			addTranslations( 'pl', {
 			addTranslations( 'pl', {
@@ -187,6 +188,35 @@ describe( 'Locale', () => {
 			expect( t( '%1 - %0 - %2' ) ).to.equal( '%1 - %0 - %2' );
 			expect( t( '%1 - %0 - %2' ) ).to.equal( '%1 - %0 - %2' );
 			expect( t( '%1 - %0 - %2', [ 'a' ] ) ).to.equal( '%1 - a - %2' );
 			expect( t( '%1 - %0 - %2', [ 'a' ] ) ).to.equal( '%1 - a - %2' );
 		} );
 		} );
+
+		it( 'should interpolate a message with a provided value (shorthand version)', () => {
+			const t = locale.t;
+
+			expect( t( 'Add %0', 'space' ) ).to.equal( 'Add space' );
+			expect( t( 'Remove %0 %1', 'spaces' ) ).to.equal( 'Remove spaces %1' );
+
+			expect( t( '%0 bar %0', 'foo' ) ).to.equal( 'foo bar foo' );
+		} );
+
+		it( 'should throw an error when a value used to determine the plural version is not a number', () => {
+			const t = locale.t;
+
+			expectToThrowCKEditorError( () => {
+				t( { string: 'Add space', plural: 'Add %0 spaces' }, 'space' );
+			}, /translation-service-amount-not-a-number:/, null, { amount: 'space' } );
+
+			expectToThrowCKEditorError( () => {
+				t( { string: 'Add space', plural: 'Add %0 spaces' }, [ 'space' ] );
+			}, /translation-service-amount-not-a-number:/, null, { amount: 'space' } );
+
+			expect( () => {
+				t( { string: 'Add space', plural: 'Add %0 spaces' }, [ 3 ] );
+				t( { string: 'Add space', plural: 'Add %0 spaces' }, 3 );
+				t( { string: 'Add %1', plural: 'Add %0 %1' }, [ 3, 'spaces' ] );
+				t( { string: 'Add %0' }, [ 'space' ] );
+				t( { string: 'Add %0' }, 'space' );
+			} ).to.not.throw();
+		} );
 	} );
 	} );
 
 
 	describe( 'language()', () => {
 	describe( 'language()', () => {