locize 3.3.0 → 4.0.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 (95) hide show
  1. package/README.md +74 -36
  2. package/dist/cjs/{processLegacy.js → _processLegacy.js} +1 -2
  3. package/dist/cjs/{startStandalone.js → _startStandalone.js} +2 -2
  4. package/dist/cjs/api/handleCommitKeys.js +7 -0
  5. package/dist/cjs/api/handleEditKey.js +1 -1
  6. package/dist/cjs/api/handleIsLocizeEnabled.js +2 -2
  7. package/dist/cjs/api/handleRequestPopupChanges.js +11 -0
  8. package/dist/cjs/api/handleSendMatchedUninstrumented.js +26 -0
  9. package/dist/cjs/api/postMessage.js +32 -45
  10. package/dist/cjs/implementations/dummyImplementation.js +35 -0
  11. package/dist/cjs/implementations/i18nextImplementation.js +94 -0
  12. package/dist/cjs/index.d.ts +9 -16
  13. package/dist/cjs/index.js +4 -9
  14. package/dist/cjs/locizePlugin.js +6 -90
  15. package/dist/cjs/observer.js +1 -0
  16. package/dist/cjs/parser.js +100 -14
  17. package/dist/cjs/process.js +37 -5
  18. package/dist/cjs/store.js +1 -0
  19. package/dist/cjs/ui/elements/highlightBox.js +13 -0
  20. package/dist/cjs/ui/elements/icons.js +1 -17
  21. package/dist/cjs/ui/elements/popup.js +3 -3
  22. package/dist/cjs/ui/elements/ribbonBox.js +3 -6
  23. package/dist/cjs/ui/highlightNode.js +28 -77
  24. package/dist/cjs/ui/popup.js +10 -0
  25. package/dist/cjs/ui/utils.js +18 -0
  26. package/dist/cjs/uninstrumentedStore.js +18 -2
  27. package/dist/cjs/utils.js +54 -0
  28. package/dist/cjs/vars.js +5 -2
  29. package/dist/esm/{processLegacy.js → _processLegacy.js} +1 -2
  30. package/dist/esm/{startStandalone.js → _startStandalone.js} +1 -1
  31. package/dist/esm/api/handleCommitKeys.js +7 -0
  32. package/dist/esm/api/handleEditKey.js +1 -1
  33. package/dist/esm/api/handleIsLocizeEnabled.js +2 -2
  34. package/dist/esm/api/handleRequestPopupChanges.js +11 -0
  35. package/dist/esm/api/handleSendMatchedUninstrumented.js +20 -0
  36. package/dist/esm/api/postMessage.js +33 -44
  37. package/dist/esm/implementations/dummyImplementation.js +31 -0
  38. package/dist/esm/implementations/i18nextImplementation.js +85 -0
  39. package/dist/esm/index.d.ts +9 -16
  40. package/dist/esm/index.js +5 -8
  41. package/dist/esm/locizePlugin.js +5 -85
  42. package/dist/esm/observer.js +1 -0
  43. package/dist/esm/parser.js +101 -16
  44. package/dist/esm/process.js +38 -6
  45. package/dist/esm/store.js +1 -0
  46. package/dist/esm/ui/elements/highlightBox.js +9 -0
  47. package/dist/esm/ui/elements/icons.js +2 -16
  48. package/dist/esm/ui/elements/popup.js +3 -3
  49. package/dist/esm/ui/elements/ribbonBox.js +4 -7
  50. package/dist/esm/ui/highlightNode.js +28 -78
  51. package/dist/esm/ui/popup.js +10 -0
  52. package/dist/esm/ui/utils.js +18 -1
  53. package/dist/esm/uninstrumentedStore.js +18 -2
  54. package/dist/esm/utils.js +53 -1
  55. package/dist/esm/vars.js +5 -3
  56. package/dist/umd/locize.js +726 -496
  57. package/dist/umd/locize.min.js +1 -1
  58. package/index.d.ts +9 -16
  59. package/locize.js +726 -496
  60. package/locize.min.js +1 -1
  61. package/package.json +1 -1
  62. package/src/_startStandalone.js +22 -0
  63. package/src/api/handleCommitKeys.js +9 -0
  64. package/src/api/handleEditKey.js +5 -11
  65. package/src/api/handleIsLocizeEnabled.js +7 -2
  66. package/src/api/handleRequestPopupChanges.js +27 -0
  67. package/src/api/handleSendMatchedUninstrumented.js +38 -0
  68. package/src/api/index.js +1 -4
  69. package/src/api/postMessage.js +37 -53
  70. package/src/implementations/dummyImplementation.js +29 -0
  71. package/src/implementations/i18nextImplementation.js +114 -0
  72. package/src/implementations/index.js +2 -0
  73. package/src/index.js +8 -7
  74. package/src/locizePlugin.js +51 -28
  75. package/src/observer.js +1 -0
  76. package/src/parser.js +207 -19
  77. package/src/process.js +52 -5
  78. package/src/startStandalone.js +4 -17
  79. package/src/store.js +2 -0
  80. package/src/ui/elements/highlightBox.js +17 -0
  81. package/src/ui/elements/popup.js +4 -4
  82. package/src/ui/elements/ribbonBox.js +12 -8
  83. package/src/ui/highlightNode.js +102 -71
  84. package/src/ui/popup.js +33 -5
  85. package/src/ui/utils.js +28 -1
  86. package/src/uninstrumentedStore.js +18 -2
  87. package/src/utils.js +72 -5
  88. package/src/vars.js +6 -4
  89. package/dist/cjs/api/handleTurnOff.js +0 -8
  90. package/dist/cjs/api/handleTurnOn.js +0 -8
  91. package/dist/esm/api/handleTurnOff.js +0 -6
  92. package/dist/esm/api/handleTurnOn.js +0 -6
  93. /package/src/{processLegacy.js → _processLegacy.js} +0 -0
  94. /package/src/api/{handleTurnOff.js → _handleTurnOff.js} +0 -0
  95. /package/src/api/{handleTurnOn.js → _handleTurnOn.js} +0 -0
