Bladeren bron

Merge branch 'master' into stable

Piotrek Koszuliński 6 jaren geleden
bovenliggende
commit
6d768a91e9
34 gewijzigde bestanden met toevoegingen van 2254 en 1239 verwijderingen
  1. 65 1
      CHANGELOG.md
  2. 0 0
      docs/_snippets/features/build-ui-language-source.html
  3. 12 0
      docs/_snippets/features/build-ui-language-source.js
  4. 4 0
      docs/_snippets/features/ui-language-content.html
  5. 25 0
      docs/_snippets/features/ui-language-content.js
  6. 4 0
      docs/_snippets/features/ui-language-rtl.html
  7. 23 0
      docs/_snippets/features/ui-language-rtl.js
  8. 1 1
      docs/_snippets/features/ui-language.html
  9. 2 5
      docs/_snippets/features/ui-language.js
  10. 1 1
      docs/_snippets/features/wproofreader.html
  11. 0 2
      docs/_snippets/features/wproofreader.js
  12. BIN
      docs/assets/img/builds-content-styles.png
  13. 10 16
      docs/builds/guides/faq.md
  14. 54 2
      docs/builds/guides/frameworks/angular.md
  15. 281 204
      docs/builds/guides/frameworks/react.md
  16. 4 4
      docs/builds/guides/integration/advanced-setup.md
  17. 193 0
      docs/builds/guides/integration/content-styles.md
  18. 7 1
      docs/features/image-upload.md
  19. 0 12
      docs/features/spell-checker.md
  20. 70 21
      docs/features/ui-language.md
  21. 12 1
      docs/framework/guides/contributing/development-environment.md
  22. 5 1
      docs/framework/guides/contributing/testing-environment.md
  23. 2 2
      docs/framework/guides/development-tools.md
  24. 5 5
      docs/framework/guides/quick-start.md
  25. 3 3
      docs/framework/guides/tutorials/implementing-a-block-widget.md
  26. 3 3
      docs/framework/guides/tutorials/implementing-an-inline-widget.md
  27. 7 1
      docs/umberto.json
  28. 58 57
      package.json
  29. 241 0
      scripts/docs/build-content-styles.js
  30. 76 0
      scripts/docs/content-styles/ckeditor.js
  31. 35 0
      scripts/docs/content-styles/list-content-styles.js
  32. 38 3
      scripts/docs/snippetadapter.js
  33. 3 3
      scripts/update-stable-branches.sh
  34. 1010 890
      yarn.lock

File diff suppressed because it is too large
+ 65 - 1
CHANGELOG.md


+ 0 - 0
docs/_snippets/features/build-ui-language-source.html


+ 12 - 0
docs/_snippets/features/build-ui-language-source.js

@@ -0,0 +1,12 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals window */
+
+/* config { "additionalLanguages": [ "ar", "es" ] } */
+
+import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
+
+window.ClassicEditor = ClassicEditor;

File diff suppressed because it is too large
+ 4 - 0
docs/_snippets/features/ui-language-content.html


+ 25 - 0
docs/_snippets/features/ui-language-content.js

