@ckeditor/ckeditor5-language 48.8.1-alpha.3 → 49.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/augmentation.d.ts +45 -45
  2. package/dist/index-content.css +3 -0
  3. package/dist/index-content.css.map +1 -0
  4. package/dist/index-editor.css +3 -0
  5. package/dist/index-editor.css.map +1 -0
  6. package/dist/index.d.ts +12 -12
  7. package/dist/index.js +398 -394
  8. package/dist/index.js.map +1 -1
  9. package/dist/textpartlanguage.d.ts +34 -34
  10. package/dist/textpartlanguagecommand.d.ts +65 -65
  11. package/dist/textpartlanguageconfig.d.ts +20 -20
  12. package/dist/textpartlanguageediting.d.ts +28 -28
  13. package/dist/textpartlanguageui.d.ts +26 -26
  14. package/dist/translations/af.js +1 -1
  15. package/dist/translations/af.umd.js +5 -3
  16. package/dist/translations/ar.js +1 -1
  17. package/dist/translations/ar.umd.js +5 -3
  18. package/dist/translations/ast.js +1 -1
  19. package/dist/translations/ast.umd.js +5 -3
  20. package/dist/translations/az.js +1 -1
  21. package/dist/translations/az.umd.js +5 -3
  22. package/dist/translations/be.js +1 -1
  23. package/dist/translations/be.umd.js +5 -3
  24. package/dist/translations/bg.js +1 -1
  25. package/dist/translations/bg.umd.js +5 -3
  26. package/dist/translations/bn.js +1 -1
  27. package/dist/translations/bn.umd.js +5 -3
  28. package/dist/translations/bs.js +1 -1
  29. package/dist/translations/bs.umd.js +5 -3
  30. package/dist/translations/ca.js +1 -1
  31. package/dist/translations/ca.umd.js +5 -3
  32. package/dist/translations/cs.js +1 -1
  33. package/dist/translations/cs.umd.js +5 -3
  34. package/dist/translations/da.js +1 -1
  35. package/dist/translations/da.umd.js +5 -3
  36. package/dist/translations/de-ch.js +1 -1
  37. package/dist/translations/de-ch.umd.js +5 -3
  38. package/dist/translations/de.js +1 -1
  39. package/dist/translations/de.umd.js +5 -3
  40. package/dist/translations/el.js +1 -1
  41. package/dist/translations/el.umd.js +5 -3
  42. package/dist/translations/en-au.js +1 -1
  43. package/dist/translations/en-au.umd.js +5 -3
  44. package/dist/translations/en-gb.js +1 -1
  45. package/dist/translations/en-gb.umd.js +5 -3
  46. package/dist/translations/en.js +1 -1
  47. package/dist/translations/en.umd.js +5 -3
  48. package/dist/translations/eo.js +1 -1
  49. package/dist/translations/eo.umd.js +5 -3
  50. package/dist/translations/es-co.js +1 -1
  51. package/dist/translations/es-co.umd.js +5 -3
  52. package/dist/translations/es.js +1 -1
  53. package/dist/translations/es.umd.js +5 -3
  54. package/dist/translations/et.js +1 -1
  55. package/dist/translations/et.umd.js +5 -3
  56. package/dist/translations/eu.js +1 -1
  57. package/dist/translations/eu.umd.js +5 -3
  58. package/dist/translations/fa.js +1 -1
  59. package/dist/translations/fa.umd.js +5 -3
  60. package/dist/translations/fi.js +1 -1
  61. package/dist/translations/fi.umd.js +5 -3
  62. package/dist/translations/fr.js +1 -1
  63. package/dist/translations/fr.umd.js +5 -3
  64. package/dist/translations/gl.js +1 -1
  65. package/dist/translations/gl.umd.js +5 -3
  66. package/dist/translations/gu.js +1 -1
  67. package/dist/translations/gu.umd.js +5 -3
  68. package/dist/translations/he.js +1 -1
  69. package/dist/translations/he.umd.js +5 -3
  70. package/dist/translations/hi.js +1 -1
  71. package/dist/translations/hi.umd.js +5 -3
  72. package/dist/translations/hr.js +1 -1
  73. package/dist/translations/hr.umd.js +5 -3
  74. package/dist/translations/hu.js +1 -1
  75. package/dist/translations/hu.umd.js +5 -3
  76. package/dist/translations/hy.js +1 -1
  77. package/dist/translations/hy.umd.js +5 -3
  78. package/dist/translations/id.js +1 -1
  79. package/dist/translations/id.umd.js +5 -3
  80. package/dist/translations/it.js +1 -1
  81. package/dist/translations/it.umd.js +5 -3
  82. package/dist/translations/ja.js +1 -1
  83. package/dist/translations/ja.umd.js +5 -3
  84. package/dist/translations/jv.js +1 -1
  85. package/dist/translations/jv.umd.js +5 -3
  86. package/dist/translations/kk.js +1 -1
  87. package/dist/translations/kk.umd.js +5 -3
  88. package/dist/translations/km.js +1 -1
  89. package/dist/translations/km.umd.js +5 -3
  90. package/dist/translations/kn.js +1 -1
  91. package/dist/translations/kn.umd.js +5 -3
  92. package/dist/translations/ko.js +1 -1
  93. package/dist/translations/ko.umd.js +5 -3
  94. package/dist/translations/ku.js +1 -1
  95. package/dist/translations/ku.umd.js +5 -3
  96. package/dist/translations/lt.js +1 -1
  97. package/dist/translations/lt.umd.js +5 -3
  98. package/dist/translations/lv.js +1 -1
  99. package/dist/translations/lv.umd.js +5 -3
  100. package/dist/translations/ms.js +1 -1
  101. package/dist/translations/ms.umd.js +5 -3
  102. package/dist/translations/nb.js +1 -1
  103. package/dist/translations/nb.umd.js +5 -3
  104. package/dist/translations/ne.js +1 -1
  105. package/dist/translations/ne.umd.js +5 -3
  106. package/dist/translations/nl.js +1 -1
  107. package/dist/translations/nl.umd.js +5 -3
  108. package/dist/translations/no.js +1 -1
  109. package/dist/translations/no.umd.js +5 -3
  110. package/dist/translations/oc.js +1 -1
  111. package/dist/translations/oc.umd.js +5 -3
  112. package/dist/translations/pl.js +1 -1
  113. package/dist/translations/pl.umd.js +5 -3
  114. package/dist/translations/pt-br.js +1 -1
  115. package/dist/translations/pt-br.umd.js +5 -3
  116. package/dist/translations/pt.js +1 -1
  117. package/dist/translations/pt.umd.js +5 -3
  118. package/dist/translations/ro.js +1 -1
  119. package/dist/translations/ro.umd.js +5 -3
  120. package/dist/translations/ru.js +1 -1
  121. package/dist/translations/ru.umd.js +5 -3
  122. package/dist/translations/si.js +1 -1
  123. package/dist/translations/si.umd.js +5 -3
  124. package/dist/translations/sk.js +1 -1
  125. package/dist/translations/sk.umd.js +5 -3
  126. package/dist/translations/sl.js +1 -1
  127. package/dist/translations/sl.umd.js +5 -3
  128. package/dist/translations/sq.js +1 -1
  129. package/dist/translations/sq.umd.js +5 -3
  130. package/dist/translations/sr-latn.js +1 -1
  131. package/dist/translations/sr-latn.umd.js +5 -3
  132. package/dist/translations/sr.js +1 -1
  133. package/dist/translations/sr.umd.js +5 -3
  134. package/dist/translations/sv.js +1 -1
  135. package/dist/translations/sv.umd.js +5 -3
  136. package/dist/translations/th.js +1 -1
  137. package/dist/translations/th.umd.js +5 -3
  138. package/dist/translations/ti.js +1 -1
  139. package/dist/translations/ti.umd.js +5 -3
  140. package/dist/translations/tk.js +1 -1
  141. package/dist/translations/tk.umd.js +5 -3
  142. package/dist/translations/tr.js +1 -1
  143. package/dist/translations/tr.umd.js +5 -3
  144. package/dist/translations/tt.js +1 -1
  145. package/dist/translations/tt.umd.js +5 -3
  146. package/dist/translations/ug.js +1 -1
  147. package/dist/translations/ug.umd.js +5 -3
  148. package/dist/translations/uk.js +1 -1
  149. package/dist/translations/uk.umd.js +5 -3
  150. package/dist/translations/ur.js +1 -1
  151. package/dist/translations/ur.umd.js +5 -3
  152. package/dist/translations/uz.js +1 -1
  153. package/dist/translations/uz.umd.js +5 -3
  154. package/dist/translations/vi.js +1 -1
  155. package/dist/translations/vi.umd.js +5 -3
  156. package/dist/translations/zh-cn.js +1 -1
  157. package/dist/translations/zh-cn.umd.js +5 -3
  158. package/dist/translations/zh.js +1 -1
  159. package/dist/translations/zh.umd.js +5 -3
  160. package/dist/utils.d.ts +35 -35
  161. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -2,412 +2,416 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { ModelDocumentSelection } from '@ckeditor/ckeditor5-engine/dist/index.js';
