Skip to content

Commit e2886c7

Browse files
author
Sebi Nemeth
committed
Merge branch 'develop'
2 parents 527a418 + 689844b commit e2886c7

File tree

2 files changed

+268
-246
lines changed

2 files changed

+268
-246
lines changed

dist/index.js

Lines changed: 117 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
var __importDefault = (this && this.__importDefault) || function (mod) {
33
return (mod && mod.__esModule) ? mod : { "default": mod };
44
};
5+
var _a;
56
Object.defineProperty(exports, "__esModule", { value: true });
67
exports.LiveTranslatorPlugin = void 0;
78
const throttle_1 = __importDefault(require("lodash/throttle"));
@@ -59,14 +60,7 @@ const css = `
5960
}
6061
`;
6162
class ZeroWidthEncoder {
62-
constructor() {
63-
this.START = '\u200B';
64-
this.ZERO = '\u200C';
65-
this.ONE = '\u200D';
66-
this.SPACE = '\u200E';
67-
this.END = '\u200F';
68-
}
69-
encode(text) {
63+
static encode(text) {
7064
const binary = text
7165
.split('')
7266
.map((char) => char.charCodeAt(0).toString(2))
@@ -86,7 +80,7 @@ class ZeroWidthEncoder {
8680
.join('');
8781
return this.START + zeroWidth + this.END;
8882
}
89-
decode(zeroWidth) {
83+
static decode(zeroWidth) {
9084
const binary = zeroWidth
9185
.split('')
9286
.slice(1, zeroWidth.length - 1) // remove START and END
@@ -107,20 +101,75 @@ class ZeroWidthEncoder {
107101
return text;
108102
}
109103
}
110-
class LiveTranslatorEnabler {
111-
constructor(persist) {
104+
_a = ZeroWidthEncoder;
105+
ZeroWidthEncoder.START = '\u200B';
106+
ZeroWidthEncoder.ZERO = '\u200C';
107+
ZeroWidthEncoder.ONE = '\u200D';
108+
ZeroWidthEncoder.SPACE = '\u200E';
109+
ZeroWidthEncoder.END = '\u200F';
110+
ZeroWidthEncoder.PATTERN = `${_a.START}[${_a.ZERO}${_a.ONE}${_a.SPACE}]+${_a.END}`;
111+
class LiveTranslatorManager {
112+
constructor(options) {
112113
this._enabled = false;
113-
this.persist = persist;
114+
this._options = options;
115+
// handle persistance
114116
const savedRaw = localStorage.getItem('live-translator-enabled');
115-
if (persist && savedRaw) {
117+
if (this._options.persist && savedRaw) {
116118
const saved = JSON.parse(savedRaw);
117119
if (typeof saved === 'boolean') {
118120
this.toggle(saved);
119121
}
120122
}
123+
// initialize UI
124+
this._enableButton = document.createElement('button');
125+
this._indicator = document.createElement('span');
126+
const style = document.createElement('style');
127+
style.id = 'live-translator-plugin-style';
128+
style.innerHTML = css;
129+
document.head.appendChild(style);
130+
this._enableButton.innerText = 'LT';
131+
this._enableButton.classList.add('live-translator-enable-button');
132+
this._indicator.classList.add('live-translator-enable-button-indicator');
133+
this._enableButton.appendChild(this._indicator);
134+
this._enableButton.addEventListener('click', () => {
135+
this.toggle();
136+
this.refreshI18n();
137+
this.render();
138+
});
139+
document.body.appendChild(this._enableButton);
140+
// initialize encode
141+
const originalFormatter = this._options.i18n.formatter;
142+
const self = this;
143+
this._options.i18n.formatter = {
144+
interpolate(message, values, path) {
145+
const meta = ZeroWidthEncoder.encode(JSON.stringify({
146+
message,
147+
values,
148+
path,
149+
locale: self._options.i18n.locale,
150+
}));
151+
const original = originalFormatter.interpolate(message, values, path);
152+
return (original && self._enabled) ? [meta, ...original] : original;
153+
},
154+
};
155+
// initialize decode & render
156+
const throttler = (0, throttle_1.default)(() => this.render(), 800);
157+
const observer = new MutationObserver(throttler);
158+
observer.observe(document.documentElement, {
159+
subtree: true,
160+
attributes: true,
161+
characterData: true,
162+
childList: false,
163+
});
164+
document.documentElement.addEventListener('mousemove', throttler);
165+
// render for the first time
166+
this.refreshI18n();
167+
this.render();
121168
}
122-
enabled() {
123-
return this._enabled;
169+
refreshI18n() {
170+
const originalLocale = this._options.i18n.locale;
171+
this._options.i18n.locale = '';
172+
this._options.i18n.locale = originalLocale;
124173
}
125174
toggle(enable) {
126175
if (enable !== undefined) {
@@ -129,9 +178,60 @@ class LiveTranslatorEnabler {
129178
else {
130179
this._enabled = !this._enabled;
131180
}
132-
if (this.persist) {
181+
if (this._options.persist) {
133182
localStorage.setItem('live-translator-enabled', JSON.stringify(this._enabled));
134183
}
184+
console.log(`%c Live Translator ${this._enabled ? 'ON' : 'OFF'} `, 'background: #222; color: #bada55');
185+
}
186+
render() {
187+
const badges = document.querySelectorAll('.live-translator-badge');
188+
badges.forEach((badge) => {
189+
badge.remove();
190+
});
191+
this._indicator.style.background = this._enabled ? 'lightgreen' : 'red';
192+
if (!this._enabled) {
193+
return;
194+
}
195+
const re = new RegExp(ZeroWidthEncoder.PATTERN, 'gm');
196+
const queue = [document.documentElement];
197+
while (queue.length > 0) {
198+
const node = queue.pop();
199+
const badges = [];
200+
const parent = node.parentElement;
201+
if (node instanceof Text) {
202+
const matches = node.textContent.match(re);
203+
for (const match of matches !== null && matches !== void 0 ? matches : []) {
204+
const meta = JSON.parse(ZeroWidthEncoder.decode(match));
205+
badges.push(createBadge(meta, this._options));
206+
}
207+
}
208+
const attributes = (node.attributes ? [...node.attributes] : [])
209+
.map((attribute) => ({ attribute, match: attribute.value.match(re) }))
210+
.filter(({ match }) => !!match);
211+
for (const { attribute, match } of attributes) {
212+
for (const m of match) {
213+
const meta = JSON.parse(ZeroWidthEncoder.decode(m));
214+
badges.push(createBadge(meta, this._options, attribute.name));
215+
}
216+
}
217+
if (badges.length) {
218+
let container;
219+
if (node.previousElementSibling && node.previousElementSibling.classList.contains('live-translator-badge-container')) {
220+
container = node.previousElementSibling;
221+
}
222+
else {
223+
container = document.createElement('span');
224+
container.classList.add('live-translator-badge-container');
225+
parent.insertBefore(container, node);
226+
}
227+
for (const badge of badges) {
228+
container.appendChild(badge);
229+
}
230+
}
231+
for (const child of node.childNodes) {
232+
queue.push(child);
233+
}
234+
}
135235
}
136236
}
137237
const createBadge = (meta, options, attribute) => {
@@ -158,98 +258,6 @@ const createBadge = (meta, options, attribute) => {
158258
exports.LiveTranslatorPlugin = {
159259
install(app, options) {
160260
console.log('LiveTranslator is installed');
161-
const zw = new ZeroWidthEncoder();
162-
const ltEnabler = new LiveTranslatorEnabler(options.persist || false);
163-
const enableButton = document.createElement('button');
164-
enableButton.innerText = 'LT';
165-
enableButton.classList.add('live-translator-enable-button');
166-
const indicator = document.createElement('span');
167-
indicator.classList.add('live-translator-enable-button-indicator');
168-
enableButton.appendChild(indicator);
169-
enableButton.addEventListener('click', () => {
170-
ltEnabler.toggle();
171-
visualize();
172-
// Refresh translations to show immediately
173-
const originalLocale = options.i18n.locale;
174-
options.i18n.locale = '';
175-
options.i18n.locale = originalLocale;
176-
});
177-
document.body.appendChild(enableButton);
178-
const style = document.createElement('style');
179-
style.id = 'live-translator-plugin-style';
180-
style.innerHTML = css;
181-
document.head.appendChild(style);
182-
const visualize = () => {
183-
const badges = document.querySelectorAll('.live-translator-badge');
184-
badges.forEach((badge) => {
185-
badge.remove();
186-
});
187-
indicator.style.background = ltEnabler.enabled() ? 'lightgreen' : 'red';
188-
if (!ltEnabler.enabled()) {
189-
return;
190-
}
191-
const re = new RegExp(`${zw.START}[${zw.ZERO}${zw.ONE}${zw.SPACE}]+${zw.END}`, 'gm');
192-
const queue = [document.documentElement];
193-
while (queue.length > 0) {
194-
const node = queue.pop();
195-
const badges = [];
196-
const parent = node.parentElement;
197-
if (node instanceof Text) {
198-
const matches = node.textContent.match(re);
199-
for (const match of matches !== null && matches !== void 0 ? matches : []) {
200-
const meta = JSON.parse(zw.decode(match));
201-
badges.push(createBadge(meta, options));
202-
}
203-
}
204-
const attributes = (node.attributes ? [...node.attributes] : [])
205-
.map((attribute) => ({ attribute, match: attribute.value.match(re) }))
206-
.filter(({ match }) => !!match);
207-
for (const { attribute, match } of attributes) {
208-
for (const m of match) {
209-
const meta = JSON.parse(zw.decode(m));
210-
badges.push(createBadge(meta, options, attribute.name));
211-
}
212-
}
213-
if (badges.length) {
214-
let container;
215-
if (node.previousElementSibling && node.previousElementSibling.classList.contains('live-translator-badge-container')) {
216-
container = node.previousElementSibling;
217-
}
218-
else {
219-
container = document.createElement('span');
220-
container.classList.add('live-translator-badge-container');
221-
parent.insertBefore(container, node);
222-
}
223-
for (const badge of badges) {
224-
container.appendChild(badge);
225-
}
226-
}
227-
for (const child of node.childNodes) {
228-
queue.push(child);
229-
}
230-
}
231-
};
232-
const originalFormatter = options.i18n.formatter;
233-
options.i18n.formatter = {
234-
interpolate(message, values, path) {
235-
const meta = zw.encode(JSON.stringify({
236-
message,
237-
values,
238-
path,
239-
locale: options.i18n.locale,
240-
}));
241-
const original = originalFormatter.interpolate(message, values, path);
242-
return (original && ltEnabler.enabled()) ? [meta, ...original] : original;
243-
},
244-
};
245-
const throttler = (0, throttle_1.default)(visualize, 800);
246-
const observer = new MutationObserver(throttler);
247-
observer.observe(document.documentElement, {
248-
subtree: true,
249-
attributes: true,
250-
characterData: true,
251-
childList: false,
252-
});
253-
document.documentElement.addEventListener('mousemove', throttler);
261+
new LiveTranslatorManager(options);
254262
},
255263
};

0 commit comments

Comments
 (0)