@@ -0,0 +1,25 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals ClassicEditor, console, window, document */
+
+import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
+
+ClassicEditor
+	.create( document.querySelector( '#snippet-ui-language-content' ), {
+		language: {
+			content: 'ar'
+		},
+		cloudServices: CS_CONFIG,
+		toolbar: {
+			viewportTopOffset: window.getViewportTopOffsetConfig()
+		}
+	} )
+	.then( editor => {
+		window.editor = editor;
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

File diff suppressed because it is too large
+ 4 - 0
docs/_snippets/features/ui-language-rtl.html


+ 23 - 0
docs/_snippets/features/ui-language-rtl.js

@@ -0,0 +1,23 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals ClassicEditor, console, window, document */
+
+import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
+
+ClassicEditor
+	.create( document.querySelector( '#snippet-ui-language-rtl' ), {
+		language: 'ar',
+		cloudServices: CS_CONFIG,
+		toolbar: {
+			viewportTopOffset: window.getViewportTopOffsetConfig()
+		}
+	} )
+	.then( editor => {
+		window.editor = editor;
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

File diff suppressed because it is too large
+ 1 - 1
docs/_snippets/features/ui-language.html


+ 2 - 5
docs/_snippets/features/ui-language.js

@@ -3,16 +3,13 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
 
-/* globals console, window, document */
-
-/* config { "language": "de" } */
-
-import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
+/* globals ClassicEditor, console, window, document */
 
 import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
 
 ClassicEditor
 	.create( document.querySelector( '#snippet-ui-language' ), {
+		language: 'es',
 		cloudServices: CS_CONFIG,
 		toolbar: {
 			viewportTopOffset: window.getViewportTopOffsetConfig()

+ 1 - 1
docs/_snippets/features/wproofreader.html

@@ -6,7 +6,7 @@
 		serviceId: '1:Eebp63-lWHbt2-ASpHy4-AYUpy2-fo3mk4-sKrza1-NsuXy4-I1XZC2-0u2F54-aqYWd1-l3Qf14-umd'
 	};
 </script>
-<div id="snippet-wproofreader" >
+<div id="snippet-wproofreader">
 	<p>Typos hapen. We striving to correct them. Hover on the marked words for instant correction suggestions or click the dialog icon in the bottom right corner to have the whole text proofread at once.</p>
 	<p>You can also paste your own text here to have its spelling and grammar checked.</p>
 </div>

+ 0 - 2
docs/_snippets/features/wproofreader.js

@@ -16,8 +16,6 @@ ClassicEditor
 	} )
 	.then( editor => {
 		window.editor = editor;
-		// Temporary fix for WProofreader dialog (https://github.com/WebSpellChecker/wproofreader/issues/17).
-		editor.ui.getEditableElement().editor = editor;
 	} )
 	.catch( err => {
 		console.error( err.stack );

BIN
docs/assets/img/builds-content-styles.png


+ 10 - 16
docs/builds/guides/faq.md

@@ -10,7 +10,7 @@ order: 40
 
 Unlike [CKEditor 4](https://ckeditor.com/ckeditor-4/), CKEditor 5 implements a custom {@link framework/guides/architecture/editing-engine data model}. This means that every piece of content that is loaded into the editor needs to be converted to that model and then rendered back to the view.
 
-Each kind of content must be handled by some feature. For instance the [ckeditor5-basic-styles](https://www.npmjs.com/package/@ckeditor/ckeditor5-basic-styles) package handles HTML elements such as `<b>`, `<i>`, `<u>`, etc. along with their representation in the model. The feature defines the two–way conversion between the HTML (view) and the editor model.
+Each kind of content must be handled by some feature. For instance the [`ckeditor5-basic-styles`](https://www.npmjs.com/package/@ckeditor/ckeditor5-basic-styles) package handles HTML elements such as `<b>`, `<i>`, `<u>`, etc. along with their representation in the model. The feature defines the two–way conversion between the HTML (view) and the editor model.
 
 If you load some content unknown to any editor feature, it will be dropped. If you want all the HTML5 elements to be supported, you need to write plugins to support them. Once you do that, CKEditor 5 will not filter anything out.
 
@@ -22,15 +22,9 @@ See the [relevant issue](https://github.com/ckeditor/ckeditor5/issues/592) on Gi
 
 ## What happened to the `contents.css` file? How do I style the content of the editor?
 
-There is no such thing as the `contents.css` file because in CKEditor 5 features bring their own content styles, which are by default included in the JavaScript build and {@link framework/guides/theme-customization#styles-processing-and-bundling loaded by the style–loader} (they can be {@link builds/guides/integration/advanced-setup#option-extracting-css extracted}, too). It optimizes the size of the builds as the styles of unused features are simply excluded.
+There is no such thing as the `contents.css` file because in CKEditor 5 features bring their own content styles, which are by default included in the JavaScript build and {@link framework/guides/theme-customization#styles-processing-and-bundling loaded by the style loader}. It optimizes the size of the builds as the styles of unused features are simply excluded.
 
-Although some styles are provided by the features, it is up to the developers to make sure the content created by CKEditor 5 is properly styled, both in the front–end and in the back–end. To style the content in the editor (back–end), use the `.ck-content` CSS class:
-
-```css
-.ck-content a {
-	color: teal;
-}
-```
+You can get the full list of editor content styles in a {@link builds/guides/integration/content-styles dedicated guide}. You can also {@link builds/guides/integration/advanced-setup#option-extracting-css extract all CSS} brought by CKEditor 5 (content and UI) to a separate file when creating a custom editor build.
 
 ## The build I downloaded is missing some features. How do I add them?
 
@@ -40,7 +34,7 @@ You can learn which editor features are available in the {@link features/index f
 
 ## Where are the `editor.insertHtml()` and `editor.insertText()` methods? How to insert some content?
 
-Because CKEditor 5 uses a custom {@link framework/guides/architecture/editing-engine data model}, whenever you want to insert anything, you should modify the model first, which is then converted back to the view where the users input their content (called editable). In CKEditor 5, HTML is just one of many possible output formats. You can learn more about the ways of changing the model in the {@link framework/guides/architecture/editing-engine#changing-the-model dedicated guide}.
+Because CKEditor 5 uses a custom {@link framework/guides/architecture/editing-engine data model}, whenever you want to insert anything, you should modify the model first, which is then converted back to the view where the users input their content (called "editable"). In CKEditor 5, HTML is just one of many possible output formats. You can learn more about the ways of changing the model in the {@link framework/guides/architecture/editing-engine#changing-the-model dedicated guide}.
 
 To insert a new link at the current position, use the following snippet:
 
@@ -80,11 +74,11 @@ By default, CKEditor 5 has no global registry of editor instances. But if necess
 
 The {@link features/image Image} and {@link features/image-upload Image upload} features are enabled by default in all editor builds. However, to fully enable image upload when installing CKEditor 5 you need to configure one of the available upload adapters. Check out the {@link features/image-upload comprehensive "Image upload" guide} to find out the best image upload strategy for your project.
 
-## How to use CKEditor 5 with frameworks (Angular, React, etc.)?
+## How to use CKEditor 5 with frameworks (Angular, React, Vue, etc.)?
 
 For the full list of official integrations see the {@link builds/guides/frameworks/overview#official-wysiwyg-editor-integrations "Official integrations"} section.
 
-If an official integration for the framework of your choice does not exist yet, make sure to read the {@link builds/guides/frameworks/overview "Integrating CKEditor 5 with JavaScript frameworks"} guide. CKEditor 5 offers a rich JavaScript API and ready to use builds which make it possible to use CKEditor 5 with whichever framework you need.
+If an official integration for the framework of your choice does not exist yet, make sure to read the {@link builds/guides/frameworks/overview "Integrating CKEditor 5 with JavaScript frameworks"} guide. CKEditor 5 offers a rich JavaScript API and ready-to-use builds that make it possible to use CKEditor 5 with whichever framework you need.
 
 We plan to provide more official integrations with time. [Your feedback on what should we work on next](https://github.com/ckeditor/ckeditor5/issues/1002) will be most welcome!
 
@@ -114,7 +108,7 @@ Learn more about {@link builds/guides/integration/advanced-setup#webpack-configu
 
 ## How to get the editor instance object from the DOM element?
 
-If you have a reference to the editor editable's DOM element (that's the one with the `.ck-editor__editable` class and the `contenteditable` attribute), you can access the editor instance this editable element belongs to using the `ckeditorInstance` property:
+If you have a reference to the editor editable's DOM element (the one with the `.ck-editor__editable` class and the `contenteditable` attribute), you can access the editor instance this editable element belongs to using the `ckeditorInstance` property:
 
 ```html
 <!-- The editable element in the editor's DOM structure. -->
@@ -124,7 +118,7 @@ If you have a reference to the editor editable's DOM element (that's the one wit
 ```
 
 ```js
-// A reference to the editor editable element in DOM.
+// A reference to the editor editable element in the DOM.
 const domEditableElement = document.querySelector( '.ck-editor__editable' );
 
 // Get the editor instance from the editable element.
@@ -146,14 +140,14 @@ editor.editing.view.change( writer => {
 } );
 ```
 
-If you do not have the reference to the editor instance but you have access to the editable element in DOM, you can [access it using the `ckeditorInstance` property](#how-to-get-the-editor-instance-object-from-the-dom-element) and then use the same API to set the attribute:
+If you do not have the reference to the editor instance but you have access to the editable element in the DOM, you can [access it using the `ckeditorInstance` property](#how-to-get-the-editor-instance-object-from-the-dom-element) and then use the same API to set the attribute:
 
 ```js
 const domEditableElement = document.querySelector( '.ck-editor__editable' );
 const editorInstance = domEditableElement.ckeditorInstance;
 
 editorInstance.editing.view.change( writer => {
-	// Map the editable element in DOM to the editable element in editor's view.
+	// Map the editable element in the DOM to the editable element in the editor's view.
 	const viewEditableRoot = editorInstance.editing.view.domConverter.mapDomToView( domEditableElement );
 
 	writer.setAttribute( 'myAttribute', 'value', viewEditableRoot );

+ 54 - 2
docs/builds/guides/frameworks/angular.md

@@ -24,7 +24,7 @@ In your existing Angular project, install the [CKEditor 5 WYSIWYG editor compone
 npm install --save @ckeditor/ckeditor5-angular
 ```
 
-Install one of the {@link builds/guides/overview#available-builds official editor builds} or {@link builds/guides/development/custom-builds create a custom one} (e.g. if you want to install more plugins or customize something that cannot be controlled with the {@link builds/guides/integration/configuration editor configuration}).
+Install one of the {@link builds/guides/overview#available-builds official editor builds} or [create a custom one](#using-a-custom-ckeditor-5-build).
 
 Assuming that you picked [`@ckeditor/ckeditor5-build-classic`](https://www.npmjs.com/package/@ckeditor/ckeditor5-build-classic):
 
@@ -68,7 +68,7 @@ Finally, use the `<ckeditor>` tag in the template to run the rich text editor:
 
 Rebuild your application and CKEditor 5 should greet you with "Hello, world!".
 
-### Note: Using the Document editor build
+### Using the Document editor build
 
 If you want to use the {@link framework/guides/document-editor document editor build}, you need to {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create add the toolbar to the DOM manually}.
 
@@ -77,6 +77,7 @@ import * as DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
 
 @Component( {
 	// ...
+} )
 export class MyComponent {
 	public Editor = DecoupledEditor;
 
@@ -95,6 +96,57 @@ And then, in the template:
 <ckeditor [editor]="Editor" data="<p>Hello, world!</p>" (ready)="onReady($event)"></ckeditor>
 ```
 
+### Using a custom CKEditor 5 build
+
+If you want to add more plugins to the existing build or customize something that cannot be controlled with the {@link builds/guides/integration/configuration editor configuration} you should create a custom build first, using the {@link builds/guides/development/custom-builds create a custom build guide}.
+
+You should finish the above tutorial with the generated `ckeditor.js` file (and corresponding translation files). In the next step you should copy it to the `src` directory and import it to the component file.
+
+```ts
+import * as Editor from 'path/to/the/ckeditor';
+
+@Component( {
+	// ...
+} )
+export class MyComponent {
+	public Editor = Editor;
+	// ...
+}
+```
+
+Note that to allow importing JavaScript files without providing their corresponding types you need to set `allowJs` to `true` in the `tsconfig.json` file. Also, make sure that you target `ES6` or higher, otherwise you are likely to end up with [a weird transpilation error](https://github.com/ckeditor/ckeditor5-angular/issues/20) in the production build.
+
+```json
+"compilerOptions": {
+	"allowJs": true,
+	"target": "es2015"
+	// other options
+}
+```
+
+<info-box>
+	If you cannot set the target higher than `es5`, try to set `"buildOptimizer": false` which will produce a bigger, but correct production build.
+</info-box>
+
+### Strict mode project tips
+
+If you have the strict mode set in your project, you need to specify types for CKEditor 5 packages. Otherwise you will get the `Could not find a declaration file for module` error.
+
+To fix that you need to create a TypeScript declaration file and declare modules that miss their types:
+
+```ts
+// typings.d.ts
+
+// You should specify the CKEditor 5 build you use here:
+declare module '@ckeditor/ckeditor5-build-classic' {
+	const ClassicEditorBuild: any;
+
+	export = ClassicEditorBuild;
+}
+```
+
+Unfortunately, CKEditor 5 builds do not ship with corresponding TypeScript typings yet. If you are interested in this topic you can add your vote or a comment [here](https://github.com/ckeditor/ckeditor5/issues/504).
+
 ## Integration with `ngModel`
 
 The component implements the [`ControlValueAccessor`](https://angular.io/api/forms/ControlValueAccessor) interface and works with the `ngModel`. Here is how to use it:

+ 281 - 204
docs/builds/guides/frameworks/react.md

@@ -30,31 +30,31 @@ import CKEditor from '@ckeditor/ckeditor5-react';
 import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
 
 class App extends Component {
-    render() {
-        return (
-            <div className="App">
-                <h2>Using CKEditor 5 build in React</h2>
-                <CKEditor
-                    editor={ ClassicEditor }
-                    data="<p>Hello from CKEditor 5!</p>"
-                    onInit={ editor => {
-                        // You can store the "editor" and use when it is needed.
-                        console.log( 'Editor is ready to use!', editor );
-                    } }
-                    onChange={ ( event, editor ) => {
-                        const data = editor.getData();
-                        console.log( { event, editor, data } );
-                    } }
-                    onBlur={ editor => {
-                        console.log( 'Blur.', editor );
-                    } }
-                    onFocus={ editor => {
-                        console.log( 'Focus.', editor );
-                    } }
-                />
-            </div>
-        );
-    }
+	render() {
+		return (
+			<div className="App">
+				<h2>Using CKEditor 5 build in React</h2>
+				<CKEditor
+					editor={ ClassicEditor }
+					data="<p>Hello from CKEditor 5!</p>"
+					onInit={ editor => {
+						// You can store the "editor" and use when it is needed.
+						console.log( 'Editor is ready to use!', editor );
+					} }
+					onChange={ ( event, editor ) => {
+						const data = editor.getData();
+						console.log( { event, editor, data } );
+					} }
+					onBlur={ ( event, editor ) => {
+						console.log( 'Blur.', editor );
+					} }
+					onFocus={ ( event, editor ) => {
+						console.log( 'Focus.', editor );
+					} }
+				/>
+			</div>
+		);
+	}
 }
 
 export default App;
@@ -67,16 +67,16 @@ The `<CKEditor>` component supports the following properties:
 * `editor` (required) &ndash; The {@link module:core/editor/editor~Editor `Editor`} constructor to use.
 * `data` &ndash; The initial data for the created editor. See the {@link builds/guides/integration/basic-api#interacting-with-the-editor Basic API} guide.
 * `config` &ndash; The editor configuration. See the {@link builds/guides/integration/configuration Configuration} guide.
-* `onChange` &ndash; A function called when the editor's data has changed. See the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`} event.
+* `onInit` &ndash; A function called when the editor was initialized. It receives the initialized {@link module:core/editor/editor~Editor `editor`} as a parameter.
+* `disabled` &ndash; A Boolean value. The {@link module:core/editor/editor~Editor `editor`} is being switched to read-only mode if the property is set to `true`.
+* `onChange` &ndash; A function called when the editor data has changed. See the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`} event.
+* `onBlur` &ndash; A function called when the editor was blurred. See the {@link module:engine/view/document~Document#event:blur `editor.editing.view.document#blur`} event.
+* `onFocus` &ndash; A function called when the editor was focused. See the {@link module:engine/view/document~Document#event:focus `editor.editing.view.document#focus`} event.
 
-	The callback receives two parameters:
+The editor events callbacks (`onChange`, `onBlur`, `onFocus`) receive two parameters:
 
-	1. An {@link module:utils/eventinfo~EventInfo `EventInfo`} object,
-	2. An {@link module:core/editor/editor~Editor `Editor`} instance.
-* `onInit` &ndash; A function called when the editor was initialized. It receives the initialized {@link module:core/editor/editor~Editor `editor`} as a parameter.
-* `onBlur` &ndash; A function called when the editor was blurred. It receives the blurred {@link module:core/editor/editor~Editor `editor`} as a parameter.
-* `onFocus` &ndash; A function called when the editor was focused. It receives the focused {@link module:core/editor/editor~Editor `editor`} as a parameter.
-* `disabled` &ndash; A boolean. The {@link module:core/editor/editor~Editor `editor`} is being switched to read-only mode if the property is set to `true`.
+1. An {@link module:utils/eventinfo~EventInfo `EventInfo`} object.
+2. An {@link module:core/editor/editor~Editor `Editor`} instance.
 
 ### Customizing the builds
 
@@ -113,27 +113,27 @@ If you use the {@link framework/guides/document-editor Document editor}, you nee
 import DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
 
 class App extends Component {
-    render() {
-        return (
-            <div className="App">
-                <h2>CKEditor 5 using a custom build - DecoupledEditor</h2>
-                <CKEditor
-                    onInit={ editor => {
-                        console.log( 'Editor is ready to use!', editor );
-
-                        // Insert the toolbar before the editable area.
-                        editor.ui.getEditableElement().parentElement.insertBefore(
-                            editor.ui.view.toolbar.element,
-                            editor.ui.getEditableElement()
-                        );
-                    } }
-                    onChange={ ( event, editor ) => console.log( { event, editor } ) }
-                    editor={ DecoupledEditor }
-                    data="<p>Hello from CKEditor 5's DecoupledEditor!</p>"
-                    config={ /* the editor configuration */ }
-                />
-        );
-    }
+	render() {
+		return (
+			<div className="App">
+				<h2>CKEditor 5 using a custom build - DecoupledEditor</h2>
+				<CKEditor
+					onInit={ editor => {
+						console.log( 'Editor is ready to use!', editor );
+
+						// Insert the toolbar before the editable area.
+						editor.ui.getEditableElement().parentElement.insertBefore(
+							editor.ui.view.toolbar.element,
+							editor.ui.getEditableElement()
+						);
+					} }
+					onChange={ ( event, editor ) => console.log( { event, editor } ) }
+					editor={ DecoupledEditor }
+					data="<p>Hello from CKEditor 5's DecoupledEditor!</p>"
+					config={ /* the editor configuration */ }
+				/>
+		);
+	}
 }
 
 export default App;
@@ -175,7 +175,7 @@ Before you start modifying the webpack configuration, first install some CKEdito
 
 ```bash
 yarn add \
-	raw-loader@1 \
+	raw-loader@3 \
 	@ckeditor/ckeditor5-dev-utils \
 	@ckeditor/ckeditor5-theme-lark \
 	@ckeditor/ckeditor5-react \
@@ -199,28 +199,28 @@ Then, add two new elements to the exported object under the `module.rules` array
 
 ```js
 {
-  test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
-  use: [ 'raw-loader' ]
+	test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
+	use: [ 'raw-loader' ]
 },
 {
-  test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
-  use: [
-    {
-      loader: 'style-loader',
-      options: {
-        singleton: true
-      }
-    },
-    {
-      loader: 'postcss-loader',
-      options: styles.getPostCssConfig( {
-        themeImporter: {
-          themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
-        },
-        minify: true
-      } )
-    }
-  ]
+	test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
+	use: [
+		{
+			loader: 'style-loader',
+			options: {
+				injectType: 'singletonStyleTag'
+			}
+		},
+		{
+			loader: 'postcss-loader',
+			options: styles.getPostCssConfig( {
+				themeImporter: {
+					themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
+				},
+				minify: true
+			} )
+		}
+	]
 },
 ```
 
@@ -230,12 +230,12 @@ First, find a loader that starts its definition with the following code: `test:
 
 ```js
 {
-  test: cssRegex,
-  exclude: [
-    cssModuleRegex,
-    /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
-  ],
-  // (...)
+	test: cssRegex,
+	exclude: [
+		cssModuleRegex,
+		/ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
+	],
+	// (...)
 }
 ```
 
@@ -243,11 +243,11 @@ Below it, you will find another loader that handles CSS files. You need to disab
 
 ```js
 {
-  test: cssModuleRegex,
-  exclude: [
-    /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
-  ],
-  // (...)
+	test: cssModuleRegex,
+	exclude: [
+		/ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
+	],
+	// (...)
 }
 ```
 
@@ -255,21 +255,21 @@ Finally, exclude CKEditor 5 SVG and CSS files from `file-loader` . Find the last
 
 ```js
 {
-  loader: require.resolve('file-loader'),
-  // Exclude `js` files to keep the "css" loader working as it injects
-  // its runtime that would otherwise be processed through the "file" loader.
-  // Also exclude `html` and `json` extensions so they get processed
-  // by webpack's internal loaders.
-  exclude: [
-    /\.(js|mjs|jsx|ts|tsx)$/,
-    /\.html$/,
-    /\.json$/,
-    /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
-    /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/
-  ],
-  options: {
-    name: 'static/media/[name].[hash:8].[ext]',
-  }
+	loader: require.resolve( 'file-loader' ),
+	// Exclude `js` files to keep the "css" loader working as it injects
+	// its runtime that would otherwise be processed through the "file" loader.
+	// Also exclude `html` and `json` extensions so they get processed
+	// by webpack's internal loaders.
+	exclude: [
+		/\.(js|mjs|jsx|ts|tsx)$/,
+		/\.html$/,
+		/\.json$/,
+		/ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
+		/ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/
+	],
+	options: {
+		name: 'static/media/[name].[hash:8].[ext]',
+	}
 }
 ```
 
@@ -291,37 +291,37 @@ import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 
 const editorConfiguration = {
-  plugins: [ Essentials, Bold, Italic, Paragraph ],
-  toolbar: [ 'bold', 'italic' ]
+	plugins: [ Essentials, Bold, Italic, Paragraph ],
+	toolbar: [ 'bold', 'italic' ]
 };
 
 class App extends Component {
-  render() {
-    return (
-      <div className="App">
-        <h2>Using CKEditor 5 from source in React</h2>
-        <CKEditor
-          editor={ ClassicEditor }
-          config={ editorConfiguration }
-          data="<p>Hello from CKEditor 5!</p>"
-          onInit={ editor => {
-            // You can store the "editor" and use when it is needed.
-            console.log( 'Editor is ready to use!', editor );
-          } }
-          onChange={ ( event, editor ) => {
-            const data = editor.getData();
-            console.log( { event, editor, data } );
-          } }
-          onBlur={ editor => {
-            console.log( 'Blur.', editor );
-          } }
-          onFocus={ editor => {
-            console.log( 'Focus.', editor );
-          } }
-        />
-      </div>
-    );
-  }
+	render() {
+		return (
+			<div className="App">
+				<h2>Using CKEditor 5 from source in React</h2>
+				<CKEditor
+					editor={ ClassicEditor }
+					config={ editorConfiguration }
+					data="<p>Hello from CKEditor 5!</p>"
+					onInit={ editor => {
+						// You can store the "editor" and use when it is needed.
+						console.log( 'Editor is ready to use!', editor );
+					} }
+					onChange={ ( event, editor ) => {
+						const data = editor.getData();
+						console.log( { event, editor, data } );
+					} }
+					onBlur={ ( event, editor ) => {
+						console.log( 'Blur.', editor );
+					} }
+					onFocus={ ( event, editor ) => {
+						console.log( 'Focus.', editor );
+					} }
+				/>
+			</div>
+		);
+	}
 }
 
 export default App;
@@ -400,26 +400,26 @@ In the end, the entire plugin definition should look as follows:
 ```js
 // Minify the code.
 new UglifyJsWebpackPlugin( {
-  uglifyOptions: {
-    compress: {
-      warnings: false,
-      // Disabled because of an issue with Uglify breaking seemingly valid code:
-      // https://github.com/facebookincubator/create-react-app/issues/2376
-      // Pending further investigation:
-      // https://github.com/mishoo/UglifyJS2/issues/2011
-      comparisons: false,
-    },
-    mangle: {
-        safari10: true,
-    },
-    output: {
-        comments: false,
-        // Turned on because emoji and regex is not minified properly using default
-        // https://github.com/facebookincubator/create-react-app/issues/2488
-        ascii_only: true,
-    },
-  },
-  sourceMap: shouldUseSourceMap,
+	uglifyOptions: {
+		compress: {
+			warnings: false,
+			// Disabled because of an issue with Uglify breaking seemingly valid code:
+			// https://github.com/facebookincubator/create-react-app/issues/2376
+			// Pending further investigation:
+			// https://github.com/mishoo/UglifyJS2/issues/2011
+			comparisons: false,
+		},
+		mangle: {
+			safari10: true,
+		},
+		output: {
+			comments: false,
+			// Turned on because emoji and regex is not minified properly using default
+			// https://github.com/facebookincubator/create-react-app/issues/2488
+			ascii_only: true,
+		},
+	},
+	sourceMap: shouldUseSourceMap,
 } )
 ```
 
@@ -444,28 +444,28 @@ Then add two new elements to the exported object under the `module.rules` array
 
 ```js
 {
-  test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
-  use: [ 'raw-loader' ]
+	test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
+	use: [ 'raw-loader' ]
 },
 {
-  test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
-  use: [
-    {
-      loader: 'style-loader',
-      options: {
-        singleton: true
-      }
-    },
-    {
-      loader: 'postcss-loader',
-      options: styles.getPostCssConfig( {
-        themeImporter: {
-          themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
-        },
-        minify: true
-      } )
-    }
-  ]
+	test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
+	use: [
+		{
+			loader: 'style-loader',
+			options: {
+				injectType: 'singletonStyleTag'
+			}
+		},
+		{
+			loader: 'postcss-loader',
+			options: styles.getPostCssConfig( {
+				themeImporter: {
+					themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
+				},
+				minify: true
+			} )
+		}
+	]
 },
 ```
 
@@ -473,9 +473,9 @@ Exclude CSS files used by CKEditor 5 from project's CSS loader:
 
 ```js
 {
-  test: /\.css$/,
-  exclude: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
-  // (...)
+	test: /\.css$/,
+	exclude: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
+	// (...)
 }
 ```
 
@@ -483,21 +483,21 @@ And exclude CKEditor 5 SVG and CSS files from `file-loader` because these files
 
 ```js
 {
-  loader: require.resolve('file-loader'),
-  // Exclude `js` files to keep the "css" loader working as it injects
-  // its runtime that would otherwise be processed through the "file" loader.
-  // Also exclude `html` and `json` extensions so they get processed
-  // by webpack's internal loaders.
-  exclude: [
-    /\.(js|jsx|mjs)$/,
-    /\.html$/,
-    /\.json$/,
-    /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
-    /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/
-  ],
-  options: {
-    name: 'static/media/[name].[hash:8].[ext]'
-  }
+	loader: require.resolve( 'file-loader' ),
+	// Exclude `js` files to keep the "css" loader working as it injects
+	// its runtime that would otherwise be processed through the "file" loader.
+	// Also exclude `html` and `json` extensions so they get processed
+	// by webpack's internal loaders.
+	exclude: [
+		/\.(js|jsx|mjs)$/,
+		/\.html$/,
+		/\.json$/,
+		/ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
+		/ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/
+	],
+	options: {
+		name: 'static/media/[name].[hash:8].[ext]'
+	}
 }
 ```
 
@@ -537,28 +537,105 @@ import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
 import Heading from '@ckeditor/ckeditor5-heading/src/heading';
 
 class App extends Component {
-    render() {
-        return (
-            <div className="App">
-                <h2>Using CKEditor 5 Framework in React</h2>
-                <CKEditor
-                    onInit={ editor => console.log( 'Editor is ready to use!', editor ) }
-                    onChange={ ( event, editor ) => console.log( { event, editor } ) }
-                    config={ {
-                        plugins: [ Essentials, Paragraph, Bold, Italic, Heading ],
-                        toolbar: [ 'heading', '|', 'bold', 'italic', '|', 'undo', 'redo', ]
-                    } }
-                    editor={ ClassicEditor }
-                    data="<p>Hello from CKEditor 5!</p>"
-                />
-            </div>
-        );
-    }
+	render() {
+		return (
+			<div className="App">
+				<h2>Using CKEditor 5 Framework in React</h2>
+				<CKEditor
+					onInit={ editor => console.log( 'Editor is ready to use!', editor ) }
+					onChange={ ( event, editor ) => console.log( { event, editor } ) }
+					config={ {
+						plugins: [ Essentials, Paragraph, Bold, Italic, Heading ],
+						toolbar: [ 'heading', '|', 'bold', 'italic', '|', 'undo', 'redo', ]
+					} }
+					editor={ ClassicEditor }
+					data="<p>Hello from CKEditor 5!</p>"
+				/>
+			</div>
+		);
+	}
 }
 
 export default App;
 ```
 
+## Localization
+
+CKEditor 5 supports {@link features/ui-language multiple UI languages}, and so does the official React component. Follow the instructions below to translate CKEditor 5 in your React application.
+
+### Ready-to-use builds
+
+When using one of the {@link builds/guides/overview#available-builds official editor builds}, you need to import the translations first:
+
+```js
+import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
+
+// Import translations for the German language.
+import '@ckeditor/ckeditor5-build-classic/build/translations/de';
+
+// ...
+```
+
+Then, {@link builds/guides/integration/configuration configure} the language of the editor in the component:
+
+```jsx
+<CKEditor
+	config={ {
+		// Use the German language for this editor.
+		language: 'de',
+
+		// ...
+	} }
+	editor={ ClassicEditor }
+	data="<p>Hello from CKEditor 5!</p>"
+/>
+```
+
+For more information, please refer to the {@link features/ui-language "Setting UI language"} guide.
+
+### CKEditor 5 built from source
+
+Using the editor [built from source](#integrating-ckeditor-5-built-from-source) requires you to modify the webpack configuration. First, install the [official webpack plugin](https://www.npmjs.com/package/@ckeditor/ckeditor5-dev-webpack-plugin) that allows localizing editor builds:
+
+```bash
+npm install @ckeditor/ckeditor5-dev-webpack-plugin --save-dev
+```
+
+Then, add the installed plugin to the webpack configuration:
+
+<info-box>
+	We assume that you use `create-react-app@2`. For earlier versions, make sure to modify [both webpack configuration files](#changes-required-in-webpacks-production-configuration).
+</info-box>
+
+```js
+// webpack.config.js
+'use strict';
+
+// ...
+const CKEditorWebpackPlugin = require( '@ckeditor/ckeditor5-dev-webpack-plugin' );
+
+module.exports = {
+	// ...
+
+	plugins: [
+		// ....
+
+		new CKEditorWebpackPlugin( {
+			// The UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
+			language: 'de'
+		} ),
+
+		// ....
+	],
+
+	// ...
+};
+```
+
+After building the application, CKEditor 5 will run with the UI translated to the specified language.
+
+For more information, please refer to the {@link features/ui-language "Setting UI language"} guide.
+
 ## Contributing and reporting issues
 
 The source code of rich text editor component for React is available on GitHub in https://github.com/ckeditor/ckeditor5-react.

+ 4 - 4
docs/builds/guides/integration/advanced-setup.md

@@ -100,8 +100,8 @@ npm install --save \
 	@ckeditor/ckeditor5-dev-webpack-plugin \
 	@ckeditor/ckeditor5-dev-utils \
 	postcss-loader@3 \
-	raw-loader@1 \
-	style-loader@0.23.0 \
+	raw-loader@3 \
+	style-loader@1 \
 	webpack@4 \
 	webpack-cli@3 \
 ```
@@ -133,7 +133,7 @@ module.exports = {
 	module: {
 		rules: [
 			{
-				// Or /ckeditor5-[^/]+\/theme\/icons\/[^/]+\.svg$/ if you want to limit this loader
+				// Or /ckeditor5-[^/]+\/theme\/icons\/.+\.svg$/ if you want to limit this loader
 				// to CKEditor 5 icons only.
 				test: /\.svg$/,
 
@@ -147,7 +147,7 @@ module.exports = {
 					{
 						loader: 'style-loader',
 						options: {
-							singleton: true
+							injectType: 'singletonStyleTag'
 						}
 					},
 					{

File diff suppressed because it is too large
+ 193 - 0
docs/builds/guides/integration/content-styles.md


+ 7 - 1
docs/features/image-upload.md

@@ -68,7 +68,13 @@ There are two ways you can integrate CKEditor 5 with the CKFinder file manager:
 
 {@link features/ckfinder **Learn how to integrate CKEditor 5 with CKFinder in your project**}.
 
-### Base64
+### Simple adapter
+
+The {@link features/simple-upload-adapter Simple upload adapter} allows uploading images to your server using the [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) API with a minimal editor configuration.
+
+{@link features/simple-upload-adapter **Learn how to use the Simple upload adapter in CKEditor 5**}.
+
+### Base64 adapter
 
 The {@link features/base64-upload-adapter Base64 upload feature} converts images inserted into the editor into [Base64 strings](https://en.wikipedia.org/wiki/Base64) in the {@link builds/guides/integration/saving-data editor output}.
 

+ 0 - 12
docs/features/spell-checker.md

@@ -33,18 +33,6 @@ WProofreader is installed separately from CKEditor 5 and does not need to be com
 
 The proofreader can be used either as a [cloud solution](#wproofreader-cloud) or [hosted on your own server](#wproofreader-server).
 
-The "Proofread in dialog" feature requires access to the editor instance to edit content. To grant access for WProofreader, it is necessary to link the editor's instance with the editable element. You can add the following configuration to the editor to use "Proofread in dialog":
-
-```js
-ClassicEditor
-	.create(
-		document.querySelector( '#editor' )
-	)
-	.then( ( editor ) => {
-		editor.ui.getEditableElement( 'main' ).editor = editor;
-	} );
-```
-
 ### WProofreader Cloud
 
 After signing up for a [trial or paid version](https://ckeditor.com/contact/), you will receive your service ID which is used to activate the service.

File diff suppressed because it is too large
+ 70 - 21
docs/features/ui-language.md


+ 12 - 1
docs/framework/guides/contributing/development-environment.md

@@ -193,7 +193,7 @@ To create a server for manual tests use the `manual` task:
 yarn run manual
 ```
 
-It accepts the `--source-map` (`-s`) option. Note that it watches for changes in the JavaScript files only (see the [bug](https://github.com/ckeditor/ckeditor5-dev/issues/52)).
+It accepts the `--source-map` (`-s`) and `--additionalLanguages="ar,pl,..."` options. Note that it watches for changes in the JavaScript files only (see the [bug](https://github.com/ckeditor/ckeditor5-dev/issues/52)).
 
 You can read more about the {@link framework/guides/contributing/testing-environment Testing environment}.
 
@@ -223,6 +223,17 @@ Note: These arguments must be passed after additional `--`:
 yarn run docs --skip-api
 ```
 
+## Generating content styles
+
+It is possible to generate a stylesheet containing content styles brought by all CKEditor 5 features. In order to do that, execute:
+
+```bash
+yarn docs:content-styles
+```
+The stylesheet will be saved in the `build/content-styles` folder.
+
+To learn more, refer to the {@link builds/guides/integration/content-styles Content styles} guide.
+
 ## Bisecting through a multi-repository
 
 CKEditor 5 is a multi-repository project. It means that [`git bisect`](https://git-scm.com/docs/git-bisect) (which is super handy when tracking which commit introduced a bug) will not work out of the box.

+ 5 - 1
docs/framework/guides/contributing/testing-environment.md

@@ -25,6 +25,7 @@ It accepts the following arguments (must be passed after the `--` option):
 * `--verbose` (alias `-v`) &ndash; Allows switching on webpack logs.
 * `--files` &ndash; Specifies tests files to run. Accepts a package name or a glob. Read more about the [rules for converting the `--files` option to a glob pattern](https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-tests#rules-for-converting---files-option-to-glob-pattern).
 * `--browsers` &ndash; Browsers which will be used to run the tests. Defaults to `Chrome`.
+* `--debug` (alias `-d`) &ndash; Allows specifying custom debug flags. For example, the `--debug engine` option uncomments the `// @if CK_DEBUG_ENGINE //` lines in the code. The `--debug false` option turns the debugging mechanism off and leaves the lines starting with `// @if CK_DEBUG //` untouched.
 
 ### Examples
 
@@ -50,7 +51,10 @@ yarn run test -cw --files=basic-styles/bold*.js
 
 In order to start the manual tests server use the `yarn run manual` task.
 
-The task accepts the `--source-map` (alias `-s`) option.
+The task accepts the following options:
+
+* `--source-map` (alias `-s`) that generates useful source maps for the code.
+* `--additionalLanguages="ar,pl,..."` that passes extra languages to the [CKEditor 5 webpack plugin](https://www.npmjs.com/package/@ckeditor/ckeditor5-dev-webpack-plugin). Check out the {@link features/ui-language UI language guide} to learn more.
 
 It starts the server available at http://localhost:8125.
 

+ 2 - 2
docs/framework/guides/development-tools.md

@@ -60,8 +60,8 @@ You can specify the name of the editor when attaching to make working with multi
 
 ```js
 // Inspecting two editor instances at the same time.
-CKEditorInspector.attach( 'header-editor' editor );
-CKEditorInspector.attach( 'body-editor' editor );
+CKEditorInspector.attach( 'header-editor', editor );
+CKEditorInspector.attach( 'body-editor', editor );
 ```
 
 The editor switcher is in the upper–right corner of the inspector panel.

+ 5 - 5
docs/framework/guides/quick-start.md

@@ -27,8 +27,8 @@ First, install packages needed to build CKEditor 5:
 ```bash
 npm install --save \
 	postcss-loader@3 \
-	raw-loader@1 \
-	style-loader@0.23.0 \
+	raw-loader@3 \
+	style-loader@1 \
 	webpack@4 \
 	webpack-cli@3
 ```
@@ -56,14 +56,14 @@ module.exports = {
 	module: {
 		rules: [
 			{
-				// Or /ckeditor5-[^/]+\/theme\/icons\/[^/]+\.svg$/ if you want to limit this loader
+				// Or /ckeditor5-[^/]+\/theme\/icons\/.+\.svg$/ if you want to limit this loader
 				// to CKEditor 5 icons only.
 				test: /\.svg$/,
 
 				use: [ 'raw-loader' ]
 			},
 			{
-				// Or /ckeditor5-[^/]+\/theme\/[^/]+\.css$/ if you want to limit this loader
+				// Or /ckeditor5-[^/]+\/theme\/.+\.css$/ if you want to limit this loader
 				// to CKEditor 5 theme only.
 				test: /\.css$/,
 
@@ -71,7 +71,7 @@ module.exports = {
 					{
 						loader: 'style-loader',
 						options: {
-							singleton: true
+							injectType: 'singletonStyleTag'
 						}
 					},
 					{

+ 3 - 3
docs/framework/guides/tutorials/implementing-a-block-widget.md

@@ -30,8 +30,8 @@ First, install packages needed to build and set up a basic CKEditor 5 instance.
 ```bash
 npm install --save \
 	postcss-loader@3 \
-	raw-loader@1 \
-	style-loader@0.23.0 \
+	raw-loader@3 \
+	style-loader@1 \
 	webpack@4 \
 	webpack-cli@3 \
 	@ckeditor/ckeditor5-dev-utils \
@@ -74,7 +74,7 @@ module.exports = {
 					{
 						loader: 'style-loader',
 						options: {
-							singleton: true
+							injectType: 'singletonStyleTag'
 						}
 					},
 					{

+ 3 - 3
docs/framework/guides/tutorials/implementing-an-inline-widget.md

@@ -26,8 +26,8 @@ First, install required dependencies:
 ```bash
 npm install --save \
 	postcss-loader@3 \
-	raw-loader@1 \
-	style-loader@0.23.0 \
+	raw-loader@3 \
+	style-loader@1 \
 	webpack@4 \
 	webpack-cli@3 \
 	@ckeditor/ckeditor5-basic-styles \
@@ -75,7 +75,7 @@ module.exports = {
 					{
 						loader: 'style-loader',
 						options: {
-							singleton: true
+							injectType: 'singletonStyleTag'
 						}
 					},
 					{

+ 7 - 1
docs/umberto.json

@@ -25,7 +25,8 @@
 		"features/ckfinder.html": "features/image-upload/ckfinder.html",
 		"features/easy-image.html": "features/image-upload/easy-image.html",
 		"features/collaboration/comments/integrate-comments-with-application.html": "features/collaboration/comments/comments-integration.html",
-		"features/collaboration/track-changes.html": "features/collaboration/track-changes/track-changes.html"
+		"features/collaboration/track-changes.html": "features/collaboration/track-changes/track-changes.html",
+		"features/paste-from-word.html": "features/pasting/paste-from-word.html"
 	},
 	"scripts": {
 		"snippet-adapter": "../scripts/docs/snippetadapter",
@@ -216,6 +217,11 @@
 					"name": "Image upload",
 					"id": "features-image-upload",
 					"slug": "image-upload"
+				},
+				{
+					"name": "Pasting",
+					"id": "features-pasting",
+					"slug": "pasting"
 				}
 			]
 		},

+ 58 - 57
package.json

@@ -1,6 +1,6 @@
 {
   "name": "ckeditor5",
-  "version": "12.3.1",
+  "version": "12.4.0",
   "description": "The development environment of CKEditor 5 – the best browser-based rich text editor.",
   "private": true,
   "keywords": [
@@ -21,61 +21,61 @@
     "framework"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-adapter-ckfinder": "^11.0.4",
-    "@ckeditor/ckeditor5-alignment": "^11.1.3",
-    "@ckeditor/ckeditor5-autoformat": "^11.0.4",
-    "@ckeditor/ckeditor5-autosave": "^11.0.4",
-    "@ckeditor/ckeditor5-basic-styles": "^11.1.3",
-    "@ckeditor/ckeditor5-block-quote": "^11.1.2",
-    "@ckeditor/ckeditor5-build-balloon": "^12.3.1",
-    "@ckeditor/ckeditor5-build-balloon-block": "^12.3.1",
-    "@ckeditor/ckeditor5-build-classic": "^12.3.1",
-    "@ckeditor/ckeditor5-build-decoupled-document": "^12.3.1",
-    "@ckeditor/ckeditor5-build-inline": "^12.3.1",
-    "@ckeditor/ckeditor5-ckfinder": "^11.0.4",
-    "@ckeditor/ckeditor5-clipboard": "^12.0.1",
-    "@ckeditor/ckeditor5-cloud-services": "^11.0.4",
-    "@ckeditor/ckeditor5-core": "^12.2.1",
-    "@ckeditor/ckeditor5-easy-image": "^11.0.4",
-    "@ckeditor/ckeditor5-editor-balloon": "^12.2.1",
-    "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
-    "@ckeditor/ckeditor5-editor-decoupled": "^12.2.1",
-    "@ckeditor/ckeditor5-editor-inline": "^12.2.1",
-    "@ckeditor/ckeditor5-engine": "^13.2.1",
-    "@ckeditor/ckeditor5-enter": "^11.0.4",
-    "@ckeditor/ckeditor5-essentials": "^11.0.4",
-    "@ckeditor/ckeditor5-font": "^11.2.1",
-    "@ckeditor/ckeditor5-heading": "^11.0.4",
-    "@ckeditor/ckeditor5-highlight": "^11.0.4",
-    "@ckeditor/ckeditor5-image": "^13.1.2",
-    "@ckeditor/ckeditor5-indent": "^10.0.1",
-    "@ckeditor/ckeditor5-link": "^11.1.1",
-    "@ckeditor/ckeditor5-list": "^12.0.4",
-    "@ckeditor/ckeditor5-markdown-gfm": "^11.0.4",
-    "@ckeditor/ckeditor5-media-embed": "^11.1.3",
-    "@ckeditor/ckeditor5-mention": "^12.0.1",
-    "@ckeditor/ckeditor5-paragraph": "^11.0.4",
-    "@ckeditor/ckeditor5-paste-from-office": "^11.0.4",
-    "@ckeditor/ckeditor5-remove-format": "^10.0.3",
-    "@ckeditor/ckeditor5-table": "^13.0.2",
-    "@ckeditor/ckeditor5-theme-lark": "^14.1.1",
-    "@ckeditor/ckeditor5-typing": "^12.1.1",
-    "@ckeditor/ckeditor5-ui": "^13.0.2",
-    "@ckeditor/ckeditor5-undo": "^11.0.4",
-    "@ckeditor/ckeditor5-upload": "^11.1.1",
-    "@ckeditor/ckeditor5-utils": "^13.0.1",
-    "@ckeditor/ckeditor5-watchdog": "^10.0.1",
-    "@ckeditor/ckeditor5-widget": "^11.0.4",
-    "@ckeditor/ckeditor5-word-count": "^10.0.1"
+    "@ckeditor/ckeditor5-adapter-ckfinder": "^11.0.5",
+    "@ckeditor/ckeditor5-alignment": "^11.2.0",
+    "@ckeditor/ckeditor5-autoformat": "^11.0.5",
+    "@ckeditor/ckeditor5-autosave": "^11.0.5",
+    "@ckeditor/ckeditor5-basic-styles": "^11.1.4",
+    "@ckeditor/ckeditor5-block-quote": "^11.1.3",
+    "@ckeditor/ckeditor5-build-balloon": "^12.4.0",
+    "@ckeditor/ckeditor5-build-balloon-block": "^12.4.0",
+    "@ckeditor/ckeditor5-build-classic": "^12.4.0",
+    "@ckeditor/ckeditor5-build-decoupled-document": "^12.4.0",
+    "@ckeditor/ckeditor5-build-inline": "^12.4.0",
+    "@ckeditor/ckeditor5-ckfinder": "^11.0.5",
+    "@ckeditor/ckeditor5-clipboard": "^12.0.2",
+    "@ckeditor/ckeditor5-cloud-services": "^11.0.5",
+    "@ckeditor/ckeditor5-core": "^12.3.0",
+    "@ckeditor/ckeditor5-easy-image": "^11.0.5",
+    "@ckeditor/ckeditor5-editor-balloon": "^12.2.2",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.4",
+    "@ckeditor/ckeditor5-editor-decoupled": "^12.2.2",
+    "@ckeditor/ckeditor5-editor-inline": "^12.3.0",
+    "@ckeditor/ckeditor5-engine": "^14.0.0",
+    "@ckeditor/ckeditor5-enter": "^11.1.0",
+    "@ckeditor/ckeditor5-essentials": "^11.0.5",
+    "@ckeditor/ckeditor5-font": "^11.2.2",
+    "@ckeditor/ckeditor5-heading": "^11.0.5",
+    "@ckeditor/ckeditor5-highlight": "^11.0.5",
+    "@ckeditor/ckeditor5-image": "^14.0.0",
+    "@ckeditor/ckeditor5-indent": "^10.1.0",
+    "@ckeditor/ckeditor5-link": "^11.1.2",
+    "@ckeditor/ckeditor5-list": "^12.1.0",
+    "@ckeditor/ckeditor5-markdown-gfm": "^11.0.5",
+    "@ckeditor/ckeditor5-media-embed": "^11.1.4",
+    "@ckeditor/ckeditor5-mention": "^13.0.0",
+    "@ckeditor/ckeditor5-paragraph": "^11.0.5",
+    "@ckeditor/ckeditor5-paste-from-office": "^11.1.0",
+    "@ckeditor/ckeditor5-remove-format": "^10.0.4",
+    "@ckeditor/ckeditor5-table": "^14.0.0",
+    "@ckeditor/ckeditor5-theme-lark": "^14.2.0",
+    "@ckeditor/ckeditor5-typing": "^12.2.0",
+    "@ckeditor/ckeditor5-ui": "^14.0.0",
+    "@ckeditor/ckeditor5-undo": "^11.0.5",
+    "@ckeditor/ckeditor5-upload": "^12.0.0",
+    "@ckeditor/ckeditor5-utils": "^14.0.0",
+    "@ckeditor/ckeditor5-watchdog": "^11.0.0",
+    "@ckeditor/ckeditor5-widget": "^11.1.0",
+    "@ckeditor/ckeditor5-word-count": "^10.0.2"
   },
   "devDependencies": {
     "@ckeditor/ckeditor5-comments": "^3.2.0",
-    "@ckeditor/ckeditor5-dev-docs": "^11.0.2",
-    "@ckeditor/ckeditor5-dev-env": "^14.1.1",
-    "@ckeditor/ckeditor5-dev-tests": "^16.4.0",
-    "@ckeditor/ckeditor5-dev-utils": "^12.0.1",
-    "@ckeditor/ckeditor5-dev-webpack-plugin": "^8.0.1",
-    "@ckeditor/ckeditor5-inspector": "^1.2.0",
+    "@ckeditor/ckeditor5-dev-docs": "^11.0.5",
+    "@ckeditor/ckeditor5-dev-env": "^16.0.0",
+    "@ckeditor/ckeditor5-dev-tests": "^16.7.1",
+    "@ckeditor/ckeditor5-dev-utils": "^12.0.3",
+    "@ckeditor/ckeditor5-dev-webpack-plugin": "^8.0.3",
+    "@ckeditor/ckeditor5-inspector": "^1.3.0",
     "@ckeditor/ckeditor5-real-time-collaboration": "^12.3.0",
     "@ckeditor/ckeditor5-track-changes": "^1.0.0",
     "@wiris/mathtype-ckeditor5": "^7.16.1",
@@ -91,12 +91,12 @@
     "mrgit": "^1.0.0",
     "postcss-loader": "^3.0.0",
     "progress-bar-webpack-plugin": "^1.12.1",
-    "raw-loader": "^1.0.0",
-    "style-loader": "^0.23.0",
+    "raw-loader": "^3.1.0",
+    "style-loader": "^1.0.0",
     "svgo": "^1.1.0",
-    "uglifyjs-webpack-plugin": "^1.2.7",
+    "uglifyjs-webpack-plugin": "^1.3.0",
     "umberto": "^1.0.0",
-    "webpack": "^4.15.0"
+    "webpack": "^4.39.1"
   },
   "engines": {
     "node": ">=8.0.0",
@@ -122,6 +122,7 @@
     "docs:api": "node ./scripts/docs/build-api-docs.js",
     "docs:build-and-publish": "node ./scripts/docs/build-and-publish.js",
     "docs:build-and-publish-nightly": "node ./scripts/docs/build-and-publish-nightly.js",
+    "docs:content-styles": "node ./scripts/docs/build-content-styles.js",
     "translations:collect": "ckeditor5-dev-env-translations collect",
     "translations:download": "ckeditor5-dev-env-translations download",
     "translations:upload": "ckeditor5-dev-env-translations upload",

+ 241 - 0
scripts/docs/build-content-styles.js

@@ -0,0 +1,241 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* eslint-env node */
+
+const path = require( 'path' );
+const fs = require( 'fs' );
+const webpack = require( 'webpack' );
+const { styles } = require( '@ckeditor/ckeditor5-dev-utils' );
+const { version } = require( '../../package.json' );
+
+const DESTINATION_DIRECTORY = path.join( __dirname, '..', '..', 'build', 'content-styles' );
+const DOCUMENTATION_URL = 'https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html';
+const VARIABLE_DEFINITION_REGEXP = /(--[\w-]+):\s+(.*);/g;
+const VARIABLE_USAGE_REGEXP = /var\((--[\w-]+)\)/g;
+
+const contentRules = {
+	selector: [],
+	variables: []
+};
+
+const webpackConfig = getWebpackConfig();
+const packagesPath = path.join( process.cwd(), 'packages' );
+
+runWebpack( webpackConfig )
+	.then( () => {
+		// All variables are placed inside the `:root` selector. Let's extract their names and values as a map.
+		const cssVariables = new Map( contentRules.variables
+			.map( rule => {
+				// Let's extract all of them as an array of pairs: [ name, value ].
+				const allRules = [];
+				let match;
+
+				while ( ( match = VARIABLE_DEFINITION_REGEXP.exec( rule.css ) ) ) {
+					allRules.push( [ match[ 1 ], match[ 2 ] ] );
+				}
+
+				return allRules;
+			} )
+			.reduce( ( previousValue, currentValue ) => {
+				// And simplify nested arrays as a flattened array.
+				previousValue.push( ...currentValue );
+
+				return previousValue;
+			}, [] ) );
+
+		// CSS variables that are used by the `.ck-content` selector.
+		const usedVariables = new Set();
+
+		const selectorCss = contentRules.selector
+			.map( rule => {
+				// Removes all comments from the rule definition.
+				const cssAsArray = rule.css.replace( /\/\*[^*]+\*\//g, '' ).split( '\n' );
+
+				// We want to fix invalid indentations. We need to find a number of how many indentations we want to remove.
+				// Because the last line ends the block, we can use this value.
+				const lastLineIndent = cssAsArray[ cssAsArray.length - 1 ].length - 1;
+
+				const css = cssAsArray
+					.filter( line => line.trim().length > 0 )
+					.map( ( line, index ) => {
+						// Do not touch the first line. It is always correct.
+						if ( index === 0 ) {
+							return line;
+						}
+
+						return line.slice( lastLineIndent );
+					} )
+					.join( '\n' );
+
+				return `/* ${ rule.file.replace( packagesPath + path.sep, '' ) } */\n${ css }`;
+			} )
+			.filter( rule => {
+				// 1st: path to the CSS file, 2nd: selector definition - start block, 3rd: end block
+				// If the rule contains only 3 lines, it means that it does not define any rules.
+				return rule.split( '\n' ).length > 3;
+			} )
+			.join( '\n' );
+
+		// Find all CSS variables inside the `.ck-content` selector.
+		let match;
+
+		while ( ( match = VARIABLE_USAGE_REGEXP.exec( selectorCss ) ) ) {
+			usedVariables.add( match[ 1 ] );
+		}
+
+		// We need to also look at whether any of the used variables requires the value of other variables.
+		let clearRun = false;
+
+		// We need to process all variables as long as the entire collection won't be changed.
+		while ( !clearRun ) {
+			clearRun = true;
+
+			// For every used variable...
+			for ( const variable of usedVariables ) {
+				const value = cssVariables.get( variable );
+
+				let match;
+
+				// ...find its value and check whether it requires another variable.
+				while ( ( match = VARIABLE_USAGE_REGEXP.exec( value ) ) ) {
+					// If so, mark the entire `while()` block as it should be checked once again.
+					// Also, add the new variable to the used variables collection.
+					if ( !usedVariables.has( match[ 1 ] ) ) {
+						clearRun = false;
+						usedVariables.add( match[ 1 ] );
+					}
+				}
+			}
+		}
+
+		// Build the final content of the CSS file.
+		let data = [
+			'/*',
+			` * CKEditor 5 (v${ version }) content styles.`,
+			` * Generated on ${ new Date().toUTCString() }.`,
+			` * For more information, check out ${ DOCUMENTATION_URL }`,
+			' */\n\n',
+		].join( '\n' );
+
+		data += ':root {\n';
+
+		for ( const variable of [ ...usedVariables ].sort() ) {
+			data += `\t${ variable }: ${ cssVariables.get( variable ) };\n`;
+		}
+
+		data += '}\n\n';
+		data += selectorCss;
+
+		return writeFile( path.join( DESTINATION_DIRECTORY, 'content-styles.css' ), data );
+	} )
+	.then( () => {
+		console.log( `Content styles have been extracted to ${ path.join( DESTINATION_DIRECTORY, 'content-styles.css' ) }` );
+	} )
+	.catch( err => {
+		console.log( err );
+	} );
+
+/**
+ * Prepares the configuration for webpack.
+ *
+ * @returns {Object}
+ */
+function getWebpackConfig() {
+	const postCssConfig = styles.getPostCssConfig( {
+		themeImporter: {
+			themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
+		},
+		minify: false
+	} );
+
+	const contentStylesPlugin = require( './content-styles/list-content-styles' )( { contentRules } );
+
+	postCssConfig.plugins.push( contentStylesPlugin );
+
+	return {
+		mode: 'development',
+
+		devtool: 'source-map',
+
+		entry: {
+			ckeditor5: path.join( __dirname, 'content-styles', 'ckeditor.js' )
+		},
+
+		output: {
+			path: DESTINATION_DIRECTORY,
+			filename: '[name].js'
+		},
+
+		// Configure the paths so building CKEditor 5 snippets work even if the script
+		// is triggered from a directory outside `ckeditor5` (e.g. in a multi-project case).
+		resolve: {
+			modules: getModuleResolvePaths()
+		},
+
+		resolveLoader: {
+			modules: getModuleResolvePaths()
+		},
+
+		module: {
+			rules: [
+				{
+					test: /\.svg$/,
+					use: [ 'raw-loader' ]
+				},
+				{
+					test: /\.css$/,
+					use: [
+						'style-loader',
+						{
+							loader: 'postcss-loader',
+							options: postCssConfig
+						}
+					]
+				}
+			]
+		}
+	};
+}
+
+/**
+ * @param {Object} webpackConfig
+ * @returns {Promise}
+ */
+function runWebpack( webpackConfig ) {
+	return new Promise( ( resolve, reject ) => {
+		webpack( webpackConfig, ( err, stats ) => {
+			if ( err ) {
+				reject( err );
+			} else if ( stats.hasErrors() ) {
+				reject( new Error( stats.toString() ) );
+			} else {
+				resolve();
+			}
+		} );
+	} );
+}
+
+/**
+ * @returns {Array.<String>}
+ */
+function getModuleResolvePaths() {
+	return [
+		path.resolve( __dirname, '..', '..', 'node_modules' ),
+		'node_modules'
+	];
+}
+
+function writeFile( file, data ) {
+	return new Promise( ( resolve, reject ) => {
+		fs.writeFile( file, data, err => {
+			if ( err ) {
+				return reject( err );
+			}
+
+			return resolve();
+		} );
+	} );
+}

+ 76 - 0
scripts/docs/content-styles/ckeditor.js

@@ -0,0 +1,76 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+// The editor creator to use.
+import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+
+import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
+import UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';
+import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
+import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
+import Code from '@ckeditor/ckeditor5-basic-styles/src/code';
+import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
+import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';
+import Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript';
+import Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript';
+import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';
+import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
+import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';
+import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
+import Heading from '@ckeditor/ckeditor5-heading/src/heading';
+import Image from '@ckeditor/ckeditor5-image/src/image';
+import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
+import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
+import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
+import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
+import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
+import Link from '@ckeditor/ckeditor5-link/src/link';
+import List from '@ckeditor/ckeditor5-list/src/list';
+import TodoList from '@ckeditor/ckeditor5-list/src/todolist';
+import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';
+import Table from '@ckeditor/ckeditor5-table/src/table';
+import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
+import Font from '@ckeditor/ckeditor5-font/src/font';
+import Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';
+import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment';
+
+export default class ClassicEditor extends ClassicEditorBase {}
+
+// Plugins to include in the build.
+ClassicEditor.builtinPlugins = [
+	Essentials,
+	UploadAdapter,
+	Autoformat,
+	Bold,
+	Code,
+	Italic,
+	Strikethrough,
+	Subscript,
+	Superscript,
+	Underline,
+	BlockQuote,
+	CKFinder,
+	EasyImage,
+	Heading,
+	Image,
+	ImageCaption,
+	ImageResize,
+	ImageStyle,
+	ImageToolbar,
+	ImageUpload,
+	Link,
+	List,
+	TodoList,
+	MediaEmbed,
+	Paragraph,
+	PasteFromOffice,
+	Table,
+	TableToolbar,
+	Font,
+	Highlight,
+	Alignment
+];

+ 35 - 0
scripts/docs/content-styles/list-content-styles.js

@@ -0,0 +1,35 @@
+#!/usr/bin/env node
+
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* eslint-env node */
+
+const postcss = require( 'postcss' );
+
+module.exports = postcss.plugin( 'list-content-styles', function( options ) {
+	const selectorStyles = options.contentRules.selector;
+	const variables = options.contentRules.variables;
+
+	return root => {
+		root.walkRules( rule => {
+			rule.selectors.forEach( selector => {
+				if ( selector.match( ':root' ) ) {
+					variables.push( {
+						file: root.source.input.file,
+						css: rule.toString()
+					} );
+				}
+
+				if ( selector.match( '.ck-content' ) ) {
+					selectorStyles.push( {
+						file: root.source.input.file,
+						css: rule.toString()
+					} );
+				}
+			} );
+		} );
+	};
+} );

+ 38 - 3
scripts/docs/snippetadapter.js

@@ -16,6 +16,7 @@ const UglifyJsWebpackPlugin = require( 'uglifyjs-webpack-plugin' );
 const ProgressBarPlugin = require( 'progress-bar-webpack-plugin' );
 
 const DEFAULT_LANGUAGE = 'en';
+const MULTI_LANGUAGE = 'multi-language';
 
 /**
  * @param {Set.<Snippet>} snippets Snippet collection extracted from documentation files.
@@ -91,6 +92,12 @@ module.exports = function snippetAdapter( snippets, options, umbertoHelpers ) {
 	// Group snippets by language. There is no way to build different languages in a single Webpack process.
 	// Webpack must be called as many times as different languages are being used in snippets.
 	for ( const snippetData of snippets ) {
+		// Multi-languages editors must be built separately.
+		if ( snippetData.snippetConfig.additionalLanguages ) {
+			snippetData.snippetConfig.additionalLanguages.push( snippetData.snippetConfig.language );
+			snippetData.snippetConfig.language = MULTI_LANGUAGE;
+		}
+
 		if ( !groupedSnippetsByLanguage[ snippetData.snippetConfig.language ] ) {
 			groupedSnippetsByLanguage[ snippetData.snippetConfig.language ] = new Set();
 		}
@@ -178,6 +185,13 @@ module.exports = function snippetAdapter( snippets, options, umbertoHelpers ) {
 					if ( wasCSSGenerated ) {
 						cssFiles.unshift( path.join( snippetData.relativeOutputPath, snippetData.snippetName, 'snippet.css' ) );
 					}
+
+					// Additional languages must be imported by the HTML code.
+					if ( snippetData.snippetConfig.additionalLanguages ) {
+						snippetData.snippetConfig.additionalLanguages.forEach( language => {
+							jsFiles.push( path.join( snippetData.relativeOutputPath, 'translations', `${ language }.js` ) );
+						} );
+					}
 				}
 
 				const cssImportsHTML = getHTMLImports( cssFiles, importPath => {
@@ -261,6 +275,27 @@ function getWebpackConfig( snippets, config ) {
 		definitions[ definitionKey ] = JSON.stringify( config.definitions[ definitionKey ] );
 	}
 
+	const ckeditorWebpackPluginOptions = {};
+
+	if ( config.language === MULTI_LANGUAGE ) {
+		const additionalLanguages = new Set();
+
+		// Find all additional languages that must be built.
+		for ( const snippetData of snippets ) {
+			for ( const language of snippetData.snippetConfig.additionalLanguages ) {
+				additionalLanguages.add( language );
+			}
+		}
+
+		// Pass unique values of `additionalLanguages` to `CKEditorWebpackPlugin`.
+		ckeditorWebpackPluginOptions.additionalLanguages = [ ...additionalLanguages ];
+
+		// Also, set the default language because of the warning that comes from the plugin.
+		ckeditorWebpackPluginOptions.language = DEFAULT_LANGUAGE;
+	} else {
+		ckeditorWebpackPluginOptions.language = config.language;
+	}
+
 	const webpackConfig = {
 		mode: config.production ? 'production' : 'development',
 
@@ -288,9 +323,7 @@ function getWebpackConfig( snippets, config ) {
 
 		plugins: [
 			new MiniCssExtractPlugin( { filename: '[name]/snippet.css' } ),
-			new CKEditorWebpackPlugin( {
-				language: config.language
-			} ),
+			new CKEditorWebpackPlugin( ckeditorWebpackPluginOptions ),
 			new webpack.BannerPlugin( {
 				banner: bundler.getLicenseBanner(),
 				raw: true
@@ -469,4 +502,6 @@ function getHTMLImports( files, mapFunction ) {
  * @property {String} [language] A language that will be used for building the editor.
  *
  * @property {Array.<String>} [dependencies] Names of samples that are required to working.
+ *
+ * @property {Array.<String>} [additionalLanguages] Additional languages that are required by the snippet.
  */

+ 3 - 3
scripts/update-stable-branches.sh

@@ -14,14 +14,14 @@ then
 	git checkout stable && git merge master && git checkout master
 
 	# Add `#stable` branches in all repos which don't have them yet.
-	mgit exec 'git checkout -b stable 2> /dev/null && git push origin stable && git checkout master'
+	mrgit exec 'git checkout -b stable 2> /dev/null && git push origin stable && git checkout master'
 
 	# Update all `#stable` branches in all packages.
-	mgit exec 'git checkout stable && git pull origin stable && git merge master && git checkout master'
+	mrgit exec 'git checkout stable && git pull origin stable && git merge master && git checkout master'
 
 	# Push the `#stable` branches.
 	git push origin stable master && \
 	mrgit exec 'git push origin stable'
 
 	echo "Success! 🎂"
-fi
+fi

File diff suppressed because it is too large
+ 1010 - 890
yarn.lock