locize 3.0.5 → 3.1.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ### 3.1.0
2
+
3
+ - additional plugin interface that shows incontext only if passing `?incontext=true``
4
+
1
5
  ### 3.0.5
2
6
 
3
7
  - fix scrollTop
package/README.md CHANGED
@@ -16,67 +16,92 @@ npm i locize
16
16
 
17
17
  **Hint:** This module runs only in browser.
18
18
 
19
- ## Using
19
+ ### InContext variants
20
20
 
21
- ### with a bundler
21
+ For i18next based solutions (i18next, react-i18next, locizify, ...) there are two options to work with locize incontext:
22
22
 
23
- Just init like:
23
+ #### a) Iframe on your page
24
24
 
25
- ```js
26
- import 'locize';
27
- ```
25
+ The solution is best in class and uses [i18next-subliminal](https://github.com/i18next/i18next-subliminal) to add information about key and namespace as hidden text to the output of the `i18next.t` calls. Beside that it scans your website based on mutation observer to look out for those texts.
28
26
 
29
- ### by including the script
27
+ You can both click text elements on your website or keys in the locize iframe to edit content. Results will always be exact matches based on the namespace and key.
30
28
 
31
- ```html
32
- <script src="https://unpkg.com/locize/locize.min.js" />
33
- ```
29
+ **Hint:** You can bind the ifame to a specific project by setting `ì18next.options.editor = { projectId, version }` or `ì18next.options.backend = { projectId, verstion }` (backend info might already exist when using i18next-locize-backend)
30
+
31
+ **Caveats:** You might have elements that rerender too often in short time. This might will give you a warning output in console that that element change was ignored for passing to the iframe. Consider adding the `data-locize-editor-ignore: true` attribute to the element to ignore it completely.
32
+
33
+ #### b) Opening it on https://locize.app
34
34
 
35
- ### with i18next
35
+ Details for setting this up can be found [here](https://docs.locize.com/different-views/incontext)
36
36
 
37
+ The solution extracts the text on the clicked element and passes it for a fuzzy search to the parent frame. As the search is fuzzy there is no guarantee for exact results.
38
+
39
+ **hint** To get exact matches you can add following attributes to the element or it's parent:
40
+
41
+ `data-i18n` -> will pass exact key
42
+ `data-i18n-ns` -> will pass namespace name
43
+
44
+ # Using
45
+
46
+ ## with locizify
47
+
48
+ This plugin is already included in [locizify](https://github.com/locize/locizify) >= v4.1.0
49
+
50
+ ## with i18next
51
+
52
+ ### this will show the locize incontext editor as a popup in your website
37
53
  ```js
38
54
  import { locizePlugin } from 'locize';
39
55
 
40
56
  i18next.use(locizePlugin);
41
57
  ```
42
58
 
59
+ ### this will show the locize incontext editor as a popup in your website only if the url contains the incontext=true query paramenter, i.e. http://localhost:8080?incontext=true
60
+ ```js
61
+ import { locizeEditorPlugin } from 'locize';
62
+
63
+ i18next.use(locizeEditorPlugin());
64
+ ```
65
+
43
66
  Using react-i18next you might want to bind the editorSaved event to trigger a rerender:
44
67
 
45
68
  ```js
46
69
  i18next.init({
47
70
  // ...
48
71
  react: {
49
- bindI18n: 'languageChanged editorSaved',
50
- },
51
- });
72
+ bindI18n: 'languageChanged editorSaved'
73
+ }
74
+ })
52
75
  ```
53
76
 
54
- ### with locizify
77
+ ## without i18next
55
78
 
56
- This plugin is already included in [locizify](https://github.com/locize/locizify) >= v4.1.0
79
+ Not using i18next currently only the option to show your website inside the locize incontext solution (https://locize.app) is available.
57
80
 
58
81
  ### with other as module
59
82
 
60
83
  ```js
61
- import { addLocizeSavedHandler, startStandalone, setEditorLng } from 'locize';
84
+ import { addLocizeSavedHandler, startStandalone, setEditorLng } from 'locize'
62
85
 
63
86
  addLocizeSavedHandler(res => {
64
87
  res.updated.forEach(item => {
65
- const { lng, ns, key, data } = item;
88
+ const { lng, ns, key, data } = item
66
89
  // load the translations somewhere...
67
90
  // and maybe rerender your UI
68
- });
69
- });
91
+ })
92
+ })
70
93
 