7
- import { getLanguageDirection, Collection } from '@ckeditor/ckeditor5-utils/dist/index.js';
8
- import { createDropdown, addListToDropdown, MenuBarMenuView, MenuBarMenuListView, ListSeparatorView, MenuBarMenuListItemView, MenuBarMenuListItemButtonView, UIModel } from '@ckeditor/ckeditor5-ui/dist/index.js';
5
+ import { Command, Plugin } from "@ckeditor/ckeditor5-core";
6
+ import { ModelDocumentSelection } from "@ckeditor/ckeditor5-engine";
7
+ import { Collection, getLanguageDirection } from "@ckeditor/ckeditor5-utils";
8
+ import { ListSeparatorView, MenuBarMenuListItemButtonView, MenuBarMenuListItemView, MenuBarMenuListView, MenuBarMenuView, UIModel, addListToDropdown, createDropdown } from "@ckeditor/ckeditor5-ui";
9
9
 
10
10
  /**
11
- * Returns the language attribute value in a human-readable text format:
12
- *
13
- * ```
14
- * <languageCode>:<textDirection>
15
- * ```
16
- *
17
- * * `languageCode` - The language code used for the `lang` attribute in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
18
- * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language.
19
- *
20
- * See the {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part language configuration}
21
- * for more information about language properties.
22
- *
23
- * If the `textDirection` argument is omitted, it will be automatically detected based on `languageCode`.
24
- *
25
- * @param languageCode The language code in the ISO 639-1 format.
26
- * @param textDirection The language text direction. Automatically detected if omitted.
27
- * @internal
28
- */ function stringifyLanguageAttribute(languageCode, textDirection) {
29
- textDirection = textDirection || getLanguageDirection(languageCode);
30
- return `${languageCode}:${textDirection}`;
11
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
12
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
13
+ */
14
+ /**
15
+ * @module language/utils
16
+ */
17
+ /**
18
+ * Returns the language attribute value in a human-readable text format:
19
+ *
20
+ * ```
21
+ * <languageCode>:<textDirection>
22
+ * ```
23
+ *
24
+ * * `languageCode` - The language code used for the `lang` attribute in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
25
+ * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language.
26
+ *
27
+ * See the {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part language configuration}
28
+ * for more information about language properties.
29
+ *
30
+ * If the `textDirection` argument is omitted, it will be automatically detected based on `languageCode`.
31
+ *
32
+ * @param languageCode The language code in the ISO 639-1 format.
33
+ * @param textDirection The language text direction. Automatically detected if omitted.
34
+ * @internal
35
+ */
36
+ function stringifyLanguageAttribute(languageCode, textDirection) {
37
+ textDirection = textDirection || getLanguageDirection(languageCode);
38
+ return `${languageCode}:${textDirection}`;
31
39
  }
32
40
  /**
33
- * Retrieves language properties converted to attribute value by the
34
- * {@link module:language/utils~stringifyLanguageAttribute stringifyLanguageAttribute} function.
35
- *
36
- * @internal
37
- * @param str The attribute value.
38
- * @returns The object with properties:
39
- * * languageCode - The language code in the ISO 639 format.
40
- * * textDirection - The language text direction.
41
- */ function parseLanguageAttribute(str) {
42
- const [languageCode, textDirection] = str.split(':');
43
- return {
44
- languageCode,
45
- textDirection
46
- };
41
+ * Retrieves language properties converted to attribute value by the
42
+ * {@link module:language/utils~stringifyLanguageAttribute stringifyLanguageAttribute} function.
43
+ *
44
+ * @internal
45
+ * @param str The attribute value.
46
+ * @returns The object with properties:
47
+ * * languageCode - The language code in the ISO 639 format.
48
+ * * textDirection - The language text direction.
49
+ */
50
+ function parseLanguageAttribute(str) {
51
+ const [languageCode, textDirection] = str.split(":");
52
+ return {
53
+ languageCode,
54
+ textDirection
55
+ };
47
56
  }
48
57
 
49
58
  /**
50
- * The text part language command plugin.
51
- */ class TextPartLanguageCommand extends Command {
52
- /**
53
- * @inheritDoc
54
- */ refresh() {
55
- const model = this.editor.model;
56
- const doc = model.document;
57
- this.value = this._getValueFromFirstAllowedNode();
58
- this.isEnabled = model.schema.checkAttributeInSelection(doc.selection, 'language');
59
- }
60
- /**
61
- * Executes the command. Applies the attribute to the selection or removes it from the selection.
62
- *
63
- * If `languageCode` is set to `false` or a `null` value, it will remove attributes. Otherwise, it will set
64
- * the attribute in the `{@link #value value}` format.
65
- *
66
- * The execution result differs, depending on the {@link module:engine/model/document~ModelDocument#selection}:
67
- *
68
- * * If the selection is on a range, the command applies the attribute to all nodes in that range
69
- * (if they are allowed to have this attribute by the {@link module:engine/model/schema~ModelSchema schema}).
70
- * * If the selection is collapsed in a non-empty node, the command applies the attribute to the
71
- * {@link module:engine/model/document~ModelDocument#selection} itself (note that typed characters copy attributes from the selection).
72
- * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note
73
- * that the selection inherits all attributes from a node if it is in an empty node).
74
- *
75
- * @fires execute
76
- * @param options Command options.
77
- * @param options.languageCode The language code to be applied to the model.
78
- * @param options.textDirection The language text direction.
79
- */ execute({ languageCode, textDirection } = {}) {
80
- const model = this.editor.model;
81
- const doc = model.document;
82
- const selection = doc.selection;
83
- const value = languageCode ? stringifyLanguageAttribute(languageCode, textDirection) : false;
84
- model.change((writer)=>{
85
- if (selection.isCollapsed) {
86
- if (value) {
87
- writer.setSelectionAttribute('language', value);
88
- } else {
89
- writer.removeSelectionAttribute('language');
90
- }
91
- } else {
92
- const ranges = model.schema.getValidRanges(selection.getRanges(), 'language', {
93
- includeEmptyRanges: true
94
- });
95
- for (const range of ranges){
96
- let itemOrRange = range;
97
- let attributeKey = 'language';
98
- if (range.isCollapsed) {
99
- itemOrRange = range.start.parent;
100
- attributeKey = ModelDocumentSelection._getStoreAttributeKey('language');
101
- }
102
- if (value) {
103
- writer.setAttribute(attributeKey, value, itemOrRange);
104
- } else {
105
- writer.removeAttribute(attributeKey, itemOrRange);
106
- }
107
- }
108
- }
109
- });
110
- }
111
- /**
112
- * Returns the attribute value of the first node in the selection that allows the attribute.
113
- * For a collapsed selection it returns the selection attribute.
114
- *
115
- * @returns The attribute value.
116
- */ _getValueFromFirstAllowedNode() {
117
- const model = this.editor.model;
118
- const schema = model.schema;
119
- const selection = model.document.selection;
120
- if (selection.isCollapsed) {
121
- return selection.getAttribute('language') || false;
122
- }
123
- for (const range of selection.getRanges()){
124
- for (const item of range.getItems()){
125
- if (schema.checkAttribute(item, 'language')) {
126
- return item.getAttribute('language') || false;
127
- }
128
- }
129
- }
130
- return false;
131
- }
132
- }
59
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
60
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
61
+ */
62
+ /**
63
+ * The text part language command plugin.
64
+ */
65
+ var TextPartLanguageCommand = class extends Command {
66
+ /**
67
+ * @inheritDoc
68
+ */
69
+ refresh() {
70
+ const model = this.editor.model;
71
+ const doc = model.document;
72
+ this.value = this._getValueFromFirstAllowedNode();
73
+ this.isEnabled = model.schema.checkAttributeInSelection(doc.selection, "language");
74
+ }
75
+ /**
76
+ * Executes the command. Applies the attribute to the selection or removes it from the selection.
77
+ *
78
+ * If `languageCode` is set to `false` or a `null` value, it will remove attributes. Otherwise, it will set
79
+ * the attribute in the `{@link #value value}` format.
80
+ *
81
+ * The execution result differs, depending on the {@link module:engine/model/document~ModelDocument#selection}:
82
+ *
83
+ * * If the selection is on a range, the command applies the attribute to all nodes in that range
84
+ * (if they are allowed to have this attribute by the {@link module:engine/model/schema~ModelSchema schema}).
85
+ * * If the selection is collapsed in a non-empty node, the command applies the attribute to the
86
+ * {@link module:engine/model/document~ModelDocument#selection} itself (note that typed characters copy attributes from the selection).
87
+ * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note
88
+ * that the selection inherits all attributes from a node if it is in an empty node).
89
+ *
90
+ * @fires execute
91
+ * @param options Command options.
92
+ * @param options.languageCode The language code to be applied to the model.
93
+ * @param options.textDirection The language text direction.
94
+ */
95
+ execute({ languageCode, textDirection } = {}) {
96
+ const model = this.editor.model;
97
+ const selection = model.document.selection;
98
+ const value = languageCode ? stringifyLanguageAttribute(languageCode, textDirection) : false;
99
+ model.change((writer) => {
100
+ if (selection.isCollapsed) {
101
+ if (value) writer.setSelectionAttribute("language", value);
102
+ else writer.removeSelectionAttribute("language");
103
+ } else {
104
+ const ranges = model.schema.getValidRanges(selection.getRanges(), "language", { includeEmptyRanges: true });
105
+ for (const range of ranges) {
106
+ let itemOrRange = range;
107
+ let attributeKey = "language";
108
+ if (range.isCollapsed) {
109
+ itemOrRange = range.start.parent;
110
+ attributeKey = ModelDocumentSelection._getStoreAttributeKey("language");
111
+ }
112
+ if (value) writer.setAttribute(attributeKey, value, itemOrRange);
113
+ else writer.removeAttribute(attributeKey, itemOrRange);
114
+ }
115
+ }
116
+ });
117
+ }
118
+ /**
119
+ * Returns the attribute value of the first node in the selection that allows the attribute.
120
+ * For a collapsed selection it returns the selection attribute.
121
+ *
122
+ * @returns The attribute value.
123
+ */
124
+ _getValueFromFirstAllowedNode() {
125
+ const model = this.editor.model;
126
+ const schema = model.schema;
127
+ const selection = model.document.selection;
128
+ if (selection.isCollapsed) return selection.getAttribute("language") || false;
129
+ for (const range of selection.getRanges()) for (const item of range.getItems()) if (schema.checkAttribute(item, "language")) return item.getAttribute("language") || false;
130
+ return false;
131
+ }
132
+ };
133
133
 
134
134
  /**
135
- * The text part language editing.
136
- *
137
- * Introduces the `'textPartLanguage'` command and the `'language'` model element attribute.
138
- */ class TextPartLanguageEditing extends Plugin {
139
- /**
140
- * @inheritDoc
141
- */ static get pluginName() {
142
- return 'TextPartLanguageEditing';
143
- }
144
- /**
145
- * @inheritDoc
146
- */ static get isOfficialPlugin() {
147
- return true;
148
- }
149
- /**
150
- * @inheritDoc
151
- */ constructor(editor){
152
- super(editor);
153
- // Text part language options are only used to ensure that the feature works by default.
154
- // In the real usage it should be reconfigured by a developer. We are not providing
155
- // translations for `title` properties on purpose, as it's only an example configuration.
156
- editor.config.define('language', {
157
- textPartLanguage: [
158
- {
159
- title: 'Arabic',
160
- languageCode: 'ar'
161
- },
162
- {
163
- title: 'French',
164
- languageCode: 'fr'
165
- },
166
- {
167
- title: 'Spanish',
168
- languageCode: 'es'
169
- }
170
- ]
171
- });
172
- }
173
- /**
174
- * @inheritDoc
175
- */ init() {
176
- const editor = this.editor;
177
- editor.model.schema.extend('$text', {
178
- allowAttributes: 'language'
179
- });
180
- editor.model.schema.setAttributeProperties('language', {
181
- copyOnEnter: true
182
- });
183
- this._defineConverters();
184
- editor.commands.add('textPartLanguage', new TextPartLanguageCommand(editor));
185
- }
186
- /**
187
- * @private
188
- */ _defineConverters() {
189
- const conversion = this.editor.conversion;
190
- conversion.for('upcast').elementToAttribute({
191
- model: {
192
- key: 'language',
193
- value: (viewElement)=>{
194
- const languageCode = viewElement.getAttribute('lang');
195
- const textDirection = viewElement.getAttribute('dir');
196
- return stringifyLanguageAttribute(languageCode, textDirection);
197
- }
198
- },
199
- view: {
200
- name: 'span',
201
- attributes: {
202
- lang: /[\s\S]+/
203
- }
204
- }
205
- });
206
- conversion.for('downcast').attributeToElement({
207
- model: 'language',
208
- view: (attributeValue, { writer }, data)=>{
209
- if (!attributeValue) {
210
- return;
211
- }
212
- if (!data.item.is('$textProxy') && !data.item.is('documentSelection')) {
213
- return;
214
- }
215
- const { languageCode, textDirection } = parseLanguageAttribute(attributeValue);
216
- return writer.createAttributeElement('span', {
217
- lang: languageCode,
218
- dir: textDirection
219
- });
220
- }
221
- });
222
- }
223
- }
135
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
136
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
137
+ */
138
+ /**
139
+ * The text part language editing.
140
+ *
141
+ * Introduces the `'textPartLanguage'` command and the `'language'` model element attribute.
142
+ */
143
+ var TextPartLanguageEditing = class extends Plugin {
144
+ /**
145
+ * @inheritDoc
146
+ */
147
+ static get pluginName() {
148
+ return "TextPartLanguageEditing";
149
+ }
150
+ /**
151
+ * @inheritDoc
152
+ */
153
+ static get isOfficialPlugin() {
154
+ return true;
155
+ }
156
+ /**
157
+ * @inheritDoc
158
+ */
159
+ constructor(editor) {
160
+ super(editor);
161
+ editor.config.define("language", { textPartLanguage: [
162
+ {
163
+ title: "Arabic",
164
+ languageCode: "ar"
165
+ },
166
+ {
167
+ title: "French",
168
+ languageCode: "fr"
169
+ },
170
+ {
171
+ title: "Spanish",
172
+ languageCode: "es"
173
+ }
174
+ ] });
175
+ }
176
+ /**
177
+ * @inheritDoc
178
+ */
179
+ init() {
180
+ const editor = this.editor;
181
+ editor.model.schema.extend("$text", { allowAttributes: "language" });
182
+ editor.model.schema.setAttributeProperties("language", { copyOnEnter: true });
183
+ this._defineConverters();
184
+ editor.commands.add("textPartLanguage", new TextPartLanguageCommand(editor));
185
+ }
186
+ /**
187
+ * @private
188
+ */
189
+ _defineConverters() {
190
+ const conversion = this.editor.conversion;
191
+ conversion.for("upcast").elementToAttribute({
192
+ model: {
193
+ key: "language",
194
+ value: (viewElement) => {
195
+ const languageCode = viewElement.getAttribute("lang");
196
+ const textDirection = viewElement.getAttribute("dir");
197
+ return stringifyLanguageAttribute(languageCode, textDirection);
198
+ }
199
+ },
200
+ view: {
201
+ name: "span",
202
+ attributes: { lang: /[\s\S]+/ }
203
+ }
204
+ });
205
+ conversion.for("downcast").attributeToElement({
206
+ model: "language",
207
+ view: (attributeValue, { writer }, data) => {
208
+ if (!attributeValue) return;
209
+ if (!data.item.is("$textProxy") && !data.item.is("documentSelection")) return;
210
+ const { languageCode, textDirection } = parseLanguageAttribute(attributeValue);
211
+ return writer.createAttributeElement("span", {
212
+ lang: languageCode,
213
+ dir: textDirection
214
+ });
215
+ }
216
+ });
217
+ }
218
+ };
224
219
 
225
220
  /**
226
- * The text part language UI plugin.
227
- *
228
- * It introduces the `'language'` dropdown.
229
- */ class TextPartLanguageUI extends Plugin {
230
- /**
231
- * @inheritDoc
232
- */ static get pluginName() {
233
- return 'TextPartLanguageUI';
234
- }
235
- /**
236
- * @inheritDoc
237
- */ static get isOfficialPlugin() {
238
- return true;
239
- }
240
- /**
241
- * @inheritDoc
242
- */ init() {
243
- const editor = this.editor;
244
- const t = editor.t;
245
- const defaultTitle = t('Choose language');
246
- const accessibleLabel = t('Language');
247
- // Register UI component.
248
- editor.ui.componentFactory.add('textPartLanguage', (locale)=>{
249
- const { definitions, titles } = this._getItemMetadata();
250
- const languageCommand = editor.commands.get('textPartLanguage');
251
- const dropdownView = createDropdown(locale);
252
- addListToDropdown(dropdownView, definitions, {
253
- ariaLabel: accessibleLabel,
254
- role: 'menu'
255
- });
256
- dropdownView.buttonView.set({
257
- ariaLabel: accessibleLabel,
258
- ariaLabelledBy: undefined,
259
- isOn: false,
260
- withText: true,
261
- tooltip: accessibleLabel
262
- });
263
- dropdownView.extendTemplate({
264
- attributes: {
265
- class: [
266
- 'ck-text-fragment-language-dropdown'
267
- ]
268
- }
269
- });
270
- dropdownView.bind('isEnabled').to(languageCommand, 'isEnabled');
271
- dropdownView.buttonView.bind('label').to(languageCommand, 'value', (value)=>{
272
- return value && titles[value] || defaultTitle;
273
- });
274
- dropdownView.buttonView.bind('ariaLabel').to(languageCommand, 'value', (value)=>{
275
- const selectedLanguageTitle = value && titles[value];
276
- if (!selectedLanguageTitle) {
277
- return accessibleLabel;
278
- }
279
- return `${selectedLanguageTitle}, ${accessibleLabel}`;
280
- });
281
- // Execute command when an item from the dropdown is selected.
282
- this.listenTo(dropdownView, 'execute', (evt)=>{
283
- languageCommand.execute({
284
- languageCode: evt.source.languageCode,
285
- textDirection: evt.source.textDirection
286
- });
287
- editor.editing.view.focus();
288
- });
289
- return dropdownView;
290
- });
291
- // Register menu bar UI component.
292
- editor.ui.componentFactory.add('menuBar:textPartLanguage', (locale)=>{
293
- const { definitions } = this._getItemMetadata();
294
- const languageCommand = editor.commands.get('textPartLanguage');
295
- const menuView = new MenuBarMenuView(locale);
296
- menuView.buttonView.set({
297
- label: accessibleLabel
298
- });
299
- const listView = new MenuBarMenuListView(locale);
300
- listView.set({
301
- ariaLabel: t('Language'),
302
- role: 'menu'
303
- });
304
- for (const definition of definitions){
305
- if (definition.type != 'button') {
306
- listView.items.add(new ListSeparatorView(locale));
307
- continue;
308
- }
309
- const listItemView = new MenuBarMenuListItemView(locale, menuView);
310
- const buttonView = new MenuBarMenuListItemButtonView(locale);
311
- buttonView.set({
312
- role: 'menuitemradio',
313
- isToggleable: true
314
- });
315
- buttonView.bind(...Object.keys(definition.model)).to(definition.model);
316
- buttonView.delegate('execute').to(menuView);
317
- listItemView.children.add(buttonView);
318
- listView.items.add(listItemView);
319
- }
320
- menuView.bind('isEnabled').to(languageCommand, 'isEnabled');
321
- menuView.panelView.children.add(listView);
322
- menuView.on('execute', (evt)=>{
323
- languageCommand.execute({
324
- languageCode: evt.source.languageCode,
325
- textDirection: evt.source.textDirection
326
- });
327
- editor.editing.view.focus();
328
- });
329
- return menuView;
330
- });
331
- }
332
- /**
333
- * Returns metadata for dropdown and menu items.
334
- */ _getItemMetadata() {
335
- const editor = this.editor;
336
- const itemDefinitions = new Collection();
337
- const titles = {};
338
- const languageCommand = editor.commands.get('textPartLanguage');
339
- const options = editor.config.get('language.textPartLanguage');
340
- const t = editor.locale.t;
341
- const removeTitle = t('Remove language');
342
- // Item definition with false `languageCode` will behave as remove lang button.
343
- itemDefinitions.add({
344
- type: 'button',
345
- model: new UIModel({
346
- label: removeTitle,
347
- languageCode: false,
348
- withText: true
349
- })
350
- });
351
- itemDefinitions.add({
352
- type: 'separator'
353
- });
354
- for (const option of options){
355
- const def = {
356
- type: 'button',
357
- model: new UIModel({
358
- label: option.title,
359
- languageCode: option.languageCode,
360
- role: 'menuitemradio',
361
- textDirection: option.textDirection,
362
- withText: true
363
- })
364
- };
365
- const language = stringifyLanguageAttribute(option.languageCode, option.textDirection);
366
- def.model.bind('isOn').to(languageCommand, 'value', (value)=>value === language);
367
- itemDefinitions.add(def);
368
- titles[language] = option.title;
369
- }
370
- return {
371
- definitions: itemDefinitions,
372
- titles
373
- };
374
- }
375
- }
221
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
222
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
223
+ */
224
+ /**
225
+ * @module language/textpartlanguageui
226
+ */
227
+ /**
228
+ * The text part language UI plugin.
229
+ *
230
+ * It introduces the `'language'` dropdown.
231
+ */
232
+ var TextPartLanguageUI = class extends Plugin {
233
+ /**
234
+ * @inheritDoc
235
+ */
236
+ static get pluginName() {
237
+ return "TextPartLanguageUI";
238
+ }
239
+ /**
240
+ * @inheritDoc
241
+ */
242
+ static get isOfficialPlugin() {
243
+ return true;
244
+ }
245
+ /**
246
+ * @inheritDoc
247
+ */
248
+ init() {
249
+ const editor = this.editor;
250
+ const t = editor.t;
251
+ const defaultTitle = t("Choose language");
252
+ const accessibleLabel = t("Language");
253
+ editor.ui.componentFactory.add("textPartLanguage", (locale) => {
254
+ const { definitions, titles } = this._getItemMetadata();
255
+ const languageCommand = editor.commands.get("textPartLanguage");
256
+ const dropdownView = createDropdown(locale);
257
+ addListToDropdown(dropdownView, definitions, {
258
+ ariaLabel: accessibleLabel,
259
+ role: "menu"
260
+ });
261
+ dropdownView.buttonView.set({
262
+ ariaLabel: accessibleLabel,
263
+ ariaLabelledBy: void 0,
264
+ isOn: false,
265
+ withText: true,
266
+ tooltip: accessibleLabel
267
+ });
268
+ dropdownView.extendTemplate({ attributes: { class: ["ck-text-fragment-language-dropdown"] } });
269
+ dropdownView.bind("isEnabled").to(languageCommand, "isEnabled");
270
+ dropdownView.buttonView.bind("label").to(languageCommand, "value", (value) => {
271
+ return value && titles[value] || defaultTitle;
272
+ });
273
+ dropdownView.buttonView.bind("ariaLabel").to(languageCommand, "value", (value) => {
274
+ const selectedLanguageTitle = value && titles[value];
275
+ if (!selectedLanguageTitle) return accessibleLabel;
276
+ return `${selectedLanguageTitle}, ${accessibleLabel}`;
277
+ });
278
+ this.listenTo(dropdownView, "execute", (evt) => {
279
+ languageCommand.execute({
280
+ languageCode: evt.source.languageCode,
281
+ textDirection: evt.source.textDirection
282
+ });
283
+ editor.editing.view.focus();
284
+ });
285
+ return dropdownView;
286
+ });
287
+ editor.ui.componentFactory.add("menuBar:textPartLanguage", (locale) => {
288
+ const { definitions } = this._getItemMetadata();
289
+ const languageCommand = editor.commands.get("textPartLanguage");
290
+ const menuView = new MenuBarMenuView(locale);
291
+ menuView.buttonView.set({ label: accessibleLabel });
292
+ const listView = new MenuBarMenuListView(locale);
293
+ listView.set({
294
+ ariaLabel: t("Language"),
295
+ role: "menu"
296
+ });
297
+ for (const definition of definitions) {
298
+ if (definition.type != "button") {
299
+ listView.items.add(new ListSeparatorView(locale));
300
+ continue;
301
+ }
302
+ const listItemView = new MenuBarMenuListItemView(locale, menuView);
303
+ const buttonView = new MenuBarMenuListItemButtonView(locale);
304
+ buttonView.set({
305
+ role: "menuitemradio",
306
+ isToggleable: true
307
+ });
308
+ buttonView.bind(...Object.keys(definition.model)).to(definition.model);
309
+ buttonView.delegate("execute").to(menuView);
310
+ listItemView.children.add(buttonView);
311
+ listView.items.add(listItemView);
312
+ }
313
+ menuView.bind("isEnabled").to(languageCommand, "isEnabled");
314
+ menuView.panelView.children.add(listView);
315
+ menuView.on("execute", (evt) => {
316
+ languageCommand.execute({
317
+ languageCode: evt.source.languageCode,
318
+ textDirection: evt.source.textDirection
319
+ });
320
+ editor.editing.view.focus();
321
+ });
322
+ return menuView;
323
+ });
324
+ }
325
+ /**
326
+ * Returns metadata for dropdown and menu items.
327
+ */
328
+ _getItemMetadata() {
329
+ const editor = this.editor;
330
+ const itemDefinitions = new Collection();
331
+ const titles = {};
332
+ const languageCommand = editor.commands.get("textPartLanguage");
333
+ const options = editor.config.get("language.textPartLanguage");
334
+ const t = editor.locale.t;
335
+ const removeTitle = t("Remove language");
336
+ itemDefinitions.add({
337
+ type: "button",
338
+ model: new UIModel({
339
+ label: removeTitle,
340
+ languageCode: false,
341
+ withText: true
342
+ })
343
+ });
344
+ itemDefinitions.add({ type: "separator" });
345
+ for (const option of options) {
346
+ const def = {
347
+ type: "button",
348
+ model: new UIModel({
349
+ label: option.title,
350
+ languageCode: option.languageCode,
351
+ role: "menuitemradio",
352
+ textDirection: option.textDirection,
353
+ withText: true
354
+ })
355
+ };
356
+ const language = stringifyLanguageAttribute(option.languageCode, option.textDirection);
357
+ def.model.bind("isOn").to(languageCommand, "value", (value) => value === language);
358
+ itemDefinitions.add(def);
359
+ titles[language] = option.title;
360
+ }
361
+ return {
362
+ definitions: itemDefinitions,
363
+ titles
364
+ };
365
+ }
366
+ };
376
367
 
377
368
  /**
378
- * The text part language feature.
379
- *
380
- * This feature allows setting a language of the document's text part to support
381
- * [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification.
382
- *
383
- * To change the editor's UI language, refer to the {@glink getting-started/setup/ui-language Setting the UI language} guide.
384
- *
385
- * For more information about this feature, check the {@glink api/language package page} as well as the {@glink features/language
386
- * Text part language} feature guide.
387
- *
388
- * This is a "glue" plugin which loads the
389
- * {@link module:language/textpartlanguageediting~TextPartLanguageEditing text part language editing feature}
390
- * and the {@link module:language/textpartlanguageui~TextPartLanguageUI text part language UI feature}.
391
- */ class TextPartLanguage extends Plugin {
392
- /**
393
- * @inheritDoc
394
- */ static get requires() {
395
- return [
396
- TextPartLanguageEditing,
397
- TextPartLanguageUI
398
- ];
399
- }
400
- /**
401
- * @inheritDoc
402
- */ static get pluginName() {
403
- return 'TextPartLanguage';
404
- }
405
- /**
406
- * @inheritDoc
407
- */ static get isOfficialPlugin() {
408
- return true;
409
- }
410
- }
369
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
370
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
371
+ */
372
+ /**
373
+ * @module language/textpartlanguage
374
+ */
375
+ /**
376
+ * The text part language feature.
377
+ *
378
+ * This feature allows setting a language of the document's text part to support
379
+ * [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification.
380
+ *
381
+ * To change the editor's UI language, refer to the {@glink getting-started/setup/ui-language Setting the UI language} guide.
382
+ *
383
+ * For more information about this feature, check the {@glink api/language package page} as well as the {@glink features/language
384
+ * Text part language} feature guide.
385
+ *
386
+ * This is a "glue" plugin which loads the
387
+ * {@link module:language/textpartlanguageediting~TextPartLanguageEditing text part language editing feature}
388
+ * and the {@link module:language/textpartlanguageui~TextPartLanguageUI text part language UI feature}.
389
+ */
390
+ var TextPartLanguage = class extends Plugin {
391
+ /**
392
+ * @inheritDoc
393
+ */
394
+ static get requires() {
395
+ return [TextPartLanguageEditing, TextPartLanguageUI];
396
+ }
397
+ /**
398
+ * @inheritDoc
399
+ */
400
+ static get pluginName() {
401
+ return "TextPartLanguage";
402
+ }
403
+ /**
404
+ * @inheritDoc
405
+ */
406
+ static get isOfficialPlugin() {
407
+ return true;
408
+ }
409
+ };
410
+
411
+ /**
412
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
413
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
414
+ */
411
415
 
412
416
  export { TextPartLanguage, TextPartLanguageCommand, TextPartLanguageEditing, TextPartLanguageUI, parseLanguageAttribute as _parseLanguageAttribute, stringifyLanguageAttribute as _stringifyLanguageAttribute };
413
- //# sourceMappingURL=index.js.map
417
+ //# sourceMappingURL=index.js.map