@@ -1,5 +1,7 @@
1
1
  import { getIframeUrl } from '../vars.js'
2
2
  import { store } from '../store.js'
3
+ import { uninstrumentedStore } from '../uninstrumentedStore.js'
4
+ import { debounce } from '../utils.js'
3
5
 
4
6
  const legacyEventMapping = {
5
7
  committed: 'commitKeys'
@@ -13,32 +15,23 @@ export function addLocizeSavedHandler (handler) {
13
15
  api.locizeSavedHandler = handler
14
16
  }
15
17
 
16
- export function turnOn () {
17
- api.scriptTurnedOff = false // unlock
18
-
19
- api.turnOn()
20
- return api.scriptTurnedOff
21
- }
22
-
23
- export function turnOff () {
24
- api.turnOff()
25
-
26
- api.scriptTurnedOff = true // lock
27
- return api.scriptTurnedOff
28
- }
29
-
30
18
  export function setEditorLng (lng) {
31
19
  api.sendCurrentTargetLanguage(lng)
32
20
  }
33
21
 
34
22
  let pendingMsgs = []
23
+ const allowedActionsBeforeInit = ['locizeIsEnabled', 'requestInitialize']
35
24
  export function sendMessage (action, payload) {
36
25
  if (!api.source) {
37
26
  api.source = document.getElementById('i18next-editor-iframe')?.contentWindow
38
27
  }
39
28
  if (!api.origin) api.origin = getIframeUrl()
40
29
 
41
- if (!api.source || !api.source.postMessage) {
30
+ if (
31
+ !api.source ||
32
+ !api.source.postMessage ||
33
+ (!api.initialized && allowedActionsBeforeInit.indexOf(action) < 0)
34
+ ) {
42
35
  // console.warn('out nok queuing - ', api.source, api.origin, action, payload);
43
36
  pendingMsgs.push({ action, payload })
44
37
  return
@@ -55,11 +48,11 @@ export function sendMessage (action, payload) {
55
48
  api.source.postMessage(
56
49
  {
57
50
  sender: 'i18next-editor',
58
- senderAPIVersion: 'v1',
51
+ senderAPIVersion: 'v2',
59
52
  action,
60
53
  message: action,
61
54
  payload
62
- }, // message for legacy
55
+ },
63
56
  api.origin
64
57
  )
65
58
  }
@@ -72,6 +65,23 @@ export function sendMessage (action, payload) {
72
65
  })
73
66
  }
74
67
 
68
+ const sendCurrentParsedContentDebounced = () => {
69
+ sendMessage('sendCurrentParsedContent', {
70
+ content: Object.values(store.data).map(item => {
71
+ return {
72
+ id: item.id,
73
+ keys: item.keys
74
+ }
75
+ }),
76
+ uninstrumented: Object.values(uninstrumentedStore.data).map(item => {
77
+ return {
78
+ id: item.id,
79
+ keys: item.keys
80
+ }
81
+ })
82
+ })
83
+ }
84
+
75
85
  const handlers = {}
76
86
  let repeat = 5
77
87
  export const api = {
@@ -92,7 +102,7 @@ export const api = {
92
102
  clearInterval(api.initInterval)
93
103
  delete api.initInterval
94
104
  }
95
- }, 1000)
105
+ }, 2000)
96
106
  },