71
94
  // start
72
- startStandalone();
95
+ startStandalone()
73
96
 
74
97
  // switch lng in locize editor
75
- setEditorLng(lng);
98
+ setEditorLng(lng)
76
99
  ```
77
100
 
78
101
  ### with other in vanilla javascript
79
102
 
103
+ Only relevant when your website is shown inside the locize incontext solution on https://locize.app.
104
+
80
105
  ```html
81
106
  <script src="https://unpkg.com/locize/locize.min.js" />
82
107
  ```
@@ -84,23 +109,34 @@ setEditorLng(lng);
84
109
  ```js
85
110
  window.locizeSavedHandler = res => {
86
111
  res.updated.forEach(item => {
87
- const { lng, ns, key, data } = item;
112
+ const { lng, ns, key, data } = item
88
113
  // load the translations somewhere...
89
114
  // and maybe rerender your UI
90
- });
91
- };
115
+ })
116
+ }
117
+
118
+ window.locizeStartStandalone()
119
+ ```
120
+
121
+ **Hint** you can fix the integration to a locize project by adding:
92
122
 
93
- window.locizeStartStandalone();
123
+ ```js
124
+ <script
125
+ id="locize"
126
+ projectid="5e9ed7da-51ab-4b15-888b-27903f06be09"
127
+ version="latest"
128
+ src="https://unpkg.com/locize/locize.min.js"
129
+ >
94
130
  ```
95
131
 
96
- ## turn on/off programmatically
132
+ ### turn on/off click interception programmatically
97
133
 
98
134
  ```js
99
- import { turnOn, turnOff } from 'locize';
135
+ import { turnOn, turnOff } from 'locize'
100
136
 
101
- let isOff;
137
+ let isOff
102
138
 
103
139
  // or use window.locize.turnOn
