8
0
Просмотр исходного кода

Merge branch 'master' into t/ckeditor5/416d

Aleksander Nowodzinski 6 лет назад
Родитель
Сommit
72b32d422f

+ 19 - 0
packages/ckeditor5-utils/CHANGELOG.md

@@ -1,6 +1,25 @@
 Changelog
 =========
 
+## [14.0.0](https://github.com/ckeditor/ckeditor5-utils/compare/v13.0.1...v14.0.0) (2019-08-26)
+
+### Features
+
+* Add feature detection of Unicode properties entities' support. ([21c0f6b](https://github.com/ckeditor/ckeditor5-utils/commit/21c0f6b))
+* Allowed specifying editor content language in `Locale`. Implemented the (UI and content) language direction discovery in `Locale`. Implemented `Locale#uiLanguage`, `Locale#uiLanguageDirection`, `Locale#contentLanguage`, and `Locale#contentLanguageDirection` properties. See [ckeditor/ckeditor5#1151](https://github.com/ckeditor/ckeditor5/issues/1151). ([91c95f3](https://github.com/ckeditor/ckeditor5-utils/commit/91c95f3))
+
+### Other changes
+
+* The issue tracker for this package was moved to https://github.com/ckeditor/ckeditor5/issues. See [ckeditor/ckeditor5#1988](https://github.com/ckeditor/ckeditor5/issues/1988). ([71469ac](https://github.com/ckeditor/ckeditor5-utils/commit/71469ac))
+* Removed the CKEditor 5 logger and its usage. Part of [ckeditor/ckeditor5#383](https://github.com/ckeditor/ckeditor5/issues/383). ([584ef1d](https://github.com/ckeditor/ckeditor5-utils/commit/584ef1d))
+
+### BREAKING CHANGES
+
+* The`Locale()` constructor arguments syntax has changed. Please refer to the API documentation to learn more.
+* The `Locale#language` property has been deprecated by `Locale#uiLanguage`. Please refer to the API documentation to learn more.
+* Removed the CKEditor 5 logger utility.
+
+
 ## [13.0.1](https://github.com/ckeditor/ckeditor5-utils/compare/v13.0.0...v13.0.1) (2019-07-10)
 
 Internal changes only (updated dependencies, documentation, etc.).

+ 1 - 1
packages/ckeditor5-utils/docs/api/utils.md

@@ -26,5 +26,5 @@ The source code of this package is available on GitHub in https://github.com/cke
 
 * [`@ckeditor/ckeditor5-utils` on npm](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)
 * [`ckeditor/ckeditor5-utils` on GitHub](https://github.com/ckeditor/ckeditor5-utils)
-* [Issue tracker](https://github.com/ckeditor/ckeditor5-utils/issues)
+* [Issue tracker](https://github.com/ckeditor/ckeditor5/issues)
 * [Changelog](https://github.com/ckeditor/ckeditor5-utils/blob/master/CHANGELOG.md)

+ 7 - 6
packages/ckeditor5-utils/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@ckeditor/ckeditor5-utils",
-  "version": "13.0.1",
+  "version": "14.0.0",
   "description": "Miscellaneous utils used by CKEditor 5.",
   "keywords": [
     "ckeditor",
@@ -9,13 +9,14 @@
     "ckeditor5-lib"
   ],
   "dependencies": {
-    "ckeditor5": "^12.3.1",
+    "ckeditor5": "^12.4.0",
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-build-classic": "^12.3.1",
-    "@ckeditor/ckeditor5-core": "^12.2.1",
-    "@ckeditor/ckeditor5-engine": "^13.2.1",
+    "@ckeditor/ckeditor5-build-classic": "^12.4.0",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.4",
+    "@ckeditor/ckeditor5-core": "^12.3.0",
+    "@ckeditor/ckeditor5-engine": "^14.0.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",
@@ -28,7 +29,7 @@
   "author": "CKSource (http://cksource.com/)",
   "license": "GPL-2.0-or-later",
   "homepage": "https://ckeditor.com/ckeditor-5",
-  "bugs": "https://github.com/ckeditor/ckeditor5-utils/issues",
+  "bugs": "https://github.com/ckeditor/ckeditor5/issues",
   "repository": {
     "type": "git",
     "url": "https://github.com/ckeditor/ckeditor5-utils.git"

+ 4 - 4
packages/ckeditor5-utils/src/emittermixin.js

@@ -429,9 +429,9 @@ export default EmitterMixin;
  * If not, returns `null`.
  *
  * @protected
- * @param {module:utils/emittermixin~EmitterMixin} listeningEmitter Emitter that listens.
+ * @param {module:utils/emittermixin~Emitter} listeningEmitter An emitter that listens.
  * @param {String} listenedToEmitterId Unique emitter id of emitter listened to.
- * @returns {module:utils/emittermixin~EmitterMixin|null}
+ * @returns {module:utils/emittermixin~Emitter|null}
  */
 export function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {
 	if ( listeningEmitter[ _listeningTo ] && listeningEmitter[ _listeningTo ][ listenedToEmitterId ] ) {
@@ -447,7 +447,7 @@ export function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {
  * **Note:** `_emitterId` can be set only once.
  *
  * @protected
- * @param {module:utils/emittermixin~EmitterMixin} emitter Emitter for which id will be set.
+ * @param {module:utils/emittermixin~Emitter} emitter An emitter for which id will be set.
  * @param {String} [id] Unique id to set. If not passed, random unique id will be set.
  */
 export function _setEmitterId( emitter, id ) {
@@ -460,7 +460,7 @@ export function _setEmitterId( emitter, id ) {
  * Returns emitter's unique id.
  *
  * @protected
- * @param {module:utils/emittermixin~EmitterMixin} emitter Emitter which id will be returned.
+ * @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.
  */
 export function _getEmitterId( emitter ) {
 	return emitter[ _emitterId ];

+ 88 - 8
packages/ckeditor5-utils/src/locale.js

@@ -7,29 +7,77 @@
  * @module utils/locale
  */
 
+/* globals console */
+
 import { translate } from './translation-service';
 
+const RTL_LANGUAGE_CODES = [ 'ar', 'fa', 'he', 'ku', 'ug' ];
+
 /**
  * Represents the localization services.
  */
 export default class Locale {
 	/**
-	 * Creates a new instance of the Locale class.
+	 * Creates a new instance of the Locale class. Learn more about
+	 * {@glink features/ui-language configuring language of the editor}.
 	 *
-	 * @param {String} [language='en'] The language code in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
+	 * @param {Object} [options] Locale configuration.
+	 * @param {String} [options.uiLanguage='en'] The editor UI language code in the
+	 * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. See {@link #uiLanguage}.
+	 * @param {String} [options.contentLanguage] The editor content language code in the
+	 * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. If not specified, the same as `options.language`.
+	 * See {@link #contentLanguage}.
 	 */
-	constructor( language ) {
+	constructor( options = {} ) {
+		/**
+		 * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
+		 *
+		 * If the {@link #contentLanguage content language} was not specified in the `Locale` constructor,
+		 * it also defines the language of the content.
+		 *
+		 * @readonly
+		 * @member {String}
+		 */
+		this.uiLanguage = options.uiLanguage || 'en';
+
 		/**
-		 * The language code in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
+		 * The editor content language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
+		 *
+		 * Usually the same as {@link #uiLanguage editor language}, it can be customized by passing an optional
+		 * argument to the `Locale` constructor.
 		 *
 		 * @readonly
 		 * @member {String}
 		 */
-		this.language = language || 'en';
+		this.contentLanguage = options.contentLanguage || this.uiLanguage;
 
 		/**
-		 * Translates the given string to the {@link #language}. This method is also available in {@link module:core/editor/editor~Editor#t}
-		 * and {@link module:ui/view~View#t}.
+		 * Text direction of the {@link #uiLanguage editor UI language}. Either `'ltr'` or `'rtl'`.
+		 *
+		 * @readonly
+		 * @member {String}
+		 */
+		this.uiLanguageDirection = getLanguageDirection( this.uiLanguage );
+
+		/**
+		 * Text direction of the {@link #contentLanguage editor content language}.
+		 *
+		 * If the content language was passed directly to the `Locale` constructor, this property represents the
+		 * direction of that language.
+		 *
+		 * If the {@link #contentLanguage editor content language} was derived from the {@link #uiLanguage editor language},
+		 * the content language direction is the same as the {@link #uiLanguageDirection UI language direction}.
+		 *
+		 * The value is either `'ltr'` or `'rtl'`.
+		 *
+		 * @readonly
+		 * @member {String}
+		 */
+		this.contentLanguageDirection = getLanguageDirection( this.contentLanguage );
+
+		/**
+		 * Translates the given string to the {@link #uiLanguage}. This method is also available in
+		 * {@link module:core/editor/editor~Editor#t} and {@link module:ui/view~View#t}.
 		 *
 		 * The strings may contain placeholders (`%<index>`) for values which are passed as the second argument.
 		 * `<index>` is the index in the `values` array.
@@ -49,13 +97,37 @@ export default class Locale {
 		this.t = ( ...args ) => this._t( ...args );
 	}
 
+	/**
+	 * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
+	 *
+	 * **Note**: This property has been deprecated. Please use {@link #uiLanguage} and {@link #contentLanguage}
+	 * properties instead.
+	 *
+	 * @deprecated
+	 * @member {String}
+	 */
+	get language() {
+		/**
+		 * The {@link module:utils/locale~Locale#language `Locale#language`} property has been deprecated and will
+		 * be removed in the near future. Please use {@link #uiLanguage} and {@link #contentLanguage} properties instead.
+		 *
+		 * @error locale-deprecated-language-property
+		 */
+		console.warn(
+			'locale-deprecated-language-property: ' +
+			'The Locale#language property has been deprecated and will be removed in the near future. ' +
+			'Please use #uiLanguage and #contentLanguage properties instead.' );
+
+		return this.uiLanguage;
+	}
+
 	/**
 	 * Base for the {@link #t} method.
 	 *
 	 * @private
 	 */
 	_t( str, values ) {
-		let translatedString = translate( this.language, str );
+		let translatedString = translate( this.uiLanguage, str );
 
 		if ( values ) {
 			translatedString = translatedString.replace( /%(\d+)/g, ( match, index ) => {
@@ -66,3 +138,11 @@ export default class Locale {
 		return translatedString;
 	}
 }
+
+// Helps determine whether a language is LTR or RTL.
+//
+// @param {String} language The ISO 639-1 language code.
+// @returns {String} 'ltr' or 'rtl
+function getLanguageDirection( languageCode ) {
+	return RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr';
+}

BIN
packages/ckeditor5-utils/tests/_assets/sample2.png


BIN
packages/ckeditor5-utils/tests/_assets/sample3.png


+ 105 - 5
packages/ckeditor5-utils/tests/locale.js

@@ -3,26 +3,113 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
 
+/* globals console */
+
 import Locale from '../src/locale';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 
 describe( 'Locale', () => {
 	let locale;
 
+	testUtils.createSinonSandbox();
+
 	beforeEach( () => {
 		locale = new Locale();
 	} );
 
 	describe( 'constructor', () => {
-		it( 'sets the language', () => {
-			const locale = new Locale( 'pl' );
+		it( 'sets the #language', () => {
+			const locale = new Locale( {
+				uiLanguage: 'pl'
+			} );
 
-			expect( locale ).to.have.property( 'language', 'pl' );
+			expect( locale ).to.have.property( 'uiLanguage', 'pl' );
 		} );
 
-		it( 'defaults language to en', () => {
+		it( 'sets the #contentLanguage', () => {
+			const locale = new Locale( {
+				uiLanguage: 'pl',
+				contentLanguage: 'en'
+			} );
+
+			expect( locale ).to.have.property( 'uiLanguage', 'pl' );
+			expect( locale ).to.have.property( 'contentLanguage', 'en' );
+		} );
+
+		it( 'defaults #language to en', () => {
 			const locale = new Locale();
 
-			expect( locale ).to.have.property( 'language', 'en' );
+			expect( locale ).to.have.property( 'uiLanguage', 'en' );
+		} );
+
+		it( 'inherits the #contentLanguage from the #language (if not passed)', () => {
+			const locale = new Locale( {
+				uiLanguage: 'pl'
+			} );
+
+			expect( locale ).to.have.property( 'uiLanguage', 'pl' );
+			expect( locale ).to.have.property( 'contentLanguage', 'pl' );
+		} );
+
+		it( 'determines the #uiLanguageDirection', () => {
+			expect( new Locale( {
+				uiLanguage: 'pl'
+			} ) ).to.have.property( 'uiLanguageDirection', 'ltr' );
+
+			expect( new Locale( {
+				uiLanguage: 'en'
+			} ) ).to.have.property( 'uiLanguageDirection', 'ltr' );
+
+			expect( new Locale( {
+				uiLanguage: 'ar'
+			} ) ).to.have.property( 'uiLanguageDirection', 'rtl' );
+
+			expect( new Locale( {
+				uiLanguage: 'fa'
+			} ) ).to.have.property( 'uiLanguageDirection', 'rtl' );
+
+			expect( new Locale( {
+				uiLanguage: 'he'
+			} ) ).to.have.property( 'uiLanguageDirection', 'rtl' );
+
+			expect( new Locale( {
+				uiLanguage: 'ku'
+			} ) ).to.have.property( 'uiLanguageDirection', 'rtl' );
+
+			expect( new Locale( {
+				uiLanguage: 'ug'
+			} ) ).to.have.property( 'uiLanguageDirection', 'rtl' );
+		} );
+
+		it( 'determines the #contentLanguageDirection (not passed)', () => {
+			expect( new Locale( {
+				uiLanguage: 'pl'
+			} ) ).to.have.property( 'contentLanguageDirection', 'ltr' );
+
+			expect( new Locale( {
+				uiLanguage: 'en'
+			} ) ).to.have.property( 'contentLanguageDirection', 'ltr' );
+
+			expect( new Locale( {
+				uiLanguage: 'ar'
+			} ) ).to.have.property( 'contentLanguageDirection', 'rtl' );
+		} );
+
+		it( 'determines the #contentLanguageDirection (passed)', () => {
+			expect( new Locale( {
+				uiLanguage: 'pl',
+				contentLanguage: 'pl'
+			} ) ).to.have.property( 'contentLanguageDirection', 'ltr' );
+
+			expect( new Locale( {
+				uiLanguage: 'en',
+				contentLanguage: 'ar'
+			} ) ).to.have.property( 'contentLanguageDirection', 'rtl' );
+
+			expect( new Locale( {
+				uiLanguage: 'ar',
+				contentLanguage: 'pl'
+			} ) ).to.have.property( 'contentLanguageDirection', 'ltr' );
 		} );
 	} );
 
@@ -59,4 +146,17 @@ describe( 'Locale', () => {
 			expect( t( '%1 - %0 - %2', [ 'a' ] ) ).to.equal( '%1 - a - %2' );
 		} );
 	} );
+
+	describe( 'language()', () => {
+		it( 'should return #uiLanguage', () => {
+			expect( locale.language ).to.equal( locale.uiLanguage );
+		} );
+
+		it( 'should warn about deprecation', () => {
+			const stub = testUtils.sinon.stub( console, 'warn' );
+
+			expect( locale.language ).to.equal( 'en' );
+			sinon.assert.calledWithMatch( stub, 'locale-deprecated-language-property' );
+		} );
+	} );
 } );

+ 28 - 0
packages/ckeditor5-utils/tests/manual/locale/locale.html

@@ -0,0 +1,28 @@
+<h2>language = 'en' (LTR)</h2>
+
+<div id="editor-language">
+	<p>This is an <a href="https://ckeditor.com">editor</a> instance.</p>
+	<figure class="image image-style-side"><img src="./sample.jpg"><figcaption>Caption</figcaption></figure>
+</div>
+
+<h2>language = 'ar' (RTL)</h2>
+
+<div id="editor-language-rtl">
+	<p>مرحبا <a href="https://ckeditor.com">editor</a></p>
+	<figure class="image image-style-side"><img src="./sample.jpg"><figcaption>Caption</figcaption></figure>
+</div>
+
+<h2>language = 'en' (LTR), <br />contentLanguage = 'ar' (RTL)</h2>
+
+<div id="editor-language-rtl-content">
+	<p>مرحبا <a href="https://ckeditor.com">editor</a></p>
+	<figure class="image image-style-side"><img src="./sample.jpg"><figcaption>Caption</figcaption></figure>
+</div>
+
+<h2>language = 'ar' (RTL), <br />contentLanguage = 'en' (LTR)</h2>
+
+<div id="editor-language-rtl-ui">
+	<p>This is an <a href="https://ckeditor.com">editor</a> instance.</p>
+	<figure class="image image-style-side"><img src="./sample.jpg"><figcaption>Caption</figcaption></figure>
+</div>
+

+ 88 - 0
packages/ckeditor5-utils/tests/manual/locale/locale.js

@@ -0,0 +1,88 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* global window, console, document */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
+
+const config = {
+	plugins: [ ArticlePluginSet ],
+	image: {
+		toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]
+	},
+	table: {
+		contentToolbar: [
+			'tableColumn',
+			'tableRow',
+			'mergeTableCells'
+		]
+	},
+	toolbar: [
+		'heading',
+		'|',
+		'bold', 'italic', 'link',
+		'bulletedList', 'numberedList',
+		'blockQuote', 'insertTable', 'mediaEmbed',
+		'undo', 'redo'
+	]
+};
+
+ClassicEditor
+	.create( document.querySelector( '#editor-language' ), Object.assign( {}, config, {
+		language: 'en'
+	} ) )
+	.then( newEditor => {
+		window.editorLanguage = newEditor;
+
+		console.log( 'Editor created, locale:', newEditor.locale );
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );
+
+ClassicEditor
+	.create( document.querySelector( '#editor-language-rtl' ), Object.assign( {}, config, {
+		language: 'ar'
+	} ) )
+	.then( newEditor => {
+		window.editorLanguageRTL = newEditor;
+
+		console.log( 'Editor created, locale:', newEditor.locale );
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );
+
+ClassicEditor
+	.create( document.querySelector( '#editor-language-rtl-content' ), Object.assign( {}, config, {
+		language: {
+			content: 'ar'
+		}
+	} ) )
+	.then( newEditor => {
+		window.editorLanguageRTLContent = newEditor;
+
+		console.log( 'Editor created, locale:', newEditor.locale );
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );
+
+ClassicEditor
+	.create( document.querySelector( '#editor-language-rtl-ui' ), Object.assign( {}, config, {
+		language: {
+			ui: 'ar',
+			content: 'en'
+		}
+	} ) )
+	.then( newEditor => {
+		window.editorLanguageRTLUI = newEditor;
+
+		console.log( 'Editor created, locale:', newEditor.locale );
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

+ 39 - 0
packages/ckeditor5-utils/tests/manual/locale/locale.md

@@ -0,0 +1,39 @@
+## Editor locales
+
+**Note**: For the best testing, run manual tests adding Arabic to [additional languages configuration](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/testing-environment.html#running-manual-tests).
+
+---
+
+Play with different editor configurations to make sure localization and the right–to–left language support work fine.
+
+### language = 'en' (LTR)
+
+1. Make sure the UI of the editor is English.
+2. Make sure the language of the content is English (`lang` attribute of th editable) and aligned to the **left** side.
+3. Delete **all** the content.
+4. Write something in Arabic.
+5. The text you've just written should be aligned **right**.
+
+### language = 'ar' (RTL)
+
+1. Make sure the UI of the editor is Arabic.
+2. Make sure the language of the content is Arabic (`lang` attribute of th editable) and aligned to the **right** side.
+3. Delete **all** the content.
+4. Write something in English.
+5. The text you've just written should be aligned **left**.
+
+### language = 'en' (LTR), contentLanguage = 'ar' (RTL)
+
+1. Make sure the UI of the editor is English.
+2. Make sure the language of the content is Arabic (`lang` attribute of th editable) and aligned to the **right** side.
+3. Delete **all** the content.
+4. Write something in English.
+5. The text you've just written should be aligned **right**.
+
+### language = 'ar' (RTL), contentLanguage = 'en' (LTR)
+
+1. Make sure the UI of the editor is Arabic.
+2. Make sure the language of the content is English (`lang` attribute of th editable) and aligned to the **left** side.
+3. Delete **all** the content.
+4. Write something in Arabic.
+5. The text you've just written should be aligned **left**.

BIN
packages/ckeditor5-utils/tests/manual/locale/sample.jpg