97
107
 
98
108
  selectKey: meta => {
@@ -103,17 +113,7 @@ export const api = {
103
113
  sendMessage('confirmResourceBundle', payload)
104
114
  },
105
115
 
106
- sendCurrentParsedContent: () => {
107
- sendMessage('sendCurrentParsedContent', {
108
- content: Object.values(store.data).map(item => {
109
- return {
110
- id: item.id,
111
- // subliminal: item.subliminal,
112
- keys: item.keys
113
- }
114
- })
115
- })
116
- },
116
+ sendCurrentParsedContent: debounce(sendCurrentParsedContentDebounced, 500),
117
117
 
118
118
  sendCurrentTargetLanguage: lng => {
119
119
  sendMessage('sendCurrentTargetLanguage', {
@@ -121,34 +121,17 @@ export const api = {
121
121
  })
122
122
  },
123
123
 
124
+ sendHrefchanged: href => {
125
+ sendMessage('hrefChanged', { href })
126
+ },
127
+
124
128
  addHandler: (action, fc) => {
125
129
  if (!handlers[action]) handlers[action] = []
126
130
  handlers[action].push(fc)
127
131
  },
128
132
 
129
- // legacy
130
- sendLocizeIsEnabled: () => {
131
- sendMessage('locizeIsEnabled', { enabled: true })
132
- },
133
-
134
- turnOn: () => {
135
- if (api.scriptTurnedOff) return sendMessage('forcedOff')
136
-
137
- if (!api.clickInterceptionEnabled) {
138
- window.document.body.addEventListener('click', api.clickHandler, true)
139
- }
140
- api.clickInterceptionEnabled = true
141
- sendMessage('turnedOn')
142
- },
143
-
144
- turnOff: () => {
145
- if (api.scriptTurnedOff) return sendMessage('forcedOff')
146
-
147
- if (api.clickInterceptionEnabled) {
148
- window.document.body.removeEventListener('click', api.clickHandler, true)
149
- }
150
- api.clickInterceptionEnabled = false
151
- sendMessage('turnedOff')
133
+ sendLocizeIsEnabled: payload => {
134
+ sendMessage('locizeIsEnabled', { ...payload, enabled: true })
152
135
  },
153
136
 
154
137
  onAddedKey: (lng, ns, key, value) => {
@@ -166,6 +149,7 @@ export const api = {
166
149
  if (typeof window !== 'undefined') {
167
150
  window.addEventListener('message', e => {
168
151
  const { sender, /* senderAPIVersion, */ action, message, payload } = e.data
152
+ // console.warn(sender, action, message, payload)
169
153
 
170
154
  if (message) {
171
155
  const usedEventName = getMappedLegacyEvent(message)
@@ -177,7 +161,7 @@ if (typeof window !== 'undefined') {
177
161
  } else if (sender === 'i18next-editor-frame' && handlers[action]) {
178
162
  // console.warn('ok in', action, payload);
179
163
  handlers[action].forEach(fc => {
180
- fc(payload)
164
+ fc(payload, e)
181
165
  })
182
166
  }
183
167
  })
@@ -0,0 +1,29 @@
1
+ export function getImplementation () {
2
+ const impl = {
3
+ getResource: (lng, ns, key) => {
4
+ return {}
5
+ },
6
+ setResource: (lng, ns, key, value) => {
7
+ return
8
+ },
9
+ getResourceBundle: (lng, ns, cb) => {
10
+ cb({})
11
+ },
12
+ getDefaultNS: () => {
13
+ return
14
+ },
15
+ getLng: () => {
16
+ return
17
+ },
18
+ getSourceLng: () => {
19
+ return
20
+ },
21
+ getLocizeDetails: () => {
22
+ return {}
23
+ },
24
+ bindLanguageChange: cb => {},
25
+ bindMissingKeyHandler: cb => {},
26
+ triggerRerender: () => {}
27
+ }
28
+ return impl
29
+ }
@@ -0,0 +1,114 @@
1
+ export function getImplementation (i18n) {
2
+ const impl = {
3
+ getResource: (lng, ns, key) => {
4
+ return i18n.getResource && i18n.getResource(lng, ns, key)
5
+ },
6
+ setResource: (lng, ns, key, value) => {
7
+ return i18n.addResource(lng, ns, key, value, { silent: true })
8
+ },
9
+ getResourceBundle: (lng, ns, cb) => {
10
+ i18n.loadNamespaces(ns, () => {
11
+ cb(i18n.getResourceBundle(lng, ns))
12
+ })
13
+ },
14
+ getDefaultNS: () => {
15
+ return i18n.options.defaultNS
16
+ },
17
+ getLng: () => {
18
+ return (
19
+ i18n.resolvedLanguage ||
20
+ (i18n.languages && i18n.languages[0]) ||
21
+ i18n.options.lng
22
+ )
23
+ },
24
+ getSourceLng: () => {
25
+ const fallback = i18n.options.fallbackLng
26
+ if (typeof fallback === 'string') return fallback
27
+ if (Array.isArray(fallback)) return fallback[fallback.length - 1]
28
+
29
+ if (fallback && fallback.default) {
30
+ if (typeof fallback.default === 'string') return fallback
31
+ if (Array.isArray(fallback.default))
32
+ return fallback.default[fallback.default.length - 1]
33
+ }
34
+
35
+ if (typeof fallback === 'function') {
36
+ const res = fallback(i18n.resolvedLanguage)
37
+ if (typeof res === 'string') return res
38
+ if (Array.isArray(res)) return res[res.length - 1]
39
+ }
40
+
41
+ return 'dev'
42
+ },
43
+ getLocizeDetails: () => {
44
+ let backendName
45
+ if (
46
+ i18n.services.backendConnector.backend &&
47
+ i18n.services.backendConnector.backend.options &&
48
+ i18n.services.backendConnector.backend.options.loadPath &&
49
+ i18n.services.backendConnector.backend.options.loadPath.indexOf(
50
+ '.locize.'
51
+ ) > 0
52
+ ) {
53
+ backendName = 'I18nextLocizeBackend'
54
+ } else {
55
+ backendName = i18n.services.backendConnector.backend
56
+ ? i18n.services.backendConnector.backend.constructor.name
57
+ : 'options.resources'
58
+ }
59
+
60
+ const opts = {
61
+ backendName,
62
+ sourceLng: impl.getSourceLng(),
63
+ i18nFormat:
64
+ i18n.options.compatibilityJSON === 'v3' ? 'i18next_v3' : 'i18next_v4',
65
+ i18nFramework: 'i18next',
66
+ isLocizify: i18n.options.isLocizify,
67
+ defaultNS: i18n.options.defaultNS,
68
+ targetLngs: [
69
+ ...new Set(
70
+ [].concat(i18n.options.preload, i18n.options.supportedLngs, [
71
+ impl.getLng()
72
+ ])
73
+ )
74
+ ].filter(
75
+ l =>
76
+ l !== 'cimode' &&
77
+ l !== false &&
78
+ l !== 'false' &&
79
+ l !== undefined &&
80
+ l !== impl.getSourceLng()
81
+ ),
82
+ ns: [
83
+ ...new Set(
84
+ [].concat(
85
+ i18n.options.ns,
86
+ i18n.options.fallbackNS,
87
+ i18n.options.defaultNS
88
+ )
89
+ )
90
+ ].filter(n => n !== false && n !== 'false')
91
+ }
92
+
93
+ if (!i18n.options.backend && !i18n.options.editor) return opts
94
+ const pickFrom = i18n.options.editor || i18n.options.backend
95
+ return {
96
+ ...opts,
97
+ projectId: pickFrom.projectId,
98
+ version: pickFrom.version
99
+ }
100
+ },
101
+ bindLanguageChange: cb => {
102
+ i18n.on('languageChanged', cb)
103
+ },
104
+ bindMissingKeyHandler: cb => {
105
+ i18n.options.missingKeyHandler = (lng, ns, k, val, isUpdate, opts) => {
106
+ if (!isUpdate) cb(lng, ns, k, val)
107
+ }
108
+ },
109
+ triggerRerender: () => {
110
+ i18n.emit('editorSaved')
111
+ }
112
+ }
113
+ return impl
114
+ }
@@ -0,0 +1,2 @@
1
+ export * as i18next from './i18nextImplementation'
2
+ export * as dummy from './dummyImplementation'
package/src/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  import { locizePlugin, locizeEditorPlugin } from './locizePlugin.js'
2
- import { startStandalone } from './startStandalone.js'
3
- import { addLocizeSavedHandler, turnOn, turnOff, setEditorLng } from './api/index.js'
4
- import { wrap, unwrap, containsHiddenMeta, PostProcessor } from 'i18next-subliminal'
2
+ import { startStandalone } from './_startStandalone.js'
3
+ import { addLocizeSavedHandler, setEditorLng } from './api/index.js'
4
+ import {
5
+ wrap,
6
+ unwrap,
7
+ containsHiddenMeta,
8
+ PostProcessor
9
+ } from 'i18next-subliminal'
5
10
 
6
11
  export {
7
12
  wrap,
@@ -11,8 +16,6 @@ export {
11
16
  locizePlugin,
12
17
  locizeEditorPlugin,
13
18
  addLocizeSavedHandler,
14
- turnOn,
15
- turnOff,
16
19
  setEditorLng,
17
20
  startStandalone
18
21
  }
@@ -25,8 +28,6 @@ export default {
25
28
  addLocizeSavedHandler,
26
29
  locizePlugin,
27
30
  locizeEditorPlugin,
28
- turnOn,
29
- turnOff,
30
31
  setEditorLng,
31
32
  startStandalone
32
33
  }
@@ -1,14 +1,7 @@
1
1
  import { PostProcessor, unwrap } from 'i18next-subliminal'
2
2
  import { start } from './process.js'
3
- import { startLegacy } from './processLegacy.js'
4
- import { getQsParameterByName } from './utils.js'
5
3
 
6
- let isInIframe = typeof window !== 'undefined'
7
- try {
8
- // eslint-disable-next-line no-undef, no-restricted-globals
9
- isInIframe = self !== top
10
- // eslint-disable-next-line no-empty
11
- } catch (e) {}
4
+ import * as implementations from './implementations/index.js'
12
5
 
13
6
  function configurePostProcessor (i18next, options) {
14
7
  i18next.use(PostProcessor)
@@ -27,7 +20,7 @@ function configurePostProcessor (i18next, options) {
27
20
  function getImplementation (i18n) {
28
21
  const impl = {
29
22
  getResource: (lng, ns, key) => {
30
- return i18n.getResource(lng, ns, key)
23
+ return i18n.getResource && i18n.getResource(lng, ns, key)
31
24
  },
32
25
  setResource: (lng, ns, key, value) => {
33
26
  return i18n.addResource(lng, ns, key, value, { silent: true })
@@ -37,8 +30,15 @@ function getImplementation (i18n) {
37
30
  cb(i18n.getResourceBundle(lng, ns))
38
31
  })
39
32
  },
33
+ getDefaultNS: () => {
34
+ return i18n.options.defaultNS
35
+ },
40
36
  getLng: () => {
41
- return i18n.resolvedLanguage || i18n.languages[0]
37
+ return (
38
+ i18n.resolvedLanguage ||
39
+ (i18n.languages && i18n.languages[0]) ||
40
+ i18n.options.lng
41
+ )
42
42
  },
43
43
  getSourceLng: () => {
44
44
  const fallback = i18n.options.fallbackLng
@@ -47,7 +47,8 @@ function getImplementation (i18n) {
47
47
 
48
48
  if (fallback && fallback.default) {
49
49
  if (typeof fallback.default === 'string') return fallback
50
- if (Array.isArray(fallback.default)) return fallback.default[fallback.default.length - 1]
50
+ if (Array.isArray(fallback.default))
51
+ return fallback.default[fallback.default.length - 1]
51
52
  }
52
53
 
53
54
  if (typeof fallback === 'function') {
@@ -60,8 +61,15 @@ function getImplementation (i18n) {
60
61
  },
61
62
  getLocizeDetails: () => {
62
63
  let backendName
63
- 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) {
64
- backendName = 'I18NextLocizeBackend'
64
+ if (
65
+ i18n.services.backendConnector.backend &&
66
+ i18n.services.backendConnector.backend.options &&
67
+ i18n.services.backendConnector.backend.options.loadPath &&
68
+ i18n.services.backendConnector.backend.options.loadPath.indexOf(
69
+ '.locize.'
70
+ ) > 0
71
+ ) {
72
+ backendName = 'I18nextLocizeBackend'
65
73
  } else {
66
74
  backendName = i18n.services.backendConnector.backend
67
75
  ? i18n.services.backendConnector.backend.constructor.name
@@ -71,14 +79,38 @@ function getImplementation (i18n) {
71
79
  const opts = {
72
80
  backendName,
73
81
  sourceLng: impl.getSourceLng(),
74
- i18nFormat: i18n.options.compatibilityJSON === 'v3' ? 'i18next_v3' : 'i18next_v4',
82
+ i18nFormat:
83
+ i18n.options.compatibilityJSON === 'v3' ? 'i18next_v3' : 'i18next_v4',
75
84
  i18nFramework: 'i18next',
76
85
  isLocizify: i18n.options.isLocizify,
77
- defaultNS: i18n.options.defaultNS
86
+ defaultNS: i18n.options.defaultNS,
87
+ targetLngs: [
88
+ ...new Set(
89
+ [].concat(i18n.options.preload, i18n.options.supportedLngs, [
90
+ impl.getLng()
91
+ ])
92
+ )
93
+ ].filter(
94
+ l =>
95
+ l !== 'cimode' &&
96
+ l !== false &&
97
+ l !== 'false' &&
98
+ l !== undefined &&
99
+ l !== impl.getSourceLng()
100
+ ),
101
+ ns: [
102
+ ...new Set(
103
+ [].concat(
104
+ i18n.options.ns,
105
+ i18n.options.fallbackNS,
106
+ i18n.options.defaultNS
107
+ )
108
+ )
109
+ ].filter(n => n !== false && n !== 'false')
78
110
  }
79
111
 
80
112
  if (!i18n.options.backend && !i18n.options.editor) return opts
81
- const pickFrom = i18n.options.backend || i18n.options.editor
113
+ const pickFrom = i18n.options.editor || i18n.options.backend
82
114
  return {
83
115
  ...opts,
84
116
  projectId: pickFrom.projectId,
@@ -113,19 +145,10 @@ export const locizeEditorPlugin = (opt = {}) => {
113
145
  // store for later
114
146
  i18next = i18n
115
147
 
116
- const showInContext = opt.show || getQsParameterByName(opt.qsProp) === 'true'
117
-
118
- // add postProcessor and needed options now
119
- if (!isInIframe && showInContext) configurePostProcessor(i18next, options)
148
+ const impl = implementations.i18next.getImplementation(i18n)
120
149
 
121
- const impl = getImplementation(i18n)
122
-
123
- // start process and expose some implementation functions
124
- if (!isInIframe && showInContext) {
125
- start(impl)
126
- } else if (isInIframe) {
127
- startLegacy(impl)
128
- }
150
+ configurePostProcessor(i18next, options)
151
+ start(impl, opt) // we no longer show the legacy process but use the new way without popup opening
129
152
  }
130
153
  }
131
154
  }
package/src/observer.js CHANGED
@@ -156,6 +156,7 @@ export function createObserver (ele, handle) {
156
156
  subtree: true
157
157
  }
158
158
  ) => {
159
+ handle([ele]) // handle initial content - might be we're not using i18next that triggers mutations on translation (think of static content)
159
160
  observer.observe(ele, observerConfig)
160
161
  },
161
162
  skipNext () {