104
- isOff = turnOff(); // -> true
105
- isOff = turnOn(); // -> false
140
+ isOff = turnOff() // -> true
141
+ isOff = turnOn() // -> false
106
142
  ```
@@ -5,6 +5,7 @@ var postMessage = require('./postMessage.js');
5
5
  function handler(payload) {
6
6
  postMessage.api.initialized = true;
7
7
  clearInterval(postMessage.api.initInterval);
8
+ delete postMessage.api.initInterval;
8
9
  postMessage.api.sendCurrentParsedContent();
9
10
  postMessage.api.sendCurrentTargetLanguage();
10
11
  }
@@ -1,15 +1,45 @@
1
1
  export * from 'i18next-subliminal'
2
2
 
3
+ /**
4
+ * The i18next plugin for the locize incontext editor.
5
+ */
3
6
  export interface LocizePlugin {
4
7
  type: '3rdParty';
5
8
  init(i18next: any): () => void;
6
9
  }
7
10
 
11
+ /**
12
+ * Returns an i18next plugin that will show the incontext editor.
13
+ */
8
14
  export const locizePlugin: LocizePlugin
9
15
 
16
+ /**
17
+ * Returns an i18next plugin that will only show the incontext editor if the qsProp in your url is set to true.
18
+ * @param opt defaults to: { qsProp: 'incontext' }
19
+ */
20
+ export function locizeEditorPlugin(opt?: { qsProp?: string }): LocizePlugin
21
+
22
+ /**
23
+ * Turn on programmatically.
24
+ */
10
25
  export function turnOn(): void;
26
+
27
+ /**
28
+ * Turn off programmatically.
29
+ */
11
30
  export function turnOff(): void;
31
+
32
+ /**
33
+ * Set the language for the editor.
34
+ */
12
35
  export function setEditorLng(lng: string): void;
36
+
37
+ /**
38
+ * To load the translations somewhere.
39
+ */
13
40
  export function addLocizeSavedHandler(fn: (data: any) => void): void;
14
41
 
42
+ /**
43
+ * If used without i18next.
44
+ */
15
45
  export function startStandalone(): void;
package/dist/cjs/index.js CHANGED
@@ -24,12 +24,14 @@ var index = {
24
24
  PostProcessor: i18nextSubliminal.PostProcessor,
25
25
  addLocizeSavedHandler: postMessage.addLocizeSavedHandler,
26
26
  locizePlugin: locizePlugin.locizePlugin,
27
+ locizeEditorPlugin: locizePlugin.locizeEditorPlugin,
27
28
  turnOn: postMessage.turnOn,
28
29
  turnOff: postMessage.turnOff,
29
30
  setEditorLng: postMessage.setEditorLng,
30
31
  startStandalone: startStandalone.startStandalone
31
32
  };
32
33
 
34
+ exports.locizeEditorPlugin = locizePlugin.locizeEditorPlugin;
33
35
  exports.locizePlugin = locizePlugin.locizePlugin;
34
36
  exports.startStandalone = startStandalone.startStandalone;
35
37
  exports.addLocizeSavedHandler = postMessage.addLocizeSavedHandler;
@@ -6,6 +6,7 @@ var _defineProperty = require('@babel/runtime/helpers/defineProperty');
6
6
  var i18nextSubliminal = require('i18next-subliminal');
7
7
  var process = require('./process.js');
8
8
  var processLegacy = require('./processLegacy.js');
9
+ var utils = require('./utils.js');
9
10
 
10
11
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
12
 
@@ -17,89 +18,94 @@ var isInIframe = typeof window !== 'undefined';
17
18
  try {
18
19
  isInIframe = self !== top;
19
20
  } catch (e) {}
21
+ function configurePostProcessor(i18next, options) {
22
+ i18next.use(i18nextSubliminal.PostProcessor);
23
+ if (typeof options.postProcess === 'string') {
24
+ options.postProcess = [options.postProcess, 'subliminal'];
25
+ } else if (Array.isArray(options.postProcess)) {
26
+ options.postProcess.push('subliminal');
27
+ } else {
28
+ options.postProcess = 'subliminal';
29
+ }
30
+ options.postProcessPassResolved = true;
31
+ }
32
+ function getImplementation(i18n) {
33
+ var impl = {
34
+ getResource: function getResource(lng, ns, key) {
35
+ return i18n.getResource(lng, ns, key);
36
+ },
37
+ setResource: function setResource(lng, ns, key, value) {
38
+ return i18n.addResource(lng, ns, key, value, {
39
+ silent: true
40
+ });
41
+ },
42
+ getResourceBundle: function getResourceBundle(lng, ns, cb) {
43
+ i18n.loadNamespaces(ns, function () {
44
+ cb(i18n.getResourceBundle(lng, ns));
45
+ });
46
+ },
47
+ getLng: function getLng() {
48
+ return i18n.languages[0];
49
+ },
50
+ getSourceLng: function getSourceLng() {
51
+ var fallback = i18n.options.fallbackLng;
52
+ if (typeof fallback === 'string') return fallback;
53
+ if (Array.isArray(fallback)) return fallback[fallback.length - 1];
54
+ if (fallback && fallback["default"]) {
55
+ if (typeof fallback["default"] === 'string') return fallback;
56
+ if (Array.isArray(fallback["default"])) return fallback["default"][fallback["default"].length - 1];
57
+ }
58
+ if (typeof fallback === 'function') {
59
+ var res = fallback(i18n.resolvedLanguage);
60
+ if (typeof res === 'string') return res;
61
+ if (Array.isArray(res)) return res[res.length - 1];
62
+ }
63
+ return 'dev';
64
+ },
65
+ getLocizeDetails: function getLocizeDetails() {
66
+ var backendName;
67
+ if (i18n.services.backendConnector.backend && i18n.services.backendConnector.backend.options && i18n.services.backendConnector.backend.options.loadPath && i18n.services.backendConnector.backend.options.loadPath.indexOf('.locize.') > 0) {
68
+ backendName = 'I18NextLocizeBackend';
69
+ } else {
70
+ backendName = i18n.services.backendConnector.backend ? i18n.services.backendConnector.backend.constructor.name : 'options.resources';
71
+ }
72
+ var opts = {
73
+ backendName: backendName,
74
+ sourceLng: impl.getSourceLng(),
75
+ i18nFormat: i18n.options.compatibilityJSON === 'v3' ? 'i18next_v3' : 'i18next_v4',
76
+ i18nFramework: 'i18next',
77
+ isLocizify: i18n.options.isLocizify,
78
+ defaultNS: i18n.options.defaultNS
79
+ };
80
+ if (!i18n.options.backend && !i18n.options.editor) return opts;
81
+ var pickFrom = i18n.options.backend || i18n.options.editor;
82
+ return _objectSpread(_objectSpread({}, opts), {}, {
83
+ projectId: pickFrom.projectId,
84
+ version: pickFrom.version
85
+ });
86
+ },
87
+ bindLanguageChange: function bindLanguageChange(cb) {
88
+ i18n.on('languageChanged', cb);
89
+ },
90
+ bindMissingKeyHandler: function bindMissingKeyHandler(cb) {
91
+ i18n.options.missingKeyHandler = function (lng, ns, k, val, isUpdate, opts) {
92
+ if (!isUpdate) cb(lng, ns, k, val);
93
+ };
94
+ },
95
+ triggerRerender: function triggerRerender() {
96
+ i18n.emit('editorSaved');
97
+ }
98
+ };
99
+ return impl;
100
+ }
20
101
  var i18next;
21
102
  var locizePlugin = {
22
103
  type: '3rdParty',
23
104
  init: function init(i18n) {
24
105
  var options = i18n.options;
25
106
  i18next = i18n;
26
- if (!isInIframe) {
27
- i18next.use(i18nextSubliminal.PostProcessor);
28
- if (typeof options.postProcess === 'string') {
29
- options.postProcess = [options.postProcess, 'subliminal'];
30
- } else if (Array.isArray(options.postProcess)) {
31
- options.postProcess.push('subliminal');
32
- } else {
33
- options.postProcess = 'subliminal';
34
- }
35
- options.postProcessPassResolved = true;
36
- }
37
- var impl = {
38
- getResource: function getResource(lng, ns, key) {
39
- return i18n.getResource(lng, ns, key);
40
- },
41
- setResource: function setResource(lng, ns, key, value) {
42
- return i18n.addResource(lng, ns, key, value, {
43
- silent: true
44
- });
45
- },
46
- getResourceBundle: function getResourceBundle(lng, ns, cb) {
47
- i18n.loadNamespaces(ns, function () {
48
- cb(i18n.getResourceBundle(lng, ns));
49
- });
50
- },
51
- getLng: function getLng() {
52
- return i18n.languages[0];
53
- },
54
- getSourceLng: function getSourceLng() {
55
- var fallback = i18n.options.fallbackLng;
56
- if (typeof fallback === 'string') return fallback;
57
- if (Array.isArray(fallback)) return fallback[fallback.length - 1];
58
- if (fallback && fallback["default"]) {
59
- if (typeof fallback["default"] === 'string') return fallback;
60
- if (Array.isArray(fallback["default"])) return fallback["default"][fallback["default"].length - 1];
61
- }
62
- if (typeof fallback === 'function') {
63
- var res = fallback(i18n.resolvedLanguage);
64
- if (typeof res === 'string') return res;
65
- if (Array.isArray(res)) return res[res.length - 1];
66
- }
67
- return 'dev';
68
- },
69
- getLocizeDetails: function getLocizeDetails() {
70
- var backendName;
71
- if (i18n.services.backendConnector.backend && i18n.services.backendConnector.backend.options && i18n.services.backendConnector.backend.options.loadPath && i18n.services.backendConnector.backend.options.loadPath.indexOf('.locize.') > 0) {
72
- backendName = 'I18NextLocizeBackend';
73
- } else {
74
- backendName = i18n.services.backendConnector.backend ? i18n.services.backendConnector.backend.constructor.name : 'options.resources';
75
- }
76
- var opts = {
77
- backendName: backendName,
78
- sourceLng: impl.getSourceLng(),
79
- i18nFormat: i18n.options.compatibilityJSON === 'v3' ? 'i18next_v3' : 'i18next_v4',
80
- i18nFramework: 'i18next',
81
- isLocizify: i18n.options.isLocizify,
82
- defaultNS: i18n.options.defaultNS
83
- };
84
- if (!i18n.options.backend && !i18n.options.editor) return opts;
85
- var pickFrom = i18n.options.backend || i18n.options.editor;
86
- return _objectSpread(_objectSpread({}, opts), {}, {
87
- projectId: pickFrom.projectId,
88
- version: pickFrom.version
89
- });
90
- },
91
- bindLanguageChange: function bindLanguageChange(cb) {
92
- i18n.on('languageChanged', cb);
93
- },
94
- bindMissingKeyHandler: function bindMissingKeyHandler(cb) {
95
- i18n.options.missingKeyHandler = function (lng, ns, k, val, isUpdate, opts) {
96
- if (!isUpdate) cb(lng, ns, k, val);
97
- };
98
- },
99
- triggerRerender: function triggerRerender() {
100
- i18n.emit('editorSaved');
101
- }
102
- };
107
+ if (!isInIframe) configurePostProcessor(i18next, options);
108
+ var impl = getImplementation(i18n);
103
109
  if (!isInIframe) {
104
110
  process.start(impl);
105
111
  } else {
@@ -107,9 +113,29 @@ var locizePlugin = {
107
113
  }
108
114
  }
109
115
  };
116
+ var locizeEditorPlugin = function locizeEditorPlugin() {
117
+ var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
118
+ opt.qsProp = opt.qsProp || 'incontext';
119
+ return {
120
+ type: '3rdParty',
121
+ init: function init(i18n) {
122
+ var options = i18n.options;
123
+ i18next = i18n;
124
+ var showInContext = utils.getQsParameterByName(opt.qsProp) === 'true';
125
+ if (!isInIframe && showInContext) configurePostProcessor(i18next, options);
126
+ var impl = getImplementation(i18n);
127
+ if (!isInIframe && showInContext) {
128
+ process.start(impl);
129
+ } else {
130
+ processLegacy.startLegacy(impl);
131
+ }
132
+ }
133
+ };
134
+ };
110
135
 
111
136
  Object.defineProperty(exports, 'unwrap', {
112
137
  enumerable: true,
113
138
  get: function () { return i18nextSubliminal.unwrap; }
114
139
  });
140
+ exports.locizeEditorPlugin = locizeEditorPlugin;
115
141
  exports.locizePlugin = locizePlugin;
@@ -5,7 +5,18 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var utils = require('./utils.js');
6
6
  var vars = require('./vars.js');
7
7
 
8
+ var mutationTriggeringElements = {};
8
9
  function ignoreMutation(ele) {
10
+ if (ele.uniqueID) {
11
+ var info = mutationTriggeringElements[ele.uniqueID];
12
+ if (info && info.triggered > 10 && info.lastTriggerDate + 500 < Date.now()) {
13
+ if (!info.warned && console) {
14
+ console.warn('locize ::: ignoring element change - an element is rerendering too often in short interval', '\n', 'consider adding the "data-locize-editor-ignore:" attribute to the element:', ele);
15
+ info.warned = true;
16
+ }
17
+ return true;
18
+ }
19
+ }
9
20
  var ret = ele.dataset && (ele.dataset.i18nextEditorElement === 'true' || ele.dataset.locizeEditorIgnore === 'true');
10
21
  if (!ret && ele.parentElement) return ignoreMutation(ele.parentElement);
11
22
  return ret;
@@ -34,6 +45,12 @@ function createObserver(ele, handle) {
34
45
  if (mutation.type === 'attributes' && !vars.validAttributes.includes(mutation.attributeName)) {
35
46
  return;
36
47
  }
48
+ Object.keys(mutationTriggeringElements).forEach(function (k) {
49
+ var info = mutationTriggeringElements[k];
50
+ if (info.lastTriggerDate + 60000 < Date.now()) {
51
+ delete mutationTriggeringElements[k];
52
+ }
53
+ });
37
54
  if (mutation.type === 'childList') {
38
55
  var notOurs = 0;
39
56
  if (!ignoreMutation(mutation.target)) {
@@ -49,8 +66,18 @@ function createObserver(ele, handle) {
49
66
  if (notOurs === 0) return;
50
67
  }
51
68
  triggerMutation = true;
69
+ if (mutation.target && mutation.target.uniqueID) {
70
+ var info = mutationTriggeringElements[mutation.target.uniqueID] || {
71
+ triggered: 0
72
+ };
73
+ info.triggered = info.triggered + 1;
74
+ info.lastTriggerDate = Date.now();
75
+ mutationTriggeringElements[mutation.target.uniqueID] = info;
76
+ }
52
77
  var includedAlready = targetEles.reduce(function (mem, element) {
53
- if (mem || element.contains(mutation.target) || !mutation.target.parentElement) return true;
78
+ if (mem || element.contains(mutation.target) || !mutation.target.parentElement) {
79
+ return true;
80
+ }
54
81
  return false;
55
82
  }, false);
56
83
  if (!includedAlready) {
package/dist/cjs/utils.js CHANGED
@@ -127,12 +127,23 @@ function getElementNamespace(el) {
127
127
  find(el);
128
128
  return found;
129
129
  }
130
+ function getQsParameterByName(name, url) {
131
+ if (typeof window === 'undefined') return null;
132
+ if (!url) url = window.location.href.toLowerCase();
133
+ name = name.replace(/[\[\]]/g, '\\$&');
134
+ var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
135
+ var results = regex.exec(url);
136
+ if (!results) return null;
137
+ if (!results[2]) return '';
138
+ return decodeURIComponent(results[2].replace(/\+/g, ' '));
139
+ }
130
140
 
131
141
  exports.debounce = debounce;
132
142
  exports.getClickedElement = getClickedElement;
133
143
  exports.getElementI18nKey = getElementI18nKey;
134
144
  exports.getElementNamespace = getElementNamespace;
135
145
  exports.getElementText = getElementText;
146
+ exports.getQsParameterByName = getQsParameterByName;
136
147
  exports.getWindow = getWindow;
137
148
  exports.isWindow = isWindow;
138
149
  exports.offset = offset;
@@ -3,6 +3,7 @@ import { api } from './postMessage.js';
3
3
  function handler(payload) {
4
4
  api.initialized = true;
5
5
  clearInterval(api.initInterval);
6
+ delete api.initInterval;
6
7
  api.sendCurrentParsedContent();
7
8
  api.sendCurrentTargetLanguage();
8
9
  }
@@ -1,15 +1,45 @@
1
1
  export * from 'i18next-subliminal'
2
2
 
3
+ /**
4
+ * The i18next plugin for the locize incontext editor.
5
+ */
3
6
  export interface LocizePlugin {
4
7
  type: '3rdParty';
5
8
  init(i18next: any): () => void;
6
9
  }
7
10
 
11
+ /**
12
+ * Returns an i18next plugin that will show the incontext editor.
13
+ */
8
14
  export const locizePlugin: LocizePlugin
9
15
 
16
+ /**
17
+ * Returns an i18next plugin that will only show the incontext editor if the qsProp in your url is set to true.
18
+ * @param opt defaults to: { qsProp: 'incontext' }
19
+ */
20
+ export function locizeEditorPlugin(opt?: { qsProp?: string }): LocizePlugin
21
+
22
+ /**
23
+ * Turn on programmatically.
24
+ */
10
25
  export function turnOn(): void;
26
+
27
+ /**
28
+ * Turn off programmatically.
29
+ */
11
30
  export function turnOff(): void;
31
+
32
+ /**
33
+ * Set the language for the editor.
34
+ */
12
35
  export function setEditorLng(lng: string): void;
36
+
37
+ /**
38
+ * To load the translations somewhere.
39
+ */
13
40
  export function addLocizeSavedHandler(fn: (data: any) => void): void;
14
41
 
42
+ /**
43
+ * If used without i18next.
44
+ */
15
45
  export function startStandalone(): void;
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { locizePlugin } from './locizePlugin.js';
2
- export { locizePlugin } from './locizePlugin.js';
1
+ import { locizePlugin, locizeEditorPlugin } from './locizePlugin.js';
2
+ export { locizeEditorPlugin, locizePlugin } from './locizePlugin.js';
3
3
  import { startStandalone } from './startStandalone.js';
4
4
  export { startStandalone } from './startStandalone.js';
5
5
  import './api/handleEditKey.js';
@@ -24,6 +24,7 @@ var index = {
24
24
  PostProcessor: PostProcessor,
25
25
  addLocizeSavedHandler: addLocizeSavedHandler,
26
26
  locizePlugin: locizePlugin,
27
+ locizeEditorPlugin: locizeEditorPlugin,
27
28
  turnOn: turnOn,
28
29
  turnOff: turnOff,
29
30
  setEditorLng: setEditorLng,