@yander/translation-widget 1.1.4-yander.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/LICENSE +13 -0
- package/README.md +483 -0
- package/dist/constants/index.d.ts +18 -0
- package/dist/constants/languages.d.ts +2 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +3000 -0
- package/dist/index.min.js +1 -0
- package/dist/lib/dom/index.d.ts +19 -0
- package/dist/lib/storage/localstorage.d.ts +24 -0
- package/dist/lib/translation/index.d.ts +19 -0
- package/dist/types/index.d.ts +79 -0
- package/dist/utils/utils.d.ts +15 -0
- package/dist/widget/index.d.ts +163 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3000 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
const styles = 'Base Styles :root{--jigts-base-color: white;--jigts-text-color: black;--jigts-bg-color: color-mix(in srgb, var(--jigts-base-color) 10%, white);--jigts-bg-hover: color-mix(in srgb, var(--jigts-text-color) 10%, white);--jigts-bg-active: color-mix(in srgb, var(--jigts-base-color) 30%, white)}*{box-sizing:border-box}.jigts-translation-widget{--jigts-base-color: var(--jigts-custom-base-color, white);--jigts-text-color: var(--jigts-custom-text-color, black);--jigts-bg-color: color-mix(in srgb, var(--jigts-base-color) 10%, white);--jigts-bg-hover: color-mix(in srgb, var(--jigts-text-color) 10%, white);--jigts-bg-active: color-mix(in srgb, var(--jigts-base-color) 30%, white);position:fixed;z-index:1000;color:var(--jigts-text-color)}.jigts-translation-widget.jigts-position-top-right{top:2rem;right:2rem}.jigts-translation-widget.jigts-position-top-left{top:2rem;left:2rem}.jigts-translation-widget.jigts-position-bottom-left{bottom:2rem;left:2rem}.jigts-translation-widget.jigts-position-bottom-right{bottom:2rem;right:2rem}.jigts-position-top-right .jigts-widget-dropdown,.jigts-position-top-left .jigts-widget-dropdown{top:calc(100% + .5rem)}.jigts-position-bottom-right .jigts-widget-dropdown,.jigts-position-bottom-left .jigts-widget-dropdown{bottom:calc(100% + .5rem)}.jigts-position-top-right .jigts-widget-dropdown,.jigts-position-bottom-right .jigts-widget-dropdown{right:0}.jigts-position-top-left .jigts-widget-dropdown,.jigts-position-bottom-left .jigts-widget-dropdown{left:0}.jigts-translation-widget{position:fixed}.jigts-translation-widget{max-width:fit-content}.jigts-trigger-content{display:flex;cursor:pointer;border-radius:6px;transition:all .2s ease}.jigts-trigger-icon{display:flex;align-items:center}.jigts-lang-code{font-weight:500;color:var(--jigts-text-color);font-size:14px}.jigts-lang-name{color:var(--jigts-text-color);font-size:14px;opacity:0;max-width:0;overflow:hidden;white-space:nowrap;transition:all .3s ease-in-out;display:inline-block}.jigts-lang-code{transition:all .3s ease-in-out}.jigts-widget-trigger:hover .jigts-lang-code{background:#e5e7eb;border-radius:50%;padding:.1rem .3rem;color:var(--jigts-text-color);font-weight:600;font-size:12px;transition:all .3s ease-in-out}.jigts-widget-trigger:hover .jigts-lang-name{opacity:1;margin-left:.5rem;max-width:150px}.jigts-widget-trigger{background:var(--jigts-bg-color);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid color-mix(in srgb,var(--jigts-base-color) 30%,white);border-radius:.75rem;padding:.3rem .6rem;cursor:pointer;display:flex;align-items:center;gap:.2rem;font-size:.9rem;font-weight:500;color:var(--jigts-text-color);box-shadow:0 10px 25px -5px #0000001a,0 10px 10px -5px #0000000a;transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden;min-height:2.2rem;min-width:unset}.jigts-widget-trigger:hover{transform:scale(1.05) translateY(-2px);box-shadow:0 20px 40px -10px #00000026,0 10px 20px -5px #0000001a}.jigts-widget-trigger:active{transform:scale(.98)}.jigts-widget-trigger:before{content:"";position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(var(--jigts-base-color),.1),transparent);transition:left .6s ease}.jigts-widget-trigger:hover:before{left:100%}.jigts-widget-dropdown{position:absolute;width:20rem;background:var(--jigts-bg-color);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid color-mix(in srgb,var(--jigts-base-color) 30%,white);border-radius:.75rem;box-shadow:0 25px 50px -12px #00000040;opacity:0;visibility:hidden;transform:scale(.95) translateY(10px);transition:all .3s cubic-bezier(.4,0,.2,1);max-height:28rem;overflow:hidden;display:none;flex-direction:column;z-index:1000}.jigts-widget-dropdown.jigts-open{opacity:1;visibility:visible;transform:scale(1) translateY(0);display:flex}.jigts-widget-dropdown.jigts-closing{opacity:0;transform:translateY(10px)}.jigts-dropdown-header{padding:1rem;border-bottom:1px solid color-mix(in srgb,var(--jigts-base-color) 20%,white);background:var(--jigts-bg-hover);border-radius:.75rem .75rem 0 0;animation:headerSlideDown .4s ease .1s both}.jigts-dropdown-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem}.jigts-title-left{display:flex;align-items:center;gap:.5rem}.jigts-languages-icon{width:1rem;height:1rem;color:var(--jigts-text-color)}.jigts-title-text{font-size:.875rem;font-weight:600;color:var(--jigts-text-color)}.jigts-language-count{background:var(--jigts-bg-hover);border:1px solid color-mix(in srgb,var(--jigts-base-color) 30%,white);color:var(--jigts-text-color);padding:.125rem .5rem;border-radius:.375rem;font-size:.75rem;font-weight:500}.jigts-search-container{position:relative}.jigts-search-input{width:100%;padding:.5rem .75rem .5rem 2.5rem;border:1px solid #d1d5db;border-radius:.5rem;outline:none;font-size:.875rem;color:var(--jigts-text-color);background:#fff;transition:all .2s ease}.jigts-search-icon{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:var(--jigts-text-color);opacity:.7}.jigts-clear-search{position:absolute;right:.75rem;top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:var(--jigts-text-color);cursor:pointer;opacity:0;transition:all .2s ease}.jigts-clear-search.jigts-visible{opacity:.7}.jigts-clear-search:hover{opacity:1;transform:translateY(-50%) scale(1.1)}.jigts-reset-option{padding:.75rem 1rem;border-bottom:1px solid color-mix(in srgb,var(--jigts-base-color) 20%,white);cursor:pointer;display:flex;align-items:center;gap:.75rem;transition:background-color .2s ease;animation:resetSlideIn .4s ease .15s both;background:var(--jigts-bg-color)}.jigts-reset-option:hover{background:var(--jigts-bg-hover)}.jigts-reset-icon{width:1rem;height:1rem;color:var(--jigts-text-color);transition:transform .3s ease}.jigts-reset-option:hover .jigts-reset-icon{transform:rotate(-180deg)}.jigts-reset-text{display:flex;flex-direction:column}.jigts-reset-title{font-weight:500;color:var(--jigts-text-color);font-size:.875rem}.jigts-reset-subtitle{font-size:.75rem;color:var(--jigts-text-color);opacity:.7}.jigts-language-list{flex:1;overflow-y:auto;padding:.5rem;position:relative;min-height:200px}.jigts-language-item{display:flex;align-items:center;justify-content:space-between;margin-left:.5rem;margin-right:.5rem;margin-bottom:.5rem;padding:.625rem .75rem;border-radius:.5rem;cursor:pointer;transition:all .2s ease;border:1px solid transparent;animation:languageSlideIn .4s ease both;background:var(--jigts-bg-color)}.jigts-language-item.jigts-focused{background:var(--jigts-bg-hover);border-color:color-mix(in srgb,var(--jigts-base-color) 40%,white)}.jigts-language-item.jigts-selected{background:var(--jigts-bg-active)}.jigts-language-item:hover{background:var(--jigts-bg-hover)}.jigts-language-info{display:flex;flex-direction:column;align-items:flex-start;min-width:0;flex:1}.jigts-language-main{display:flex;align-items:center;gap:.5rem;width:100%}.jigts-language-name{font-weight:500;color:var(--jigts-text-color);font-size:.875rem;transition:color .2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.jigts-language-item:hover .jigts-language-name{color:var(--jigts-text-color);opacity:.8}.jigts-language-code{background:var(--jigts-bg-hover);color:var(--jigts-text-color);padding:.125rem .375rem;border-radius:.25rem;font-size:.75rem;font-weight:600;flex-shrink:0}.jigts-language-details{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--jigts-text-color);opacity:.7;width:100%;margin-top:.125rem}.jigts-language-native{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.jigts-language-separator,.jigts-language-region{flex-shrink:0}.jigts-globe-icon{width:1rem;height:1rem;color:var(--jigts-text-color);transition:transform .5s ease}.jigts-widget-trigger:hover .jigts-globe-icon{transform:rotate(360deg)}.jigts-check-icon{width:1rem;height:1rem;color:var(--jigts-text-color);opacity:0;transform:scale(0);transition:all .3s cubic-bezier(.34,1.56,.64,1)}.jigts-language-item.jigts-selected .jigts-check-icon{opacity:1;transform:scale(1)}.jigts-loading-spinner{width:1rem;height:1rem;border:2px solid #e5e7eb;border-top:2px solid var(--jigts-base-color);border-radius:50%;animation:spin 1s linear infinite}.jigts-trigger-loading{display:none}.jigts-no-results{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);display:none;flex-direction:column;align-items:center;justify-content:center;color:var(--jigts-text-color);text-align:center;padding:24px;animation:fadeIn .4s ease}.jigts-no-results-icon{width:2rem;height:2rem;margin-bottom:.5rem;color:var(--jigts-text-color);opacity:.5}.jigts-no-results-title{font-size:.875rem;margin-bottom:.25rem}.jigts-no-results-subtitle{font-size:.75rem}.jigts-dropdown-footer{padding:.5rem 1rem;border-top:1px solid color-mix(in srgb,var(--jigts-base-color) 20%,white);background:var(--jigts-bg-hover);border-radius:0 0 .75rem .75rem;animation:footerSlideUp .4s ease .2s both}.jigts-footer-text{font-size:.75rem;color:var(--jigts-text-color);text-align:center;opacity:.7}.jigts-language-list::-webkit-scrollbar{width:6px}.jigts-language-list::-webkit-scrollbar-track{background:#f3f4f6;border-radius:3px}.jigts-language-list::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:3px}.jigts-language-list::-webkit-scrollbar-thumb:hover{background:#9ca3af}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes badgeSlideIn{0%{transform:scale(0) translate(10px);opacity:0}to{transform:scale(1) translate(0);opacity:1}}@keyframes headerSlideDown{0%{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes resetSlideIn{0%{transform:translate(-20px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes languageSlideIn{0%{transform:translate(-20px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes footerSlideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.jigts-language-item:nth-child(1){animation-delay:.2s}.jigts-language-item:nth-child(2){animation-delay:.22s}.jigts-language-item:nth-child(3){animation-delay:.24s}.jigts-language-item:nth-child(4){animation-delay:.26s}.jigts-language-item:nth-child(5){animation-delay:.28s}.jigts-language-item:nth-child(6){animation-delay:.3s}.jigts-language-item:nth-child(7){animation-delay:.32s}.jigts-language-item:nth-child(8){animation-delay:.34s}.jigts-language-item:nth-child(9){animation-delay:.36s}.jigts-language-item:nth-child(10){animation-delay:.38s}@media(max-width:400px){.jigts-widget-dropdown{width:70vw;right:auto;left:50%;transform:translate(-59%) scale(.95) translateY(10px)}.jigts-widget-dropdown.jigts-open{transform:translate(-90%) scale(1) translateY(0)}}@media(prefers-contrast:high){.jigts-widget-trigger,.jigts-widget-dropdown{border:2px solid #000}}@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.jigts-translated-content{transition:all .3s ease}.jigts-translated-content.jigts-has-html{line-height:1.5}.jigts-translated-content.jigts-font-adjusted{transition:font-size .3s ease}.jigts-content-transition{animation:jigtsContentFade .3s ease-in-out}@keyframes jigtsContentFade{0%{opacity:.7;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}';
|
|
5
|
+
const BATCH_SIZE = 90;
|
|
6
|
+
const CACHE_PREFIX = "jss-";
|
|
7
|
+
const MAX_REQUESTS_PER_SECOND = 45;
|
|
8
|
+
const DEFAULT_TRANSLATE_API_URL = "https://api.jigsawstack.com/v1/ai/translate";
|
|
9
|
+
const DEFAULT_TARGET_LANGUAGE_CODES = ["zh"];
|
|
10
|
+
const DEFAULT_SOURCE_LANGUAGE_CODE = "en";
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
pageLanguage: "en",
|
|
13
|
+
autoDetectLanguage: false,
|
|
14
|
+
adjustFontSize: false,
|
|
15
|
+
mockMode: false,
|
|
16
|
+
position: "top-right",
|
|
17
|
+
targetLanguages: DEFAULT_TARGET_LANGUAGE_CODES,
|
|
18
|
+
apiUrl: DEFAULT_TRANSLATE_API_URL,
|
|
19
|
+
requestHeaders: {},
|
|
20
|
+
includeApiKeyHeader: true
|
|
21
|
+
};
|
|
22
|
+
class RateLimiter {
|
|
23
|
+
constructor(maxRequests, intervalMs = 1e3) {
|
|
24
|
+
__publicField(this, "timestamps", []);
|
|
25
|
+
__publicField(this, "pending", Promise.resolve());
|
|
26
|
+
this.maxRequests = maxRequests;
|
|
27
|
+
this.intervalMs = intervalMs;
|
|
28
|
+
}
|
|
29
|
+
acquire() {
|
|
30
|
+
this.pending = this.pending.then(() => this._acquire());
|
|
31
|
+
return this.pending;
|
|
32
|
+
}
|
|
33
|
+
async _acquire() {
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
this.timestamps = this.timestamps.filter((t) => now - t < this.intervalMs);
|
|
36
|
+
if (this.timestamps.length < this.maxRequests) {
|
|
37
|
+
this.timestamps.push(Date.now());
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const waitTime = this.intervalMs - (now - this.timestamps[0]);
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
42
|
+
this.timestamps = this.timestamps.filter((t) => Date.now() - t < this.intervalMs);
|
|
43
|
+
this.timestamps.push(Date.now());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const MOCK_LANGUAGE_LABELS = {
|
|
47
|
+
ar: "AR",
|
|
48
|
+
de: "DE",
|
|
49
|
+
en: "EN",
|
|
50
|
+
es: "ES",
|
|
51
|
+
fr: "FR",
|
|
52
|
+
hi: "HI",
|
|
53
|
+
it: "IT",
|
|
54
|
+
ja: "JA",
|
|
55
|
+
ko: "KO",
|
|
56
|
+
pt: "PT",
|
|
57
|
+
zh: "ZH"
|
|
58
|
+
};
|
|
59
|
+
const PSEUDO_TRANSLATION_MAP = {
|
|
60
|
+
a: "á",
|
|
61
|
+
e: "é",
|
|
62
|
+
i: "í",
|
|
63
|
+
o: "ó",
|
|
64
|
+
u: "ú",
|
|
65
|
+
A: "Á",
|
|
66
|
+
E: "É",
|
|
67
|
+
I: "Í",
|
|
68
|
+
O: "Ó",
|
|
69
|
+
U: "Ú"
|
|
70
|
+
};
|
|
71
|
+
function pseudoTranslateSegment(segment, targetLang) {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
const trimmed = segment.trim();
|
|
74
|
+
if (!trimmed) return segment;
|
|
75
|
+
const prefix = `【${MOCK_LANGUAGE_LABELS[targetLang] || targetLang.toUpperCase()}】`;
|
|
76
|
+
const pseudoText = trimmed.replace(/[aeiouAEIOU]/g, (char) => PSEUDO_TRANSLATION_MAP[char] || char);
|
|
77
|
+
const leadingWhitespace = ((_a = segment.match(/^\s*/)) == null ? void 0 : _a[0]) || "";
|
|
78
|
+
const trailingWhitespace = ((_b = segment.match(/\s*$/)) == null ? void 0 : _b[0]) || "";
|
|
79
|
+
return `${leadingWhitespace}${prefix} ${pseudoText}${trailingWhitespace}`;
|
|
80
|
+
}
|
|
81
|
+
function mockTranslateText(text, targetLang) {
|
|
82
|
+
if (text.includes("<")) {
|
|
83
|
+
return text.split(/(<[^>]+>)/g).map((part) => part.startsWith("<") ? part : pseudoTranslateSegment(part, targetLang)).join("");
|
|
84
|
+
}
|
|
85
|
+
return pseudoTranslateSegment(text, targetLang);
|
|
86
|
+
}
|
|
87
|
+
class TranslationService {
|
|
88
|
+
constructor(publicKey, options = {}) {
|
|
89
|
+
__publicField(this, "publicKey");
|
|
90
|
+
__publicField(this, "apiUrl");
|
|
91
|
+
__publicField(this, "rateLimiter");
|
|
92
|
+
__publicField(this, "mockMode");
|
|
93
|
+
__publicField(this, "requestHeaders");
|
|
94
|
+
__publicField(this, "includeApiKeyHeader");
|
|
95
|
+
this.publicKey = publicKey;
|
|
96
|
+
this.rateLimiter = new RateLimiter(MAX_REQUESTS_PER_SECOND);
|
|
97
|
+
this.mockMode = options.mockMode ?? false;
|
|
98
|
+
this.apiUrl = options.apiUrl || DEFAULT_TRANSLATE_API_URL;
|
|
99
|
+
this.requestHeaders = options.requestHeaders ?? {};
|
|
100
|
+
this.includeApiKeyHeader = options.includeApiKeyHeader ?? true;
|
|
101
|
+
}
|
|
102
|
+
normalizeTranslations(result) {
|
|
103
|
+
var _a;
|
|
104
|
+
if (Array.isArray((_a = result.data) == null ? void 0 : _a.translations)) {
|
|
105
|
+
return result.data.translations.map((item) => (item == null ? void 0 : item.translatedText) || "");
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(result.translated_text)) {
|
|
108
|
+
return result.translated_text;
|
|
109
|
+
}
|
|
110
|
+
if (typeof result.translated_text === "string") {
|
|
111
|
+
return [result.translated_text];
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
getRequestTargetLanguageCode(targetLang) {
|
|
116
|
+
if (targetLang === "zh") {
|
|
117
|
+
return "zh-CN";
|
|
118
|
+
}
|
|
119
|
+
return targetLang;
|
|
120
|
+
}
|
|
121
|
+
async translateBatchText(texts, targetLang, maxRetries = 2, retryDelay = 100) {
|
|
122
|
+
if (this.mockMode) {
|
|
123
|
+
await new Promise((resolve) => setTimeout(resolve, 120));
|
|
124
|
+
return texts.map((text) => mockTranslateText(text, targetLang));
|
|
125
|
+
}
|
|
126
|
+
await this.rateLimiter.acquire();
|
|
127
|
+
let attempt = 0;
|
|
128
|
+
while (attempt < maxRetries) {
|
|
129
|
+
try {
|
|
130
|
+
const headers = {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
...this.requestHeaders
|
|
133
|
+
};
|
|
134
|
+
if (this.includeApiKeyHeader && this.publicKey) {
|
|
135
|
+
headers["x-api-key"] = this.publicKey;
|
|
136
|
+
}
|
|
137
|
+
const response = await fetch(this.apiUrl, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers,
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
texts,
|
|
142
|
+
targetLanguageCode: this.getRequestTargetLanguageCode(targetLang),
|
|
143
|
+
sourceLanguageCode: DEFAULT_SOURCE_LANGUAGE_CODE
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const error = new Error(`Error translating text: ${response.statusText}`);
|
|
148
|
+
error.status = response.status;
|
|
149
|
+
error.response = response;
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
const result = await response.json();
|
|
153
|
+
if (typeof result.code === "number" && result.code !== 1e3) {
|
|
154
|
+
const error = new Error(result.message || "Translation service returned an invalid code");
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
const translations = this.normalizeTranslations(result);
|
|
158
|
+
if (translations.length === 0) {
|
|
159
|
+
const error = new Error("Translation service returned empty translations");
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
return translations;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
attempt++;
|
|
165
|
+
if (attempt >= maxRetries) {
|
|
166
|
+
console.error("Translation error after retries:", error);
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
await this.rateLimiter.acquire();
|
|
170
|
+
await new Promise((res) => setTimeout(res, retryDelay));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const languages = [
|
|
177
|
+
{
|
|
178
|
+
code: "af",
|
|
179
|
+
name: "Afrikaans",
|
|
180
|
+
native: "Afrikaans",
|
|
181
|
+
writing_system: "Latin"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
code: "am",
|
|
185
|
+
name: "Amharic",
|
|
186
|
+
native: "አማርኛ",
|
|
187
|
+
writing_system: "Ethiopic"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
code: "ar",
|
|
191
|
+
name: "Arabic",
|
|
192
|
+
native: "العربية",
|
|
193
|
+
rtl: 1,
|
|
194
|
+
writing_system: "Arabic"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
code: "as",
|
|
198
|
+
name: "Assamese",
|
|
199
|
+
native: "অসমীয়া",
|
|
200
|
+
writing_system: "Bengali"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
code: "az",
|
|
204
|
+
name: "Azerbaijani",
|
|
205
|
+
native: "Azərbaycanca / آذربايجان",
|
|
206
|
+
writing_system: "Latin"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
code: "ba",
|
|
210
|
+
name: "Bashkir",
|
|
211
|
+
native: "Башҡорт",
|
|
212
|
+
writing_system: "Cyrillic"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
code: "be",
|
|
216
|
+
name: "Belarusian",
|
|
217
|
+
native: "Беларуская",
|
|
218
|
+
writing_system: "Cyrillic"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
code: "bg",
|
|
222
|
+
name: "Bulgarian",
|
|
223
|
+
native: "Български",
|
|
224
|
+
writing_system: "Cyrillic"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
code: "bn",
|
|
228
|
+
name: "Bengali",
|
|
229
|
+
native: "বাংলা",
|
|
230
|
+
writing_system: "Bengali"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
code: "bo",
|
|
234
|
+
name: "Tibetan",
|
|
235
|
+
native: "བོད་ཡིག / Bod skad",
|
|
236
|
+
writing_system: "Tibetan"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
code: "br",
|
|
240
|
+
name: "Breton",
|
|
241
|
+
native: "Brezhoneg",
|
|
242
|
+
writing_system: "Latin"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
code: "bs",
|
|
246
|
+
name: "Bosnian",
|
|
247
|
+
native: "Bosanski",
|
|
248
|
+
writing_system: "Latin"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
code: "ca",
|
|
252
|
+
name: "Catalan",
|
|
253
|
+
native: "Català",
|
|
254
|
+
writing_system: "Latin"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
code: "ch",
|
|
258
|
+
name: "Chamorro",
|
|
259
|
+
native: "Chamoru",
|
|
260
|
+
writing_system: "Latin"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
code: "co",
|
|
264
|
+
name: "Corsican",
|
|
265
|
+
native: "Corsu",
|
|
266
|
+
writing_system: "Latin"
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
code: "cs",
|
|
270
|
+
name: "Czech",
|
|
271
|
+
native: "Česky",
|
|
272
|
+
writing_system: "Latin"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
code: "cy",
|
|
276
|
+
name: "Welsh",
|
|
277
|
+
native: "Cymraeg",
|
|
278
|
+
writing_system: "Latin"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
code: "da",
|
|
282
|
+
name: "Danish",
|
|
283
|
+
native: "Dansk",
|
|
284
|
+
writing_system: "Latin"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
code: "de",
|
|
288
|
+
name: "German",
|
|
289
|
+
native: "Deutsch",
|
|
290
|
+
writing_system: "Latin"
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
code: "dv",
|
|
294
|
+
name: "Divehi",
|
|
295
|
+
native: "ދިވެހިބަސް",
|
|
296
|
+
rtl: 1,
|
|
297
|
+
writing_system: "Thaana"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
code: "dz",
|
|
301
|
+
name: "Dzongkha",
|
|
302
|
+
native: "ཇོང་ཁ",
|
|
303
|
+
writing_system: "Tibetan"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
code: "el",
|
|
307
|
+
name: "Greek",
|
|
308
|
+
native: "Ελληνικά",
|
|
309
|
+
writing_system: "Greek"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
code: "en",
|
|
313
|
+
name: "English",
|
|
314
|
+
native: "English",
|
|
315
|
+
writing_system: "Latin"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
code: "eo",
|
|
319
|
+
name: "Esperanto",
|
|
320
|
+
native: "Esperanto",
|
|
321
|
+
writing_system: "Latin"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
code: "es",
|
|
325
|
+
name: "Spanish",
|
|
326
|
+
native: "Español",
|
|
327
|
+
writing_system: "Latin"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
code: "et",
|
|
331
|
+
name: "Estonian",
|
|
332
|
+
native: "Eesti",
|
|
333
|
+
writing_system: "Latin"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
code: "eu",
|
|
337
|
+
name: "Basque",
|
|
338
|
+
native: "Euskara",
|
|
339
|
+
writing_system: "Latin"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
code: "fa",
|
|
343
|
+
name: "Persian",
|
|
344
|
+
native: "فارسی",
|
|
345
|
+
rtl: 1,
|
|
346
|
+
writing_system: "Arabic"
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
code: "ff",
|
|
350
|
+
name: "Peul",
|
|
351
|
+
native: "Fulfulde",
|
|
352
|
+
writing_system: "Latin"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
code: "fi",
|
|
356
|
+
name: "Finnish",
|
|
357
|
+
native: "Suomi",
|
|
358
|
+
writing_system: "Latin"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
code: "fj",
|
|
362
|
+
name: "Fijian",
|
|
363
|
+
native: "Na Vosa Vakaviti",
|
|
364
|
+
writing_system: "Latin"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
code: "fo",
|
|
368
|
+
name: "Faroese",
|
|
369
|
+
native: "Føroyskt",
|
|
370
|
+
writing_system: "Latin"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
code: "fr",
|
|
374
|
+
name: "French",
|
|
375
|
+
native: "Français",
|
|
376
|
+
writing_system: "Latin"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
code: "fy",
|
|
380
|
+
name: "West Frisian",
|
|
381
|
+
native: "Frysk",
|
|
382
|
+
writing_system: "Latin"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
code: "ga",
|
|
386
|
+
name: "Irish",
|
|
387
|
+
native: "Gaeilge",
|
|
388
|
+
writing_system: "Latin"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
code: "gd",
|
|
392
|
+
name: "Scottish Gaelic",
|
|
393
|
+
native: "Gàidhlig",
|
|
394
|
+
writing_system: "Latin"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
code: "gl",
|
|
398
|
+
name: "Galician",
|
|
399
|
+
native: "Galego",
|
|
400
|
+
writing_system: "Latin"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
code: "gn",
|
|
404
|
+
name: "Guarani",
|
|
405
|
+
native: "Avañe'ẽ",
|
|
406
|
+
writing_system: "Latin"
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
code: "gu",
|
|
410
|
+
name: "Gujarati",
|
|
411
|
+
native: "ગુજરાતી",
|
|
412
|
+
writing_system: "Gujarati"
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
code: "gv",
|
|
416
|
+
name: "Manx",
|
|
417
|
+
native: "Gaelg",
|
|
418
|
+
writing_system: "Latin"
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
code: "ha",
|
|
422
|
+
name: "Hausa",
|
|
423
|
+
native: "هَوُسَ",
|
|
424
|
+
rtl: 1,
|
|
425
|
+
writing_system: "Latin"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
code: "he",
|
|
429
|
+
name: "Hebrew",
|
|
430
|
+
native: "עברית",
|
|
431
|
+
rtl: 1,
|
|
432
|
+
writing_system: "Hebrew"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
code: "hi",
|
|
436
|
+
name: "Hindi",
|
|
437
|
+
native: "हिन्दी",
|
|
438
|
+
writing_system: "Devanagari"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
code: "hr",
|
|
442
|
+
name: "Croatian",
|
|
443
|
+
native: "Hrvatski",
|
|
444
|
+
writing_system: "Latin"
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
code: "ht",
|
|
448
|
+
name: "Haitian",
|
|
449
|
+
native: "Krèyol ayisyen",
|
|
450
|
+
writing_system: "Latin"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
code: "hu",
|
|
454
|
+
name: "Hungarian",
|
|
455
|
+
native: "Magyar",
|
|
456
|
+
writing_system: "Latin"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
code: "hy",
|
|
460
|
+
name: "Armenian",
|
|
461
|
+
native: "Հայերեն",
|
|
462
|
+
writing_system: "Armenian"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
code: "id",
|
|
466
|
+
name: "Indonesian",
|
|
467
|
+
native: "Bahasa Indonesia",
|
|
468
|
+
writing_system: "Latin"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
code: "ig",
|
|
472
|
+
name: "Igbo",
|
|
473
|
+
native: "Igbo",
|
|
474
|
+
writing_system: "Latin"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
code: "is",
|
|
478
|
+
name: "Icelandic",
|
|
479
|
+
native: "Íslenska",
|
|
480
|
+
writing_system: "Latin"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
code: "it",
|
|
484
|
+
name: "Italian",
|
|
485
|
+
native: "Italiano",
|
|
486
|
+
writing_system: "Latin"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
code: "iu",
|
|
490
|
+
name: "Inuktitut",
|
|
491
|
+
native: "ᐃᓄᒃᑎᑐᑦ",
|
|
492
|
+
writing_system: "Unified Canadian Aboriginal Syllabics"
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
code: "ja",
|
|
496
|
+
name: "Japanese",
|
|
497
|
+
native: "日本語",
|
|
498
|
+
writing_system: "Japanese"
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
code: "jv",
|
|
502
|
+
name: "Javanese",
|
|
503
|
+
native: "Basa Jawa",
|
|
504
|
+
writing_system: "Javanese"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
code: "ka",
|
|
508
|
+
name: "Georgian",
|
|
509
|
+
native: "ქართული",
|
|
510
|
+
writing_system: "Georgian"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
code: "kg",
|
|
514
|
+
name: "Kongo",
|
|
515
|
+
native: "KiKongo",
|
|
516
|
+
writing_system: "Latin"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
code: "ki",
|
|
520
|
+
name: "Kikuyu",
|
|
521
|
+
native: "Gĩkũyũ",
|
|
522
|
+
writing_system: "Latin"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
code: "kj",
|
|
526
|
+
name: "Kuanyama",
|
|
527
|
+
native: "Kuanyama",
|
|
528
|
+
writing_system: "Latin"
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
code: "kk",
|
|
532
|
+
name: "Kazakh",
|
|
533
|
+
native: "Қазақша",
|
|
534
|
+
writing_system: "Cyrillic"
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
code: "kl",
|
|
538
|
+
name: "Greenlandic",
|
|
539
|
+
native: "Kalaallisut",
|
|
540
|
+
writing_system: "Latin"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
code: "km",
|
|
544
|
+
name: "Cambodian",
|
|
545
|
+
native: "ភាសាខ្មែរ",
|
|
546
|
+
writing_system: "Khmer"
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
code: "kn",
|
|
550
|
+
name: "Kannada",
|
|
551
|
+
native: "ಕನ್ನಡ",
|
|
552
|
+
writing_system: "Kannada"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
code: "ko",
|
|
556
|
+
name: "Korean",
|
|
557
|
+
native: "한국어",
|
|
558
|
+
writing_system: "Korean"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
code: "kr",
|
|
562
|
+
name: "Kanuri",
|
|
563
|
+
native: "Kanuri",
|
|
564
|
+
writing_system: "Latin"
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
code: "ks",
|
|
568
|
+
name: "Kashmiri",
|
|
569
|
+
native: "कश्मीरी / كشميري",
|
|
570
|
+
rtl: 1,
|
|
571
|
+
writing_system: "Arabic"
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
code: "ku",
|
|
575
|
+
name: "Kurdish",
|
|
576
|
+
native: "Kurdî / كوردی",
|
|
577
|
+
rtl: 1,
|
|
578
|
+
writing_system: "Arabic"
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
code: "kv",
|
|
582
|
+
name: "Komi",
|
|
583
|
+
native: "Коми",
|
|
584
|
+
writing_system: "Cyrillic"
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
code: "kw",
|
|
588
|
+
name: "Cornish",
|
|
589
|
+
native: "Kernewek",
|
|
590
|
+
writing_system: "Latin"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
code: "ky",
|
|
594
|
+
name: "Kirghiz",
|
|
595
|
+
native: "Kırgızca / Кыргызча",
|
|
596
|
+
writing_system: "Cyrillic"
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
code: "la",
|
|
600
|
+
name: "Latin",
|
|
601
|
+
native: "Latina",
|
|
602
|
+
writing_system: "Latin"
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
code: "lb",
|
|
606
|
+
name: "Luxembourgish",
|
|
607
|
+
native: "Lëtzebuergesch",
|
|
608
|
+
writing_system: "Latin"
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
code: "lg",
|
|
612
|
+
name: "Ganda",
|
|
613
|
+
native: "Luganda",
|
|
614
|
+
writing_system: "Latin"
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
code: "li",
|
|
618
|
+
name: "Limburgian",
|
|
619
|
+
native: "Limburgs",
|
|
620
|
+
writing_system: "Latin"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
code: "ln",
|
|
624
|
+
name: "Lingala",
|
|
625
|
+
native: "Lingála",
|
|
626
|
+
writing_system: "Latin"
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
code: "lo",
|
|
630
|
+
name: "Laotian",
|
|
631
|
+
native: "ລາວ / Pha xa lao",
|
|
632
|
+
writing_system: "Lao"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
code: "lt",
|
|
636
|
+
name: "Lithuanian",
|
|
637
|
+
native: "Lietuvių",
|
|
638
|
+
writing_system: "Latin"
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
code: "lu",
|
|
642
|
+
name: "Luba-Katanga",
|
|
643
|
+
native: "Tshiluba",
|
|
644
|
+
writing_system: "Latin"
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
code: "lv",
|
|
648
|
+
name: "Latvian",
|
|
649
|
+
native: "Latviešu",
|
|
650
|
+
writing_system: "Latin"
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
code: "mg",
|
|
654
|
+
name: "Malagasy",
|
|
655
|
+
native: "Malagasy",
|
|
656
|
+
writing_system: "Latin"
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
code: "mh",
|
|
660
|
+
name: "Marshallese",
|
|
661
|
+
native: "Kajin Majel / Ebon",
|
|
662
|
+
writing_system: "Latin"
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
code: "mi",
|
|
666
|
+
name: "Maori",
|
|
667
|
+
native: "Māori",
|
|
668
|
+
writing_system: "Latin"
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
code: "mk",
|
|
672
|
+
name: "Macedonian",
|
|
673
|
+
native: "Македонски",
|
|
674
|
+
writing_system: "Cyrillic"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
code: "ml",
|
|
678
|
+
name: "Malayalam",
|
|
679
|
+
native: "മലയാളം",
|
|
680
|
+
writing_system: "Malayalam"
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
code: "mn",
|
|
684
|
+
name: "Mongolian",
|
|
685
|
+
native: "Монгол",
|
|
686
|
+
writing_system: "Mongolian"
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
code: "mo",
|
|
690
|
+
name: "Moldovan",
|
|
691
|
+
native: "Moldovenească",
|
|
692
|
+
writing_system: "Latin"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
code: "mr",
|
|
696
|
+
name: "Marathi",
|
|
697
|
+
native: "मराठी",
|
|
698
|
+
writing_system: "Devanagari"
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
code: "ms",
|
|
702
|
+
name: "Malay",
|
|
703
|
+
native: "Bahasa Melayu",
|
|
704
|
+
writing_system: "Latin"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
code: "mt",
|
|
708
|
+
name: "Maltese",
|
|
709
|
+
native: "bil-Malti",
|
|
710
|
+
writing_system: "Latin"
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
code: "my",
|
|
714
|
+
name: "Burmese",
|
|
715
|
+
native: "မြန်မာစာ",
|
|
716
|
+
writing_system: "Myanmar"
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
code: "na",
|
|
720
|
+
name: "Nauruan",
|
|
721
|
+
native: "Dorerin Naoero",
|
|
722
|
+
writing_system: "Latin"
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
code: "nb",
|
|
726
|
+
name: "Norwegian Bokmål",
|
|
727
|
+
native: "Norsk bokmål",
|
|
728
|
+
writing_system: "Latin"
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
code: "nd",
|
|
732
|
+
name: "North Ndebele",
|
|
733
|
+
native: "Sindebele",
|
|
734
|
+
writing_system: "Latin"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
code: "ne",
|
|
738
|
+
name: "Nepali",
|
|
739
|
+
native: "नेपाली",
|
|
740
|
+
writing_system: "Devanagari"
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
code: "ng",
|
|
744
|
+
name: "Ndonga",
|
|
745
|
+
native: "Oshiwambo",
|
|
746
|
+
writing_system: "Latin"
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
code: "nl",
|
|
750
|
+
name: "Dutch",
|
|
751
|
+
native: "Nederlands",
|
|
752
|
+
writing_system: "Latin"
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
code: "nn",
|
|
756
|
+
name: "Norwegian Nynorsk",
|
|
757
|
+
native: "Norsk nynorsk",
|
|
758
|
+
writing_system: "Latin"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
code: "no",
|
|
762
|
+
name: "Norwegian",
|
|
763
|
+
native: "Norsk",
|
|
764
|
+
writing_system: "Latin"
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
code: "nr",
|
|
768
|
+
name: "South Ndebele",
|
|
769
|
+
native: "isiNdebele",
|
|
770
|
+
writing_system: "Latin"
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
code: "nv",
|
|
774
|
+
name: "Navajo",
|
|
775
|
+
native: "Diné bizaad",
|
|
776
|
+
writing_system: "Latin"
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
code: "ny",
|
|
780
|
+
name: "Chichewa",
|
|
781
|
+
native: "Chi-Chewa",
|
|
782
|
+
writing_system: "Latin"
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
code: "oc",
|
|
786
|
+
name: "Occitan",
|
|
787
|
+
native: "Occitan",
|
|
788
|
+
writing_system: "Latin"
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
code: "oj",
|
|
792
|
+
name: "Ojibwa",
|
|
793
|
+
native: "ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin",
|
|
794
|
+
writing_system: "Unified Canadian Aboriginal Syllabics"
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
code: "om",
|
|
798
|
+
name: "Oromo",
|
|
799
|
+
native: "Oromoo",
|
|
800
|
+
writing_system: "Latin"
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
code: "or",
|
|
804
|
+
name: "Oriya",
|
|
805
|
+
native: "ଓଡ଼ିଆ",
|
|
806
|
+
writing_system: "Odia"
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
code: "os",
|
|
810
|
+
name: "Ossetian / Ossetic",
|
|
811
|
+
native: "Иронау",
|
|
812
|
+
writing_system: "Cyrillic"
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
code: "pa",
|
|
816
|
+
name: "Panjabi / Punjabi",
|
|
817
|
+
native: "ਪੰਜਾਬੀ / पंजाबी / پنجابي",
|
|
818
|
+
writing_system: "Gurmukhi"
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
code: "pi",
|
|
822
|
+
name: "Pali",
|
|
823
|
+
native: "Pāli / पाऴि",
|
|
824
|
+
writing_system: "Devanagari"
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
code: "pl",
|
|
828
|
+
name: "Polish",
|
|
829
|
+
native: "Polski",
|
|
830
|
+
writing_system: "Latin"
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
code: "ps",
|
|
834
|
+
name: "Pashto",
|
|
835
|
+
native: "پښتو",
|
|
836
|
+
rtl: 1,
|
|
837
|
+
writing_system: "Arabic"
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
code: "pt",
|
|
841
|
+
name: "Portuguese",
|
|
842
|
+
native: "Português",
|
|
843
|
+
writing_system: "Latin"
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
code: "qu",
|
|
847
|
+
name: "Quechua",
|
|
848
|
+
native: "Runa Simi",
|
|
849
|
+
writing_system: "Latin"
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
code: "rm",
|
|
853
|
+
name: "Raeto Romance",
|
|
854
|
+
native: "Rumantsch",
|
|
855
|
+
writing_system: "Latin"
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
code: "rn",
|
|
859
|
+
name: "Kirundi",
|
|
860
|
+
native: "Kirundi",
|
|
861
|
+
writing_system: "Latin"
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
code: "ro",
|
|
865
|
+
name: "Romanian",
|
|
866
|
+
native: "Română",
|
|
867
|
+
writing_system: "Latin"
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
code: "ru",
|
|
871
|
+
name: "Russian",
|
|
872
|
+
native: "Русский",
|
|
873
|
+
writing_system: "Cyrillic"
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
code: "rw",
|
|
877
|
+
name: "Rwandi",
|
|
878
|
+
native: "Kinyarwandi",
|
|
879
|
+
writing_system: "Latin"
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
code: "sa",
|
|
883
|
+
name: "Sanskrit",
|
|
884
|
+
native: "संस्कृतम्",
|
|
885
|
+
writing_system: "Devanagari"
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
code: "sc",
|
|
889
|
+
name: "Sardinian",
|
|
890
|
+
native: "Sardu",
|
|
891
|
+
writing_system: "Latin"
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
code: "sd",
|
|
895
|
+
name: "Sindhi",
|
|
896
|
+
native: "सिनधि",
|
|
897
|
+
writing_system: "Arabic"
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
code: "se",
|
|
901
|
+
name: "Northern Sami",
|
|
902
|
+
native: "Sámegiella",
|
|
903
|
+
writing_system: "Latin"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
code: "sg",
|
|
907
|
+
name: "Sango",
|
|
908
|
+
native: "Sängö",
|
|
909
|
+
writing_system: "Latin"
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
code: "sh",
|
|
913
|
+
name: "Serbo-Croatian",
|
|
914
|
+
native: "Srpskohrvatski / Српскохрватски",
|
|
915
|
+
writing_system: "Latin"
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
code: "si",
|
|
919
|
+
name: "Sinhalese",
|
|
920
|
+
native: "සිංහල",
|
|
921
|
+
writing_system: "Sinhala"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
code: "sk",
|
|
925
|
+
name: "Slovak",
|
|
926
|
+
native: "Slovenčina",
|
|
927
|
+
writing_system: "Latin"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
code: "sl",
|
|
931
|
+
name: "Slovenian",
|
|
932
|
+
native: "Slovenščina",
|
|
933
|
+
writing_system: "Latin"
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
code: "sm",
|
|
937
|
+
name: "Samoan",
|
|
938
|
+
native: "Gagana Samoa",
|
|
939
|
+
writing_system: "Latin"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
code: "sn",
|
|
943
|
+
name: "Shona",
|
|
944
|
+
native: "chiShona",
|
|
945
|
+
writing_system: "Latin"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
code: "so",
|
|
949
|
+
name: "Somalia",
|
|
950
|
+
native: "Soomaaliga",
|
|
951
|
+
writing_system: "Latin"
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
code: "sq",
|
|
955
|
+
name: "Albanian",
|
|
956
|
+
native: "Shqip",
|
|
957
|
+
writing_system: "Latin"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
code: "sr",
|
|
961
|
+
name: "Serbian",
|
|
962
|
+
native: "Српски",
|
|
963
|
+
writing_system: "Cyrillic"
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
code: "ss",
|
|
967
|
+
name: "Swati",
|
|
968
|
+
native: "SiSwati",
|
|
969
|
+
writing_system: "Latin"
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
code: "st",
|
|
973
|
+
name: "Southern Sotho",
|
|
974
|
+
native: "Sesotho",
|
|
975
|
+
writing_system: "Latin"
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
code: "su",
|
|
979
|
+
name: "Sundanese",
|
|
980
|
+
native: "Basa Sunda",
|
|
981
|
+
writing_system: "Sundanese"
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
code: "sv",
|
|
985
|
+
name: "Swedish",
|
|
986
|
+
native: "Svenska",
|
|
987
|
+
writing_system: "Latin"
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
code: "sw",
|
|
991
|
+
name: "Swahili",
|
|
992
|
+
native: "Kiswahili",
|
|
993
|
+
writing_system: "Latin"
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
code: "ta",
|
|
997
|
+
name: "Tamil",
|
|
998
|
+
native: "தமிழ்",
|
|
999
|
+
writing_system: "Tamil"
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
code: "te",
|
|
1003
|
+
name: "Telugu",
|
|
1004
|
+
native: "తెలుగు",
|
|
1005
|
+
writing_system: "Telugu"
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
code: "tg",
|
|
1009
|
+
name: "Tajik",
|
|
1010
|
+
native: "Тоҷикӣ",
|
|
1011
|
+
writing_system: "Cyrillic"
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
code: "th",
|
|
1015
|
+
name: "Thai",
|
|
1016
|
+
native: "ไทย / Phasa Thai",
|
|
1017
|
+
writing_system: "Thai"
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
code: "ti",
|
|
1021
|
+
name: "Tigrinya",
|
|
1022
|
+
native: "ትግርኛ",
|
|
1023
|
+
writing_system: "Ethiopic"
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
code: "tk",
|
|
1027
|
+
name: "Turkmen",
|
|
1028
|
+
native: "Туркмен / تركمن",
|
|
1029
|
+
writing_system: "Latin"
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
code: "tl",
|
|
1033
|
+
name: "Tagalog / Filipino",
|
|
1034
|
+
native: "Tagalog",
|
|
1035
|
+
writing_system: "Latin"
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
code: "tn",
|
|
1039
|
+
name: "Tswana",
|
|
1040
|
+
native: "Setswana",
|
|
1041
|
+
writing_system: "Latin"
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
code: "to",
|
|
1045
|
+
name: "Tonga",
|
|
1046
|
+
native: "Lea Faka-Tonga",
|
|
1047
|
+
writing_system: "Latin"
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
code: "tr",
|
|
1051
|
+
name: "Turkish",
|
|
1052
|
+
native: "Türkçe",
|
|
1053
|
+
writing_system: "Latin"
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
code: "ts",
|
|
1057
|
+
name: "Tsonga",
|
|
1058
|
+
native: "Xitsonga",
|
|
1059
|
+
writing_system: "Latin"
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
code: "tt",
|
|
1063
|
+
name: "Tatar",
|
|
1064
|
+
native: "Tatarça",
|
|
1065
|
+
writing_system: "Cyrillic"
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
code: "tw",
|
|
1069
|
+
name: "Twi",
|
|
1070
|
+
native: "Twi",
|
|
1071
|
+
writing_system: "Latin"
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
code: "ty",
|
|
1075
|
+
name: "Tahitian",
|
|
1076
|
+
native: "Reo Mā`ohi",
|
|
1077
|
+
writing_system: "Latin"
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
code: "ug",
|
|
1081
|
+
name: "Uyghur",
|
|
1082
|
+
native: "Uyƣurqə / ئۇيغۇرچە",
|
|
1083
|
+
writing_system: "Arabic"
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
code: "uk",
|
|
1087
|
+
name: "Ukrainian",
|
|
1088
|
+
native: "Українська",
|
|
1089
|
+
writing_system: "Cyrillic"
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
code: "ur",
|
|
1093
|
+
name: "Urdu",
|
|
1094
|
+
native: "اردو",
|
|
1095
|
+
rtl: 1,
|
|
1096
|
+
writing_system: "Arabic"
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
code: "uz",
|
|
1100
|
+
name: "Uzbek",
|
|
1101
|
+
native: "Ўзбек",
|
|
1102
|
+
writing_system: "Latin"
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
code: "ve",
|
|
1106
|
+
name: "Venda",
|
|
1107
|
+
native: "Tshivenḓa",
|
|
1108
|
+
writing_system: "Latin"
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
code: "vi",
|
|
1112
|
+
name: "Vietnamese",
|
|
1113
|
+
native: "Tiếng Việt",
|
|
1114
|
+
writing_system: "Latin"
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
code: "vo",
|
|
1118
|
+
name: "Volapük",
|
|
1119
|
+
native: "Volapük",
|
|
1120
|
+
writing_system: "Latin"
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
code: "wo",
|
|
1124
|
+
name: "Wolof",
|
|
1125
|
+
native: "Wollof",
|
|
1126
|
+
writing_system: "Latin"
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
code: "xh",
|
|
1130
|
+
name: "Xhosa",
|
|
1131
|
+
native: "isiXhosa",
|
|
1132
|
+
writing_system: "Latin"
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
code: "yi",
|
|
1136
|
+
name: "Yiddish",
|
|
1137
|
+
native: "ייִדיש",
|
|
1138
|
+
rtl: 1,
|
|
1139
|
+
writing_system: "Hebrew"
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
code: "yo",
|
|
1143
|
+
name: "Yoruba",
|
|
1144
|
+
native: "Yorùbá",
|
|
1145
|
+
writing_system: "Latin"
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
code: "zh",
|
|
1149
|
+
name: "Chinese (Simplified)",
|
|
1150
|
+
native: "简体中文",
|
|
1151
|
+
writing_system: "Simplied Han"
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
code: "zh-TW",
|
|
1155
|
+
name: "Chinese (Traditional)",
|
|
1156
|
+
native: "繁體中文",
|
|
1157
|
+
writing_system: "Traditional Han"
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
code: "zu",
|
|
1161
|
+
name: "Zulu",
|
|
1162
|
+
native: "isiZulu",
|
|
1163
|
+
writing_system: "Latin"
|
|
1164
|
+
}
|
|
1165
|
+
];
|
|
1166
|
+
function generateHashForContent(nodes) {
|
|
1167
|
+
const content = nodes.map((node) => {
|
|
1168
|
+
return node.text.replace(/\s+/g, " ").trim().toLocaleLowerCase();
|
|
1169
|
+
}).join(" ").trim();
|
|
1170
|
+
const hash = murmurhash3_32_gc(content.toLowerCase(), 42).toString(16);
|
|
1171
|
+
return hash;
|
|
1172
|
+
}
|
|
1173
|
+
function murmurhash3_32_gc(key, seed) {
|
|
1174
|
+
let remainder = key.length & 3, bytes = key.length - remainder;
|
|
1175
|
+
let h1 = seed, c1 = 3432918353, c2 = 461845907;
|
|
1176
|
+
let i = 0;
|
|
1177
|
+
while (i < bytes) {
|
|
1178
|
+
let k12 = key.charCodeAt(i) & 255 | (key.charCodeAt(++i) & 255) << 8 | (key.charCodeAt(++i) & 255) << 16 | (key.charCodeAt(++i) & 255) << 24;
|
|
1179
|
+
++i;
|
|
1180
|
+
k12 = (k12 & 65535) * c1 + (((k12 >>> 16) * c1 & 65535) << 16) & 4294967295;
|
|
1181
|
+
k12 = k12 << 15 | k12 >>> 17;
|
|
1182
|
+
k12 = (k12 & 65535) * c2 + (((k12 >>> 16) * c2 & 65535) << 16) & 4294967295;
|
|
1183
|
+
h1 ^= k12;
|
|
1184
|
+
h1 = h1 << 13 | h1 >>> 19;
|
|
1185
|
+
const h1b = (h1 & 65535) * 5 + (((h1 >>> 16) * 5 & 65535) << 16) & 4294967295;
|
|
1186
|
+
h1 = (h1b & 65535) + 27492 + (((h1b >>> 16) + 58964 & 65535) << 16);
|
|
1187
|
+
}
|
|
1188
|
+
let k1 = 0;
|
|
1189
|
+
switch (remainder) {
|
|
1190
|
+
//@ts-expect-error - this is a valid case
|
|
1191
|
+
case 3:
|
|
1192
|
+
k1 ^= key.charCodeAt(i + 2) << 16;
|
|
1193
|
+
//@ts-expect-error - this is a valid case
|
|
1194
|
+
case 2:
|
|
1195
|
+
k1 ^= key.charCodeAt(i + 1) << 8;
|
|
1196
|
+
case 1:
|
|
1197
|
+
k1 ^= key.charCodeAt(i);
|
|
1198
|
+
k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
|
|
1199
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
1200
|
+
k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
|
|
1201
|
+
h1 ^= k1;
|
|
1202
|
+
}
|
|
1203
|
+
h1 ^= key.length;
|
|
1204
|
+
h1 ^= h1 >>> 16;
|
|
1205
|
+
h1 = (h1 & 65535) * 2246822507 + (((h1 >>> 16) * 2246822507 & 65535) << 16) & 4294967295;
|
|
1206
|
+
h1 ^= h1 >>> 13;
|
|
1207
|
+
h1 = (h1 & 65535) * 3266489909 + (((h1 >>> 16) * 3266489909 & 65535) << 16) & 4294967295;
|
|
1208
|
+
h1 ^= h1 >>> 16;
|
|
1209
|
+
return h1 >>> 0;
|
|
1210
|
+
}
|
|
1211
|
+
const removeEmojis = (text) => text.replace(/[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu, "");
|
|
1212
|
+
const getUserLanguage = () => {
|
|
1213
|
+
const userLanguages = window.navigator.languages;
|
|
1214
|
+
const userLanguage = languages.find((lang) => userLanguages.includes(lang.code));
|
|
1215
|
+
return (userLanguage == null ? void 0 : userLanguage.code) || "en";
|
|
1216
|
+
};
|
|
1217
|
+
function validatePublicApiKey(publicKey) {
|
|
1218
|
+
if (!publicKey) {
|
|
1219
|
+
return {
|
|
1220
|
+
isValid: false,
|
|
1221
|
+
message: "Public key is required to initialize the translation widget"
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
if (publicKey.startsWith("sk_")) {
|
|
1225
|
+
return {
|
|
1226
|
+
isValid: false,
|
|
1227
|
+
message: "Please use public api key for security reasons. You can get one from https://jigsawstack.com"
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
if (!publicKey.startsWith("pk_")) {
|
|
1231
|
+
return {
|
|
1232
|
+
isValid: false,
|
|
1233
|
+
message: "Please use proper api key. You can get one from https://jigsawstack.com"
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
return { isValid: true };
|
|
1237
|
+
}
|
|
1238
|
+
class DocumentNavigator {
|
|
1239
|
+
/**
|
|
1240
|
+
* Retrieves text nodes eligible for translation from the document
|
|
1241
|
+
* @returns Collection of text nodes ready for translation
|
|
1242
|
+
*/
|
|
1243
|
+
static findTranslatableContent() {
|
|
1244
|
+
var _a;
|
|
1245
|
+
if (typeof window === "undefined") return [];
|
|
1246
|
+
const validator = {
|
|
1247
|
+
acceptNode(node) {
|
|
1248
|
+
var _a2;
|
|
1249
|
+
if (node.nodeType !== Node.TEXT_NODE) return NodeFilter.FILTER_REJECT;
|
|
1250
|
+
const container = node.parentElement;
|
|
1251
|
+
if (!container) return NodeFilter.FILTER_REJECT;
|
|
1252
|
+
if (container.closest('[aria-hidden="true"]')) return NodeFilter.FILTER_REJECT;
|
|
1253
|
+
if (container.classList.contains("sr-only")) return NodeFilter.FILTER_REJECT;
|
|
1254
|
+
const skipBySelector = container.closest(
|
|
1255
|
+
"script, style, code, noscript, next-route-announcer, .jigts-translation-widget, .jigts-widget-trigger, .jigts-widget-dropdown, .notranslate"
|
|
1256
|
+
);
|
|
1257
|
+
if (skipBySelector) return NodeFilter.FILTER_REJECT;
|
|
1258
|
+
const isInSpanWrapper = container.tagName === "SPAN" && Array.from(container.childNodes).every((n) => n.nodeType === Node.TEXT_NODE);
|
|
1259
|
+
const interactiveAncestor = container.closest(
|
|
1260
|
+
"button, input, select, textarea, [role='button'], [role='link']"
|
|
1261
|
+
);
|
|
1262
|
+
if (interactiveAncestor && !isInSpanWrapper) {
|
|
1263
|
+
const isTextSiblingToElement = Array.from(container.childNodes).some(
|
|
1264
|
+
(n) => n.nodeType === Node.ELEMENT_NODE && node.parentNode === container
|
|
1265
|
+
// sibling to another element in same container
|
|
1266
|
+
);
|
|
1267
|
+
const isDirectChildOfInteractive = interactiveAncestor === container;
|
|
1268
|
+
if (isTextSiblingToElement && isDirectChildOfInteractive) {
|
|
1269
|
+
return NodeFilter.FILTER_REJECT;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
if (!((_a2 = node.textContent) == null ? void 0 : _a2.trim())) return NodeFilter.FILTER_REJECT;
|
|
1273
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
const navigator = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, validator);
|
|
1277
|
+
const groupedText = /* @__PURE__ */ new Map();
|
|
1278
|
+
let currentNode;
|
|
1279
|
+
while (currentNode = navigator.nextNode()) {
|
|
1280
|
+
const parentElement = currentNode.parentElement;
|
|
1281
|
+
if (!parentElement) continue;
|
|
1282
|
+
if (!groupedText.has(parentElement)) {
|
|
1283
|
+
groupedText.set(parentElement, []);
|
|
1284
|
+
}
|
|
1285
|
+
groupedText.get(parentElement).push(currentNode);
|
|
1286
|
+
}
|
|
1287
|
+
const results = [];
|
|
1288
|
+
let isNested = false;
|
|
1289
|
+
const processedNestedElements = /* @__PURE__ */ new Set();
|
|
1290
|
+
for (const [element, textNodes] of groupedText.entries()) {
|
|
1291
|
+
isNested = false;
|
|
1292
|
+
let combinedText = "";
|
|
1293
|
+
let isDescendantOfNested = false;
|
|
1294
|
+
for (const nestedElement of processedNestedElements) {
|
|
1295
|
+
if (nestedElement.contains(element)) {
|
|
1296
|
+
isDescendantOfNested = true;
|
|
1297
|
+
break;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
if (isDescendantOfNested) continue;
|
|
1301
|
+
const childNodes = Array.from(element.childNodes);
|
|
1302
|
+
const hasText = childNodes.some(
|
|
1303
|
+
(n) => {
|
|
1304
|
+
var _a2;
|
|
1305
|
+
return n.nodeType === Node.TEXT_NODE && ((_a2 = n.textContent) == null ? void 0 : _a2.trim());
|
|
1306
|
+
}
|
|
1307
|
+
);
|
|
1308
|
+
const hasInteractiveElements = childNodes.some(
|
|
1309
|
+
(n) => n.nodeType === Node.ELEMENT_NODE && ["BUTTON", "INPUT", "TEXTAREA", "SELECT"].includes(
|
|
1310
|
+
n.tagName
|
|
1311
|
+
)
|
|
1312
|
+
);
|
|
1313
|
+
const isTextMixedWithInteractivity = hasText && hasInteractiveElements;
|
|
1314
|
+
if (isTextMixedWithInteractivity) {
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
for (const node of textNodes) {
|
|
1318
|
+
let text = ((_a = node.textContent) == null ? void 0 : _a.trim()) || "";
|
|
1319
|
+
const originalText = element.getAttribute("data-original-text");
|
|
1320
|
+
if (originalText) text = originalText;
|
|
1321
|
+
const textWithoutEmojis = removeEmojis(text);
|
|
1322
|
+
if (text.length === 0 || text.length === 1 || textWithoutEmojis.length === 0) continue;
|
|
1323
|
+
combinedText += (combinedText ? " " : "") + text;
|
|
1324
|
+
const hasMixedContent = Array.from(element.childNodes).some(
|
|
1325
|
+
(child) => child.nodeType !== Node.TEXT_NODE
|
|
1326
|
+
);
|
|
1327
|
+
if (hasMixedContent) {
|
|
1328
|
+
isNested = true;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
if (combinedText.length > 0) {
|
|
1332
|
+
if (isNested) {
|
|
1333
|
+
const fullHtml = element.outerHTML;
|
|
1334
|
+
results.push({ element, text: fullHtml, isNested });
|
|
1335
|
+
processedNestedElements.add(element);
|
|
1336
|
+
} else {
|
|
1337
|
+
results.push({ element, text: combinedText, isNested });
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return results;
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Divides a collection into smaller groups
|
|
1345
|
+
* @param items Collection to divide
|
|
1346
|
+
* @param groupSize Maximum size of each group
|
|
1347
|
+
* @returns Array of item groups
|
|
1348
|
+
*/
|
|
1349
|
+
static divideIntoGroups(items, groupSize) {
|
|
1350
|
+
const groups = [];
|
|
1351
|
+
for (let i = 0; i < items.length; i += groupSize) {
|
|
1352
|
+
groups.push(items.slice(i, i + groupSize));
|
|
1353
|
+
}
|
|
1354
|
+
return groups;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
var LOCALSTORAGE_KEYS = /* @__PURE__ */ ((LOCALSTORAGE_KEYS2) => {
|
|
1358
|
+
LOCALSTORAGE_KEYS2["PREFERRED_LANGUAGE"] = "jss-pref";
|
|
1359
|
+
return LOCALSTORAGE_KEYS2;
|
|
1360
|
+
})(LOCALSTORAGE_KEYS || {});
|
|
1361
|
+
var ATTRIBUTES = /* @__PURE__ */ ((ATTRIBUTES2) => {
|
|
1362
|
+
ATTRIBUTES2["TRANSLATED_LANG"] = "data-translated-lang";
|
|
1363
|
+
ATTRIBUTES2["ORIGINAL_TEXT"] = "data-original-text";
|
|
1364
|
+
ATTRIBUTES2["ORIGINAL_FONT_SIZE"] = "data-original-font-size";
|
|
1365
|
+
return ATTRIBUTES2;
|
|
1366
|
+
})(ATTRIBUTES || {});
|
|
1367
|
+
const LANG_PARAM = "lang";
|
|
1368
|
+
const widgetTemplate = '<!-- Widget Trigger Button -->\r\n<div class="jigts-widget-trigger" tabindex="0" role="button" aria-label="Open translation menu" aria-expanded="false">\r\n <!-- Normal State -->\r\n <div class="jigts-trigger-content">\r\n <span class="jigts-trigger-icon">\r\n <svg class="jigts-languages-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">\r\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"\r\n d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129">\r\n </path>\r\n </svg>\r\n </span>\r\n </div>\r\n\r\n <!-- Loading State (hidden by default) -->\r\n <div class="jigts-trigger-loading" style="display: none;">\r\n <div class="jigts-loading-spinner"></div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dropdown Menu -->\r\n<div class="jigts-widget-dropdown">\r\n <!-- Header -->\r\n <div class="jigts-dropdown-header">\r\n <div class="jigts-dropdown-title">\r\n <div class="jigts-title-left">\r\n <svg class="jigts-languages-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">\r\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"\r\n d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129">\r\n </path>\r\n </svg>\r\n <span class="jigts-title-text">Select Language</span>\r\n </div>\r\n <div class="jigts-language-count">{{languageCountLabel}}</div>\r\n </div>\r\n\r\n {{searchSection}}\r\n </div>\r\n\r\n <!-- Reset Option -->\r\n <div class="jigts-reset-option" tabindex="0" role="button" aria-label="Reset to original language">\r\n <svg class="jigts-reset-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">\r\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"\r\n d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"></path>\r\n </svg>\r\n <div class="jigts-reset-text">\r\n <span class="jigts-reset-title">Original Language</span>\r\n <span class="jigts-reset-subtitle">Reset translation</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Language List -->\r\n <div class="jigts-language-list">\r\n {{languageOptions}}\r\n <div class="jigts-no-results" style="display: none;">\r\n <svg class="jigts-no-results-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">\r\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"\r\n d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>\r\n </svg>\r\n <span>No languages found</span>\r\n </div>\r\n </div>\r\n</div>\r\n';
|
|
1369
|
+
function getDefaultExportFromCjs(x) {
|
|
1370
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
1371
|
+
}
|
|
1372
|
+
var lzString = { exports: {} };
|
|
1373
|
+
var hasRequiredLzString;
|
|
1374
|
+
function requireLzString() {
|
|
1375
|
+
if (hasRequiredLzString) return lzString.exports;
|
|
1376
|
+
hasRequiredLzString = 1;
|
|
1377
|
+
(function(module) {
|
|
1378
|
+
var LZString2 = (function() {
|
|
1379
|
+
var f = String.fromCharCode;
|
|
1380
|
+
var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
1381
|
+
var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
|
|
1382
|
+
var baseReverseDic = {};
|
|
1383
|
+
function getBaseValue(alphabet, character) {
|
|
1384
|
+
if (!baseReverseDic[alphabet]) {
|
|
1385
|
+
baseReverseDic[alphabet] = {};
|
|
1386
|
+
for (var i = 0; i < alphabet.length; i++) {
|
|
1387
|
+
baseReverseDic[alphabet][alphabet.charAt(i)] = i;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return baseReverseDic[alphabet][character];
|
|
1391
|
+
}
|
|
1392
|
+
var LZString3 = {
|
|
1393
|
+
compressToBase64: function(input) {
|
|
1394
|
+
if (input == null) return "";
|
|
1395
|
+
var res = LZString3._compress(input, 6, function(a) {
|
|
1396
|
+
return keyStrBase64.charAt(a);
|
|
1397
|
+
});
|
|
1398
|
+
switch (res.length % 4) {
|
|
1399
|
+
// To produce valid Base64
|
|
1400
|
+
default:
|
|
1401
|
+
// When could this happen ?
|
|
1402
|
+
case 0:
|
|
1403
|
+
return res;
|
|
1404
|
+
case 1:
|
|
1405
|
+
return res + "===";
|
|
1406
|
+
case 2:
|
|
1407
|
+
return res + "==";
|
|
1408
|
+
case 3:
|
|
1409
|
+
return res + "=";
|
|
1410
|
+
}
|
|
1411
|
+
},
|
|
1412
|
+
decompressFromBase64: function(input) {
|
|
1413
|
+
if (input == null) return "";
|
|
1414
|
+
if (input == "") return null;
|
|
1415
|
+
return LZString3._decompress(input.length, 32, function(index) {
|
|
1416
|
+
return getBaseValue(keyStrBase64, input.charAt(index));
|
|
1417
|
+
});
|
|
1418
|
+
},
|
|
1419
|
+
compressToUTF16: function(input) {
|
|
1420
|
+
if (input == null) return "";
|
|
1421
|
+
return LZString3._compress(input, 15, function(a) {
|
|
1422
|
+
return f(a + 32);
|
|
1423
|
+
}) + " ";
|
|
1424
|
+
},
|
|
1425
|
+
decompressFromUTF16: function(compressed) {
|
|
1426
|
+
if (compressed == null) return "";
|
|
1427
|
+
if (compressed == "") return null;
|
|
1428
|
+
return LZString3._decompress(compressed.length, 16384, function(index) {
|
|
1429
|
+
return compressed.charCodeAt(index) - 32;
|
|
1430
|
+
});
|
|
1431
|
+
},
|
|
1432
|
+
//compress into uint8array (UCS-2 big endian format)
|
|
1433
|
+
compressToUint8Array: function(uncompressed) {
|
|
1434
|
+
var compressed = LZString3.compress(uncompressed);
|
|
1435
|
+
var buf = new Uint8Array(compressed.length * 2);
|
|
1436
|
+
for (var i = 0, TotalLen = compressed.length; i < TotalLen; i++) {
|
|
1437
|
+
var current_value = compressed.charCodeAt(i);
|
|
1438
|
+
buf[i * 2] = current_value >>> 8;
|
|
1439
|
+
buf[i * 2 + 1] = current_value % 256;
|
|
1440
|
+
}
|
|
1441
|
+
return buf;
|
|
1442
|
+
},
|
|
1443
|
+
//decompress from uint8array (UCS-2 big endian format)
|
|
1444
|
+
decompressFromUint8Array: function(compressed) {
|
|
1445
|
+
if (compressed === null || compressed === void 0) {
|
|
1446
|
+
return LZString3.decompress(compressed);
|
|
1447
|
+
} else {
|
|
1448
|
+
var buf = new Array(compressed.length / 2);
|
|
1449
|
+
for (var i = 0, TotalLen = buf.length; i < TotalLen; i++) {
|
|
1450
|
+
buf[i] = compressed[i * 2] * 256 + compressed[i * 2 + 1];
|
|
1451
|
+
}
|
|
1452
|
+
var result = [];
|
|
1453
|
+
buf.forEach(function(c) {
|
|
1454
|
+
result.push(f(c));
|
|
1455
|
+
});
|
|
1456
|
+
return LZString3.decompress(result.join(""));
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
//compress into a string that is already URI encoded
|
|
1460
|
+
compressToEncodedURIComponent: function(input) {
|
|
1461
|
+
if (input == null) return "";
|
|
1462
|
+
return LZString3._compress(input, 6, function(a) {
|
|
1463
|
+
return keyStrUriSafe.charAt(a);
|
|
1464
|
+
});
|
|
1465
|
+
},
|
|
1466
|
+
//decompress from an output of compressToEncodedURIComponent
|
|
1467
|
+
decompressFromEncodedURIComponent: function(input) {
|
|
1468
|
+
if (input == null) return "";
|
|
1469
|
+
if (input == "") return null;
|
|
1470
|
+
input = input.replace(/ /g, "+");
|
|
1471
|
+
return LZString3._decompress(input.length, 32, function(index) {
|
|
1472
|
+
return getBaseValue(keyStrUriSafe, input.charAt(index));
|
|
1473
|
+
});
|
|
1474
|
+
},
|
|
1475
|
+
compress: function(uncompressed) {
|
|
1476
|
+
return LZString3._compress(uncompressed, 16, function(a) {
|
|
1477
|
+
return f(a);
|
|
1478
|
+
});
|
|
1479
|
+
},
|
|
1480
|
+
_compress: function(uncompressed, bitsPerChar, getCharFromInt) {
|
|
1481
|
+
if (uncompressed == null) return "";
|
|
1482
|
+
var i, value, context_dictionary = {}, context_dictionaryToCreate = {}, context_c = "", context_wc = "", context_w = "", context_enlargeIn = 2, context_dictSize = 3, context_numBits = 2, context_data = [], context_data_val = 0, context_data_position = 0, ii;
|
|
1483
|
+
for (ii = 0; ii < uncompressed.length; ii += 1) {
|
|
1484
|
+
context_c = uncompressed.charAt(ii);
|
|
1485
|
+
if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
|
|
1486
|
+
context_dictionary[context_c] = context_dictSize++;
|
|
1487
|
+
context_dictionaryToCreate[context_c] = true;
|
|
1488
|
+
}
|
|
1489
|
+
context_wc = context_w + context_c;
|
|
1490
|
+
if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
|
|
1491
|
+
context_w = context_wc;
|
|
1492
|
+
} else {
|
|
1493
|
+
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
|
|
1494
|
+
if (context_w.charCodeAt(0) < 256) {
|
|
1495
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1496
|
+
context_data_val = context_data_val << 1;
|
|
1497
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1498
|
+
context_data_position = 0;
|
|
1499
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1500
|
+
context_data_val = 0;
|
|
1501
|
+
} else {
|
|
1502
|
+
context_data_position++;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
value = context_w.charCodeAt(0);
|
|
1506
|
+
for (i = 0; i < 8; i++) {
|
|
1507
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1508
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1509
|
+
context_data_position = 0;
|
|
1510
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1511
|
+
context_data_val = 0;
|
|
1512
|
+
} else {
|
|
1513
|
+
context_data_position++;
|
|
1514
|
+
}
|
|
1515
|
+
value = value >> 1;
|
|
1516
|
+
}
|
|
1517
|
+
} else {
|
|
1518
|
+
value = 1;
|
|
1519
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1520
|
+
context_data_val = context_data_val << 1 | value;
|
|
1521
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1522
|
+
context_data_position = 0;
|
|
1523
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1524
|
+
context_data_val = 0;
|
|
1525
|
+
} else {
|
|
1526
|
+
context_data_position++;
|
|
1527
|
+
}
|
|
1528
|
+
value = 0;
|
|
1529
|
+
}
|
|
1530
|
+
value = context_w.charCodeAt(0);
|
|
1531
|
+
for (i = 0; i < 16; i++) {
|
|
1532
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1533
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1534
|
+
context_data_position = 0;
|
|
1535
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1536
|
+
context_data_val = 0;
|
|
1537
|
+
} else {
|
|
1538
|
+
context_data_position++;
|
|
1539
|
+
}
|
|
1540
|
+
value = value >> 1;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
context_enlargeIn--;
|
|
1544
|
+
if (context_enlargeIn == 0) {
|
|
1545
|
+
context_enlargeIn = Math.pow(2, context_numBits);
|
|
1546
|
+
context_numBits++;
|
|
1547
|
+
}
|
|
1548
|
+
delete context_dictionaryToCreate[context_w];
|
|
1549
|
+
} else {
|
|
1550
|
+
value = context_dictionary[context_w];
|
|
1551
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1552
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1553
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1554
|
+
context_data_position = 0;
|
|
1555
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1556
|
+
context_data_val = 0;
|
|
1557
|
+
} else {
|
|
1558
|
+
context_data_position++;
|
|
1559
|
+
}
|
|
1560
|
+
value = value >> 1;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
context_enlargeIn--;
|
|
1564
|
+
if (context_enlargeIn == 0) {
|
|
1565
|
+
context_enlargeIn = Math.pow(2, context_numBits);
|
|
1566
|
+
context_numBits++;
|
|
1567
|
+
}
|
|
1568
|
+
context_dictionary[context_wc] = context_dictSize++;
|
|
1569
|
+
context_w = String(context_c);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
if (context_w !== "") {
|
|
1573
|
+
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
|
|
1574
|
+
if (context_w.charCodeAt(0) < 256) {
|
|
1575
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1576
|
+
context_data_val = context_data_val << 1;
|
|
1577
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1578
|
+
context_data_position = 0;
|
|
1579
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1580
|
+
context_data_val = 0;
|
|
1581
|
+
} else {
|
|
1582
|
+
context_data_position++;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
value = context_w.charCodeAt(0);
|
|
1586
|
+
for (i = 0; i < 8; i++) {
|
|
1587
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1588
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1589
|
+
context_data_position = 0;
|
|
1590
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1591
|
+
context_data_val = 0;
|
|
1592
|
+
} else {
|
|
1593
|
+
context_data_position++;
|
|
1594
|
+
}
|
|
1595
|
+
value = value >> 1;
|
|
1596
|
+
}
|
|
1597
|
+
} else {
|
|
1598
|
+
value = 1;
|
|
1599
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1600
|
+
context_data_val = context_data_val << 1 | value;
|
|
1601
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1602
|
+
context_data_position = 0;
|
|
1603
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1604
|
+
context_data_val = 0;
|
|
1605
|
+
} else {
|
|
1606
|
+
context_data_position++;
|
|
1607
|
+
}
|
|
1608
|
+
value = 0;
|
|
1609
|
+
}
|
|
1610
|
+
value = context_w.charCodeAt(0);
|
|
1611
|
+
for (i = 0; i < 16; i++) {
|
|
1612
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1613
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1614
|
+
context_data_position = 0;
|
|
1615
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1616
|
+
context_data_val = 0;
|
|
1617
|
+
} else {
|
|
1618
|
+
context_data_position++;
|
|
1619
|
+
}
|
|
1620
|
+
value = value >> 1;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
context_enlargeIn--;
|
|
1624
|
+
if (context_enlargeIn == 0) {
|
|
1625
|
+
context_enlargeIn = Math.pow(2, context_numBits);
|
|
1626
|
+
context_numBits++;
|
|
1627
|
+
}
|
|
1628
|
+
delete context_dictionaryToCreate[context_w];
|
|
1629
|
+
} else {
|
|
1630
|
+
value = context_dictionary[context_w];
|
|
1631
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1632
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1633
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1634
|
+
context_data_position = 0;
|
|
1635
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1636
|
+
context_data_val = 0;
|
|
1637
|
+
} else {
|
|
1638
|
+
context_data_position++;
|
|
1639
|
+
}
|
|
1640
|
+
value = value >> 1;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
context_enlargeIn--;
|
|
1644
|
+
if (context_enlargeIn == 0) {
|
|
1645
|
+
context_enlargeIn = Math.pow(2, context_numBits);
|
|
1646
|
+
context_numBits++;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
value = 2;
|
|
1650
|
+
for (i = 0; i < context_numBits; i++) {
|
|
1651
|
+
context_data_val = context_data_val << 1 | value & 1;
|
|
1652
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1653
|
+
context_data_position = 0;
|
|
1654
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1655
|
+
context_data_val = 0;
|
|
1656
|
+
} else {
|
|
1657
|
+
context_data_position++;
|
|
1658
|
+
}
|
|
1659
|
+
value = value >> 1;
|
|
1660
|
+
}
|
|
1661
|
+
while (true) {
|
|
1662
|
+
context_data_val = context_data_val << 1;
|
|
1663
|
+
if (context_data_position == bitsPerChar - 1) {
|
|
1664
|
+
context_data.push(getCharFromInt(context_data_val));
|
|
1665
|
+
break;
|
|
1666
|
+
} else context_data_position++;
|
|
1667
|
+
}
|
|
1668
|
+
return context_data.join("");
|
|
1669
|
+
},
|
|
1670
|
+
decompress: function(compressed) {
|
|
1671
|
+
if (compressed == null) return "";
|
|
1672
|
+
if (compressed == "") return null;
|
|
1673
|
+
return LZString3._decompress(compressed.length, 32768, function(index) {
|
|
1674
|
+
return compressed.charCodeAt(index);
|
|
1675
|
+
});
|
|
1676
|
+
},
|
|
1677
|
+
_decompress: function(length, resetValue, getNextValue) {
|
|
1678
|
+
var dictionary = [], enlargeIn = 4, dictSize = 4, numBits = 3, entry = "", result = [], i, w, bits, resb, maxpower, power, c, data = { val: getNextValue(0), position: resetValue, index: 1 };
|
|
1679
|
+
for (i = 0; i < 3; i += 1) {
|
|
1680
|
+
dictionary[i] = i;
|
|
1681
|
+
}
|
|
1682
|
+
bits = 0;
|
|
1683
|
+
maxpower = Math.pow(2, 2);
|
|
1684
|
+
power = 1;
|
|
1685
|
+
while (power != maxpower) {
|
|
1686
|
+
resb = data.val & data.position;
|
|
1687
|
+
data.position >>= 1;
|
|
1688
|
+
if (data.position == 0) {
|
|
1689
|
+
data.position = resetValue;
|
|
1690
|
+
data.val = getNextValue(data.index++);
|
|
1691
|
+
}
|
|
1692
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1693
|
+
power <<= 1;
|
|
1694
|
+
}
|
|
1695
|
+
switch (bits) {
|
|
1696
|
+
case 0:
|
|
1697
|
+
bits = 0;
|
|
1698
|
+
maxpower = Math.pow(2, 8);
|
|
1699
|
+
power = 1;
|
|
1700
|
+
while (power != maxpower) {
|
|
1701
|
+
resb = data.val & data.position;
|
|
1702
|
+
data.position >>= 1;
|
|
1703
|
+
if (data.position == 0) {
|
|
1704
|
+
data.position = resetValue;
|
|
1705
|
+
data.val = getNextValue(data.index++);
|
|
1706
|
+
}
|
|
1707
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1708
|
+
power <<= 1;
|
|
1709
|
+
}
|
|
1710
|
+
c = f(bits);
|
|
1711
|
+
break;
|
|
1712
|
+
case 1:
|
|
1713
|
+
bits = 0;
|
|
1714
|
+
maxpower = Math.pow(2, 16);
|
|
1715
|
+
power = 1;
|
|
1716
|
+
while (power != maxpower) {
|
|
1717
|
+
resb = data.val & data.position;
|
|
1718
|
+
data.position >>= 1;
|
|
1719
|
+
if (data.position == 0) {
|
|
1720
|
+
data.position = resetValue;
|
|
1721
|
+
data.val = getNextValue(data.index++);
|
|
1722
|
+
}
|
|
1723
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1724
|
+
power <<= 1;
|
|
1725
|
+
}
|
|
1726
|
+
c = f(bits);
|
|
1727
|
+
break;
|
|
1728
|
+
case 2:
|
|
1729
|
+
return "";
|
|
1730
|
+
}
|
|
1731
|
+
dictionary[3] = c;
|
|
1732
|
+
w = c;
|
|
1733
|
+
result.push(c);
|
|
1734
|
+
while (true) {
|
|
1735
|
+
if (data.index > length) {
|
|
1736
|
+
return "";
|
|
1737
|
+
}
|
|
1738
|
+
bits = 0;
|
|
1739
|
+
maxpower = Math.pow(2, numBits);
|
|
1740
|
+
power = 1;
|
|
1741
|
+
while (power != maxpower) {
|
|
1742
|
+
resb = data.val & data.position;
|
|
1743
|
+
data.position >>= 1;
|
|
1744
|
+
if (data.position == 0) {
|
|
1745
|
+
data.position = resetValue;
|
|
1746
|
+
data.val = getNextValue(data.index++);
|
|
1747
|
+
}
|
|
1748
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1749
|
+
power <<= 1;
|
|
1750
|
+
}
|
|
1751
|
+
switch (c = bits) {
|
|
1752
|
+
case 0:
|
|
1753
|
+
bits = 0;
|
|
1754
|
+
maxpower = Math.pow(2, 8);
|
|
1755
|
+
power = 1;
|
|
1756
|
+
while (power != maxpower) {
|
|
1757
|
+
resb = data.val & data.position;
|
|
1758
|
+
data.position >>= 1;
|
|
1759
|
+
if (data.position == 0) {
|
|
1760
|
+
data.position = resetValue;
|
|
1761
|
+
data.val = getNextValue(data.index++);
|
|
1762
|
+
}
|
|
1763
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1764
|
+
power <<= 1;
|
|
1765
|
+
}
|
|
1766
|
+
dictionary[dictSize++] = f(bits);
|
|
1767
|
+
c = dictSize - 1;
|
|
1768
|
+
enlargeIn--;
|
|
1769
|
+
break;
|
|
1770
|
+
case 1:
|
|
1771
|
+
bits = 0;
|
|
1772
|
+
maxpower = Math.pow(2, 16);
|
|
1773
|
+
power = 1;
|
|
1774
|
+
while (power != maxpower) {
|
|
1775
|
+
resb = data.val & data.position;
|
|
1776
|
+
data.position >>= 1;
|
|
1777
|
+
if (data.position == 0) {
|
|
1778
|
+
data.position = resetValue;
|
|
1779
|
+
data.val = getNextValue(data.index++);
|
|
1780
|
+
}
|
|
1781
|
+
bits |= (resb > 0 ? 1 : 0) * power;
|
|
1782
|
+
power <<= 1;
|
|
1783
|
+
}
|
|
1784
|
+
dictionary[dictSize++] = f(bits);
|
|
1785
|
+
c = dictSize - 1;
|
|
1786
|
+
enlargeIn--;
|
|
1787
|
+
break;
|
|
1788
|
+
case 2:
|
|
1789
|
+
return result.join("");
|
|
1790
|
+
}
|
|
1791
|
+
if (enlargeIn == 0) {
|
|
1792
|
+
enlargeIn = Math.pow(2, numBits);
|
|
1793
|
+
numBits++;
|
|
1794
|
+
}
|
|
1795
|
+
if (dictionary[c]) {
|
|
1796
|
+
entry = dictionary[c];
|
|
1797
|
+
} else {
|
|
1798
|
+
if (c === dictSize) {
|
|
1799
|
+
entry = w + w.charAt(0);
|
|
1800
|
+
} else {
|
|
1801
|
+
return null;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
result.push(entry);
|
|
1805
|
+
dictionary[dictSize++] = w + entry.charAt(0);
|
|
1806
|
+
enlargeIn--;
|
|
1807
|
+
w = entry;
|
|
1808
|
+
if (enlargeIn == 0) {
|
|
1809
|
+
enlargeIn = Math.pow(2, numBits);
|
|
1810
|
+
numBits++;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
return LZString3;
|
|
1816
|
+
})();
|
|
1817
|
+
if (module != null) {
|
|
1818
|
+
module.exports = LZString2;
|
|
1819
|
+
} else if (typeof angular !== "undefined" && angular != null) {
|
|
1820
|
+
angular.module("LZString", []).factory("LZString", function() {
|
|
1821
|
+
return LZString2;
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
})(lzString);
|
|
1825
|
+
return lzString.exports;
|
|
1826
|
+
}
|
|
1827
|
+
var lzStringExports = requireLzString();
|
|
1828
|
+
const LZString = /* @__PURE__ */ getDefaultExportFromCjs(lzStringExports);
|
|
1829
|
+
class LocalStorageWrapper {
|
|
1830
|
+
constructor(prefix = "") {
|
|
1831
|
+
__publicField(this, "prefix");
|
|
1832
|
+
__publicField(this, "COMPRESSION_THRESHOLD", 1e4);
|
|
1833
|
+
__publicField(this, "COMPRESSION_MARKER", "__COMPRESSED__");
|
|
1834
|
+
__publicField(this, "cache", {});
|
|
1835
|
+
this.prefix = prefix;
|
|
1836
|
+
}
|
|
1837
|
+
getPageKey(targetLang) {
|
|
1838
|
+
return `${this.prefix}${targetLang}`;
|
|
1839
|
+
}
|
|
1840
|
+
shouldCompress(value) {
|
|
1841
|
+
return value.length > this.COMPRESSION_THRESHOLD;
|
|
1842
|
+
}
|
|
1843
|
+
compress(value) {
|
|
1844
|
+
try {
|
|
1845
|
+
return LZString.compressToBase64(value);
|
|
1846
|
+
} catch (error) {
|
|
1847
|
+
console.error("Compression failed:", error);
|
|
1848
|
+
return value;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
decompress(value) {
|
|
1852
|
+
try {
|
|
1853
|
+
return LZString.decompressFromBase64(value) || value;
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
console.error("Decompression failed:", error);
|
|
1856
|
+
return value;
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
getItem(key) {
|
|
1860
|
+
if (this.cache[key]) {
|
|
1861
|
+
return this.cache[key];
|
|
1862
|
+
}
|
|
1863
|
+
const item = localStorage.getItem(key);
|
|
1864
|
+
if (!item) return null;
|
|
1865
|
+
try {
|
|
1866
|
+
const decompressed = item.startsWith(this.COMPRESSION_MARKER) ? this.decompress(item.slice(this.COMPRESSION_MARKER.length)) : item;
|
|
1867
|
+
const parsed = JSON.parse(decompressed);
|
|
1868
|
+
this.cache[key] = parsed;
|
|
1869
|
+
return parsed;
|
|
1870
|
+
} catch (e) {
|
|
1871
|
+
console.error("Error parsing cached item:", e);
|
|
1872
|
+
return null;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
setItem(key, value) {
|
|
1876
|
+
const stringified = JSON.stringify(value);
|
|
1877
|
+
const storeValue = () => {
|
|
1878
|
+
try {
|
|
1879
|
+
const finalValue = this.shouldCompress(stringified) ? `${this.COMPRESSION_MARKER}${this.compress(stringified)}` : stringified;
|
|
1880
|
+
localStorage.setItem(key, finalValue);
|
|
1881
|
+
this.cache[key] = value;
|
|
1882
|
+
} catch (error) {
|
|
1883
|
+
console.error("Error storing item:", error);
|
|
1884
|
+
localStorage.setItem(key, stringified);
|
|
1885
|
+
this.cache[key] = value;
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
if (typeof requestIdleCallback !== "undefined") {
|
|
1889
|
+
requestIdleCallback(() => storeValue());
|
|
1890
|
+
} else {
|
|
1891
|
+
setTimeout(storeValue, 0);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
// Get translation for a node from the page cache (object of originalText)
|
|
1895
|
+
getNodeTranslation(originalText, targetLang) {
|
|
1896
|
+
const pageKey = this.getPageKey(targetLang);
|
|
1897
|
+
const translations = this.getItem(pageKey) || {};
|
|
1898
|
+
return translations[originalText] || null;
|
|
1899
|
+
}
|
|
1900
|
+
// Store translation for a node in the page cache (object of originalText)
|
|
1901
|
+
setNodeTranslation(originalText, targetLang, translatedText) {
|
|
1902
|
+
const pageKey = this.getPageKey(targetLang);
|
|
1903
|
+
let translations = this.getItem(pageKey) || {};
|
|
1904
|
+
translations[originalText] = translatedText;
|
|
1905
|
+
this.setItem(pageKey, translations);
|
|
1906
|
+
}
|
|
1907
|
+
setBatchNodeTranslationsArray(targetLang, batch) {
|
|
1908
|
+
const pageKey = this.getPageKey(targetLang);
|
|
1909
|
+
const existing = this.getItem(pageKey) || {};
|
|
1910
|
+
batch.forEach(({ originalText, translatedText }) => {
|
|
1911
|
+
existing[originalText] = translatedText;
|
|
1912
|
+
});
|
|
1913
|
+
this.setItem(pageKey, existing);
|
|
1914
|
+
}
|
|
1915
|
+
removeItem(key) {
|
|
1916
|
+
localStorage.removeItem(key);
|
|
1917
|
+
delete this.cache[key];
|
|
1918
|
+
}
|
|
1919
|
+
clear(lang_code = []) {
|
|
1920
|
+
if (this.prefix) {
|
|
1921
|
+
for (let key in localStorage) {
|
|
1922
|
+
if (key.startsWith(this.prefix) && (!lang_code.length || lang_code.includes(key.split("--")[1]))) {
|
|
1923
|
+
localStorage.removeItem(key);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
} else if (lang_code && lang_code.length > 0) {
|
|
1927
|
+
for (let key in localStorage) {
|
|
1928
|
+
if (lang_code.includes(key.split("--")[1])) {
|
|
1929
|
+
localStorage.removeItem(key);
|
|
1930
|
+
delete this.cache[key];
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
} else {
|
|
1934
|
+
localStorage.clear();
|
|
1935
|
+
this.cache = {};
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
key(index) {
|
|
1939
|
+
return localStorage.key(index);
|
|
1940
|
+
}
|
|
1941
|
+
get length() {
|
|
1942
|
+
return localStorage.length;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
const _TranslationWidget = class _TranslationWidget {
|
|
1946
|
+
/**
|
|
1947
|
+
* @param publicKey - The public api key for the translation widget
|
|
1948
|
+
* @param config - The configuration for the translation widget
|
|
1949
|
+
*/
|
|
1950
|
+
constructor(publicKey, config = {}) {
|
|
1951
|
+
__publicField(this, "config");
|
|
1952
|
+
__publicField(this, "translationService");
|
|
1953
|
+
__publicField(this, "targetLanguages");
|
|
1954
|
+
__publicField(this, "currentLanguage");
|
|
1955
|
+
__publicField(this, "widget");
|
|
1956
|
+
__publicField(this, "elements");
|
|
1957
|
+
__publicField(this, "autoDetectLanguage");
|
|
1958
|
+
__publicField(this, "isTranslated", false);
|
|
1959
|
+
__publicField(this, "userLanguage");
|
|
1960
|
+
__publicField(this, "isTranslating", false);
|
|
1961
|
+
__publicField(this, "observer", null);
|
|
1962
|
+
__publicField(this, "translationScheduled", false);
|
|
1963
|
+
__publicField(this, "scheduleTimeout", null);
|
|
1964
|
+
__publicField(this, "showUI", true);
|
|
1965
|
+
__publicField(this, "lastTranslated", null);
|
|
1966
|
+
__publicField(this, "currentTranslationPromise", null);
|
|
1967
|
+
__publicField(this, "lastRequestedLanguage", null);
|
|
1968
|
+
__publicField(this, "translationRequestId", 0);
|
|
1969
|
+
/**
|
|
1970
|
+
* Handles the URL change
|
|
1971
|
+
*/
|
|
1972
|
+
__publicField(this, "onUrlChange", () => {
|
|
1973
|
+
this.scheduleTranslation();
|
|
1974
|
+
});
|
|
1975
|
+
const allowedPositions = ["top-right", "top-left", "bottom-left", "bottom-right"];
|
|
1976
|
+
let safeConfig = {
|
|
1977
|
+
...DEFAULT_CONFIG,
|
|
1978
|
+
...config,
|
|
1979
|
+
targetLanguages: config.targetLanguages ?? [...DEFAULT_CONFIG.targetLanguages],
|
|
1980
|
+
requestHeaders: {
|
|
1981
|
+
...DEFAULT_CONFIG.requestHeaders,
|
|
1982
|
+
...config.requestHeaders ?? {}
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
const servicePublicKey = safeConfig.mockMode ? publicKey || "pk_demo_frontend_only" : publicKey;
|
|
1986
|
+
if (safeConfig.position && !allowedPositions.includes(safeConfig.position)) {
|
|
1987
|
+
console.warn(`Invalid position '${safeConfig.position}' passed to TranslationWidget. Falling back to 'top-right'.`);
|
|
1988
|
+
safeConfig.position = "top-right";
|
|
1989
|
+
}
|
|
1990
|
+
this.config = safeConfig;
|
|
1991
|
+
this.targetLanguages = this.resolveTargetLanguages(this.config.targetLanguages);
|
|
1992
|
+
this.autoDetectLanguage = this.config.autoDetectLanguage || false;
|
|
1993
|
+
this.currentLanguage = this.config.pageLanguage;
|
|
1994
|
+
this.userLanguage = getUserLanguage();
|
|
1995
|
+
this.widget = document.createElement("div");
|
|
1996
|
+
this.showUI = this.config.showUI ?? true;
|
|
1997
|
+
this.elements = {
|
|
1998
|
+
trigger: null,
|
|
1999
|
+
dropdown: null,
|
|
2000
|
+
searchInput: null,
|
|
2001
|
+
clearSearch: null,
|
|
2002
|
+
languageItems: null,
|
|
2003
|
+
loadingIndicator: null
|
|
2004
|
+
};
|
|
2005
|
+
if (!this.config.mockMode && this.config.includeApiKeyHeader) {
|
|
2006
|
+
const apiValidationResult = validatePublicApiKey(servicePublicKey);
|
|
2007
|
+
if (!apiValidationResult.isValid) {
|
|
2008
|
+
console.error("Error initializing TranslationWidget: ", apiValidationResult.message);
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
this.translationService = new TranslationService(servicePublicKey, {
|
|
2013
|
+
mockMode: this.config.mockMode,
|
|
2014
|
+
apiUrl: this.config.apiUrl,
|
|
2015
|
+
requestHeaders: this.config.requestHeaders,
|
|
2016
|
+
includeApiKeyHeader: this.config.includeApiKeyHeader
|
|
2017
|
+
});
|
|
2018
|
+
this.initialize();
|
|
2019
|
+
_TranslationWidget.instance = this;
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Initializes the translation widget
|
|
2023
|
+
*/
|
|
2024
|
+
initialize() {
|
|
2025
|
+
var _a;
|
|
2026
|
+
const urlLang = this.getUrlParameter(LANG_PARAM);
|
|
2027
|
+
let initialLang = this.config.pageLanguage;
|
|
2028
|
+
if (this.isTargetLanguage(urlLang)) {
|
|
2029
|
+
initialLang = urlLang;
|
|
2030
|
+
} else {
|
|
2031
|
+
const storedLanguage = localStorage.getItem(LOCALSTORAGE_KEYS.PREFERRED_LANGUAGE);
|
|
2032
|
+
if (this.isTargetLanguage(storedLanguage)) {
|
|
2033
|
+
initialLang = storedLanguage;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
if (initialLang === this.config.pageLanguage && this.autoDetectLanguage && this.isTargetLanguage(this.userLanguage)) {
|
|
2037
|
+
initialLang = this.userLanguage;
|
|
2038
|
+
} else if (!this.config.pageLanguage) {
|
|
2039
|
+
const htmlTag = document.querySelector("html");
|
|
2040
|
+
if (htmlTag && htmlTag.getAttribute(LANG_PARAM)) {
|
|
2041
|
+
initialLang = htmlTag.getAttribute(LANG_PARAM);
|
|
2042
|
+
} else {
|
|
2043
|
+
initialLang = "en";
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
this.currentLanguage = initialLang;
|
|
2047
|
+
if (this.showUI) {
|
|
2048
|
+
this.createWidget();
|
|
2049
|
+
const triggerIcon = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-icon");
|
|
2050
|
+
if (triggerIcon && this.currentLanguage !== this.config.pageLanguage) {
|
|
2051
|
+
const langObj = this.findLanguageByCode(this.currentLanguage);
|
|
2052
|
+
const langName = langObj ? langObj.name : this.currentLanguage.toUpperCase();
|
|
2053
|
+
triggerIcon.innerHTML = `<span class="jigts-lang-code">${this.currentLanguage.toUpperCase()}</span><span class="jigts-lang-name">${langName}</span>`;
|
|
2054
|
+
}
|
|
2055
|
+
this.setupEventListeners();
|
|
2056
|
+
this.setupURLObserver();
|
|
2057
|
+
this.setupContentObserver();
|
|
2058
|
+
}
|
|
2059
|
+
if (this.currentLanguage !== this.config.pageLanguage) {
|
|
2060
|
+
this.translatePage(this.currentLanguage).catch((error) => {
|
|
2061
|
+
console.error("Initial translation error:", error);
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
resolveTargetLanguages(languageCodes) {
|
|
2066
|
+
const resolvedLanguages = languageCodes.map((code) => this.findLanguageByCode(code)).filter((language) => Boolean(language));
|
|
2067
|
+
if (resolvedLanguages.length > 0) {
|
|
2068
|
+
return resolvedLanguages;
|
|
2069
|
+
}
|
|
2070
|
+
return languages.filter((language) => language.code === "zh");
|
|
2071
|
+
}
|
|
2072
|
+
findLanguageByCode(code) {
|
|
2073
|
+
return languages.find((language) => language.code === code);
|
|
2074
|
+
}
|
|
2075
|
+
isTargetLanguage(code) {
|
|
2076
|
+
return Boolean(code) && this.targetLanguages.some((language) => language.code === code);
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Gets the value of a URL parameter
|
|
2080
|
+
* @param name - The name of the URL parameter
|
|
2081
|
+
* @returns The value of the URL parameter
|
|
2082
|
+
*/
|
|
2083
|
+
getUrlParameter(name) {
|
|
2084
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
2085
|
+
return urlParams.get(name);
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Sets up the content observer
|
|
2089
|
+
*/
|
|
2090
|
+
setupContentObserver() {
|
|
2091
|
+
if (!this.observer) {
|
|
2092
|
+
this.observer = new MutationObserver((mutations) => {
|
|
2093
|
+
if (this.isTranslating) return;
|
|
2094
|
+
const widgetContainer = this.widget;
|
|
2095
|
+
const relevantMutations = mutations.filter((mutation) => {
|
|
2096
|
+
if (widgetContainer.contains(mutation.target)) return false;
|
|
2097
|
+
if (mutation.type === "childList") {
|
|
2098
|
+
const addedScripts = Array.from(mutation.addedNodes).some((node) => node.nodeName === "SCRIPT");
|
|
2099
|
+
const removedScripts = Array.from(mutation.removedNodes).some((node) => node.nodeName === "SCRIPT");
|
|
2100
|
+
return !addedScripts && !removedScripts;
|
|
2101
|
+
}
|
|
2102
|
+
return true;
|
|
2103
|
+
});
|
|
2104
|
+
if (relevantMutations.length > 0) {
|
|
2105
|
+
this.scheduleTranslation();
|
|
2106
|
+
}
|
|
2107
|
+
});
|
|
2108
|
+
this.observeBody();
|
|
2109
|
+
} else {
|
|
2110
|
+
console.warn("Observer already exists. Skipping setupContentObserver");
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Observes the body for changes
|
|
2115
|
+
*/
|
|
2116
|
+
observeBody() {
|
|
2117
|
+
var _a;
|
|
2118
|
+
(_a = this.observer) == null ? void 0 : _a.observe(document.body, {
|
|
2119
|
+
childList: true,
|
|
2120
|
+
subtree: true,
|
|
2121
|
+
characterData: true,
|
|
2122
|
+
// this is needed to detect changes for "mobile-only" elements
|
|
2123
|
+
attributes: true
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Sets up the URL observer
|
|
2128
|
+
*/
|
|
2129
|
+
setupURLObserver() {
|
|
2130
|
+
const historyMethods = ["pushState", "replaceState"];
|
|
2131
|
+
historyMethods.forEach((method) => {
|
|
2132
|
+
const original = history[method];
|
|
2133
|
+
history[method] = function(state, title, url) {
|
|
2134
|
+
const result = original.call(this, state, title, url);
|
|
2135
|
+
window.dispatchEvent(new Event(method));
|
|
2136
|
+
return result;
|
|
2137
|
+
};
|
|
2138
|
+
window.addEventListener(method, this.onUrlChange);
|
|
2139
|
+
});
|
|
2140
|
+
window.addEventListener("popstate", this.onUrlChange);
|
|
2141
|
+
}
|
|
2142
|
+
/**
|
|
2143
|
+
* Creates the widget
|
|
2144
|
+
*/
|
|
2145
|
+
createWidget() {
|
|
2146
|
+
var _a;
|
|
2147
|
+
const currentLanguageLabel = this.getCurrentLanguageLabel();
|
|
2148
|
+
this.widget = document.createElement("div");
|
|
2149
|
+
this.widget.className = `jigts-translation-widget jigts-position-${this.config.position || "top-right"}`;
|
|
2150
|
+
if (this.config.theme) {
|
|
2151
|
+
if (this.config.theme.baseColor) {
|
|
2152
|
+
this.widget.style.setProperty("--jigts-custom-base-color", this.config.theme.baseColor);
|
|
2153
|
+
}
|
|
2154
|
+
if (this.config.theme.textColor) {
|
|
2155
|
+
this.widget.style.setProperty("--jigts-custom-text-color", this.config.theme.textColor);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
document.body.appendChild(this.widget);
|
|
2159
|
+
this.widget.innerHTML = this.createWidgetHTML(currentLanguageLabel);
|
|
2160
|
+
this.elements = {
|
|
2161
|
+
trigger: this.widget.querySelector(".jigts-widget-trigger"),
|
|
2162
|
+
dropdown: this.widget.querySelector(".jigts-widget-dropdown"),
|
|
2163
|
+
searchInput: this.widget.querySelector(".jigts-search-input"),
|
|
2164
|
+
clearSearch: this.widget.querySelector(".jigts-clear-search"),
|
|
2165
|
+
languageItems: this.widget.querySelectorAll(".jigts-language-item"),
|
|
2166
|
+
loadingIndicator: this.widget.querySelector(".jigts-loading-spinner")
|
|
2167
|
+
};
|
|
2168
|
+
const triggerSpan = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector("span");
|
|
2169
|
+
if (triggerSpan) {
|
|
2170
|
+
triggerSpan.classList.add("jigts-fade-in");
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Gets the current language label
|
|
2175
|
+
* @returns The current language label
|
|
2176
|
+
*/
|
|
2177
|
+
getCurrentLanguageLabel() {
|
|
2178
|
+
var _a;
|
|
2179
|
+
return ((_a = this.findLanguageByCode(this.currentLanguage)) == null ? void 0 : _a.native) || "English";
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Creates the widget HTML
|
|
2183
|
+
* @param currentLanguageLabel - The current language label
|
|
2184
|
+
* @returns The widget HTML
|
|
2185
|
+
*/
|
|
2186
|
+
createWidgetHTML(currentLanguageLabel) {
|
|
2187
|
+
const languageOptions = this.createLanguageOptions();
|
|
2188
|
+
const languageCount = this.targetLanguages.length;
|
|
2189
|
+
const languageCountLabel = `${languageCount} ${languageCount === 1 ? "language" : "languages"}`;
|
|
2190
|
+
const searchSection = languageCount > 1 ? `
|
|
2191
|
+
<!-- Search Input -->
|
|
2192
|
+
<div class="jigts-search-container">
|
|
2193
|
+
<svg class="jigts-search-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2194
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
2195
|
+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
2196
|
+
</svg>
|
|
2197
|
+
<input type="text" class="jigts-search-input" placeholder="Search languages..." aria-label="Search languages">
|
|
2198
|
+
<svg class="jigts-clear-search" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2199
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12">
|
|
2200
|
+
</path>
|
|
2201
|
+
</svg>
|
|
2202
|
+
</div>
|
|
2203
|
+
` : "";
|
|
2204
|
+
return widgetTemplate.replace("{{languageOptions}}", languageOptions).replace("{{currentLanguageLabel}}", currentLanguageLabel).replace("{{languageCountLabel}}", languageCountLabel).replace("{{searchSection}}", searchSection);
|
|
2205
|
+
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Creates the language options
|
|
2208
|
+
* @returns The language options
|
|
2209
|
+
*/
|
|
2210
|
+
createLanguageOptions() {
|
|
2211
|
+
const sortedLanguages = [...this.targetLanguages].sort((a, b) => a.native.localeCompare(b.native));
|
|
2212
|
+
const createLanguageItem = (lang, isSelected = false) => `
|
|
2213
|
+
<div class="jigts-language-item ${isSelected ? "jigts-selected" : ""}" tabindex="0" role="option" aria-selected="${isSelected}" data-language-code="${lang.code}">
|
|
2214
|
+
<div class="jigts-language-info">
|
|
2215
|
+
<div class="jigts-language-main">
|
|
2216
|
+
<span class="jigts-language-name">${lang.name}</span>
|
|
2217
|
+
<div class="jigts-language-code">${lang.code}</div>
|
|
2218
|
+
</div>
|
|
2219
|
+
<div class="jigts-language-details">
|
|
2220
|
+
<span class="jigts-language-native">${lang.native}</span>
|
|
2221
|
+
</div>
|
|
2222
|
+
</div>
|
|
2223
|
+
<svg class="jigts-check-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2224
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
2225
|
+
</svg>
|
|
2226
|
+
</div>
|
|
2227
|
+
`;
|
|
2228
|
+
return sortedLanguages.map((lang) => createLanguageItem(lang, lang.code === this.currentLanguage)).join("");
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
* Updates the trigger text
|
|
2232
|
+
* @param newText - The new text
|
|
2233
|
+
*/
|
|
2234
|
+
async updateTriggerText(newText) {
|
|
2235
|
+
var _a;
|
|
2236
|
+
const triggerSpan = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector("span");
|
|
2237
|
+
if (!triggerSpan) return;
|
|
2238
|
+
triggerSpan.offsetHeight;
|
|
2239
|
+
triggerSpan.classList.remove("jigts-fade-in");
|
|
2240
|
+
triggerSpan.classList.add("jigts-fade-out");
|
|
2241
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
2242
|
+
triggerSpan.textContent = newText;
|
|
2243
|
+
triggerSpan.offsetHeight;
|
|
2244
|
+
triggerSpan.classList.remove("jigts-fade-out");
|
|
2245
|
+
triggerSpan.classList.add("jigts-fade-in");
|
|
2246
|
+
}
|
|
2247
|
+
/**
|
|
2248
|
+
* Gets the text to translate
|
|
2249
|
+
* @param node - The node to translate
|
|
2250
|
+
* @param parent - The parent element
|
|
2251
|
+
* @param targetLang - The target language
|
|
2252
|
+
* @returns The text to translate
|
|
2253
|
+
*/
|
|
2254
|
+
getTextToTranslate(node, parent, targetLang) {
|
|
2255
|
+
var _a, _b;
|
|
2256
|
+
if (!parent.hasAttribute(ATTRIBUTES.ORIGINAL_TEXT)) {
|
|
2257
|
+
const originalText = (_a = node.text) == null ? void 0 : _a.trim();
|
|
2258
|
+
if (originalText) {
|
|
2259
|
+
parent.setAttribute(ATTRIBUTES.TRANSLATED_LANG, targetLang);
|
|
2260
|
+
parent.setAttribute(ATTRIBUTES.ORIGINAL_TEXT, originalText);
|
|
2261
|
+
if (this.config.adjustFontSize && !parent.hasAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE)) {
|
|
2262
|
+
const computedStyle = window.getComputedStyle(parent);
|
|
2263
|
+
parent.setAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE, computedStyle.fontSize);
|
|
2264
|
+
}
|
|
2265
|
+
return originalText;
|
|
2266
|
+
}
|
|
2267
|
+
} else {
|
|
2268
|
+
const textToTranslate = (_b = node.text) == null ? void 0 : _b.trim();
|
|
2269
|
+
if (this.currentLanguage !== targetLang) {
|
|
2270
|
+
parent.setAttribute(ATTRIBUTES.TRANSLATED_LANG, targetLang);
|
|
2271
|
+
let originalText = parent.getAttribute(ATTRIBUTES.ORIGINAL_TEXT);
|
|
2272
|
+
if (originalText) {
|
|
2273
|
+
return originalText;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
return textToTranslate || null;
|
|
2277
|
+
}
|
|
2278
|
+
return null;
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Calculates the font size
|
|
2282
|
+
* @param text - The text to calculate the font size for
|
|
2283
|
+
* @param originalFontSize - The original font size
|
|
2284
|
+
* @param originalText - The original text
|
|
2285
|
+
* @returns The font size
|
|
2286
|
+
*/
|
|
2287
|
+
calculateFontSize(text, originalFontSize, originalText) {
|
|
2288
|
+
const minFontSize = 12;
|
|
2289
|
+
const maxFontSize = parseInt(originalFontSize);
|
|
2290
|
+
const textLength = text.length;
|
|
2291
|
+
const originalLength = originalText.length;
|
|
2292
|
+
if (textLength <= originalLength) {
|
|
2293
|
+
return originalFontSize;
|
|
2294
|
+
}
|
|
2295
|
+
const ratio = originalLength / textLength;
|
|
2296
|
+
const fontSize = Math.max(minFontSize, Math.round(maxFontSize * ratio));
|
|
2297
|
+
return `${fontSize}px`;
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Updates the loading state
|
|
2301
|
+
* @param isLoading - Whether the widget is loading
|
|
2302
|
+
*/
|
|
2303
|
+
updateLoadingState(isLoading) {
|
|
2304
|
+
var _a, _b;
|
|
2305
|
+
const triggerContent = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-content");
|
|
2306
|
+
const triggerLoading = (_b = this.elements.trigger) == null ? void 0 : _b.querySelector(".jigts-trigger-loading");
|
|
2307
|
+
if (triggerContent && triggerLoading) {
|
|
2308
|
+
if (isLoading) {
|
|
2309
|
+
triggerContent.style.display = "none";
|
|
2310
|
+
triggerLoading.style.display = "flex";
|
|
2311
|
+
} else {
|
|
2312
|
+
triggerLoading.style.display = "none";
|
|
2313
|
+
triggerContent.style.display = "flex";
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Main function to translate the page
|
|
2319
|
+
*
|
|
2320
|
+
* Handles the translation of the page for multiple languages
|
|
2321
|
+
*
|
|
2322
|
+
* 1. Increments the request ID for each new translation
|
|
2323
|
+
* 2. Waits for the current translation to complete
|
|
2324
|
+
* 3. If the target language is the default page language, resets the translations
|
|
2325
|
+
* 4. Creates a new promise for each translation and awaits it
|
|
2326
|
+
*
|
|
2327
|
+
* @param targetLang - The target language
|
|
2328
|
+
*/
|
|
2329
|
+
async translatePage(targetLang) {
|
|
2330
|
+
const requestId = ++this.translationRequestId;
|
|
2331
|
+
this.lastRequestedLanguage = targetLang;
|
|
2332
|
+
this.updateLoadingState(true);
|
|
2333
|
+
if (this.currentTranslationPromise) {
|
|
2334
|
+
await this.currentTranslationPromise;
|
|
2335
|
+
}
|
|
2336
|
+
if (targetLang === this.config.pageLanguage) {
|
|
2337
|
+
this.resetTranslations();
|
|
2338
|
+
if (requestId === this.translationRequestId) {
|
|
2339
|
+
this.updateLoadingState(false);
|
|
2340
|
+
}
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
this.currentTranslationPromise = this._translatePage(targetLang);
|
|
2344
|
+
try {
|
|
2345
|
+
await this.currentTranslationPromise;
|
|
2346
|
+
} catch (error) {
|
|
2347
|
+
console.error("Translation failed:", error);
|
|
2348
|
+
this.resetToDefaultLanguage();
|
|
2349
|
+
} finally {
|
|
2350
|
+
if (requestId === this.translationRequestId) {
|
|
2351
|
+
this.currentTranslationPromise = null;
|
|
2352
|
+
this.updateLoadingState(false);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Reset to default Page language
|
|
2358
|
+
* @returns
|
|
2359
|
+
*/
|
|
2360
|
+
resetToDefaultLanguage() {
|
|
2361
|
+
var _a;
|
|
2362
|
+
if (this.isTranslating) {
|
|
2363
|
+
return;
|
|
2364
|
+
}
|
|
2365
|
+
this.resetTranslations();
|
|
2366
|
+
this.lastRequestedLanguage = this.config.pageLanguage;
|
|
2367
|
+
this.currentLanguage = this.config.pageLanguage;
|
|
2368
|
+
const languageItems = this.widget.querySelectorAll(".jigts-language-item");
|
|
2369
|
+
languageItems.forEach((item) => {
|
|
2370
|
+
const isSelected = item.getAttribute("data-language-code") === this.config.pageLanguage;
|
|
2371
|
+
item.classList.toggle("jigts-selected", isSelected);
|
|
2372
|
+
item.setAttribute("aria-selected", isSelected.toString());
|
|
2373
|
+
});
|
|
2374
|
+
localStorage.setItem(LOCALSTORAGE_KEYS.PREFERRED_LANGUAGE, this.config.pageLanguage);
|
|
2375
|
+
const triggerIcon = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-icon");
|
|
2376
|
+
if (triggerIcon) {
|
|
2377
|
+
triggerIcon.innerHTML = this.getLanguageSVG();
|
|
2378
|
+
}
|
|
2379
|
+
this.isTranslated = false;
|
|
2380
|
+
this.updateResetButtonVisibility();
|
|
2381
|
+
}
|
|
2382
|
+
async _translatePage(targetLang) {
|
|
2383
|
+
var _a;
|
|
2384
|
+
this.isTranslating = true;
|
|
2385
|
+
(_a = this.observer) == null ? void 0 : _a.disconnect();
|
|
2386
|
+
try {
|
|
2387
|
+
const nodes = DocumentNavigator.findTranslatableContent();
|
|
2388
|
+
const visibleNodes = nodes.filter((node) => {
|
|
2389
|
+
const rect = node.element.getBoundingClientRect();
|
|
2390
|
+
return rect.height > 0 && rect.top < window.innerHeight;
|
|
2391
|
+
});
|
|
2392
|
+
const nonVisibleNodes = nodes.filter((node) => {
|
|
2393
|
+
const rect = node.element.getBoundingClientRect();
|
|
2394
|
+
return rect.height === 0 || rect.top > window.innerHeight;
|
|
2395
|
+
});
|
|
2396
|
+
const visibleBatches = DocumentNavigator.divideIntoGroups(visibleNodes, BATCH_SIZE);
|
|
2397
|
+
const nonVisibleBatches = DocumentNavigator.divideIntoGroups(nonVisibleNodes, BATCH_SIZE);
|
|
2398
|
+
const cache = new LocalStorageWrapper(CACHE_PREFIX);
|
|
2399
|
+
const processBatches = async (batches) => {
|
|
2400
|
+
const allBatchNodes = [];
|
|
2401
|
+
const allBatchTexts = [];
|
|
2402
|
+
batches.forEach((batch) => {
|
|
2403
|
+
const textsToTranslate = [];
|
|
2404
|
+
const batchNodes = [];
|
|
2405
|
+
batch.forEach((node) => {
|
|
2406
|
+
const parent = node.element;
|
|
2407
|
+
if (!parent) return;
|
|
2408
|
+
const translatedLang = parent.getAttribute(ATTRIBUTES.TRANSLATED_LANG);
|
|
2409
|
+
if (parent.hasAttribute(ATTRIBUTES.ORIGINAL_TEXT) && targetLang === translatedLang) {
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
let textToTranslate = this.getTextToTranslate(node, parent, targetLang);
|
|
2413
|
+
textToTranslate = removeEmojis(textToTranslate || "");
|
|
2414
|
+
if (textToTranslate.length === 0 || textToTranslate.length === 1) {
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
if (textToTranslate) {
|
|
2418
|
+
const cacheObject = cache.getItem(cache.getPageKey(targetLang)) || {};
|
|
2419
|
+
const cachedTranslation = cacheObject[textToTranslate] || null;
|
|
2420
|
+
if (cachedTranslation) {
|
|
2421
|
+
if (this.lastRequestedLanguage === targetLang) {
|
|
2422
|
+
const originalText = textToTranslate;
|
|
2423
|
+
const translatedText = cachedTranslation;
|
|
2424
|
+
if (this.config.adjustFontSize) {
|
|
2425
|
+
const originalFontSize = parent.getAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE) || "16px";
|
|
2426
|
+
const newFontSize = this.calculateFontSize(translatedText, originalFontSize, originalText);
|
|
2427
|
+
parent.style.fontSize = newFontSize;
|
|
2428
|
+
}
|
|
2429
|
+
this.setTranslatedContent(parent, translatedText);
|
|
2430
|
+
}
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
textsToTranslate.push(textToTranslate.trim());
|
|
2434
|
+
batchNodes.push(node);
|
|
2435
|
+
}
|
|
2436
|
+
});
|
|
2437
|
+
if (textsToTranslate.length > 0) {
|
|
2438
|
+
allBatchNodes.push(batchNodes);
|
|
2439
|
+
allBatchTexts.push(textsToTranslate);
|
|
2440
|
+
}
|
|
2441
|
+
});
|
|
2442
|
+
if (allBatchTexts.length > 0) {
|
|
2443
|
+
const allTranslatedTexts = await Promise.all(allBatchTexts.map((texts) => {
|
|
2444
|
+
var _a2;
|
|
2445
|
+
return (_a2 = this.translationService) == null ? void 0 : _a2.translateBatchText(texts, targetLang);
|
|
2446
|
+
}));
|
|
2447
|
+
const successfulBatches = [];
|
|
2448
|
+
allTranslatedTexts.forEach((translations, batchIndex) => {
|
|
2449
|
+
if (translations && translations.length > 0) {
|
|
2450
|
+
successfulBatches.push({
|
|
2451
|
+
translations,
|
|
2452
|
+
nodes: allBatchNodes[batchIndex]
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
});
|
|
2456
|
+
if (successfulBatches.length === 0) {
|
|
2457
|
+
this.updateLoadingState(false);
|
|
2458
|
+
this.isTranslating = false;
|
|
2459
|
+
this.resetToDefaultLanguage();
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
const batchArray = [];
|
|
2463
|
+
successfulBatches.forEach(({ translations, nodes: nodes2 }) => {
|
|
2464
|
+
nodes2.forEach((node, nodeIndex) => {
|
|
2465
|
+
const parent = node.element;
|
|
2466
|
+
if (parent && translations[nodeIndex]) {
|
|
2467
|
+
const originalText = node.text || "";
|
|
2468
|
+
const translatedText = translations[nodeIndex];
|
|
2469
|
+
const originalTextWithoutEmojis = removeEmojis(originalText);
|
|
2470
|
+
if (originalTextWithoutEmojis && translatedText) {
|
|
2471
|
+
batchArray.push({
|
|
2472
|
+
originalText: originalTextWithoutEmojis,
|
|
2473
|
+
translatedText
|
|
2474
|
+
});
|
|
2475
|
+
if (this.lastRequestedLanguage === targetLang) {
|
|
2476
|
+
if (this.config.adjustFontSize) {
|
|
2477
|
+
const originalFontSize = parent.getAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE) || "16px";
|
|
2478
|
+
const newFontSize = this.calculateFontSize(translatedText, originalFontSize, originalText);
|
|
2479
|
+
parent.style.fontSize = newFontSize;
|
|
2480
|
+
}
|
|
2481
|
+
this.setTranslatedContent(parent, translatedText);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
});
|
|
2486
|
+
});
|
|
2487
|
+
if (batchArray.length > 0) {
|
|
2488
|
+
cache.setBatchNodeTranslationsArray(targetLang, batchArray);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
};
|
|
2492
|
+
await Promise.allSettled([
|
|
2493
|
+
processBatches(visibleBatches),
|
|
2494
|
+
processBatches(nonVisibleBatches)
|
|
2495
|
+
]);
|
|
2496
|
+
if (this.lastRequestedLanguage === targetLang) {
|
|
2497
|
+
this.isTranslated = true;
|
|
2498
|
+
this.updateResetButtonVisibility();
|
|
2499
|
+
}
|
|
2500
|
+
} finally {
|
|
2501
|
+
this.isTranslating = false;
|
|
2502
|
+
this.observeBody();
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
/**
|
|
2506
|
+
* Updates the visibility of the reset button
|
|
2507
|
+
*/
|
|
2508
|
+
updateResetButtonVisibility() {
|
|
2509
|
+
const resetButton = this.widget.querySelector(".jigts-reset-option");
|
|
2510
|
+
if (resetButton) {
|
|
2511
|
+
resetButton.style.display = this.isTranslated ? "flex" : "none";
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Resets the translations
|
|
2516
|
+
*/
|
|
2517
|
+
resetTranslations() {
|
|
2518
|
+
if (this.observer) {
|
|
2519
|
+
this.observer.disconnect();
|
|
2520
|
+
}
|
|
2521
|
+
const elements = document.querySelectorAll(`[${ATTRIBUTES.ORIGINAL_TEXT}]`);
|
|
2522
|
+
elements.forEach((element) => {
|
|
2523
|
+
const textNodes = Array.from(element.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE);
|
|
2524
|
+
if (textNodes.length > 0) {
|
|
2525
|
+
const originalText = element.getAttribute(ATTRIBUTES.ORIGINAL_TEXT);
|
|
2526
|
+
if (originalText) {
|
|
2527
|
+
this.setTranslatedContent(element, originalText);
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
const originalFontSize = element.getAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE);
|
|
2531
|
+
if (originalFontSize) {
|
|
2532
|
+
element.style.fontSize = originalFontSize;
|
|
2533
|
+
}
|
|
2534
|
+
element.removeAttribute(ATTRIBUTES.ORIGINAL_TEXT);
|
|
2535
|
+
element.removeAttribute(ATTRIBUTES.TRANSLATED_LANG);
|
|
2536
|
+
element.removeAttribute(ATTRIBUTES.ORIGINAL_FONT_SIZE);
|
|
2537
|
+
});
|
|
2538
|
+
this.isTranslated = false;
|
|
2539
|
+
this.currentLanguage = this.config.pageLanguage;
|
|
2540
|
+
const nodes = DocumentNavigator.findTranslatableContent();
|
|
2541
|
+
const hash = generateHashForContent(nodes);
|
|
2542
|
+
this.lastTranslated = {
|
|
2543
|
+
url: window.location.href,
|
|
2544
|
+
lang: this.config.pageLanguage,
|
|
2545
|
+
hash
|
|
2546
|
+
};
|
|
2547
|
+
this.updateResetButtonVisibility();
|
|
2548
|
+
this.observeBody();
|
|
2549
|
+
}
|
|
2550
|
+
/**
|
|
2551
|
+
* Adjusts the dropdown position
|
|
2552
|
+
*/
|
|
2553
|
+
adjustDropdownPosition() {
|
|
2554
|
+
const { dropdown, trigger } = this.elements;
|
|
2555
|
+
if (!dropdown || !trigger) return;
|
|
2556
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2557
|
+
const dropdownRect = dropdown.getBoundingClientRect();
|
|
2558
|
+
const viewportWidth = window.innerWidth;
|
|
2559
|
+
const viewportHeight = window.innerHeight;
|
|
2560
|
+
dropdown.style.top = "";
|
|
2561
|
+
dropdown.style.bottom = "";
|
|
2562
|
+
dropdown.style.left = "";
|
|
2563
|
+
dropdown.style.right = "";
|
|
2564
|
+
dropdown.style.transform = "";
|
|
2565
|
+
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
2566
|
+
const spaceAbove = triggerRect.top;
|
|
2567
|
+
const spaceRight = viewportWidth - triggerRect.right;
|
|
2568
|
+
const spaceLeft = triggerRect.left;
|
|
2569
|
+
if (spaceBelow < dropdownRect.height && spaceAbove > spaceBelow) {
|
|
2570
|
+
dropdown.style.bottom = "100%";
|
|
2571
|
+
dropdown.style.top = "auto";
|
|
2572
|
+
dropdown.style.marginBottom = "0.5rem";
|
|
2573
|
+
dropdown.style.marginTop = "0";
|
|
2574
|
+
} else {
|
|
2575
|
+
dropdown.style.top = "100%";
|
|
2576
|
+
dropdown.style.bottom = "auto";
|
|
2577
|
+
dropdown.style.marginTop = "0.5rem";
|
|
2578
|
+
dropdown.style.marginBottom = "0";
|
|
2579
|
+
}
|
|
2580
|
+
if (spaceRight < dropdownRect.width && spaceLeft > spaceRight) {
|
|
2581
|
+
dropdown.style.right = "0";
|
|
2582
|
+
dropdown.style.left = "auto";
|
|
2583
|
+
} else {
|
|
2584
|
+
dropdown.style.left = "0";
|
|
2585
|
+
dropdown.style.right = "auto";
|
|
2586
|
+
}
|
|
2587
|
+
const finalRect = dropdown.getBoundingClientRect();
|
|
2588
|
+
if (finalRect.right > viewportWidth) {
|
|
2589
|
+
dropdown.style.right = "0";
|
|
2590
|
+
dropdown.style.left = "auto";
|
|
2591
|
+
}
|
|
2592
|
+
if (finalRect.left < 0) {
|
|
2593
|
+
dropdown.style.left = "0";
|
|
2594
|
+
dropdown.style.right = "auto";
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
/**
|
|
2598
|
+
* Sets up the event listeners
|
|
2599
|
+
*/
|
|
2600
|
+
setupEventListeners() {
|
|
2601
|
+
const { trigger, dropdown, searchInput, clearSearch, languageItems } = this.elements;
|
|
2602
|
+
if (!trigger || !dropdown || !languageItems) {
|
|
2603
|
+
console.error("Failed to find required elements");
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2606
|
+
const resetButton = this.widget.querySelector(".jigts-reset-option");
|
|
2607
|
+
if (resetButton) {
|
|
2608
|
+
resetButton.addEventListener("click", () => {
|
|
2609
|
+
var _a;
|
|
2610
|
+
if (this.isTranslating) return;
|
|
2611
|
+
this.resetToDefaultLanguage();
|
|
2612
|
+
resetButton.classList.remove("jigts-active");
|
|
2613
|
+
this.isTranslated = false;
|
|
2614
|
+
this.updateResetButtonVisibility();
|
|
2615
|
+
const languageItems2 = this.widget.querySelectorAll(".jigts-language-item");
|
|
2616
|
+
languageItems2.forEach((item) => {
|
|
2617
|
+
const isSelected = item.getAttribute("data-language-code") === this.config.pageLanguage;
|
|
2618
|
+
item.classList.toggle("jigts-selected", isSelected);
|
|
2619
|
+
item.setAttribute("aria-selected", isSelected.toString());
|
|
2620
|
+
});
|
|
2621
|
+
const triggerIcon = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-icon");
|
|
2622
|
+
if (triggerIcon) {
|
|
2623
|
+
triggerIcon.innerHTML = this.getLanguageSVG();
|
|
2624
|
+
}
|
|
2625
|
+
dropdown.classList.remove("jigts-open");
|
|
2626
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
2627
|
+
const triggerContent = trigger.querySelector(".jigts-trigger-content");
|
|
2628
|
+
if (triggerContent) triggerContent.classList.remove("jigts-has-translation");
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
this.updateResetButtonVisibility();
|
|
2632
|
+
trigger.addEventListener("click", () => {
|
|
2633
|
+
dropdown.classList.toggle("jigts-open");
|
|
2634
|
+
const isOpen = dropdown.classList.contains("jigts-open");
|
|
2635
|
+
trigger.setAttribute("aria-expanded", isOpen.toString());
|
|
2636
|
+
if (isOpen && searchInput) {
|
|
2637
|
+
this.adjustDropdownPosition();
|
|
2638
|
+
searchInput.focus();
|
|
2639
|
+
}
|
|
2640
|
+
});
|
|
2641
|
+
window.addEventListener("resize", () => {
|
|
2642
|
+
if (dropdown.classList.contains("jigts-open")) {
|
|
2643
|
+
this.adjustDropdownPosition();
|
|
2644
|
+
}
|
|
2645
|
+
});
|
|
2646
|
+
document.addEventListener("click", (e) => {
|
|
2647
|
+
if (!e.target.closest(".jigts-translation-widget")) {
|
|
2648
|
+
if (dropdown.classList.contains("jigts-open")) {
|
|
2649
|
+
dropdown.classList.add("jigts-closing");
|
|
2650
|
+
setTimeout(() => {
|
|
2651
|
+
dropdown.classList.remove("jigts-open", "jigts-closing");
|
|
2652
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
2653
|
+
}, 300);
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
});
|
|
2657
|
+
if (searchInput && clearSearch) {
|
|
2658
|
+
searchInput.addEventListener("input", () => {
|
|
2659
|
+
const searchTerm = searchInput.value.toLowerCase();
|
|
2660
|
+
const hasValue = searchTerm.length > 0;
|
|
2661
|
+
clearSearch.classList.toggle("jigts-visible", hasValue);
|
|
2662
|
+
const items = this.widget.querySelectorAll(".jigts-language-item");
|
|
2663
|
+
const noResults = this.widget.querySelector(".jigts-no-results");
|
|
2664
|
+
let visibleCount = 0;
|
|
2665
|
+
items.forEach((item) => {
|
|
2666
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2667
|
+
const name = ((_b = (_a = item.querySelector(".jigts-language-name")) == null ? void 0 : _a.textContent) == null ? void 0 : _b.toLowerCase()) || "";
|
|
2668
|
+
const native = ((_d = (_c = item.querySelector(".jigts-language-native")) == null ? void 0 : _c.textContent) == null ? void 0 : _d.toLowerCase()) || "";
|
|
2669
|
+
const code = ((_f = (_e = item.querySelector(".jigts-language-code")) == null ? void 0 : _e.textContent) == null ? void 0 : _f.toLowerCase()) || "";
|
|
2670
|
+
const region = ((_h = (_g = item.querySelector(".jigts-language-region")) == null ? void 0 : _g.textContent) == null ? void 0 : _h.toLowerCase()) || "";
|
|
2671
|
+
const matches = name.includes(searchTerm) || native.includes(searchTerm) || code.includes(searchTerm) || region.includes(searchTerm);
|
|
2672
|
+
item.style.display = matches ? "" : "none";
|
|
2673
|
+
if (matches) visibleCount++;
|
|
2674
|
+
});
|
|
2675
|
+
if (noResults) {
|
|
2676
|
+
noResults.style.display = visibleCount === 0 ? "flex" : "none";
|
|
2677
|
+
}
|
|
2678
|
+
});
|
|
2679
|
+
clearSearch.addEventListener("click", () => {
|
|
2680
|
+
searchInput.value = "";
|
|
2681
|
+
clearSearch.classList.remove("jigts-visible");
|
|
2682
|
+
searchInput.focus();
|
|
2683
|
+
const items = this.widget.querySelectorAll(".jigts-language-item");
|
|
2684
|
+
const noResults = this.widget.querySelector(".jigts-no-results");
|
|
2685
|
+
items.forEach((item) => {
|
|
2686
|
+
item.style.display = "";
|
|
2687
|
+
});
|
|
2688
|
+
if (noResults) {
|
|
2689
|
+
noResults.style.display = "none";
|
|
2690
|
+
}
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2693
|
+
languageItems.forEach((item) => {
|
|
2694
|
+
item.addEventListener("click", async () => {
|
|
2695
|
+
var _a, _b;
|
|
2696
|
+
languageItems.forEach((i) => {
|
|
2697
|
+
i.classList.remove("jigts-selected");
|
|
2698
|
+
i.setAttribute("aria-selected", "false");
|
|
2699
|
+
});
|
|
2700
|
+
item.classList.add("jigts-selected");
|
|
2701
|
+
item.setAttribute("aria-selected", "true");
|
|
2702
|
+
const langName = (_a = item.querySelector(".jigts-language-name")) == null ? void 0 : _a.textContent;
|
|
2703
|
+
const langCode = item.getAttribute("data-language-code");
|
|
2704
|
+
dropdown.classList.remove("jigts-open");
|
|
2705
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
2706
|
+
if (langName) {
|
|
2707
|
+
await this.updateTriggerText(langName);
|
|
2708
|
+
}
|
|
2709
|
+
if (langCode) {
|
|
2710
|
+
localStorage.setItem(LOCALSTORAGE_KEYS.PREFERRED_LANGUAGE, langCode);
|
|
2711
|
+
}
|
|
2712
|
+
const triggerIcon = (_b = this.elements.trigger) == null ? void 0 : _b.querySelector(".jigts-trigger-icon");
|
|
2713
|
+
if (triggerIcon && langCode && langName) {
|
|
2714
|
+
triggerIcon.innerHTML = `<span class="jigts-lang-code">${langCode.toUpperCase()}</span><span class="jigts-lang-name">${langName}</span>`;
|
|
2715
|
+
}
|
|
2716
|
+
const triggerContent = trigger.querySelector(".jigts-trigger-content");
|
|
2717
|
+
if (langCode && langCode !== this.currentLanguage) {
|
|
2718
|
+
if (triggerContent) triggerContent.classList.add("jigts-has-translation");
|
|
2719
|
+
const triggerLoading = trigger.querySelector(".jigts-trigger-loading");
|
|
2720
|
+
if (triggerContent && triggerLoading) {
|
|
2721
|
+
triggerContent.style.display = "none";
|
|
2722
|
+
triggerLoading.style.display = "flex";
|
|
2723
|
+
}
|
|
2724
|
+
try {
|
|
2725
|
+
await this.translatePage(langCode);
|
|
2726
|
+
this.currentLanguage = langCode;
|
|
2727
|
+
} catch (error) {
|
|
2728
|
+
console.error("Translation error:", error);
|
|
2729
|
+
alert("An error occurred during translation. Please try again.");
|
|
2730
|
+
}
|
|
2731
|
+
} else if (triggerContent) {
|
|
2732
|
+
triggerContent.classList.remove("jigts-has-translation");
|
|
2733
|
+
}
|
|
2734
|
+
});
|
|
2735
|
+
});
|
|
2736
|
+
document.addEventListener("keydown", (e) => {
|
|
2737
|
+
if (!dropdown.classList.contains("jigts-open")) return;
|
|
2738
|
+
if (e.key === "Escape") {
|
|
2739
|
+
dropdown.classList.remove("jigts-open");
|
|
2740
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
2741
|
+
trigger.focus();
|
|
2742
|
+
}
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
scheduleTranslation() {
|
|
2746
|
+
if (this.translationScheduled) return;
|
|
2747
|
+
const currentUrl = window.location.href;
|
|
2748
|
+
const currentLang = this.currentLanguage;
|
|
2749
|
+
const nodes = DocumentNavigator.findTranslatableContent();
|
|
2750
|
+
const hash = generateHashForContent(nodes);
|
|
2751
|
+
if (this.lastTranslated && this.lastTranslated.url === currentUrl && this.lastTranslated.lang === currentLang && this.lastTranslated.hash === hash) {
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
this.translationScheduled = true;
|
|
2755
|
+
if (this.scheduleTimeout) clearTimeout(this.scheduleTimeout);
|
|
2756
|
+
this.scheduleTimeout = window.setTimeout(() => {
|
|
2757
|
+
var _a, _b;
|
|
2758
|
+
this.translationScheduled = false;
|
|
2759
|
+
if (this.currentLanguage !== this.config.pageLanguage) {
|
|
2760
|
+
this.lastTranslated = { url: currentUrl, lang: currentLang, hash };
|
|
2761
|
+
const triggerContent = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-content");
|
|
2762
|
+
const triggerLoading = (_b = this.elements.trigger) == null ? void 0 : _b.querySelector(".jigts-trigger-loading");
|
|
2763
|
+
if (triggerContent && triggerLoading) {
|
|
2764
|
+
triggerContent.style.display = "none";
|
|
2765
|
+
triggerLoading.style.display = "flex";
|
|
2766
|
+
}
|
|
2767
|
+
this.translatePage(this.currentLanguage).then(() => {
|
|
2768
|
+
const languageItems = this.widget.querySelectorAll(".jigts-language-item");
|
|
2769
|
+
languageItems.forEach((item) => {
|
|
2770
|
+
const isSelected = item.getAttribute("data-language-code") === this.currentLanguage;
|
|
2771
|
+
item.classList.toggle("jigts-selected", isSelected);
|
|
2772
|
+
item.setAttribute("aria-selected", isSelected.toString());
|
|
2773
|
+
});
|
|
2774
|
+
}).catch((error) => {
|
|
2775
|
+
console.error("Auto-translation error:", error);
|
|
2776
|
+
});
|
|
2777
|
+
}
|
|
2778
|
+
}, 200);
|
|
2779
|
+
}
|
|
2780
|
+
/**
|
|
2781
|
+
* Public method to translate the page to a specific language
|
|
2782
|
+
* @param langCode The language code to translate to
|
|
2783
|
+
* @returns Promise that resolves when translation is complete
|
|
2784
|
+
*/
|
|
2785
|
+
async translateTo(langCode, onComplete, onError) {
|
|
2786
|
+
var _a;
|
|
2787
|
+
const startTime = Date.now();
|
|
2788
|
+
if (this.isTranslating) {
|
|
2789
|
+
console.warn("Translation already in progress");
|
|
2790
|
+
onError == null ? void 0 : onError(new Error("Translation already in progress"));
|
|
2791
|
+
return {
|
|
2792
|
+
success: false,
|
|
2793
|
+
targetLanguage: langCode,
|
|
2794
|
+
translatedNodes: 0,
|
|
2795
|
+
error: "Translation already in progress",
|
|
2796
|
+
duration: 0
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2799
|
+
const supportedLang = this.targetLanguages.find((lang) => lang.code === langCode);
|
|
2800
|
+
if (!supportedLang) {
|
|
2801
|
+
onError == null ? void 0 : onError(new Error(`Unsupported language code: ${langCode}`));
|
|
2802
|
+
return {
|
|
2803
|
+
success: false,
|
|
2804
|
+
targetLanguage: langCode,
|
|
2805
|
+
translatedNodes: 0,
|
|
2806
|
+
error: `Unsupported language code: ${langCode}`,
|
|
2807
|
+
duration: 0
|
|
2808
|
+
};
|
|
2809
|
+
}
|
|
2810
|
+
if (langCode === this.currentLanguage) {
|
|
2811
|
+
onComplete == null ? void 0 : onComplete({
|
|
2812
|
+
success: true,
|
|
2813
|
+
targetLanguage: langCode,
|
|
2814
|
+
translatedNodes: 0,
|
|
2815
|
+
duration: 0
|
|
2816
|
+
});
|
|
2817
|
+
return {
|
|
2818
|
+
success: true,
|
|
2819
|
+
targetLanguage: langCode,
|
|
2820
|
+
translatedNodes: 0,
|
|
2821
|
+
duration: 0
|
|
2822
|
+
};
|
|
2823
|
+
}
|
|
2824
|
+
try {
|
|
2825
|
+
localStorage.setItem(LOCALSTORAGE_KEYS.PREFERRED_LANGUAGE, langCode);
|
|
2826
|
+
await this.translatePage(langCode);
|
|
2827
|
+
this.currentLanguage = langCode;
|
|
2828
|
+
const languageItems = this.widget.querySelectorAll(".jigts-language-item");
|
|
2829
|
+
for (const item of languageItems) {
|
|
2830
|
+
const isSelected = item.getAttribute("data-language-code") === langCode;
|
|
2831
|
+
item.classList.toggle("jigts-selected", isSelected);
|
|
2832
|
+
item.setAttribute("aria-selected", isSelected.toString());
|
|
2833
|
+
}
|
|
2834
|
+
const triggerContent = (_a = this.elements.trigger) == null ? void 0 : _a.querySelector(".jigts-trigger-content");
|
|
2835
|
+
if (triggerContent) {
|
|
2836
|
+
triggerContent.classList.add("jigts-has-translation");
|
|
2837
|
+
const triggerIcon = triggerContent.querySelector(".jigts-trigger-icon");
|
|
2838
|
+
if (triggerIcon && supportedLang) {
|
|
2839
|
+
triggerIcon.innerHTML = `<span class="jigts-lang-code">${supportedLang.code.toUpperCase()}</span><span class="jigts-lang-name">${supportedLang.name}</span>`;
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
const endTime = Date.now();
|
|
2843
|
+
const translatedNodes = document.querySelectorAll(`[${ATTRIBUTES.TRANSLATED_LANG}]`).length;
|
|
2844
|
+
onComplete == null ? void 0 : onComplete({
|
|
2845
|
+
success: true,
|
|
2846
|
+
targetLanguage: langCode,
|
|
2847
|
+
translatedNodes,
|
|
2848
|
+
duration: endTime - startTime
|
|
2849
|
+
});
|
|
2850
|
+
return {
|
|
2851
|
+
success: true,
|
|
2852
|
+
targetLanguage: langCode,
|
|
2853
|
+
translatedNodes,
|
|
2854
|
+
duration: endTime - startTime
|
|
2855
|
+
};
|
|
2856
|
+
} catch (error) {
|
|
2857
|
+
onError == null ? void 0 : onError(error);
|
|
2858
|
+
return {
|
|
2859
|
+
success: false,
|
|
2860
|
+
targetLanguage: langCode,
|
|
2861
|
+
translatedNodes: 0,
|
|
2862
|
+
error: error instanceof Error ? error.message : "Unknown error occurred",
|
|
2863
|
+
duration: 0
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Get the current instance of TranslationWidget
|
|
2869
|
+
* @returns The current TranslationWidget instance or null if not initialized
|
|
2870
|
+
*/
|
|
2871
|
+
static getInstance() {
|
|
2872
|
+
return _TranslationWidget.instance;
|
|
2873
|
+
}
|
|
2874
|
+
// Add this helper method to the class
|
|
2875
|
+
getLanguageSVG() {
|
|
2876
|
+
return `
|
|
2877
|
+
<svg class="jigts-languages-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2878
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
2879
|
+
d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129">
|
|
2880
|
+
</path>
|
|
2881
|
+
</svg>
|
|
2882
|
+
`;
|
|
2883
|
+
}
|
|
2884
|
+
/**
|
|
2885
|
+
* Safely sets HTML content for translated text, handling nested HTML structures
|
|
2886
|
+
* @param element - The element to update
|
|
2887
|
+
* @param translatedText - The translated text that may contain HTML
|
|
2888
|
+
*/
|
|
2889
|
+
setTranslatedContent(element, translatedText) {
|
|
2890
|
+
var _a;
|
|
2891
|
+
const hasHtmlTags = /<[^>]*>/g.test(translatedText);
|
|
2892
|
+
if (hasHtmlTags) {
|
|
2893
|
+
const tempContainer = document.createElement("div");
|
|
2894
|
+
tempContainer.innerHTML = translatedText;
|
|
2895
|
+
if (tempContainer.children.length === 1 && ((_a = tempContainer.firstElementChild) == null ? void 0 : _a.tagName.toLowerCase()) === element.tagName.toLowerCase()) {
|
|
2896
|
+
element.innerHTML = tempContainer.firstElementChild.innerHTML;
|
|
2897
|
+
} else {
|
|
2898
|
+
element.innerHTML = translatedText;
|
|
2899
|
+
}
|
|
2900
|
+
} else {
|
|
2901
|
+
element.textContent = translatedText;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2905
|
+
__publicField(_TranslationWidget, "instance", null);
|
|
2906
|
+
let TranslationWidget = _TranslationWidget;
|
|
2907
|
+
if (typeof window !== "undefined") {
|
|
2908
|
+
window.resetTranslation = (defaultLang, onComplete, onError) => {
|
|
2909
|
+
const instance = TranslationWidget.getInstance();
|
|
2910
|
+
if (!instance) {
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
try {
|
|
2914
|
+
instance.resetToDefaultLanguage();
|
|
2915
|
+
onComplete == null ? void 0 : onComplete({
|
|
2916
|
+
success: true,
|
|
2917
|
+
targetLanguage: defaultLang
|
|
2918
|
+
});
|
|
2919
|
+
} catch (error) {
|
|
2920
|
+
onError == null ? void 0 : onError(error);
|
|
2921
|
+
}
|
|
2922
|
+
};
|
|
2923
|
+
window.translate = async (langCode, onComplete, onError) => {
|
|
2924
|
+
const instance = TranslationWidget.getInstance();
|
|
2925
|
+
if (!instance) {
|
|
2926
|
+
onError == null ? void 0 : onError(new Error("Translation widget not initialized"));
|
|
2927
|
+
return {
|
|
2928
|
+
success: false,
|
|
2929
|
+
targetLanguage: langCode,
|
|
2930
|
+
translatedNodes: 0,
|
|
2931
|
+
error: "Translation widget not initialized",
|
|
2932
|
+
duration: 0
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2935
|
+
const startTime = Date.now();
|
|
2936
|
+
try {
|
|
2937
|
+
const result = await instance.translateTo(langCode, onComplete, onError);
|
|
2938
|
+
onComplete == null ? void 0 : onComplete(result);
|
|
2939
|
+
return result;
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
onError == null ? void 0 : onError(error);
|
|
2942
|
+
return {
|
|
2943
|
+
success: false,
|
|
2944
|
+
targetLanguage: langCode,
|
|
2945
|
+
translatedNodes: 0,
|
|
2946
|
+
error: error instanceof Error ? error.message : "Unknown error occurred",
|
|
2947
|
+
duration: Date.now() - startTime
|
|
2948
|
+
};
|
|
2949
|
+
}
|
|
2950
|
+
};
|
|
2951
|
+
window.clearCache = (lang_code = [], onComplete, onError) => {
|
|
2952
|
+
const localStorageWrapper = new LocalStorageWrapper(CACHE_PREFIX);
|
|
2953
|
+
try {
|
|
2954
|
+
localStorageWrapper.clear(lang_code);
|
|
2955
|
+
onComplete == null ? void 0 : onComplete();
|
|
2956
|
+
} catch (error) {
|
|
2957
|
+
onError == null ? void 0 : onError(error);
|
|
2958
|
+
}
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
let widgetInstance;
|
|
2962
|
+
const initializeTranslationWidget = (publicKey, config) => {
|
|
2963
|
+
if (typeof window === "undefined") {
|
|
2964
|
+
throw new Error("Translation widget can only be used in browser environment");
|
|
2965
|
+
}
|
|
2966
|
+
const initWidget = () => {
|
|
2967
|
+
if (!widgetInstance) {
|
|
2968
|
+
if (!document.querySelector("style[data-translation-widget]")) {
|
|
2969
|
+
const style = document.createElement("style");
|
|
2970
|
+
style.setAttribute("data-translation-widget", "");
|
|
2971
|
+
style.textContent = styles;
|
|
2972
|
+
document.head.appendChild(style);
|
|
2973
|
+
}
|
|
2974
|
+
widgetInstance = new TranslationWidget(publicKey, config);
|
|
2975
|
+
}
|
|
2976
|
+
return widgetInstance;
|
|
2977
|
+
};
|
|
2978
|
+
if (document.readyState === "loading") {
|
|
2979
|
+
window.addEventListener("DOMContentLoaded", initWidget);
|
|
2980
|
+
return void 0;
|
|
2981
|
+
} else {
|
|
2982
|
+
return initWidget();
|
|
2983
|
+
}
|
|
2984
|
+
};
|
|
2985
|
+
(() => {
|
|
2986
|
+
const originalRemoveChild = Node.prototype.removeChild;
|
|
2987
|
+
Node.prototype.removeChild = function(child) {
|
|
2988
|
+
try {
|
|
2989
|
+
return originalRemoveChild.call(this, child);
|
|
2990
|
+
} catch (err) {
|
|
2991
|
+
if (err instanceof DOMException && err.name === "NotFoundError") {
|
|
2992
|
+
return child;
|
|
2993
|
+
}
|
|
2994
|
+
throw err;
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
})();
|
|
2998
|
+
export {
|
|
2999
|
+
initializeTranslationWidget as default
|
|
3000
|
+
};
|