2
2
var __importDefault = ( this && this . __importDefault ) || function ( mod ) {
3
3
return ( mod && mod . __esModule ) ? mod : { "default" : mod } ;
4
4
} ;
5
+ var _a ;
5
6
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
6
7
exports . LiveTranslatorPlugin = void 0 ;
7
8
const throttle_1 = __importDefault ( require ( "lodash/throttle" ) ) ;
@@ -59,14 +60,7 @@ const css = `
59
60
}
60
61
` ;
61
62
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 ) {
70
64
const binary = text
71
65
. split ( '' )
72
66
. map ( ( char ) => char . charCodeAt ( 0 ) . toString ( 2 ) )
@@ -86,7 +80,7 @@ class ZeroWidthEncoder {
86
80
. join ( '' ) ;
87
81
return this . START + zeroWidth + this . END ;
88
82
}
89
- decode ( zeroWidth ) {
83
+ static decode ( zeroWidth ) {
90
84
const binary = zeroWidth
91
85
. split ( '' )
92
86
. slice ( 1 , zeroWidth . length - 1 ) // remove START and END
@@ -107,20 +101,75 @@ class ZeroWidthEncoder {
107
101
return text ;
108
102
}
109
103
}
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 ) {
112
113
this . _enabled = false ;
113
- this . persist = persist ;
114
+ this . _options = options ;
115
+ // handle persistance
114
116
const savedRaw = localStorage . getItem ( 'live-translator-enabled' ) ;
115
- if ( persist && savedRaw ) {
117
+ if ( this . _options . persist && savedRaw ) {
116
118
const saved = JSON . parse ( savedRaw ) ;
117
119
if ( typeof saved === 'boolean' ) {
118
120
this . toggle ( saved ) ;
119
121
}
120
122
}
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 ( ) ;
121
168
}
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 ;
124
173
}
125
174
toggle ( enable ) {
126
175
if ( enable !== undefined ) {
@@ -129,9 +178,60 @@ class LiveTranslatorEnabler {
129
178
else {
130
179
this . _enabled = ! this . _enabled ;
131
180
}
132
- if ( this . persist ) {
181
+ if ( this . _options . persist ) {
133
182
localStorage . setItem ( 'live-translator-enabled' , JSON . stringify ( this . _enabled ) ) ;
134
183
}
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
+ }
135
235
}
136
236
}
137
237
const createBadge = ( meta , options , attribute ) => {
@@ -158,98 +258,6 @@ const createBadge = (meta, options, attribute) => {
158
258
exports . LiveTranslatorPlugin = {
159
259
install ( app , options ) {
160
260
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 ) ;
254
262
} ,
255
263
} ;
0 commit comments