@dabalabs/lang 0.0.5-beta → 0.0.7-beta

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/dist/dabalang.cjs CHANGED
@@ -145,6 +145,35 @@ async function submitCorrection(gatewayUrl, projectId, apiKey, targetLang, sourc
145
145
  await parseOrThrow(response);
146
146
  }
147
147
 
148
+ // src/translation-cache.ts
149
+ var PREFIX = "dabalang:tcache:";
150
+ var VERSION = 1;
151
+ var MAX_ENTRY_BYTES = 512 * 1024;
152
+ function key(projectId, lang) {
153
+ return `${PREFIX}${projectId}:${lang}`;
154
+ }
155
+ function readCachedTranslations(projectId, lang) {
156
+ try {
157
+ const raw = window.localStorage.getItem(key(projectId, lang));
158
+ if (!raw) return null;
159
+ const parsed = JSON.parse(raw);
160
+ if (!parsed || parsed.v !== VERSION || typeof parsed.t !== "object") return null;
161
+ return new Map(Object.entries(parsed.t));
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+ function writeCachedTranslations(projectId, lang, translations) {
167
+ try {
168
+ if (translations.size === 0) return;
169
+ const payload = { v: VERSION, t: Object.fromEntries(translations) };
170
+ const serialised = JSON.stringify(payload);
171
+ if (serialised.length > MAX_ENTRY_BYTES) return;
172
+ window.localStorage.setItem(key(projectId, lang), serialised);
173
+ } catch {
174
+ }
175
+ }
176
+
148
177
  // src/dom/ignore.ts
149
178
  var IGNORE_ATTR = "data-dabalang-ignore";
150
179
  var SENSITIVE_ELEMENT_SELECTOR = `[${IGNORE_ATTR}], input[type="password"], input[type="hidden"], [autocomplete="current-password"], [autocomplete="new-password"], [autocomplete^="cc-"]`;
@@ -275,8 +304,28 @@ var TranslationApplier = class {
275
304
  }
276
305
  return null;
277
306
  }
307
+ /** Writes every translation this map covers into the DOM. */
308
+ paint(translations) {
309
+ let painted = 0;
310
+ for (const [sourceText, nodes] of this.groups) {
311
+ const translated = translations.get(sourceText);
312
+ if (translated === void 0) continue;
313
+ for (const node of nodes) node.textContent = translated;
314
+ painted += 1;
315
+ }
316
+ return painted;
317
+ }
278
318
  async applyLanguage(targetLang) {
279
- const cached = this.fetchedLanguages.get(targetLang);
319
+ let cached = this.fetchedLanguages.get(targetLang);
320
+ if (!cached) {
321
+ const stored = readCachedTranslations(this.projectId, targetLang);
322
+ if (stored && stored.size > 0) {
323
+ cached = stored;
324
+ this.fetchedLanguages.set(targetLang, stored);
325
+ this.paint(stored);
326
+ this.activeLang = targetLang;
327
+ }
328
+ }
280
329
  const allTexts = this.sourceTexts();
281
330
  const missing = cached ? allTexts.filter((t) => !cached.has(t)) : allTexts;
282
331
  if (missing.length > 0) {
@@ -284,13 +333,9 @@ var TranslationApplier = class {
284
333
  const map = cached ?? /* @__PURE__ */ new Map();
285
334
  for (const r of results) map.set(r.sourceText, r.translatedText);
286
335
  this.fetchedLanguages.set(targetLang, map);
336
+ writeCachedTranslations(this.projectId, targetLang, map);
287
337
  }
288
- const translations = this.fetchedLanguages.get(targetLang);
289
- for (const [sourceText, nodes] of this.groups) {
290
- const translated = translations.get(sourceText);
291
- if (translated === void 0) continue;
292
- for (const node of nodes) node.textContent = translated;
293
- }
338
+ this.paint(this.fetchedLanguages.get(targetLang));
294
339
  this.activeLang = targetLang;
295
340
  }
296
341
  restoreOriginal() {
@@ -602,10 +647,10 @@ var PathRouter = class {
602
647
  };
603
648
 
604
649
  // src/preference.ts
605
- var PREFIX = "dabalang:lang:";
650
+ var PREFIX2 = "dabalang:lang:";
606
651
  function readPreferredLanguage(projectId) {
607
652
  try {
608
- return window.localStorage.getItem(PREFIX + projectId);
653
+ return window.localStorage.getItem(PREFIX2 + projectId);
609
654
  } catch {
610
655
  return null;
611
656
  }
@@ -613,9 +658,9 @@ function readPreferredLanguage(projectId) {
613
658
  function writePreferredLanguage(projectId, langCode) {
614
659
  try {
615
660
  if (langCode === null) {
616
- window.localStorage.removeItem(PREFIX + projectId);
661
+ window.localStorage.removeItem(PREFIX2 + projectId);
617
662
  } else {
618
- window.localStorage.setItem(PREFIX + projectId, langCode);
663
+ window.localStorage.setItem(PREFIX2 + projectId, langCode);
619
664
  }
620
665
  } catch {
621
666
  }
@@ -1128,6 +1173,7 @@ function renderLanguageSwitcher(container, targetLanguages, sourceLang, onSelect
1128
1173
  let closing = false;
1129
1174
  const root = document.createElement("div");
1130
1175
  root.className = "dabalang-switcher-root";
1176
+ root.setAttribute(IGNORE_ATTR, "");
1131
1177
  const trigger = document.createElement("button");
1132
1178
  trigger.type = "button";
1133
1179
  trigger.className = "dabalang-trigger";
@@ -1185,6 +1231,7 @@ function renderLanguageSwitcher(container, targetLanguages, sourceLang, onSelect
1185
1231
  if (backdrop) return;
1186
1232
  const overlay = document.createElement("div");
1187
1233
  overlay.className = "dabalang-backdrop";
1234
+ overlay.setAttribute(IGNORE_ATTR, "");
1188
1235
  overlay.addEventListener("mousedown", (e) => {
1189
1236
  if (e.target === overlay) closeModal();
1190
1237
  });