@hkonda/loco-translate 1.1.4 → 1.1.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../server/routes/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG1C,wBAA8B,YAAY,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,iBAoEtF"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../server/routes/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAA8B,YAAY,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,iBAoEtF"}
@@ -1,4 +1,5 @@
1
1
  import { rawDb } from '../db/index.js';
2
+ import { buildLanguageNames } from '../utils/language-names.js';
2
3
  export default async function exportRoutes(app, opts) {
3
4
  app.get('/api/export', {
4
5
  schema: {
@@ -66,26 +67,21 @@ export default async function exportRoutes(app, opts) {
66
67
  return buildExportSingleLang(req.project, req.params.lang);
67
68
  });
68
69
  }
69
- function getLanguageNames(project) {
70
- let settingsLangs = [];
71
- try {
72
- settingsLangs = JSON.parse(project.settings || '{}').languages || [];
73
- }
74
- catch { }
75
- const languageNames = {};
76
- settingsLangs.forEach((l) => { if (l.code && l.name)
77
- languageNames[l.code] = l.name; });
78
- return languageNames;
79
- }
80
- function buildExport(project) {
70
+ // Static fallback display names for codes Intl may not resolve cleanly.
71
+ // All language display-name logic now lives in ../utils/language-names.ts.
72
+ // All languages that have at least one approved translation, sorted.
73
+ function getTranslatedLanguages(project) {
81
74
  const langRows = rawDb.prepare(`
82
75
  SELECT DISTINCT t.lang FROM translations t
83
76
  INNER JOIN textnodes k ON k.project_id = t.project_id AND k.key = t.key AND k.context = t.context
84
77
  WHERE t.project_id = ? AND k.status = 'approved'
85
78
  ORDER BY t.lang
86
79
  `).all(project.id);
87
- const languages = langRows.map(r => r.lang);
88
- const languageNames = getLanguageNames(project);
80
+ return langRows.map(r => r.lang);
81
+ }
82
+ function buildExport(project) {
83
+ const languages = getTranslatedLanguages(project);
84
+ const languageNames = buildLanguageNames(languages, project);
89
85
  const translations = {};
90
86
  const stmt = rawDb.prepare(`
91
87
  SELECT t.key, t.context, t.value FROM translations t
@@ -108,7 +104,13 @@ function buildExport(project) {
108
104
  return { languages, languageNames, translations, aria, timestamp: Date.now() };
109
105
  }
110
106
  function buildExportSingleLang(project, lang) {
111
- const languageNames = getLanguageNames(project);
107
+ // Advertise every language that has translations (with display names) so the
108
+ // switcher widget is complete even when only this per-language file is loaded.
109
+ const allLanguages = getTranslatedLanguages(project);
110
+ const languages = allLanguages.indexOf(lang) === -1
111
+ ? allLanguages.concat(lang)
112
+ : allLanguages;
113
+ const languageNames = buildLanguageNames(languages, project);
112
114
  const rows = rawDb.prepare(`
113
115
  SELECT t.key, t.context, t.value FROM translations t
114
116
  INNER JOIN textnodes k ON k.project_id = t.project_id AND k.key = t.key AND k.context = t.context
@@ -126,7 +128,7 @@ function buildExportSingleLang(project, lang) {
126
128
  return { key: r.key, context: r.context || '', attributes: attrs };
127
129
  });
128
130
  return {
129
- languages: [lang],
131
+ languages,
130
132
  languageNames,
131
133
  translations,
132
134
  aria,
@@ -1 +1 @@
1
- {"version":3,"file":"export.js","sourceRoot":"","sources":["../../server/routes/export.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB,EAAE,IAAsB;IAErF,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE;QACrB,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,OAAO,EAAE,mDAAmD;YAC5D,QAAQ,EAAE;gBACR,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;wBACvD,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;wBAC3E,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;wBAC5D,IAAI,EAAE;4BACJ,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE;gCACL,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACV,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;iCACzE;6BACF;yBACF;wBACD,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC9B;iBACF;aACF;SACF;KACF,EAAE,CAAC,GAAQ,EAAE,EAAE;QACd,OAAO,WAAW,CAAE,GAAW,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE;QAC3B,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,OAAO,EAAE,2CAA2C;YACpD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;gBACxC,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB;YACD,QAAQ,EAAE;gBACR,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;wBACvD,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;wBAC3E,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;wBAC5D,IAAI,EAAE;4BACJ,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE;gCACL,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACV,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;iCACzE;6BACF;yBACF;wBACD,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC9B;iBACF;aACF;SACF;KACF,EAAE,CAAC,GAAQ,EAAE,EAAE;QACd,OAAO,qBAAqB,CAAE,GAAW,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAY;IACpC,IAAI,aAAa,GAAU,EAAE,CAAC;IAC9B,IAAI,CAAC;QAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACtF,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,aAAa,CAAC,OAAO,CAAC,CAAC,CAAM,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI;QAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,WAAW,CAAC,OAAY;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC;;;;;GAK9B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAuB,CAAC;IACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEhD,MAAM,YAAY,GAA0B,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC;;;;GAI1B,CAAC,CAAC;IACH,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAsD,CAAC;QAC7F,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAC5B,+FAA+F,CAChG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAA2D,CAAC;IAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,IAAI,KAAK,GAA2B,EAAE,CAAC;QACvC,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;QACvF,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AACjF,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAY,EAAE,IAAY;IACvD,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC;;;;GAI1B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAsD,CAAC;IAE9E,MAAM,YAAY,GAA0B,EAAE,CAAC;IAC/C,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAE/F,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAC5B,+FAA+F,CAChG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAA2D,CAAC;IAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,IAAI,KAAK,GAA2B,EAAE,CAAC;QACvC,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;QACvF,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,SAAS,EAAE,CAAC,IAAI,CAAC;QACjB,aAAa;QACb,YAAY;QACZ,IAAI;QACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../server/routes/export.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../../server/routes/languages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG1C,wBAA8B,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,iBAgDzF"}
1
+ {"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../../server/routes/languages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAA8B,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,iBAgDzF"}
@@ -1,4 +1,5 @@
1
1
  import { rawDb } from '../db/index.js';
2
+ import { resolveDisplayName } from '../utils/language-names.js';
2
3
  export default async function languagesRoutes(app, opts) {
3
4
  app.get('/api/languages', {
4
5
  schema: {
@@ -27,24 +28,23 @@ export default async function languagesRoutes(app, opts) {
27
28
  settingsLangs = JSON.parse(project.settings || '{}').languages || [];
28
29
  }
29
30
  catch { }
30
- const nameMap = {};
31
- settingsLangs.forEach((l) => { if (l.code && l.name)
32
- nameMap[l.code] = l.name; });
33
- // Include both languages with translations AND languages from project settings
31
+ // Include both languages with translations AND languages from project settings.
32
+ // Display names prefer a configured name, then a derived one (Intl/static),
33
+ // so clients always get a label instead of a bare code.
34
34
  const seen = new Set();
35
35
  const result = [];
36
36
  // Settings languages first (configured)
37
37
  settingsLangs.forEach((l) => {
38
38
  if (l.code && !seen.has(l.code)) {
39
39
  seen.add(l.code);
40
- result.push({ code: l.code, name: l.name || l.code });
40
+ result.push({ code: l.code, name: resolveDisplayName(l.code, project) });
41
41
  }
42
42
  });
43
43
  // Then any from translations not already in settings
44
44
  rows.forEach(r => {
45
45
  if (!seen.has(r.lang)) {
46
46
  seen.add(r.lang);
47
- result.push({ code: r.lang, name: nameMap[r.lang] || r.lang });
47
+ result.push({ code: r.lang, name: resolveDisplayName(r.lang, project) });
48
48
  }
49
49
  });
50
50
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"languages.js","sourceRoot":"","sources":["../../server/routes/languages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,eAAe,CAAC,GAAoB,EAAE,IAAsB;IAExF,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE;QACxB,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,WAAW,CAAC;YACnB,OAAO,EAAE,yBAAyB;YAClC,QAAQ,EAAE;gBACR,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBACzB;qBACF;iBACF;aACF;SACF;KACF,EAAE,CAAC,GAAQ,EAAE,EAAE;QACd,MAAM,OAAO,GAAI,GAAW,CAAC,OAAO,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK;aACf,OAAO,CAAC,2EAA2E,CAAC;aACpF,GAAG,CAAC,OAAO,CAAC,EAAE,CAAuB,CAAC;QACzC,IAAI,aAAa,GAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACtF,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,aAAa,CAAC,OAAO,CAAC,CAAC,CAAM,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvF,+EAA+E;QAC/E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,MAAM,GAAqC,EAAE,CAAC;QACpD,wCAAwC;QACxC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAM,EAAE,EAAE;YAC/B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,qDAAqD;QACrD,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACf,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"languages.js","sourceRoot":"","sources":["../../server/routes/languages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,eAAe,CAAC,GAAoB,EAAE,IAAsB;IAExF,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE;QACxB,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,WAAW,CAAC;YACnB,OAAO,EAAE,yBAAyB;YAClC,QAAQ,EAAE;gBACR,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBACzB;qBACF;iBACF;aACF;SACF;KACF,EAAE,CAAC,GAAQ,EAAE,EAAE;QACd,MAAM,OAAO,GAAI,GAAW,CAAC,OAAO,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK;aACf,OAAO,CAAC,2EAA2E,CAAC;aACpF,GAAG,CAAC,OAAO,CAAC,EAAE,CAAuB,CAAC;QACzC,IAAI,aAAa,GAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEtF,gFAAgF;QAChF,4EAA4E;QAC5E,wDAAwD;QACxD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,MAAM,GAAqC,EAAE,CAAC;QACpD,wCAAwC;QACxC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAM,EAAE,EAAE;YAC/B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC,CAAC,CAAC;QACH,qDAAqD;QACrD,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACf,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function deriveDisplayName(code: string): string;
2
+ export declare function getConfiguredNames(project: any): Record<string, string>;
3
+ export declare function buildLanguageNames(codes: string[], project: any): Record<string, string>;
4
+ export declare function resolveDisplayName(code: string, project: any): string;
5
+ //# sourceMappingURL=language-names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-names.d.ts","sourceRoot":"","sources":["../../server/utils/language-names.ts"],"names":[],"mappings":"AAkBA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAStD;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQvE;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxF;AAGD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,CAGrE"}
@@ -0,0 +1,62 @@
1
+ // ─────────────────────────────────────────────
2
+ // Shared language display-name helpers
3
+ //
4
+ // Ensures every language code carries a human-readable display name so that
5
+ // offline / file-mode clients (and the dashboard) never have to fall back to
6
+ // showing a bare code. Prefers names configured in project settings, then
7
+ // derives one from Intl.DisplayNames (Node ships full ICU) with a small static
8
+ // map for codes Intl renders differently than we want.
9
+ // ─────────────────────────────────────────────
10
+ // Codes where we prefer a specific label over Intl's default rendering.
11
+ const STATIC_LANGUAGE_NAMES = {
12
+ 'zh-Hans': 'Chinese (Simplified)',
13
+ 'zh-Hant': 'Chinese (Traditional)',
14
+ };
15
+ // Derive a human-readable display name for a language code. Returns '' when no
16
+ // better-than-the-code name can be found.
17
+ export function deriveDisplayName(code) {
18
+ if (!code)
19
+ return '';
20
+ if (STATIC_LANGUAGE_NAMES[code])
21
+ return STATIC_LANGUAGE_NAMES[code];
22
+ try {
23
+ const dn = new Intl.DisplayNames(['en'], { type: 'language' });
24
+ const label = dn.of(code);
25
+ if (label && label !== code)
26
+ return label;
27
+ }
28
+ catch { /* Intl unavailable or invalid code */ }
29
+ return '';
30
+ }
31
+ // Names explicitly configured in project settings (only when a real name is set).
32
+ export function getConfiguredNames(project) {
33
+ let settingsLangs = [];
34
+ try {
35
+ settingsLangs = JSON.parse(project.settings || '{}').languages || [];
36
+ }
37
+ catch { /* ignore */ }
38
+ const names = {};
39
+ settingsLangs.forEach((l) => {
40
+ if (l.code && l.name && l.name !== l.code)
41
+ names[l.code] = l.name;
42
+ });
43
+ return names;
44
+ }
45
+ // Build a complete code -> display name map for the given codes, preferring
46
+ // configured names then derived names.
47
+ export function buildLanguageNames(codes, project) {
48
+ const configured = getConfiguredNames(project);
49
+ const languageNames = {};
50
+ for (const code of codes) {
51
+ const name = configured[code] || deriveDisplayName(code);
52
+ if (name)
53
+ languageNames[code] = name;
54
+ }
55
+ return languageNames;
56
+ }
57
+ // Resolve the single best display name for one code (configured → derived → code).
58
+ export function resolveDisplayName(code, project) {
59
+ const configured = getConfiguredNames(project);
60
+ return configured[code] || deriveDisplayName(code) || code;
61
+ }
62
+ //# sourceMappingURL=language-names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-names.js","sourceRoot":"","sources":["../../server/utils/language-names.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,0EAA0E;AAC1E,+EAA+E;AAC/E,uDAAuD;AACvD,gDAAgD;AAEhD,wEAAwE;AACxE,MAAM,qBAAqB,GAA2B;IACpD,SAAS,EAAE,sBAAsB;IACjC,SAAS,EAAE,uBAAuB;CACnC,CAAC;AAEF,+EAA+E;AAC/E,0CAA0C;AAC1C,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,IAAI,qBAAqB,CAAC,IAAI,CAAC;QAAE,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC,CAAC,sCAAsC,CAAC,CAAC;IAClD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,OAAY;IAC7C,IAAI,aAAa,GAAU,EAAE,CAAC;IAC9B,IAAI,CAAC;QAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACpG,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAM,EAAE,EAAE;QAC/B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;YAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACpE,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4EAA4E;AAC5E,uCAAuC;AACvC,MAAM,UAAU,kBAAkB,CAAC,KAAe,EAAE,OAAY;IAC9D,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvC,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,OAAY;IAC3D,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAC7D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkonda/loco-translate",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Self-hosted translation manager — auto-discovers text, AI translations, Svelte dashboard, CDN client.",
5
5
  "type": "module",
6
6
  "bin": {
package/public/loco.js CHANGED
@@ -1718,7 +1718,7 @@ var Loco = function() {
1718
1718
  }
1719
1719
  return parts.join("-");
1720
1720
  }
1721
- function inferLanguageName(code) {
1721
+ function inferLanguageName2(code) {
1722
1722
  var canonical = canonicalizeCode(code);
1723
1723
  if (!canonical) return "";
1724
1724
  if (FALLBACK_LANGUAGE_NAMES[canonical]) return FALLBACK_LANGUAGE_NAMES[canonical];
@@ -1742,7 +1742,7 @@ var Loco = function() {
1742
1742
  if (direct && !isSameAsCode(direct, code)) return direct;
1743
1743
  var canonical = canonicalizeCode(code);
1744
1744
  if (FALLBACK_LANGUAGE_NAMES[canonical]) return FALLBACK_LANGUAGE_NAMES[canonical];
1745
- return inferLanguageName(code) || code;
1745
+ return inferLanguageName2(code) || code;
1746
1746
  }
1747
1747
  var currentLang = getSavedLang() || null;
1748
1748
  var container = document.createElement("div");
@@ -2241,8 +2241,41 @@ var Loco = function() {
2241
2241
  }).catch(function() {
2242
2242
  });
2243
2243
  }
2244
+ var STATIC_LANGUAGE_NAMES = {
2245
+ "zh-Hans": "Chinese (Simplified)",
2246
+ "zh-Hant": "Chinese (Traditional)"
2247
+ };
2248
+ function canonicalizeLangCode(code) {
2249
+ var normalized = String(code || "").trim().replace(/_/g, "-");
2250
+ if (!normalized) return "";
2251
+ var parts = normalized.split("-").filter(Boolean);
2252
+ if (parts.length === 0) return "";
2253
+ parts[0] = parts[0].toLowerCase();
2254
+ for (var i = 1; i < parts.length; i++) {
2255
+ if (parts[i].length === 2) parts[i] = parts[i].toUpperCase();
2256
+ else if (parts[i].length === 4) parts[i] = parts[i].charAt(0).toUpperCase() + parts[i].slice(1).toLowerCase();
2257
+ else parts[i] = parts[i].toLowerCase();
2258
+ }
2259
+ return parts.join("-");
2260
+ }
2261
+ function inferLanguageName(code) {
2262
+ var canonical = canonicalizeLangCode(code);
2263
+ if (!canonical) return "";
2264
+ if (STATIC_LANGUAGE_NAMES[canonical]) return STATIC_LANGUAGE_NAMES[canonical];
2265
+ if (canonical.indexOf("-") === -1) return "";
2266
+ try {
2267
+ if (typeof Intl !== "undefined" && typeof Intl.DisplayNames === "function") {
2268
+ var dn = new Intl.DisplayNames([typeof navigator !== "undefined" && navigator.language || "en", "en"], { type: "language" });
2269
+ var label = dn.of(canonical);
2270
+ if (label && label !== canonical) return label;
2271
+ }
2272
+ } catch (e) {
2273
+ }
2274
+ return "";
2275
+ }
2244
2276
  function resolveLanguageName(code, languageNames) {
2245
- if (!code || !languageNames) return "";
2277
+ if (!code) return "";
2278
+ languageNames = languageNames || {};
2246
2279
  var direct = languageNames[code];
2247
2280
  if (direct) return direct;
2248
2281
  var normalized = String(code).replace(/_/g, "-");
@@ -2256,7 +2289,7 @@ var Loco = function() {
2256
2289
  return part;
2257
2290
  }).join("-");
2258
2291
  if (languageNames[title]) return languageNames[title];
2259
- return "";
2292
+ return inferLanguageName(code);
2260
2293
  }
2261
2294
  function buildWidgetLangs(languages, languageNames) {
2262
2295
  languages = languages || [];
@@ -2284,7 +2317,7 @@ var Loco = function() {
2284
2317
  var Loco2 = {
2285
2318
  // Version is injected by Vite at build time from versions.json.
2286
2319
  // In-browser: Loco.version → e.g. "1.0.8"
2287
- version: "1.1.4",
2320
+ version: "1.1.5",
2288
2321
  init: function(config) {
2289
2322
  if (!config) {
2290
2323
  console.warn("[loco] Loco.init() requires a config object");
@@ -2508,7 +2541,7 @@ var Loco = function() {
2508
2541
  var codes = state.fileData ? state.fileData.languages || [] : [];
2509
2542
  var names = state.fileData && state.fileData.languageNames || {};
2510
2543
  return codes.map(function(c) {
2511
- return { code: c, name: names[c] || c };
2544
+ return { code: c, name: resolveLanguageName(c, names) || c };
2512
2545
  });
2513
2546
  };
2514
2547
  if (!state.fileData && state.fileReady) {
@@ -2540,7 +2573,14 @@ var Loco = function() {
2540
2573
  }).then(function(r) {
2541
2574
  return r.json();
2542
2575
  }).then(function(langs) {
2543
- return Array.isArray(langs) ? langs : [];
2576
+ if (!Array.isArray(langs)) return [];
2577
+ return langs.map(function(l) {
2578
+ if (l && typeof l === "object" && l.code) {
2579
+ var name = l.name && l.name !== l.code ? l.name : inferLanguageName(l.code);
2580
+ return { code: l.code, name: name || l.code };
2581
+ }
2582
+ return l;
2583
+ });
2544
2584
  }).catch(function() {
2545
2585
  return [];
2546
2586
  });
@@ -1,4 +1,4 @@
1
- var Loco=function(){"use strict";var i={apiKey:null,apiBase:null,phrases:[],currentLang:null,translations:{},observer:null,fileMode:!1,fileData:null,fileReadyResolve:null,fileReady:null,fileUrl:null,fileUrls:[],scanStopped:!1,loadedFromCache:!1,screenshotsEnabled:!0,widgetPosition:null,ariaRules:{}},Fe=["SCRIPT","STYLE","NOSCRIPT","IFRAME","CODE","SVG","AUDIO","VIDEO","LINK"],Re=["VAR","STRONG","EM","B","I","SPAN","A","ABBR","MARK","SMALL","SUB","SUP","U","S","TIME"],Pe=["h1","h2","h3","h4","h5","h6","label","legend","caption","figcaption","nav","header","footer","main","section","article","form"],_=new Set(Fe),W=new Set(Re),we=[].concat(Pe),Ne=0,Te=!0,B=1e3,Z=1e4,Ae="loco-lang";function Y(){try{return localStorage.getItem(Ae)}catch{return null}}function le(e){try{e?localStorage.setItem(Ae,e):localStorage.removeItem(Ae)}catch{}}function Je(e){if(e.blockedTags){var n=e.blockedTags.disabled||[],t=e.blockedTags.custom||[];_=new Set(Fe.filter(function(a){return n.indexOf(a)<0})),t.forEach(function(a){_.add(a.toUpperCase())})}if(e.inlineTags){var n=e.inlineTags.disabled||[],t=e.inlineTags.custom||[];W=new Set(Re.filter(function(o){return n.indexOf(o)<0})),t.forEach(function(o){W.add(o.toUpperCase())})}if(e.domContextSelectors){var n=e.domContextSelectors.disabled||[],t=e.domContextSelectors.custom||[];we=Pe.filter(function(o){return n.indexOf(o)<0}).concat(t)}e.screenshotsEnabled===!1&&(i.screenshotsEnabled=!1),typeof e.contextDepth=="number"&&(Ne=e.contextDepth),e.domContextEnabled===!1&&(Te=!1)}function L(e){return e.trim().replace(/\s+/g," ")}function A(e){return!/[a-zA-Z\u00C0-\u024F\u0900-\u097F\u0600-\u06FF]/.test(e)}function se(e){var n=e.replace(/\{\{(?:text|number|decimal|date):\d+\}\}/g,"");return!n.trim()||A(n)}function De(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ee(e){var t;if(!e||e.nodeType!==1)return!1;const n=(t=e.tagName)==null?void 0:t.toUpperCase();return _.has(n)||e.hasAttribute("notranslate")||e.hasAttribute("data-notranslate")||e.hasAttribute("data-loco-translated")||e.getAttribute("translate")==="no"||e.isContentEditable}var X=new WeakMap;function Ie(e){let n=e.parentElement;for(;n&&n!==document.body;){if(X.has(n))return X.get(n);if(ee(n))return X.set(n,!0),!0;n=n.parentElement}for(n=e.parentElement;n&&n!==document.body&&!X.has(n);)X.set(n,!1),n=n.parentElement;return!1}function Ze(){X=new WeakMap}const _e=new Set(["H1","H2","H3","H4","H5","H6"]),Ye=new Set(["SCRIPT","STYLE","NOSCRIPT","CODE"]);let Q=new WeakMap,$=new WeakMap,q=null;function Le(){if(Te){q=new Set;var e=we.slice();try{var n=e.join(",");document.querySelectorAll(n).forEach(function(t){q.add(t)})}catch{e.forEach(function(a){try{document.querySelectorAll(a).forEach(function(r){q.add(r)})}catch{}})}q.forEach(function(t){$.has(t)||ne(t)})}}function te(e){return q?q.has(e):_e.has(e.tagName)?!0:we.some(function(n){try{return e.matches(n)}catch{return!1}})}function et(e){let n="";for(const t of e.childNodes)if(t.nodeType===Node.TEXT_NODE){const a=t.textContent.trim();a&&(n+=(n?" ":"")+a)}return n}function tt(e,n){for(var t="",a=document.createTreeWalker(e,NodeFilter.SHOW_ALL,{acceptNode:function(o){return o.nodeType===Node.ELEMENT_NODE?Ye.has(o.tagName)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_SKIP:NodeFilter.FILTER_ACCEPT}}),r;(r=a.nextNode())&&!(r.nodeType===Node.TEXT_NODE&&(t+=r.textContent,t.length>=n)););return t.trim()}function ne(e){if($.has(e))return $.get(e);let n=null;const t=et(e);if(t)return n=t.substring(0,60),$.set(e,n),n;if(_e.has(e.tagName)){const r=(e.textContent||"").trim().replace(/\s+/g," ");if(r)return n=r.substring(0,60),$.set(e,n),n}var a=tt(e,200);if(a){const r=a.split(/\n/)[0].trim().replace(/\s+/g," ");r.length>=2&&!A(r)&&(n=r.substring(0,60))}return $.set(e,n),n}function k(e){if(!e||!Te)return"";if(Q.has(e))return Q.get(e);var n=e.parentElement;if(n&&n!==document.body&&Q.has(n)&&!te(e)){var t=Q.get(n);return Q.set(e,t),t}const a=[],r=new Set;let o=e,l=0;if(e&&e.tagName==="TD"){var v=e.closest("table");if(v){var p=v.querySelector("thead tr th:nth-child("+(e.cellIndex+1)+")");if(p){var s=ne(p);s&&(r.add(s),a.push(s))}}}for(;o&&o!==document.body&&!(Ne>0&&l>=Ne);){l++;let c=o.previousElementSibling;for(;c;){var f=c.tagName.toUpperCase();if(_.has(f)){c=c.previousElementSibling;continue}if(f==="ARTICLE"||f==="MAIN"){c=c.previousElementSibling;continue}if(te(c)){const d=ne(c);d&&!r.has(d)&&(r.add(d),a.unshift(d));break}let u=null;for(const d of c.children)if(te(d)){u=d;break}if(!u)for(const d of c.children){for(const m of d.children)if(te(m)){u=m;break}if(u)break}if(u){const d=ne(u);d&&!r.has(d)&&(r.add(d),a.unshift(d));break}c=c.previousElementSibling}if(te(o)){const u=ne(o);u&&!r.has(u)&&(r.add(u),a.unshift(u))}var h=o.tagName;if(h==="ARTICLE"||h==="MAIN")break;o=o.parentElement}const g=a.join(" > ");return Q.set(e,g),g}function nt(e){return/^\d+$/.test(e)?"number":/^\d+\.\d+$/.test(e)?"decimal":"text"}function rt(e,n){for(var t=n.split(/(\{\{(?:text|number|decimal|date):\d+\}\})/),a=[],r=e,o=0;o<t.length;o++){var l=t[o],v=l.match(/^\{\{(text|number|decimal|date):(\d+)\}\}$/);if(v)if(r.indexOf(l)===0)a.push({type:v[1],index:parseInt(v[2]),originalText:l}),r=r.substring(l.length);else{for(var p="",s=o+1;s<t.length;s++){var f=t[s];if(/^\{\{(?:text|number|decimal|date):\d+\}\}$/.test(f)){if(r.indexOf(f)>=0){p=f;break}}else if(f!==""){p=f;break}}var h;if(p==="")h=r,r="";else{var g=r.indexOf(p);g>=0?(h=r.substring(0,g),r=r.substring(g)):(h=r,r="")}a.push({type:v[1],index:parseInt(v[2]),originalText:h})}else r.indexOf(l)===0&&(r=r.substring(l.length))}return a}function ce(e,n){e.forEach(function(t){if(!(t.varSlots&&t.varSlots.length>0)){var a=n[t.key];a&&(t.varSlots=rt(t.key,a),t.key=a)}})}function at(e,n){for(var t=n.split(/\{\{(?:text|number|decimal|date):\d+\}\}/g),a=e,r=[],o=0;o<t.length;o++)if(o===0)a.indexOf(t[o])===0&&(a=a.substring(t[o].length));else if(t[o]===""&&o===t.length-1)r.push(a),a="";else{var l=a.indexOf(t[o]);l>=0&&(r.push(a.substring(0,l)),a=a.substring(l+t[o].length))}return r.length>0&&r.every(function(v){return/^[a-zA-Z\s]+$/.test(v.trim())})}function it(e){for(var n=0,t=/\{\{(text|number|decimal|date):\d+\}\}/g,a;(a=t.exec(e))!==null;)switch(a[1]){case"number":n+=3;break;case"decimal":n+=3;break;case"date":n+=2;break;default:n+=1;break}return n}function G(e,n){for(var t=[],a=0;a<n.length;a++){var r=n[a];if(!(r.indexOf("{{text:")<0&&r.indexOf("{{number:")<0&&r.indexOf("{{decimal:")<0&&r.indexOf("{{date:")<0)){for(var o=[],l=[],v=0,p=/\{\{(text|number|decimal|date):\d+\}\}/g,s;(s=p.exec(r))!==null;)o.push(r.substring(v,s.index)),l.push(s[1]),v=p.lastIndex;o.push(r.substring(v));for(var f="",h=0;h<o.length;h++)if(f+=o[h].replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),h<l.length)switch(l[h]){case"number":f+="\\d+";break;case"decimal":f+="\\d+\\.\\d+";break;default:f+=".+";break}t.push({pattern:r,regex:new RegExp("^"+f+"$"),specificity:it(r)})}}if(t.length!==0){t.sort(function(u,d){return d.specificity-u.specificity});for(var g={},c={},a=0;a<n.length;a++)c[n[a]]=!0;return e.forEach(function(u){if(!c[u.key]&&!(u.key.length>B)){for(var d=0;d<t.length;d++)if(t[d].regex.test(u.key)&&!at(u.key,t[d].pattern)){g[u.key]=t[d].pattern;break}}}),ce(e,g),g}}var re=new WeakMap;function M(e){if(re.has(e))return re.get(e);let n=!1,t=!1;for(const r of e.childNodes)if(r.nodeType===Node.TEXT_NODE&&r.textContent.trim()&&(n=!0),r.nodeType===Node.ELEMENT_NODE){const o=r.tagName.toUpperCase();if(o==="BR")return re.set(e,!1),!1;(o==="VAR"||o==="TIME"&&r.hasAttribute("datetime")||W.has(o))&&(t=!0)}var a=n&&t;return re.set(e,a),a}function ot(){re=new WeakMap}function ue(e){let n="";const t=[];for(const a of e.childNodes){if(a.nodeType===Node.TEXT_NODE){const r=L(a.textContent);r&&(n+=r);continue}if(a.nodeType===Node.ELEMENT_NODE){const r=a.tagName.toUpperCase();if(r==="TIME"&&a.hasAttribute("datetime")){const o=t.length;t.push({type:"date",index:o,raw:a.getAttribute("datetime"),display:a.textContent,node:a}),n+=`{{date:${o}}}`;continue}if(r==="VAR"||W.has(r)){const o=L(a.textContent);if(o){const l=t.length,v=nt(o);t.push({type:v,index:l,tag:r,value:o,node:a}),n+=`{{${v}:${l}}}`}continue}}}return{key:L(n),slots:t}}var fe=["title","placeholder","aria-label"];function Me(e){const n=[],t=new Set;if(e.nodeType===Node.ELEMENT_NODE&&!ee(e)&&M(e)){const{key:s,slots:f}=ue(e);if(s&&s.length<=B)if(se(s))f.forEach(function(h){if(h.type==="text"&&h.value&&h.value.length>=2&&!A(h.value)){var g=k(h.node||e),c=h.value+"\0"+g;t.has(c)||(t.add(c),n.push({type:"text",key:h.value,slots:[],textNode:h.node?h.node.firstChild:null,element:h.node||e,context:g,original:h.value}))}});else{var a=k(e),r=s+"\0"+a;t.has(r)||t.add(r);const h=f.some(g=>g.type==="date")?"mixed-date":f.some(g=>g.type==="text")?"mixed-text":"mixed";n.push({type:h,key:s,slots:f,element:e,context:a,original:s,originalHTML:e.innerHTML})}}const o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode(s){var m,x,b;if(s.nodeType===Node.TEXT_NODE){const w=L(s.textContent);if(!w||w.length<2||w.length>B||A(w)||/\{\{(?:text|number|decimal|date):\d+\}\}/.test(w)||Ie(s))return NodeFilter.FILTER_SKIP;const y=(x=(m=s.parentElement)==null?void 0:m.tagName)==null?void 0:x.toUpperCase();if(_.has(y)||M(s.parentElement))return NodeFilter.FILTER_SKIP;for(var f=s.parentElement,h=0;f&&h<3;){var g=(b=f.tagName)==null?void 0:b.toUpperCase();if((g==="VAR"||g==="TIME"||W.has(g))&&f.parentElement&&M(f.parentElement))return NodeFilter.FILTER_SKIP;f=f.parentElement,h++}return NodeFilter.FILTER_ACCEPT}if(s.nodeType===Node.ELEMENT_NODE){const w=s.tagName.toUpperCase();if(_.has(w)||ee(s))return NodeFilter.FILTER_REJECT;if(w==="INPUT"){var c=(s.getAttribute("type")||"").toLowerCase();if(c==="button"||c==="submit"||c==="reset"){var u=L(s.value);if(u&&u.length>=2&&!A(u))return NodeFilter.FILTER_ACCEPT}var d=fe.some(function(y){var E=L(s.getAttribute(y)||"");return E&&E.length>=2&&!A(E)});return d?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return M(s)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return NodeFilter.FILTER_SKIP}});let l;for(;l=o.nextNode();){if(l.nodeType===Node.TEXT_NODE){const s=L(l.textContent);if(!s)continue;var a=k(l.parentElement),r=s+"\0"+a;t.has(r)||t.add(r),n.push({type:"text",key:s,slots:[],textNode:l,element:l.parentElement,context:a,original:s});continue}if(l.nodeType===Node.ELEMENT_NODE&&l.tagName.toUpperCase()==="INPUT"){var v=(l.getAttribute("type")||"").toLowerCase(),a=k(l);if(v==="button"||v==="submit"||v==="reset"){var p=L(l.value);if(p&&p.length>=2&&!A(p)){var r=p+"\0"+a;t.has(r)||t.add(r),n.push({type:"input-value",key:p,slots:[],element:l,context:a,original:p})}}fe.forEach(function(f){var h=L(l.getAttribute(f)||"");if(!(!h||h.length<2||A(h))){var g=h+"\0"+a+"\0"+f;t.has(g)||(t.add(g),n.push({type:"input-attr",key:h,attr:f,slots:[],element:l,context:a,original:h}))}});continue}if(l.nodeType===Node.ELEMENT_NODE){const{key:s,slots:f}=ue(l);if(!s||s.length>B)continue;if(se(s)){f.forEach(function(u){if(u.type==="text"&&u.value&&u.value.length>=2&&!A(u.value)){var d=k(u.node||l),m=u.value+"\0"+d;t.has(m)||(t.add(m),n.push({type:"text",key:u.value,slots:[],textNode:u.node?u.node.firstChild:null,element:u.node||l,context:d,original:u.value}))}});continue}var a=k(l),r=s+"\0"+a;t.has(r)||t.add(r);const c=f.some(u=>u.type==="date")?"mixed-date":f.some(u=>u.type==="text")?"mixed-text":"mixed";n.push({type:c,key:s,slots:f,element:l,context:a,original:s,originalHTML:l.innerHTML})}}return n}async function ae(e,n){n||(n=100);const t=[],a=new Set;if(Ze(),ot(),Le(),e.nodeType===Node.ELEMENT_NODE&&!ee(e)&&M(e)){const{key:c,slots:u}=ue(e);if(c&&c.length<=B)if(se(c))u.forEach(function(d){if(d.type==="text"&&d.value&&d.value.length>=2&&!A(d.value)){var m=k(d.node||e),x=d.value+"\0"+m;a.has(x)||(a.add(x),t.push({type:"text",key:d.value,slots:[],textNode:d.node?d.node.firstChild:null,element:d.node||e,context:m,original:d.value}))}});else{var r=k(e),o=c+"\0"+r;a.has(o)||a.add(o);const d=u.some(m=>m.type==="date")?"mixed-date":u.some(m=>m.type==="text")?"mixed-text":"mixed";t.push({type:d,key:c,slots:u,element:e,context:r,original:c,originalHTML:e.innerHTML})}}const l=[],v=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode(c){var y,E,T;if(c.nodeType===Node.TEXT_NODE){const N=L(c.textContent);if(!N||N.length<2||N.length>B||A(N)||/\{\{(?:text|number|decimal|date):\d+\}\}/.test(N)||Ie(c))return NodeFilter.FILTER_SKIP;const S=(E=(y=c.parentElement)==null?void 0:y.tagName)==null?void 0:E.toUpperCase();if(_.has(S)||M(c.parentElement))return NodeFilter.FILTER_SKIP;for(var u=c.parentElement,d=0;u&&d<3;){var m=(T=u.tagName)==null?void 0:T.toUpperCase();if((m==="VAR"||m==="TIME"||W.has(m))&&u.parentElement&&M(u.parentElement))return NodeFilter.FILTER_SKIP;u=u.parentElement,d++}return NodeFilter.FILTER_ACCEPT}if(c.nodeType===Node.ELEMENT_NODE){const N=c.tagName.toUpperCase();if(_.has(N)||ee(c))return NodeFilter.FILTER_REJECT;if(N==="INPUT"){var x=(c.getAttribute("type")||"").toLowerCase();if(x==="button"||x==="submit"||x==="reset"){var b=L(c.value);if(b&&b.length>=2&&!A(b))return NodeFilter.FILTER_ACCEPT}var w=fe.some(function(S){var O=L(c.getAttribute(S)||"");return O&&O.length>=2&&!A(O)});return w?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return M(c)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return NodeFilter.FILTER_SKIP}});for(var p;p=v.nextNode();)l.push(p);for(var s=0;s<l.length;s++){s>0&&s%n===0&&await new Promise(function(c){setTimeout(c,0)});var f=l[s];if(f.nodeType===Node.TEXT_NODE){const c=L(f.textContent);if(!c)continue;var r=k(f.parentElement),o=c+"\0"+r;a.has(o)||a.add(o),t.push({type:"text",key:c,slots:[],textNode:f,element:f.parentElement,context:r,original:c});continue}if(f.nodeType===Node.ELEMENT_NODE&&f.tagName.toUpperCase()==="INPUT"){var h=(f.getAttribute("type")||"").toLowerCase(),r=k(f);if(h==="button"||h==="submit"||h==="reset"){var g=L(f.value);if(g&&g.length>=2&&!A(g)){var o=g+"\0"+r;a.has(o)||a.add(o),t.push({type:"input-value",key:g,slots:[],element:f,context:r,original:g})}}fe.forEach(function(u){var d=L(f.getAttribute(u)||"");if(!(!d||d.length<2||A(d))){var m=d+"\0"+r+"\0"+u;a.has(m)||(a.add(m),t.push({type:"input-attr",key:d,attr:u,slots:[],element:f,context:r,original:d}))}});continue}if(f.nodeType===Node.ELEMENT_NODE){const{key:c,slots:u}=ue(f);if(!c||c.length>B)continue;if(se(c)){u.forEach(function(b){if(b.type==="text"&&b.value&&b.value.length>=2&&!A(b.value)){var w=k(b.node||f),y=b.value+"\0"+w;a.has(y)||(a.add(y),t.push({type:"text",key:b.value,slots:[],textNode:b.node?b.node.firstChild:null,element:b.node||f,context:w,original:b.value}))}});continue}var r=k(f),o=c+"\0"+r;a.has(o)||a.add(o);const x=u.some(b=>b.type==="date")?"mixed-date":u.some(b=>b.type==="text")?"mixed-text":"mixed";t.push({type:x,key:c,slots:u,element:f,context:r,original:c,originalHTML:f.innerHTML})}}return t}function de(e){if(i.scanStopped)return Promise.resolve({ok:!0,registered:0,keyMap:{}});var n=new Set,t=[];return e.forEach(function(a){var r=a.key+"\0"+(a.context||"");n.has(r)||a.varSlots&&a.varSlots.length>0&&/\{\{(?:text|number|decimal|date):\d+\}\}/.test(a.key)||(n.add(r),t.push({key:a.key,context:a.context||""}),a.slots&&a.slots.length>0&&a.slots.forEach(function(o){if(o.type==="text"&&o.value&&!A(o.value)){var l=o.value+"\0";n.has(l)||(n.add(l),t.push({key:o.value,context:""}))}}))}),fetch(i.apiBase+"/api/textnodes",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":i.apiKey},body:JSON.stringify({keys:t,url:window.location.href})}).then(function(a){return a.json()})}function lt(e){var n=i.apiBase+"/api/translations?lang="+encodeURIComponent(e);return fetch(n,{headers:{"X-API-Key":i.apiKey}}).then(function(t){return t.json()}).then(function(t){var a={};return Array.isArray(t)?t.forEach(function(r){a[r.key+"\0"+(r.context||"")]=r.value,a.hasOwnProperty(r.key)||(a[r.key]=r.value)}):a=t,a})}function st(){if(!(i.fileMode||!i.screenshotsEnabled)){var e=document.createElement("script");e.src=i.apiBase+"/cdn/html2canvas.min.js",e.onload=function(){typeof html2canvas=="function"&&html2canvas(document.body,{scale:.35,logging:!1,useCORS:!0,allowTaint:!0,width:window.innerWidth,height:window.innerHeight,windowWidth:window.innerWidth,windowHeight:window.innerHeight}).then(function(n){var t=n.toDataURL("image/jpeg",.5),a=t.split(",")[1];!a||a.length>5e5||fetch(i.apiBase+"/api/screenshots",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":i.apiKey},body:JSON.stringify({url:window.location.href,screenshot:a})}).catch(function(){})}).catch(function(){})},e.onerror=function(){},document.head.appendChild(e)}}function ct(e,n){return e.replace(/\{\{(text|number|decimal|date):(\d+)\}\}/g,(t,a,r)=>{const o=n[parseInt(r)];return o?a==="date"?o.display:o.value:t})}function Ke(e){if(!Array.isArray(e))return e;var n={};return e.forEach(function(t){n[t.key+"\0"+(t.context||"")]=t.value,n.hasOwnProperty(t.key)||(n[t.key]=t.value)}),n}function ke(e,n){let t=0,a=0;return e.forEach(r=>{const o=r.key+"\0"+(r.context||"");var l=n[o]||n[r.key];if(!l&&r.slots&&r.slots.length>0){var v=r.slots.some(function(h){if(h.type!=="text"||!h.value)return!1;var g=h.value+"\0"+(r.context||""),c=h.value+"\0";return n.hasOwnProperty(g)||n.hasOwnProperty(c)||n.hasOwnProperty(h.value)});v&&(l=r.key)}if(!l){a++;return}if(r.type==="input-value"&&r.element)try{r.element.value=l,r.element.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to input value",h),a++;return}if(r.type==="input-attr"&&r.element&&r.attr)try{r.element.setAttribute(r.attr,l),r.element.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to input attr",h),a++;return}if(r.type==="text"&&r.textNode)try{var p=l;r.varSlots&&r.varSlots.length>0&&(p=p.replace(/\{\{(text|number|decimal|date):(\d+)\}\}/g,function(h,g,c){var u=r.varSlots.find(function(d){return(d.type||"text")===g&&d.index===+c});return u||(u=r.varSlots[+c]),u?u.originalText:h})),p=p.replace(/\{\{(?:text|number|decimal|date):\d+\}\}/g,""),r.textNode.nodeValue=p,r.textNode.parentElement&&r.textNode.parentElement.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to text node",h),a++;return}if(r.element){try{const h=ct(l,r.slots);let g=l;var s={};r.slots.forEach(c=>{const u=`{{${c.type}:${c.index}}}`;if(c.type==="date"&&c.node)c.node.textContent=c.display,s[u]=c.node.outerHTML;else if(c.node){if(c.type==="text"&&c.value){var d=c.value+"\0"+(r.context||""),m=c.value+"\0",x=n[d]||n[m]||n[c.value];x&&(c.node.textContent=x)}s[u]=c.node.outerHTML}}),r.varSlots&&r.varSlots.length>0&&r.varSlots.forEach(function(c){var u="{{"+c.type+":"+c.index+"}}";s.hasOwnProperty(u)||(s[u]=De(c.originalText))});var f=g.split(/(\{\{(?:text|number|decimal|date):\d+\}\})/g);g=f.map(function(c){return s.hasOwnProperty(c)?s[c]:/^\{\{(?:text|number|decimal|date):\d+\}\}$/.test(c)?"":De(c)}).join(""),r.element.innerHTML=g,r.element.setAttribute("data-loco-translated",""),t++}catch(h){console.warn("[translate] Could not apply mixed translation",h),a++}return}a++}),{applied:t,skipped:a}}async function he(e,n,t){t||(t=100);for(var a=0,r=0,o=performance.now(),l=0;l<e.length;l+=t){l>0&&performance.now()-o>16&&(await new Promise(function(s){requestAnimationFrame(s)}),o=performance.now());var v=e.slice(l,l+t),p=ke(v,n);a+=p.applied,r+=p.skipped}return{applied:a,skipped:r}}function j(e){let n=0;e.forEach(t=>{try{t.type==="input-value"&&t.element?(t.element.value=t.original,t.element.removeAttribute("data-loco-translated"),n++):t.type==="input-attr"&&t.element&&t.attr?(t.element.setAttribute(t.attr,t.original),t.element.removeAttribute("data-loco-translated"),n++):t.type==="text"&&t.textNode&&(t.textNode.nodeValue=t.original,t.textNode.parentElement&&t.textNode.parentElement.removeAttribute("data-loco-translated"),n++)}catch(a){console.warn("[translate] Could not restore text node",a)}}),e.forEach(t=>{if(t.type!=="text")try{t.element&&t.originalHTML!==void 0&&(t.element.innerHTML=t.originalHTML,t.element.removeAttribute("data-loco-translated"),n++)}catch(a){console.warn("[translate] Could not restore node",a)}}),console.log("[loco] untranslated "+n+" phrase(s)")}function pe(e,n){const t=new Set(e),a=[];Object.values(n).forEach(function(u){if(u&&(t.add(u),/\{\{(text|number|decimal|date):\d+\}\}/.test(u))){var d=u.split(/\{\{(?:text|number|decimal|date):\d+\}\}/g),m=d.map(function(x){return x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")});a.push(new RegExp("^"+m.join(".+")+"$"))}});function r(u){if(t.has(u))return!0;for(var d=0;d<a.length;d++)if(a[d].test(u))return!0;return!1}let o=[],l=null,v=null,p=new Set,s=null,f=!1;function h(){if(o.length!==0){var u=o.splice(0);i.fileMode||de(u).then(function(d){d&&d.keyMap&&(ce(u,d.keyMap),f=!0,ke(u,n),s&&s.takeRecords(),f=!1)}).catch(function(){})}}function g(u){const d=Me(u);d.forEach(m=>{var x=m.key+"\0"+(m.context||"");r(m.key)||t.has(x)||(t.add(x),t.add(m.key),o.push(m),i.phrases.push(m))}),G(d,Object.keys(n)),f=!0,ke(d,n),s&&s.takeRecords(),f=!1,i.fileMode||(clearTimeout(l),l=setTimeout(h,500))}function c(u){p.add(u),v||(v=requestAnimationFrame(function(){v=null;var d=Array.from(p);p.clear(),d.forEach(function(m){m.isConnected&&g(m)})}))}return s=new MutationObserver(u=>{if(!f){var d=[],m=new Set;for(const b of u)for(const w of b.addedNodes)if(w.nodeType===Node.ELEMENT_NODE)d.push(w);else if(w.nodeType===Node.TEXT_NODE){var x=w.parentElement;x&&x.isConnected&&m.add(x)}d.forEach(function(b){g(b)}),m.forEach(function(b){c(b)})}}),s.observe(document.body,{childList:!0,subtree:!0}),s}var Ue=["aria-labelledby","aria-label","aria-describedby","role","aria-hidden","alt","title"],Be="\0";function ut(e){var n={};return!e||typeof e!="object"||Ue.forEach(function(t){if(Object.prototype.hasOwnProperty.call(e,t)){var a=e[t];typeof a=="string"&&a.trim()!==""&&(n[t]=a.trim())}}),n}function je(e){var n={};return Array.isArray(e)&&e.forEach(function(t){if(!(!t||typeof t.key!="string")){var a=typeof t.context=="string"?t.context:"",r=ut(t.attributes);Object.keys(r).length!==0&&(n[t.key+Be+a]=r,Object.prototype.hasOwnProperty.call(n,t.key)||(n[t.key]=r))}}),n}function ft(e){return e.element?e.element:e.textNode&&e.textNode.parentElement?e.textNode.parentElement:null}function He(){return!i.apiKey||!i.apiBase?Promise.resolve({}):fetch(i.apiBase+"/api/aria",{headers:{"X-API-Key":i.apiKey}}).then(function(e){return e.json()}).then(function(e){return je(e)}).catch(function(e){return console.warn("[loco] Failed to fetch ARIA rules:",e),{}})}function dt(e,n){if(!e||!n)return!1;var t=e.__locoAriaPrev||{},a=!1;return Ue.forEach(function(r){if(Object.prototype.hasOwnProperty.call(n,r)){var o=n[r];if(!(typeof o!="string"||o.trim()==="")){Object.prototype.hasOwnProperty.call(t,r)||(t[r]=e.hasAttribute(r)?e.getAttribute(r):null);try{e.setAttribute(r,o.trim()),a=!0}catch(l){console.warn("[loco] Could not set "+r,l)}}}}),a&&(e.__locoAriaPrev=t,e.setAttribute("data-loco-aria","")),a}function V(e,n){if(!n)return{applied:0};var t=0;return e.forEach(function(a){var r=a.key+Be+(a.context||""),o=n[r]||n[a.key];if(o){var l=ft(a);l&&dt(l,o)&&t++}}),{applied:t}}var We="loco",ht=2;function ie(){return new Promise(function(e,n){try{var t=indexedDB.open(We,ht);t.onupgradeneeded=function(a){var r=a.target.result;r.objectStoreNames.contains("meta")&&a.oldVersion<2&&r.deleteObjectStore("meta"),r.objectStoreNames.contains("meta")||r.createObjectStore("meta",{keyPath:"key"}),r.objectStoreNames.contains("translations")||r.createObjectStore("translations",{keyPath:"lang"})},t.onsuccess=function(a){e(a.target.result)},t.onerror=function(){n(t.error)}}catch(a){n(a)}})}function ge(){return ie().then(function(e){return new Promise(function(n,t){var a=e.transaction("meta","readonly"),r=a.objectStore("meta").get("registry");r.onsuccess=function(){e.close();var o=r.result;n(o?{languages:o.languages||[],languageNames:o.languageNames||{}}:null)},r.onerror=function(){e.close(),t(r.error)}})})}function Xe(e){var n="source:"+e;return ie().then(function(t){return new Promise(function(a,r){var o=t.transaction("meta","readonly"),l=o.objectStore("meta").get(n);l.onsuccess=function(){t.close();var v=l.result;a(v?{url:v.url,timestamp:v.timestamp,storedAt:v.storedAt}:null)},l.onerror=function(){t.close(),r(l.error)}})})}function pt(e){return ie().then(function(n){return new Promise(function(t,a){var r=n.transaction("translations","readonly"),o=r.objectStore("translations").get(e);o.onsuccess=function(){n.close();var l=o.result;t(l?l.data:null)},o.onerror=function(){n.close(),a(o.error)}})})}function gt(){return ie().then(function(e){return new Promise(function(n,t){var a=e.transaction(["meta","translations"],"readonly"),r=a.objectStore("meta"),o=r.get("registry");o.onsuccess=function(){var l=o.result;if(!l||!l.languages||l.languages.length===0){e.close(),n(null);return}var v=Y(),p=v||l.languages[0],s=a.objectStore("translations").get(p);s.onsuccess=function(){e.close();var f=s.result;if(!f||!f.data){n(null);return}var h={};h[p]=f.data;var g=a.objectStore("meta").get("aria");g.onsuccess=function(){n({languages:l.languages,languageNames:l.languageNames||{},translations:h,aria:Array.isArray(g.result&&g.result.rules)?g.result.rules:[]})},g.onerror=function(){n({languages:l.languages,languageNames:l.languageNames||{},translations:h,aria:[]})}},s.onerror=function(){e.close(),t(s.error)}},o.onerror=function(){e.close(),t(o.error)}})})}function ve(e,n,t){var a=n.languages||[],r=n.languageNames||{},o=n.translations||{},l=Array.isArray(n.aria)?n.aria:[],v=n.timestamp||0;return ie().then(function(p){return new Promise(function(s,f){var h=p.transaction(["meta","translations"],"readwrite"),g=h.objectStore("meta"),c=h.objectStore("translations"),u=g.get("registry");u.onsuccess=function(){var d=u.result,m,x;if(t&&d){var b=d.languages||[];m=b.slice();for(var w=0;w<a.length;w++)m.indexOf(a[w])===-1&&m.push(a[w]);x={};var y=d.languageNames||{},E;for(E in y)x[E]=y[E];for(E in r)x[E]=r[E]}else m=a,x=r;g.put({key:"registry",languages:m,languageNames:x}),g.put({key:"source:"+e,url:e,timestamp:v,storedAt:Date.now()});var T=g.get("aria");T.onsuccess=function(){var S=l;if(t&&T.result&&Array.isArray(T.result.rules)){for(var O="\0",F={},R=[],K=T.result.rules,J=0;J<K.length;J++){var C=K[J];if(!(!C||typeof C.key!="string")){var U=C.key+O+(C.context||"");F.hasOwnProperty(U)||R.push(U),F[U]=C}}for(var P=0;P<l.length;P++){var D=l[P];if(!(!D||typeof D.key!="string")){var I=D.key+O+(D.context||"");F.hasOwnProperty(I)||R.push(I),F[I]=D}}S=R.map(function(oe){return F[oe]})}g.put({key:"aria",rules:S})},T.onerror=function(){g.put({key:"aria",rules:l})};for(var N=0;N<a.length;N++)o[a[N]]&&(t&&Array.isArray(o[a[N]])?function(S){var O=c.get(S);O.onsuccess=function(){var F=O.result,R=F&&Array.isArray(F.data)?F.data:null,K=o[S];if(R){for(var J="\0",C={},U=[],P=0;P<R.length;P++){var D=R[P].key+J+(R[P].context||"");C.hasOwnProperty(D)||U.push(D),C[D]=R[P]}for(var I=0;I<K.length;I++){var oe=K[I].key+J+(K[I].context||"");C.hasOwnProperty(oe)||U.push(oe),C[oe]=K[I]}for(var ze=[],Oe=0;Oe<U.length;Oe++)ze.push(C[U[Oe]]);c.put({lang:S,data:ze})}else c.put({lang:S,data:K})}}(a[N]):c.put({lang:a[N],data:o[a[N]]}))},h.oncomplete=function(){p.close(),s()},h.onerror=function(){p.close(),f(h.error)}})})}function vt(){return new Promise(function(e){var n=indexedDB.deleteDatabase(We);n.onsuccess=function(){e()},n.onerror=function(){e()},n.onblocked=function(){e()}})}var mt='<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><defs><clipPath id="loco-wc"><circle cx="100" cy="100" r="90"/></clipPath></defs><circle cx="100" cy="100" r="90" fill="#1a1f2e"/><g clip-path="url(#loco-wc)"><g transform="translate(100,108) scale(0.72) translate(-334,-198)"><ellipse cx="310" cy="318" rx="10" ry="38" fill="#2ECC88" transform="rotate(-18 310 318)"/><ellipse cx="326" cy="326" rx="9" ry="42" fill="#34D99A" transform="rotate(-6 326 326)"/><ellipse cx="342" cy="328" rx="9" ry="42" fill="#7BC74A" transform="rotate(6 342 328)"/><ellipse cx="357" cy="320" rx="9" ry="36" fill="#F07040" transform="rotate(18 357 320)"/><ellipse cx="334" cy="240" rx="62" ry="80" fill="#2ECC88"/><ellipse cx="334" cy="252" rx="36" ry="52" fill="#D4F4B0"/><path d="M275 220 Q228 190 232 265 Q248 295 280 285 Q268 255 275 220Z" fill="#3A8FE0"/><path d="M277 225 Q238 208 240 262 Q252 285 278 277 Q268 252 277 225Z" fill="#6BB3FF" opacity="0.7"/><path d="M393 220 Q440 190 436 265 Q420 295 388 285 Q400 255 393 220Z" fill="#3A8FE0"/><path d="M391 225 Q430 208 428 262 Q416 285 390 277 Q400 252 391 225Z" fill="#6BB3FF" opacity="0.7"/><ellipse cx="334" cy="172" rx="38" ry="30" fill="#2ECC88"/><circle cx="334" cy="148" r="52" fill="#2ECC88"/><ellipse cx="334" cy="118" rx="30" ry="18" fill="#FFB833"/><circle cx="312" cy="138" r="14" fill="white"/><circle cx="315" cy="140" r="9" fill="#2C2C2A"/><circle cx="315" cy="140" r="4" fill="#04342C"/><circle cx="319" cy="136" r="3.5" fill="white"/><circle cx="356" cy="138" r="14" fill="white"/><circle cx="353" cy="140" r="9" fill="#2C2C2A"/><circle cx="353" cy="140" r="4" fill="#04342C"/><circle cx="357" cy="136" r="3.5" fill="white"/><path d="M326 155 Q334 144 342 155 Q342 170 334 173 Q326 170 326 155Z" fill="#E8A020"/><path d="M328 165 Q334 158 340 165 Q340 174 334 176 Q328 174 328 165Z" fill="#A06010"/><ellipse cx="302" cy="152" rx="12" ry="8" fill="#F07040" opacity="0.8"/><ellipse cx="366" cy="152" rx="12" ry="8" fill="#F07040" opacity="0.8"/><path d="M320 100 Q316 68 308 52" stroke="#FFB833" stroke-width="6" fill="none" stroke-linecap="round"/><path d="M334 97 Q334 64 334 46" stroke="#7BC74A" stroke-width="6" fill="none" stroke-linecap="round"/><path d="M348 100 Q352 68 360 52" stroke="#F07040" stroke-width="6" fill="none" stroke-linecap="round"/><circle cx="308" cy="50" r="8" fill="#FFB833"/><circle cx="334" cy="44" r="8" fill="#7BC74A"/><circle cx="360" cy="50" r="8" fill="#F07040"/><rect x="260" y="330" width="168" height="10" rx="5" fill="#8B5E20"/><path d="M310 330 L300 350 M310 330 L315 352 M310 330 L325 348" stroke="#A07030" stroke-width="4" fill="none" stroke-linecap="round"/><path d="M360 330 L350 350 M360 330 L365 352 M360 330 L375 348" stroke="#A07030" stroke-width="4" fill="none" stroke-linecap="round"/></g></g></svg>',Se=null;function me(e,n){Se=n;var t=document.getElementById("loco-lang-widget");t&&t.remove();var a={},r=e.map(function(y){return typeof y=="object"&&y.code?(y.name&&(a[y.code]=y.name),y.code):y}),o={"zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)"};function l(y){return String(y||"").trim().replace(/_/g,"-")}function v(y){return y&&y.charAt(0).toUpperCase()+y.slice(1).toLowerCase()}function p(y){var E=l(y);if(!E)return"";var T=E.split("-").filter(Boolean);if(T.length===0)return"";T[0]=T[0].toLowerCase();for(var N=1;N<T.length;N++)T[N].length===2?T[N]=T[N].toUpperCase():T[N].length===4?T[N]=v(T[N]):T[N]=T[N].toLowerCase();return T.join("-")}function s(y){var E=p(y);if(!E)return"";if(o[E])return o[E];if(E.indexOf("-")===-1)return"";try{if(typeof Intl<"u"&&typeof Intl.DisplayNames=="function"){var T=new Intl.DisplayNames([navigator.language||"en","en"],{type:"language"}),N=T.of(E);if(N&&N!==E)return N}}catch{}return""}function f(y,E){return y?p(y)===p(E):!0}function h(y){var E=a[y]||a[p(y)]||"";if(E&&!f(E,y))return E;var T=p(y);return o[T]?o[T]:s(y)||y}var g=Y()||null,c=document.createElement("div");c.id="loco-lang-widget",c.setAttribute("data-notranslate","");var u={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"};c.style.cssText='position:fixed;z-index:2147483647;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;'+(u[n]||u["bottom-right"]);var d=document.createElement("button");d.innerHTML=mt,d.style.cssText="width:52px;height:52px;border-radius:50%;border:none;background:#1a1f2e;color:#fff;font-size:22px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,0.25);display:flex;align-items:center;justify-content:center;transition:transform 0.2s,box-shadow 0.2s;overflow:hidden;padding:0;",d.onmouseenter=function(){d.style.transform="scale(1.1)",d.style.boxShadow="0 6px 20px rgba(0,0,0,0.35)"},d.onmouseleave=function(){d.style.transform="scale(1)",d.style.boxShadow="0 4px 14px rgba(0,0,0,0.25)"};var m=document.createElement("div");m.style.cssText="display:none;position:absolute;"+(n.indexOf("bottom")===0?"bottom:56px;":"top:56px;")+(n.indexOf("right")>=0?"right:0;":"left:0;")+"background:#fff;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,0.18);min-width:200px;max-height:320px;overflow-y:auto;padding:6px 0;";var x=document.createElement("div");x.textContent="Original",x.style.cssText="padding:10px 16px;cursor:pointer;color:#333;transition:background 0.15s;font-weight:600;border-bottom:1px solid #eee;",x.onmouseenter=function(){x.style.background="#f5f5f5"},x.onmouseleave=function(){x.style.background="transparent"},x.onclick=function(){g=null,window.Loco.restore(),w(),m.style.display="none"},m.appendChild(x);var b=[];r.forEach(function(y){var E=document.createElement("div");E.textContent=h(y),E.setAttribute("data-lang",y),E.style.cssText="padding:10px 16px;cursor:pointer;color:#333;transition:background 0.15s;",E.onmouseenter=function(){E.style.background="#f5f5f5"},E.onmouseleave=function(){E.style.background=g===y?"#e8f0fe":"transparent"},E.onclick=function(){g=y,window.Loco.apply(y),w(),m.style.display="none"},m.appendChild(E),b.push({el:E,code:y})});function w(){x.style.background=g===null?"#e8f0fe":"transparent",x.style.fontWeight=g===null?"600":"400",b.forEach(function(y){y.el.style.background=g===y.code?"#e8f0fe":"transparent",y.el.style.fontWeight=g===y.code?"600":"400"})}d.onclick=function(y){y.stopPropagation(),m.style.display=m.style.display==="none"?"block":"none"},document.addEventListener("click",function(y){c.contains(y.target)||(m.style.display="none")}),w(),c.appendChild(m),c.appendChild(d),document.body.appendChild(c)}function yt(e){Se&&(!e||e.length===0||me(e,Se))}var H={__proto__:1,constructor:1,prototype:1};function Qe(e){if(!e||typeof e!="string")return!1;if(e.charAt(0)==="/"||e.charAt(0)===".")return!0;try{var n=new URL(e,window.location.origin);return n.protocol==="http:"||n.protocol==="https:"}catch{return!1}}function ye(e){if(!e||typeof e!="object"||Array.isArray(e))return null;if(Array.isArray(e._raw)){for(var n={},t={},a=0;a<e._raw.length;a++){var r=e._raw[a];!r||typeof r.l!="string"||typeof r.k!="string"||typeof r.v!="string"||(n[r.l]||(n[r.l]=!0,t[r.l]=[]),t[r.l].push({key:r.k,context:typeof r.c=="string"?r.c:"",value:r.v}))}e={languages:Object.keys(n).sort(),languageNames:{},translations:t,timestamp:0}}var o={};if(!Array.isArray(e.languages))return null;o.languages=[];for(var l=0;l<e.languages.length;l++){if(typeof e.languages[l]!="string"||e.languages[l].length>20)return null;o.languages.push(e.languages[l])}if(o.timestamp=typeof e.timestamp=="number"&&isFinite(e.timestamp)?e.timestamp:0,o.languageNames={},e.languageNames&&typeof e.languageNames=="object"&&!Array.isArray(e.languageNames))for(var v in e.languageNames)!e.languageNames.hasOwnProperty(v)||H[v]||typeof e.languageNames[v]=="string"&&e.languageNames[v].length<=100&&(o.languageNames[v]=e.languageNames[v]);if(o.translations={},e.translations&&typeof e.translations=="object"&&!Array.isArray(e.translations)){for(var p in e.translations)if(!(!e.translations.hasOwnProperty(p)||H[p])&&o.languages.indexOf(p)!==-1){var s=e.translations[p];if(Array.isArray(s)){for(var f=[],h=0;h<s.length;h++){var g=s[h];!g||typeof g!="object"||typeof g.key!="string"||typeof g.value!="string"||g.key.length>Z||g.value.length>Z||H[g.key]||f.push({key:g.key,value:g.value,context:typeof g.context=="string"?g.context:""})}o.translations[p]=f}else if(typeof s=="object"){var c={};for(var u in s)!s.hasOwnProperty(u)||H[u]||typeof s[u]=="string"&&(u.length>Z||s[u].length>Z||(c[u]=s[u]));o.translations[p]=c}}}if(o.aria=[],Array.isArray(e.aria))for(var d=0;d<e.aria.length;d++){var r=e.aria[d];if(!(!r||typeof r!="object")&&!(typeof r.key!="string"||r.key.length>Z)&&!H[r.key]){var m=typeof r.context=="string"?r.context:"",x=r.attributes;!x||typeof x!="object"||Array.isArray(x)||o.aria.push({key:r.key,context:m,attributes:x})}}return o}async function $e(){try{var e=await fetch(i.apiBase+"/api/project/crawler-config",{headers:{"X-API-Key":i.apiKey}});e.ok&&Je(await e.json())}catch{}Le(),i.phrases=await ae(document.body),de(i.phrases).then(function(t){t&&t.keyMap&&ce(i.phrases,t.keyMap)}).catch(function(t){console.warn("[loco] Failed to register keys:",t)}),He().then(function(t){i.ariaRules=t||{};var a=V(i.phrases,i.ariaRules);a.applied>0&&console.log("[loco] applied ARIA rules to "+a.applied+" element(s)")}).catch(function(){}),!i.scanStopped&&i.screenshotsEnabled&&setTimeout(st,3e3),console.log("[loco] "+i.phrases.length+" text nodes discovered"),console.log(` Loco.textnodes() — list all discovered text nodes
1
+ var Loco=function(){"use strict";var i={apiKey:null,apiBase:null,phrases:[],currentLang:null,translations:{},observer:null,fileMode:!1,fileData:null,fileReadyResolve:null,fileReady:null,fileUrl:null,fileUrls:[],scanStopped:!1,loadedFromCache:!1,screenshotsEnabled:!0,widgetPosition:null,ariaRules:{}},Re=["SCRIPT","STYLE","NOSCRIPT","IFRAME","CODE","SVG","AUDIO","VIDEO","LINK"],Pe=["VAR","STRONG","EM","B","I","SPAN","A","ABBR","MARK","SMALL","SUB","SUP","U","S","TIME"],De=["h1","h2","h3","h4","h5","h6","label","legend","caption","figcaption","nav","header","footer","main","section","article","form"],_=new Set(Re),W=new Set(Pe),we=[].concat(De),Ne=0,Te=!0,B=1e3,Z=1e4,Ae="loco-lang";function Y(){try{return localStorage.getItem(Ae)}catch{return null}}function le(e){try{e?localStorage.setItem(Ae,e):localStorage.removeItem(Ae)}catch{}}function Ye(e){if(e.blockedTags){var n=e.blockedTags.disabled||[],t=e.blockedTags.custom||[];_=new Set(Re.filter(function(r){return n.indexOf(r)<0})),t.forEach(function(r){_.add(r.toUpperCase())})}if(e.inlineTags){var n=e.inlineTags.disabled||[],t=e.inlineTags.custom||[];W=new Set(Pe.filter(function(o){return n.indexOf(o)<0})),t.forEach(function(o){W.add(o.toUpperCase())})}if(e.domContextSelectors){var n=e.domContextSelectors.disabled||[],t=e.domContextSelectors.custom||[];we=De.filter(function(o){return n.indexOf(o)<0}).concat(t)}e.screenshotsEnabled===!1&&(i.screenshotsEnabled=!1),typeof e.contextDepth=="number"&&(Ne=e.contextDepth),e.domContextEnabled===!1&&(Te=!1)}function L(e){return e.trim().replace(/\s+/g," ")}function A(e){return!/[a-zA-Z\u00C0-\u024F\u0900-\u097F\u0600-\u06FF]/.test(e)}function se(e){var n=e.replace(/\{\{(?:text|number|decimal|date):\d+\}\}/g,"");return!n.trim()||A(n)}function Ie(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ee(e){var t;if(!e||e.nodeType!==1)return!1;const n=(t=e.tagName)==null?void 0:t.toUpperCase();return _.has(n)||e.hasAttribute("notranslate")||e.hasAttribute("data-notranslate")||e.hasAttribute("data-loco-translated")||e.getAttribute("translate")==="no"||e.isContentEditable}var X=new WeakMap;function _e(e){let n=e.parentElement;for(;n&&n!==document.body;){if(X.has(n))return X.get(n);if(ee(n))return X.set(n,!0),!0;n=n.parentElement}for(n=e.parentElement;n&&n!==document.body&&!X.has(n);)X.set(n,!1),n=n.parentElement;return!1}function et(){X=new WeakMap}const Me=new Set(["H1","H2","H3","H4","H5","H6"]),tt=new Set(["SCRIPT","STYLE","NOSCRIPT","CODE"]);let Q=new WeakMap,z=new WeakMap,G=null;function Le(){if(Te){G=new Set;var e=we.slice();try{var n=e.join(",");document.querySelectorAll(n).forEach(function(t){G.add(t)})}catch{e.forEach(function(r){try{document.querySelectorAll(r).forEach(function(a){G.add(a)})}catch{}})}G.forEach(function(t){z.has(t)||ne(t)})}}function te(e){return G?G.has(e):Me.has(e.tagName)?!0:we.some(function(n){try{return e.matches(n)}catch{return!1}})}function nt(e){let n="";for(const t of e.childNodes)if(t.nodeType===Node.TEXT_NODE){const r=t.textContent.trim();r&&(n+=(n?" ":"")+r)}return n}function rt(e,n){for(var t="",r=document.createTreeWalker(e,NodeFilter.SHOW_ALL,{acceptNode:function(o){return o.nodeType===Node.ELEMENT_NODE?tt.has(o.tagName)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_SKIP:NodeFilter.FILTER_ACCEPT}}),a;(a=r.nextNode())&&!(a.nodeType===Node.TEXT_NODE&&(t+=a.textContent,t.length>=n)););return t.trim()}function ne(e){if(z.has(e))return z.get(e);let n=null;const t=nt(e);if(t)return n=t.substring(0,60),z.set(e,n),n;if(Me.has(e.tagName)){const a=(e.textContent||"").trim().replace(/\s+/g," ");if(a)return n=a.substring(0,60),z.set(e,n),n}var r=rt(e,200);if(r){const a=r.split(/\n/)[0].trim().replace(/\s+/g," ");a.length>=2&&!A(a)&&(n=a.substring(0,60))}return z.set(e,n),n}function k(e){if(!e||!Te)return"";if(Q.has(e))return Q.get(e);var n=e.parentElement;if(n&&n!==document.body&&Q.has(n)&&!te(e)){var t=Q.get(n);return Q.set(e,t),t}const r=[],a=new Set;let o=e,l=0;if(e&&e.tagName==="TD"){var v=e.closest("table");if(v){var p=v.querySelector("thead tr th:nth-child("+(e.cellIndex+1)+")");if(p){var s=ne(p);s&&(a.add(s),r.push(s))}}}for(;o&&o!==document.body&&!(Ne>0&&l>=Ne);){l++;let c=o.previousElementSibling;for(;c;){var f=c.tagName.toUpperCase();if(_.has(f)){c=c.previousElementSibling;continue}if(f==="ARTICLE"||f==="MAIN"){c=c.previousElementSibling;continue}if(te(c)){const d=ne(c);d&&!a.has(d)&&(a.add(d),r.unshift(d));break}let u=null;for(const d of c.children)if(te(d)){u=d;break}if(!u)for(const d of c.children){for(const m of d.children)if(te(m)){u=m;break}if(u)break}if(u){const d=ne(u);d&&!a.has(d)&&(a.add(d),r.unshift(d));break}c=c.previousElementSibling}if(te(o)){const u=ne(o);u&&!a.has(u)&&(a.add(u),r.unshift(u))}var h=o.tagName;if(h==="ARTICLE"||h==="MAIN")break;o=o.parentElement}const g=r.join(" > ");return Q.set(e,g),g}function at(e){return/^\d+$/.test(e)?"number":/^\d+\.\d+$/.test(e)?"decimal":"text"}function it(e,n){for(var t=n.split(/(\{\{(?:text|number|decimal|date):\d+\}\})/),r=[],a=e,o=0;o<t.length;o++){var l=t[o],v=l.match(/^\{\{(text|number|decimal|date):(\d+)\}\}$/);if(v)if(a.indexOf(l)===0)r.push({type:v[1],index:parseInt(v[2]),originalText:l}),a=a.substring(l.length);else{for(var p="",s=o+1;s<t.length;s++){var f=t[s];if(/^\{\{(?:text|number|decimal|date):\d+\}\}$/.test(f)){if(a.indexOf(f)>=0){p=f;break}}else if(f!==""){p=f;break}}var h;if(p==="")h=a,a="";else{var g=a.indexOf(p);g>=0?(h=a.substring(0,g),a=a.substring(g)):(h=a,a="")}r.push({type:v[1],index:parseInt(v[2]),originalText:h})}else a.indexOf(l)===0&&(a=a.substring(l.length))}return r}function ce(e,n){e.forEach(function(t){if(!(t.varSlots&&t.varSlots.length>0)){var r=n[t.key];r&&(t.varSlots=it(t.key,r),t.key=r)}})}function ot(e,n){for(var t=n.split(/\{\{(?:text|number|decimal|date):\d+\}\}/g),r=e,a=[],o=0;o<t.length;o++)if(o===0)r.indexOf(t[o])===0&&(r=r.substring(t[o].length));else if(t[o]===""&&o===t.length-1)a.push(r),r="";else{var l=r.indexOf(t[o]);l>=0&&(a.push(r.substring(0,l)),r=r.substring(l+t[o].length))}return a.length>0&&a.every(function(v){return/^[a-zA-Z\s]+$/.test(v.trim())})}function lt(e){for(var n=0,t=/\{\{(text|number|decimal|date):\d+\}\}/g,r;(r=t.exec(e))!==null;)switch(r[1]){case"number":n+=3;break;case"decimal":n+=3;break;case"date":n+=2;break;default:n+=1;break}return n}function $(e,n){for(var t=[],r=0;r<n.length;r++){var a=n[r];if(!(a.indexOf("{{text:")<0&&a.indexOf("{{number:")<0&&a.indexOf("{{decimal:")<0&&a.indexOf("{{date:")<0)){for(var o=[],l=[],v=0,p=/\{\{(text|number|decimal|date):\d+\}\}/g,s;(s=p.exec(a))!==null;)o.push(a.substring(v,s.index)),l.push(s[1]),v=p.lastIndex;o.push(a.substring(v));for(var f="",h=0;h<o.length;h++)if(f+=o[h].replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),h<l.length)switch(l[h]){case"number":f+="\\d+";break;case"decimal":f+="\\d+\\.\\d+";break;default:f+=".+";break}t.push({pattern:a,regex:new RegExp("^"+f+"$"),specificity:lt(a)})}}if(t.length!==0){t.sort(function(u,d){return d.specificity-u.specificity});for(var g={},c={},r=0;r<n.length;r++)c[n[r]]=!0;return e.forEach(function(u){if(!c[u.key]&&!(u.key.length>B)){for(var d=0;d<t.length;d++)if(t[d].regex.test(u.key)&&!ot(u.key,t[d].pattern)){g[u.key]=t[d].pattern;break}}}),ce(e,g),g}}var re=new WeakMap;function M(e){if(re.has(e))return re.get(e);let n=!1,t=!1;for(const a of e.childNodes)if(a.nodeType===Node.TEXT_NODE&&a.textContent.trim()&&(n=!0),a.nodeType===Node.ELEMENT_NODE){const o=a.tagName.toUpperCase();if(o==="BR")return re.set(e,!1),!1;(o==="VAR"||o==="TIME"&&a.hasAttribute("datetime")||W.has(o))&&(t=!0)}var r=n&&t;return re.set(e,r),r}function st(){re=new WeakMap}function ue(e){let n="";const t=[];for(const r of e.childNodes){if(r.nodeType===Node.TEXT_NODE){const a=L(r.textContent);a&&(n+=a);continue}if(r.nodeType===Node.ELEMENT_NODE){const a=r.tagName.toUpperCase();if(a==="TIME"&&r.hasAttribute("datetime")){const o=t.length;t.push({type:"date",index:o,raw:r.getAttribute("datetime"),display:r.textContent,node:r}),n+=`{{date:${o}}}`;continue}if(a==="VAR"||W.has(a)){const o=L(r.textContent);if(o){const l=t.length,v=at(o);t.push({type:v,index:l,tag:a,value:o,node:r}),n+=`{{${v}:${l}}}`}continue}}}return{key:L(n),slots:t}}var fe=["title","placeholder","aria-label"];function Ke(e){const n=[],t=new Set;if(e.nodeType===Node.ELEMENT_NODE&&!ee(e)&&M(e)){const{key:s,slots:f}=ue(e);if(s&&s.length<=B)if(se(s))f.forEach(function(h){if(h.type==="text"&&h.value&&h.value.length>=2&&!A(h.value)){var g=k(h.node||e),c=h.value+"\0"+g;t.has(c)||(t.add(c),n.push({type:"text",key:h.value,slots:[],textNode:h.node?h.node.firstChild:null,element:h.node||e,context:g,original:h.value}))}});else{var r=k(e),a=s+"\0"+r;t.has(a)||t.add(a);const h=f.some(g=>g.type==="date")?"mixed-date":f.some(g=>g.type==="text")?"mixed-text":"mixed";n.push({type:h,key:s,slots:f,element:e,context:r,original:s,originalHTML:e.innerHTML})}}const o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode(s){var m,x,b;if(s.nodeType===Node.TEXT_NODE){const w=L(s.textContent);if(!w||w.length<2||w.length>B||A(w)||/\{\{(?:text|number|decimal|date):\d+\}\}/.test(w)||_e(s))return NodeFilter.FILTER_SKIP;const y=(x=(m=s.parentElement)==null?void 0:m.tagName)==null?void 0:x.toUpperCase();if(_.has(y)||M(s.parentElement))return NodeFilter.FILTER_SKIP;for(var f=s.parentElement,h=0;f&&h<3;){var g=(b=f.tagName)==null?void 0:b.toUpperCase();if((g==="VAR"||g==="TIME"||W.has(g))&&f.parentElement&&M(f.parentElement))return NodeFilter.FILTER_SKIP;f=f.parentElement,h++}return NodeFilter.FILTER_ACCEPT}if(s.nodeType===Node.ELEMENT_NODE){const w=s.tagName.toUpperCase();if(_.has(w)||ee(s))return NodeFilter.FILTER_REJECT;if(w==="INPUT"){var c=(s.getAttribute("type")||"").toLowerCase();if(c==="button"||c==="submit"||c==="reset"){var u=L(s.value);if(u&&u.length>=2&&!A(u))return NodeFilter.FILTER_ACCEPT}var d=fe.some(function(y){var E=L(s.getAttribute(y)||"");return E&&E.length>=2&&!A(E)});return d?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return M(s)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return NodeFilter.FILTER_SKIP}});let l;for(;l=o.nextNode();){if(l.nodeType===Node.TEXT_NODE){const s=L(l.textContent);if(!s)continue;var r=k(l.parentElement),a=s+"\0"+r;t.has(a)||t.add(a),n.push({type:"text",key:s,slots:[],textNode:l,element:l.parentElement,context:r,original:s});continue}if(l.nodeType===Node.ELEMENT_NODE&&l.tagName.toUpperCase()==="INPUT"){var v=(l.getAttribute("type")||"").toLowerCase(),r=k(l);if(v==="button"||v==="submit"||v==="reset"){var p=L(l.value);if(p&&p.length>=2&&!A(p)){var a=p+"\0"+r;t.has(a)||t.add(a),n.push({type:"input-value",key:p,slots:[],element:l,context:r,original:p})}}fe.forEach(function(f){var h=L(l.getAttribute(f)||"");if(!(!h||h.length<2||A(h))){var g=h+"\0"+r+"\0"+f;t.has(g)||(t.add(g),n.push({type:"input-attr",key:h,attr:f,slots:[],element:l,context:r,original:h}))}});continue}if(l.nodeType===Node.ELEMENT_NODE){const{key:s,slots:f}=ue(l);if(!s||s.length>B)continue;if(se(s)){f.forEach(function(u){if(u.type==="text"&&u.value&&u.value.length>=2&&!A(u.value)){var d=k(u.node||l),m=u.value+"\0"+d;t.has(m)||(t.add(m),n.push({type:"text",key:u.value,slots:[],textNode:u.node?u.node.firstChild:null,element:u.node||l,context:d,original:u.value}))}});continue}var r=k(l),a=s+"\0"+r;t.has(a)||t.add(a);const c=f.some(u=>u.type==="date")?"mixed-date":f.some(u=>u.type==="text")?"mixed-text":"mixed";n.push({type:c,key:s,slots:f,element:l,context:r,original:s,originalHTML:l.innerHTML})}}return n}async function ae(e,n){n||(n=100);const t=[],r=new Set;if(et(),st(),Le(),e.nodeType===Node.ELEMENT_NODE&&!ee(e)&&M(e)){const{key:c,slots:u}=ue(e);if(c&&c.length<=B)if(se(c))u.forEach(function(d){if(d.type==="text"&&d.value&&d.value.length>=2&&!A(d.value)){var m=k(d.node||e),x=d.value+"\0"+m;r.has(x)||(r.add(x),t.push({type:"text",key:d.value,slots:[],textNode:d.node?d.node.firstChild:null,element:d.node||e,context:m,original:d.value}))}});else{var a=k(e),o=c+"\0"+a;r.has(o)||r.add(o);const d=u.some(m=>m.type==="date")?"mixed-date":u.some(m=>m.type==="text")?"mixed-text":"mixed";t.push({type:d,key:c,slots:u,element:e,context:a,original:c,originalHTML:e.innerHTML})}}const l=[],v=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode(c){var y,E,T;if(c.nodeType===Node.TEXT_NODE){const N=L(c.textContent);if(!N||N.length<2||N.length>B||A(N)||/\{\{(?:text|number|decimal|date):\d+\}\}/.test(N)||_e(c))return NodeFilter.FILTER_SKIP;const C=(E=(y=c.parentElement)==null?void 0:y.tagName)==null?void 0:E.toUpperCase();if(_.has(C)||M(c.parentElement))return NodeFilter.FILTER_SKIP;for(var u=c.parentElement,d=0;u&&d<3;){var m=(T=u.tagName)==null?void 0:T.toUpperCase();if((m==="VAR"||m==="TIME"||W.has(m))&&u.parentElement&&M(u.parentElement))return NodeFilter.FILTER_SKIP;u=u.parentElement,d++}return NodeFilter.FILTER_ACCEPT}if(c.nodeType===Node.ELEMENT_NODE){const N=c.tagName.toUpperCase();if(_.has(N)||ee(c))return NodeFilter.FILTER_REJECT;if(N==="INPUT"){var x=(c.getAttribute("type")||"").toLowerCase();if(x==="button"||x==="submit"||x==="reset"){var b=L(c.value);if(b&&b.length>=2&&!A(b))return NodeFilter.FILTER_ACCEPT}var w=fe.some(function(C){var O=L(c.getAttribute(C)||"");return O&&O.length>=2&&!A(O)});return w?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return M(c)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return NodeFilter.FILTER_SKIP}});for(var p;p=v.nextNode();)l.push(p);for(var s=0;s<l.length;s++){s>0&&s%n===0&&await new Promise(function(c){setTimeout(c,0)});var f=l[s];if(f.nodeType===Node.TEXT_NODE){const c=L(f.textContent);if(!c)continue;var a=k(f.parentElement),o=c+"\0"+a;r.has(o)||r.add(o),t.push({type:"text",key:c,slots:[],textNode:f,element:f.parentElement,context:a,original:c});continue}if(f.nodeType===Node.ELEMENT_NODE&&f.tagName.toUpperCase()==="INPUT"){var h=(f.getAttribute("type")||"").toLowerCase(),a=k(f);if(h==="button"||h==="submit"||h==="reset"){var g=L(f.value);if(g&&g.length>=2&&!A(g)){var o=g+"\0"+a;r.has(o)||r.add(o),t.push({type:"input-value",key:g,slots:[],element:f,context:a,original:g})}}fe.forEach(function(u){var d=L(f.getAttribute(u)||"");if(!(!d||d.length<2||A(d))){var m=d+"\0"+a+"\0"+u;r.has(m)||(r.add(m),t.push({type:"input-attr",key:d,attr:u,slots:[],element:f,context:a,original:d}))}});continue}if(f.nodeType===Node.ELEMENT_NODE){const{key:c,slots:u}=ue(f);if(!c||c.length>B)continue;if(se(c)){u.forEach(function(b){if(b.type==="text"&&b.value&&b.value.length>=2&&!A(b.value)){var w=k(b.node||f),y=b.value+"\0"+w;r.has(y)||(r.add(y),t.push({type:"text",key:b.value,slots:[],textNode:b.node?b.node.firstChild:null,element:b.node||f,context:w,original:b.value}))}});continue}var a=k(f),o=c+"\0"+a;r.has(o)||r.add(o);const x=u.some(b=>b.type==="date")?"mixed-date":u.some(b=>b.type==="text")?"mixed-text":"mixed";t.push({type:x,key:c,slots:u,element:f,context:a,original:c,originalHTML:f.innerHTML})}}return t}function de(e){if(i.scanStopped)return Promise.resolve({ok:!0,registered:0,keyMap:{}});var n=new Set,t=[];return e.forEach(function(r){var a=r.key+"\0"+(r.context||"");n.has(a)||r.varSlots&&r.varSlots.length>0&&/\{\{(?:text|number|decimal|date):\d+\}\}/.test(r.key)||(n.add(a),t.push({key:r.key,context:r.context||""}),r.slots&&r.slots.length>0&&r.slots.forEach(function(o){if(o.type==="text"&&o.value&&!A(o.value)){var l=o.value+"\0";n.has(l)||(n.add(l),t.push({key:o.value,context:""}))}}))}),fetch(i.apiBase+"/api/textnodes",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":i.apiKey},body:JSON.stringify({keys:t,url:window.location.href})}).then(function(r){return r.json()})}function ct(e){var n=i.apiBase+"/api/translations?lang="+encodeURIComponent(e);return fetch(n,{headers:{"X-API-Key":i.apiKey}}).then(function(t){return t.json()}).then(function(t){var r={};return Array.isArray(t)?t.forEach(function(a){r[a.key+"\0"+(a.context||"")]=a.value,r.hasOwnProperty(a.key)||(r[a.key]=a.value)}):r=t,r})}function ut(){if(!(i.fileMode||!i.screenshotsEnabled)){var e=document.createElement("script");e.src=i.apiBase+"/cdn/html2canvas.min.js",e.onload=function(){typeof html2canvas=="function"&&html2canvas(document.body,{scale:.35,logging:!1,useCORS:!0,allowTaint:!0,width:window.innerWidth,height:window.innerHeight,windowWidth:window.innerWidth,windowHeight:window.innerHeight}).then(function(n){var t=n.toDataURL("image/jpeg",.5),r=t.split(",")[1];!r||r.length>5e5||fetch(i.apiBase+"/api/screenshots",{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":i.apiKey},body:JSON.stringify({url:window.location.href,screenshot:r})}).catch(function(){})}).catch(function(){})},e.onerror=function(){},document.head.appendChild(e)}}function ft(e,n){return e.replace(/\{\{(text|number|decimal|date):(\d+)\}\}/g,(t,r,a)=>{const o=n[parseInt(a)];return o?r==="date"?o.display:o.value:t})}function Ue(e){if(!Array.isArray(e))return e;var n={};return e.forEach(function(t){n[t.key+"\0"+(t.context||"")]=t.value,n.hasOwnProperty(t.key)||(n[t.key]=t.value)}),n}function ke(e,n){let t=0,r=0;return e.forEach(a=>{const o=a.key+"\0"+(a.context||"");var l=n[o]||n[a.key];if(!l&&a.slots&&a.slots.length>0){var v=a.slots.some(function(h){if(h.type!=="text"||!h.value)return!1;var g=h.value+"\0"+(a.context||""),c=h.value+"\0";return n.hasOwnProperty(g)||n.hasOwnProperty(c)||n.hasOwnProperty(h.value)});v&&(l=a.key)}if(!l){r++;return}if(a.type==="input-value"&&a.element)try{a.element.value=l,a.element.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to input value",h),r++;return}if(a.type==="input-attr"&&a.element&&a.attr)try{a.element.setAttribute(a.attr,l),a.element.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to input attr",h),r++;return}if(a.type==="text"&&a.textNode)try{var p=l;a.varSlots&&a.varSlots.length>0&&(p=p.replace(/\{\{(text|number|decimal|date):(\d+)\}\}/g,function(h,g,c){var u=a.varSlots.find(function(d){return(d.type||"text")===g&&d.index===+c});return u||(u=a.varSlots[+c]),u?u.originalText:h})),p=p.replace(/\{\{(?:text|number|decimal|date):\d+\}\}/g,""),a.textNode.nodeValue=p,a.textNode.parentElement&&a.textNode.parentElement.setAttribute("data-loco-translated",""),t++;return}catch(h){console.warn("[translate] Could not write to text node",h),r++;return}if(a.element){try{const h=ft(l,a.slots);let g=l;var s={};a.slots.forEach(c=>{const u=`{{${c.type}:${c.index}}}`;if(c.type==="date"&&c.node)c.node.textContent=c.display,s[u]=c.node.outerHTML;else if(c.node){if(c.type==="text"&&c.value){var d=c.value+"\0"+(a.context||""),m=c.value+"\0",x=n[d]||n[m]||n[c.value];x&&(c.node.textContent=x)}s[u]=c.node.outerHTML}}),a.varSlots&&a.varSlots.length>0&&a.varSlots.forEach(function(c){var u="{{"+c.type+":"+c.index+"}}";s.hasOwnProperty(u)||(s[u]=Ie(c.originalText))});var f=g.split(/(\{\{(?:text|number|decimal|date):\d+\}\})/g);g=f.map(function(c){return s.hasOwnProperty(c)?s[c]:/^\{\{(?:text|number|decimal|date):\d+\}\}$/.test(c)?"":Ie(c)}).join(""),a.element.innerHTML=g,a.element.setAttribute("data-loco-translated",""),t++}catch(h){console.warn("[translate] Could not apply mixed translation",h),r++}return}r++}),{applied:t,skipped:r}}async function he(e,n,t){t||(t=100);for(var r=0,a=0,o=performance.now(),l=0;l<e.length;l+=t){l>0&&performance.now()-o>16&&(await new Promise(function(s){requestAnimationFrame(s)}),o=performance.now());var v=e.slice(l,l+t),p=ke(v,n);r+=p.applied,a+=p.skipped}return{applied:r,skipped:a}}function j(e){let n=0;e.forEach(t=>{try{t.type==="input-value"&&t.element?(t.element.value=t.original,t.element.removeAttribute("data-loco-translated"),n++):t.type==="input-attr"&&t.element&&t.attr?(t.element.setAttribute(t.attr,t.original),t.element.removeAttribute("data-loco-translated"),n++):t.type==="text"&&t.textNode&&(t.textNode.nodeValue=t.original,t.textNode.parentElement&&t.textNode.parentElement.removeAttribute("data-loco-translated"),n++)}catch(r){console.warn("[translate] Could not restore text node",r)}}),e.forEach(t=>{if(t.type!=="text")try{t.element&&t.originalHTML!==void 0&&(t.element.innerHTML=t.originalHTML,t.element.removeAttribute("data-loco-translated"),n++)}catch(r){console.warn("[translate] Could not restore node",r)}}),console.log("[loco] untranslated "+n+" phrase(s)")}function pe(e,n){const t=new Set(e),r=[];Object.values(n).forEach(function(u){if(u&&(t.add(u),/\{\{(text|number|decimal|date):\d+\}\}/.test(u))){var d=u.split(/\{\{(?:text|number|decimal|date):\d+\}\}/g),m=d.map(function(x){return x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")});r.push(new RegExp("^"+m.join(".+")+"$"))}});function a(u){if(t.has(u))return!0;for(var d=0;d<r.length;d++)if(r[d].test(u))return!0;return!1}let o=[],l=null,v=null,p=new Set,s=null,f=!1;function h(){if(o.length!==0){var u=o.splice(0);i.fileMode||de(u).then(function(d){d&&d.keyMap&&(ce(u,d.keyMap),f=!0,ke(u,n),s&&s.takeRecords(),f=!1)}).catch(function(){})}}function g(u){const d=Ke(u);d.forEach(m=>{var x=m.key+"\0"+(m.context||"");a(m.key)||t.has(x)||(t.add(x),t.add(m.key),o.push(m),i.phrases.push(m))}),$(d,Object.keys(n)),f=!0,ke(d,n),s&&s.takeRecords(),f=!1,i.fileMode||(clearTimeout(l),l=setTimeout(h,500))}function c(u){p.add(u),v||(v=requestAnimationFrame(function(){v=null;var d=Array.from(p);p.clear(),d.forEach(function(m){m.isConnected&&g(m)})}))}return s=new MutationObserver(u=>{if(!f){var d=[],m=new Set;for(const b of u)for(const w of b.addedNodes)if(w.nodeType===Node.ELEMENT_NODE)d.push(w);else if(w.nodeType===Node.TEXT_NODE){var x=w.parentElement;x&&x.isConnected&&m.add(x)}d.forEach(function(b){g(b)}),m.forEach(function(b){c(b)})}}),s.observe(document.body,{childList:!0,subtree:!0}),s}var Be=["aria-labelledby","aria-label","aria-describedby","role","aria-hidden","alt","title"],je="\0";function dt(e){var n={};return!e||typeof e!="object"||Be.forEach(function(t){if(Object.prototype.hasOwnProperty.call(e,t)){var r=e[t];typeof r=="string"&&r.trim()!==""&&(n[t]=r.trim())}}),n}function He(e){var n={};return Array.isArray(e)&&e.forEach(function(t){if(!(!t||typeof t.key!="string")){var r=typeof t.context=="string"?t.context:"",a=dt(t.attributes);Object.keys(a).length!==0&&(n[t.key+je+r]=a,Object.prototype.hasOwnProperty.call(n,t.key)||(n[t.key]=a))}}),n}function ht(e){return e.element?e.element:e.textNode&&e.textNode.parentElement?e.textNode.parentElement:null}function We(){return!i.apiKey||!i.apiBase?Promise.resolve({}):fetch(i.apiBase+"/api/aria",{headers:{"X-API-Key":i.apiKey}}).then(function(e){return e.json()}).then(function(e){return He(e)}).catch(function(e){return console.warn("[loco] Failed to fetch ARIA rules:",e),{}})}function pt(e,n){if(!e||!n)return!1;var t=e.__locoAriaPrev||{},r=!1;return Be.forEach(function(a){if(Object.prototype.hasOwnProperty.call(n,a)){var o=n[a];if(!(typeof o!="string"||o.trim()==="")){Object.prototype.hasOwnProperty.call(t,a)||(t[a]=e.hasAttribute(a)?e.getAttribute(a):null);try{e.setAttribute(a,o.trim()),r=!0}catch(l){console.warn("[loco] Could not set "+a,l)}}}}),r&&(e.__locoAriaPrev=t,e.setAttribute("data-loco-aria","")),r}function q(e,n){if(!n)return{applied:0};var t=0;return e.forEach(function(r){var a=r.key+je+(r.context||""),o=n[a]||n[r.key];if(o){var l=ht(r);l&&pt(l,o)&&t++}}),{applied:t}}var Xe="loco",gt=2;function ie(){return new Promise(function(e,n){try{var t=indexedDB.open(Xe,gt);t.onupgradeneeded=function(r){var a=r.target.result;a.objectStoreNames.contains("meta")&&r.oldVersion<2&&a.deleteObjectStore("meta"),a.objectStoreNames.contains("meta")||a.createObjectStore("meta",{keyPath:"key"}),a.objectStoreNames.contains("translations")||a.createObjectStore("translations",{keyPath:"lang"})},t.onsuccess=function(r){e(r.target.result)},t.onerror=function(){n(t.error)}}catch(r){n(r)}})}function ge(){return ie().then(function(e){return new Promise(function(n,t){var r=e.transaction("meta","readonly"),a=r.objectStore("meta").get("registry");a.onsuccess=function(){e.close();var o=a.result;n(o?{languages:o.languages||[],languageNames:o.languageNames||{}}:null)},a.onerror=function(){e.close(),t(a.error)}})})}function Qe(e){var n="source:"+e;return ie().then(function(t){return new Promise(function(r,a){var o=t.transaction("meta","readonly"),l=o.objectStore("meta").get(n);l.onsuccess=function(){t.close();var v=l.result;r(v?{url:v.url,timestamp:v.timestamp,storedAt:v.storedAt}:null)},l.onerror=function(){t.close(),a(l.error)}})})}function vt(e){return ie().then(function(n){return new Promise(function(t,r){var a=n.transaction("translations","readonly"),o=a.objectStore("translations").get(e);o.onsuccess=function(){n.close();var l=o.result;t(l?l.data:null)},o.onerror=function(){n.close(),r(o.error)}})})}function mt(){return ie().then(function(e){return new Promise(function(n,t){var r=e.transaction(["meta","translations"],"readonly"),a=r.objectStore("meta"),o=a.get("registry");o.onsuccess=function(){var l=o.result;if(!l||!l.languages||l.languages.length===0){e.close(),n(null);return}var v=Y(),p=v||l.languages[0],s=r.objectStore("translations").get(p);s.onsuccess=function(){e.close();var f=s.result;if(!f||!f.data){n(null);return}var h={};h[p]=f.data;var g=r.objectStore("meta").get("aria");g.onsuccess=function(){n({languages:l.languages,languageNames:l.languageNames||{},translations:h,aria:Array.isArray(g.result&&g.result.rules)?g.result.rules:[]})},g.onerror=function(){n({languages:l.languages,languageNames:l.languageNames||{},translations:h,aria:[]})}},s.onerror=function(){e.close(),t(s.error)}},o.onerror=function(){e.close(),t(o.error)}})})}function ve(e,n,t){var r=n.languages||[],a=n.languageNames||{},o=n.translations||{},l=Array.isArray(n.aria)?n.aria:[],v=n.timestamp||0;return ie().then(function(p){return new Promise(function(s,f){var h=p.transaction(["meta","translations"],"readwrite"),g=h.objectStore("meta"),c=h.objectStore("translations"),u=g.get("registry");u.onsuccess=function(){var d=u.result,m,x;if(t&&d){var b=d.languages||[];m=b.slice();for(var w=0;w<r.length;w++)m.indexOf(r[w])===-1&&m.push(r[w]);x={};var y=d.languageNames||{},E;for(E in y)x[E]=y[E];for(E in a)x[E]=a[E]}else m=r,x=a;g.put({key:"registry",languages:m,languageNames:x}),g.put({key:"source:"+e,url:e,timestamp:v,storedAt:Date.now()});var T=g.get("aria");T.onsuccess=function(){var C=l;if(t&&T.result&&Array.isArray(T.result.rules)){for(var O="\0",F={},R=[],K=T.result.rules,J=0;J<K.length;J++){var S=K[J];if(!(!S||typeof S.key!="string")){var U=S.key+O+(S.context||"");F.hasOwnProperty(U)||R.push(U),F[U]=S}}for(var P=0;P<l.length;P++){var D=l[P];if(!(!D||typeof D.key!="string")){var I=D.key+O+(D.context||"");F.hasOwnProperty(I)||R.push(I),F[I]=D}}C=R.map(function(oe){return F[oe]})}g.put({key:"aria",rules:C})},T.onerror=function(){g.put({key:"aria",rules:l})};for(var N=0;N<r.length;N++)o[r[N]]&&(t&&Array.isArray(o[r[N]])?function(C){var O=c.get(C);O.onsuccess=function(){var F=O.result,R=F&&Array.isArray(F.data)?F.data:null,K=o[C];if(R){for(var J="\0",S={},U=[],P=0;P<R.length;P++){var D=R[P].key+J+(R[P].context||"");S.hasOwnProperty(D)||U.push(D),S[D]=R[P]}for(var I=0;I<K.length;I++){var oe=K[I].key+J+(K[I].context||"");S.hasOwnProperty(oe)||U.push(oe),S[oe]=K[I]}for(var Ze=[],Fe=0;Fe<U.length;Fe++)Ze.push(S[U[Fe]]);c.put({lang:C,data:Ze})}else c.put({lang:C,data:K})}}(r[N]):c.put({lang:r[N],data:o[r[N]]}))},h.oncomplete=function(){p.close(),s()},h.onerror=function(){p.close(),f(h.error)}})})}function yt(){return new Promise(function(e){var n=indexedDB.deleteDatabase(Xe);n.onsuccess=function(){e()},n.onerror=function(){e()},n.onblocked=function(){e()}})}var xt='<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><defs><clipPath id="loco-wc"><circle cx="100" cy="100" r="90"/></clipPath></defs><circle cx="100" cy="100" r="90" fill="#1a1f2e"/><g clip-path="url(#loco-wc)"><g transform="translate(100,108) scale(0.72) translate(-334,-198)"><ellipse cx="310" cy="318" rx="10" ry="38" fill="#2ECC88" transform="rotate(-18 310 318)"/><ellipse cx="326" cy="326" rx="9" ry="42" fill="#34D99A" transform="rotate(-6 326 326)"/><ellipse cx="342" cy="328" rx="9" ry="42" fill="#7BC74A" transform="rotate(6 342 328)"/><ellipse cx="357" cy="320" rx="9" ry="36" fill="#F07040" transform="rotate(18 357 320)"/><ellipse cx="334" cy="240" rx="62" ry="80" fill="#2ECC88"/><ellipse cx="334" cy="252" rx="36" ry="52" fill="#D4F4B0"/><path d="M275 220 Q228 190 232 265 Q248 295 280 285 Q268 255 275 220Z" fill="#3A8FE0"/><path d="M277 225 Q238 208 240 262 Q252 285 278 277 Q268 252 277 225Z" fill="#6BB3FF" opacity="0.7"/><path d="M393 220 Q440 190 436 265 Q420 295 388 285 Q400 255 393 220Z" fill="#3A8FE0"/><path d="M391 225 Q430 208 428 262 Q416 285 390 277 Q400 252 391 225Z" fill="#6BB3FF" opacity="0.7"/><ellipse cx="334" cy="172" rx="38" ry="30" fill="#2ECC88"/><circle cx="334" cy="148" r="52" fill="#2ECC88"/><ellipse cx="334" cy="118" rx="30" ry="18" fill="#FFB833"/><circle cx="312" cy="138" r="14" fill="white"/><circle cx="315" cy="140" r="9" fill="#2C2C2A"/><circle cx="315" cy="140" r="4" fill="#04342C"/><circle cx="319" cy="136" r="3.5" fill="white"/><circle cx="356" cy="138" r="14" fill="white"/><circle cx="353" cy="140" r="9" fill="#2C2C2A"/><circle cx="353" cy="140" r="4" fill="#04342C"/><circle cx="357" cy="136" r="3.5" fill="white"/><path d="M326 155 Q334 144 342 155 Q342 170 334 173 Q326 170 326 155Z" fill="#E8A020"/><path d="M328 165 Q334 158 340 165 Q340 174 334 176 Q328 174 328 165Z" fill="#A06010"/><ellipse cx="302" cy="152" rx="12" ry="8" fill="#F07040" opacity="0.8"/><ellipse cx="366" cy="152" rx="12" ry="8" fill="#F07040" opacity="0.8"/><path d="M320 100 Q316 68 308 52" stroke="#FFB833" stroke-width="6" fill="none" stroke-linecap="round"/><path d="M334 97 Q334 64 334 46" stroke="#7BC74A" stroke-width="6" fill="none" stroke-linecap="round"/><path d="M348 100 Q352 68 360 52" stroke="#F07040" stroke-width="6" fill="none" stroke-linecap="round"/><circle cx="308" cy="50" r="8" fill="#FFB833"/><circle cx="334" cy="44" r="8" fill="#7BC74A"/><circle cx="360" cy="50" r="8" fill="#F07040"/><rect x="260" y="330" width="168" height="10" rx="5" fill="#8B5E20"/><path d="M310 330 L300 350 M310 330 L315 352 M310 330 L325 348" stroke="#A07030" stroke-width="4" fill="none" stroke-linecap="round"/><path d="M360 330 L350 350 M360 330 L365 352 M360 330 L375 348" stroke="#A07030" stroke-width="4" fill="none" stroke-linecap="round"/></g></g></svg>',Ce=null;function me(e,n){Ce=n;var t=document.getElementById("loco-lang-widget");t&&t.remove();var r={},a=e.map(function(y){return typeof y=="object"&&y.code?(y.name&&(r[y.code]=y.name),y.code):y}),o={"zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)"};function l(y){return String(y||"").trim().replace(/_/g,"-")}function v(y){return y&&y.charAt(0).toUpperCase()+y.slice(1).toLowerCase()}function p(y){var E=l(y);if(!E)return"";var T=E.split("-").filter(Boolean);if(T.length===0)return"";T[0]=T[0].toLowerCase();for(var N=1;N<T.length;N++)T[N].length===2?T[N]=T[N].toUpperCase():T[N].length===4?T[N]=v(T[N]):T[N]=T[N].toLowerCase();return T.join("-")}function s(y){var E=p(y);if(!E)return"";if(o[E])return o[E];if(E.indexOf("-")===-1)return"";try{if(typeof Intl<"u"&&typeof Intl.DisplayNames=="function"){var T=new Intl.DisplayNames([navigator.language||"en","en"],{type:"language"}),N=T.of(E);if(N&&N!==E)return N}}catch{}return""}function f(y,E){return y?p(y)===p(E):!0}function h(y){var E=r[y]||r[p(y)]||"";if(E&&!f(E,y))return E;var T=p(y);return o[T]?o[T]:s(y)||y}var g=Y()||null,c=document.createElement("div");c.id="loco-lang-widget",c.setAttribute("data-notranslate","");var u={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"};c.style.cssText='position:fixed;z-index:2147483647;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;'+(u[n]||u["bottom-right"]);var d=document.createElement("button");d.innerHTML=xt,d.style.cssText="width:52px;height:52px;border-radius:50%;border:none;background:#1a1f2e;color:#fff;font-size:22px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,0.25);display:flex;align-items:center;justify-content:center;transition:transform 0.2s,box-shadow 0.2s;overflow:hidden;padding:0;",d.onmouseenter=function(){d.style.transform="scale(1.1)",d.style.boxShadow="0 6px 20px rgba(0,0,0,0.35)"},d.onmouseleave=function(){d.style.transform="scale(1)",d.style.boxShadow="0 4px 14px rgba(0,0,0,0.25)"};var m=document.createElement("div");m.style.cssText="display:none;position:absolute;"+(n.indexOf("bottom")===0?"bottom:56px;":"top:56px;")+(n.indexOf("right")>=0?"right:0;":"left:0;")+"background:#fff;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,0.18);min-width:200px;max-height:320px;overflow-y:auto;padding:6px 0;";var x=document.createElement("div");x.textContent="Original",x.style.cssText="padding:10px 16px;cursor:pointer;color:#333;transition:background 0.15s;font-weight:600;border-bottom:1px solid #eee;",x.onmouseenter=function(){x.style.background="#f5f5f5"},x.onmouseleave=function(){x.style.background="transparent"},x.onclick=function(){g=null,window.Loco.restore(),w(),m.style.display="none"},m.appendChild(x);var b=[];a.forEach(function(y){var E=document.createElement("div");E.textContent=h(y),E.setAttribute("data-lang",y),E.style.cssText="padding:10px 16px;cursor:pointer;color:#333;transition:background 0.15s;",E.onmouseenter=function(){E.style.background="#f5f5f5"},E.onmouseleave=function(){E.style.background=g===y?"#e8f0fe":"transparent"},E.onclick=function(){g=y,window.Loco.apply(y),w(),m.style.display="none"},m.appendChild(E),b.push({el:E,code:y})});function w(){x.style.background=g===null?"#e8f0fe":"transparent",x.style.fontWeight=g===null?"600":"400",b.forEach(function(y){y.el.style.background=g===y.code?"#e8f0fe":"transparent",y.el.style.fontWeight=g===y.code?"600":"400"})}d.onclick=function(y){y.stopPropagation(),m.style.display=m.style.display==="none"?"block":"none"},document.addEventListener("click",function(y){c.contains(y.target)||(m.style.display="none")}),w(),c.appendChild(m),c.appendChild(d),document.body.appendChild(c)}function Et(e){Ce&&(!e||e.length===0||me(e,Ce))}var H={__proto__:1,constructor:1,prototype:1};function ze(e){if(!e||typeof e!="string")return!1;if(e.charAt(0)==="/"||e.charAt(0)===".")return!0;try{var n=new URL(e,window.location.origin);return n.protocol==="http:"||n.protocol==="https:"}catch{return!1}}function ye(e){if(!e||typeof e!="object"||Array.isArray(e))return null;if(Array.isArray(e._raw)){for(var n={},t={},r=0;r<e._raw.length;r++){var a=e._raw[r];!a||typeof a.l!="string"||typeof a.k!="string"||typeof a.v!="string"||(n[a.l]||(n[a.l]=!0,t[a.l]=[]),t[a.l].push({key:a.k,context:typeof a.c=="string"?a.c:"",value:a.v}))}e={languages:Object.keys(n).sort(),languageNames:{},translations:t,timestamp:0}}var o={};if(!Array.isArray(e.languages))return null;o.languages=[];for(var l=0;l<e.languages.length;l++){if(typeof e.languages[l]!="string"||e.languages[l].length>20)return null;o.languages.push(e.languages[l])}if(o.timestamp=typeof e.timestamp=="number"&&isFinite(e.timestamp)?e.timestamp:0,o.languageNames={},e.languageNames&&typeof e.languageNames=="object"&&!Array.isArray(e.languageNames))for(var v in e.languageNames)!e.languageNames.hasOwnProperty(v)||H[v]||typeof e.languageNames[v]=="string"&&e.languageNames[v].length<=100&&(o.languageNames[v]=e.languageNames[v]);if(o.translations={},e.translations&&typeof e.translations=="object"&&!Array.isArray(e.translations)){for(var p in e.translations)if(!(!e.translations.hasOwnProperty(p)||H[p])&&o.languages.indexOf(p)!==-1){var s=e.translations[p];if(Array.isArray(s)){for(var f=[],h=0;h<s.length;h++){var g=s[h];!g||typeof g!="object"||typeof g.key!="string"||typeof g.value!="string"||g.key.length>Z||g.value.length>Z||H[g.key]||f.push({key:g.key,value:g.value,context:typeof g.context=="string"?g.context:""})}o.translations[p]=f}else if(typeof s=="object"){var c={};for(var u in s)!s.hasOwnProperty(u)||H[u]||typeof s[u]=="string"&&(u.length>Z||s[u].length>Z||(c[u]=s[u]));o.translations[p]=c}}}if(o.aria=[],Array.isArray(e.aria))for(var d=0;d<e.aria.length;d++){var a=e.aria[d];if(!(!a||typeof a!="object")&&!(typeof a.key!="string"||a.key.length>Z)&&!H[a.key]){var m=typeof a.context=="string"?a.context:"",x=a.attributes;!x||typeof x!="object"||Array.isArray(x)||o.aria.push({key:a.key,context:m,attributes:x})}}return o}async function Ge(){try{var e=await fetch(i.apiBase+"/api/project/crawler-config",{headers:{"X-API-Key":i.apiKey}});e.ok&&Ye(await e.json())}catch{}Le(),i.phrases=await ae(document.body),de(i.phrases).then(function(t){t&&t.keyMap&&ce(i.phrases,t.keyMap)}).catch(function(t){console.warn("[loco] Failed to register keys:",t)}),We().then(function(t){i.ariaRules=t||{};var r=q(i.phrases,i.ariaRules);r.applied>0&&console.log("[loco] applied ARIA rules to "+r.applied+" element(s)")}).catch(function(){}),!i.scanStopped&&i.screenshotsEnabled&&setTimeout(ut,3e3),console.log("[loco] "+i.phrases.length+" text nodes discovered"),console.log(` Loco.textnodes() — list all discovered text nodes
2
2
  Loco.apply("zh-Hans") — apply translations for a language
3
3
  Loco.restore() — revert to original text
4
- Loco.rescan() — re-scan DOM for new nodes`);var n=Y();n?z.apply(n):i.observer=pe(i.phrases.map(function(t){return t.key+"\0"+(t.context||"")}),{})}function xt(e,n){for(var t="\0",a={},r=[],o=0;o<e.length;o++){var l=e[o],v=l.key+t+(l.context||"");a.hasOwnProperty(v)||r.push(v),a[v]=l}for(var p=0;p<n.length;p++){var s=n[p],f=s.key+t+(s.context||"");a.hasOwnProperty(f)||r.push(f),a[f]=s}for(var h=[],g=0;g<r.length;g++)h.push(a[r[g]]);return h}async function xe(e){i.screenshotsEnabled=!1,Le(),i.phrases=await ae(document.body);var n=[],t=i.fileData.translations||{},a=(i.fileData.languages||[])[0];a&&t[a]&&(t[a]=Ke(t[a]),n=Object.keys(t[a]));var r=G(i.phrases,n),o=r?Object.keys(r).length:0,l=(i.fileData.languages||[]).length;console.log("[loco] (file mode) "+i.phrases.length+" text nodes discovered, "+l+" language(s) available"+(o?", "+o+" var-remapped":"")+" ["+e+"]"),console.log(" Languages: "+(i.fileData.languages||[]).join(", "));var v=Y();v?z.apply(v):i.observer=pe(i.phrases.map(function(p){return p.key+"\0"+(p.context||"")}),{}),i.ariaRules=je(i.fileData.aria||[]),Object.keys(i.ariaRules).length>0&&V(i.phrases,i.ariaRules)}async function qe(e){try{indexedDB.deleteDatabase("loco-translations")}catch{}try{indexedDB.deleteDatabase("loco-meta")}catch{}try{indexedDB.databases&&indexedDB.databases().then(function(t){t.forEach(function(a){if(a.name&&a.name.indexOf("loco-tr-")===0)try{indexedDB.deleteDatabase(a.name)}catch{}})}).catch(function(){})}catch{}i.fileUrls=e;var n=null;try{n=await gt()}catch{}n&&n.translations?(i.fileData={languages:n.languages,languageNames:n.languageNames||{},translations:n.translations,aria:n.aria||[],timestamp:0},i.loadedFromCache=!0,await xe("cache"),i.fileReadyResolve&&(i.fileReadyResolve(),i.fileReadyResolve=null),bt(e)):(await Et(e),await xe("network"),i.fileReadyResolve&&(i.fileReadyResolve(),i.fileReadyResolve=null))}async function Et(e){for(var n=e.map(function(p){return fetch(p).then(function(s){if(!s.ok)throw new Error("HTTP "+s.status+" for "+p);return s.text()}).then(function(s){if(!s||!s.trim())return null;var f;try{f=JSON.parse(s)}catch{return null}var h=ye(f);return h?{url:p,data:h}:(console.warn("[loco] File rejected (invalid schema): "+p),null)}).catch(function(s){return console.warn("[loco] Failed to load "+p+":",s),null})}),t=await Promise.all(n),a=!0,r=0;r<t.length;r++)if(t[r]){var o=t[r].url,l=t[r].data,v=!a||(l.languages||[]).length===1;Ee(l,a),a=!1;try{await ve(o,l,v)}catch{}}i.loadedFromCache=!1}function Ee(e,n){if(!i.fileData||n){i.fileData={languages:(e.languages||[]).slice(),languageNames:Object.assign({},e.languageNames||{}),translations:Object.assign({},e.translations||{}),aria:(e.aria||[]).slice(),timestamp:e.timestamp||0},i.fileData.aria||(i.fileData.aria=[]);var t=e.aria||[];if(t.length>0){for(var a="\0",r={},o=[],l=0;l<i.fileData.aria.length;l++){var v=i.fileData.aria[l];if(!(!v||typeof v.key!="string")){var p=v.key+a+(v.context||"");r.hasOwnProperty(p)||o.push(p),r[p]=v}}for(var s=0;s<t.length;s++){var f=t[s];if(!(!f||typeof f.key!="string")){var h=f.key+a+(f.context||"");r.hasOwnProperty(h)||o.push(h),r[h]=f}}i.fileData.aria=o.map(function(y){return r[y]})}return}for(var g=e.languages||[],c=0;c<g.length;c++)i.fileData.languages.indexOf(g[c])===-1&&i.fileData.languages.push(g[c]);var u=e.languageNames||{};i.fileData.languageNames||(i.fileData.languageNames={});for(var d in u)!u.hasOwnProperty(d)||H[d]||(i.fileData.languageNames[d]=u[d]);var m=e.translations||{};i.fileData.translations||(i.fileData.translations={});for(var x in m)if(!(!m.hasOwnProperty(x)||H[x])){var b=i.fileData.translations[x],w=m[x];!b||!Array.isArray(b)||!Array.isArray(w)?i.fileData.translations[x]=w:i.fileData.translations[x]=xt(b,w)}e.timestamp&&e.timestamp>i.fileData.timestamp&&(i.fileData.timestamp=e.timestamp)}function bt(e){var n=e.map(function(t){return Promise.all([Xe(t).catch(function(){return null}),fetch(t).then(function(a){return a.ok?a.text():null}).catch(function(){return null})]).then(function(a){var r=a[0],o=a[1];if(!o||!o.trim())return null;var l;try{l=JSON.parse(o)}catch{return null}if(l=ye(l),!l)return null;var v=l.timestamp||0,p=r&&r.timestamp||0;if(v!==p){var s=e.length>1||(l.languages||[]).length===1;return ve(t,l,s).catch(function(){}),l}return null})});Promise.all(n).then(function(t){for(var a=!1,r=0;r<t.length;r++)t[r]&&(Ee(t[r],!1),a=!0);a&&(i.loadedFromCache=!1,i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),xe("network — updated").then(function(){Ce()}),console.log("[loco] translations refreshed from file(s) (timestamp changed)"))}).catch(function(){console.log("[loco] using cached translations (network unavailable)")})}function Ce(){i.widgetPosition&&ge().then(function(e){if(e){var n=be(e.languages,e.languageNames);yt(n)}}).catch(function(){})}function Ge(e,n){if(!e||!n)return"";var t=n[e];if(t)return t;var a=String(e).replace(/_/g,"-");if(n[a])return n[a];var r=a.toLowerCase();if(n[r])return n[r];var o=r.split("-").map(function(l,v){return v===0?l:l.length===2?l.toUpperCase():l.length===4?l.charAt(0).toUpperCase()+l.slice(1):l}).join("-");return n[o]?n[o]:""}function be(e,n){return e=e||[],n=n||{},e.map(function(t){var a=Ge(t,n);return a?{code:t,name:a}:t})}function wt(e){return e?e.type==="text"?!!(e.textNode&&e.textNode.parentElement&&e.textNode.isConnected):!!(e.element&&e.element.isConnected):!1}function Ve(){if(!Array.isArray(i.phrases)||i.phrases.length===0)return[];var e=i.phrases.filter(wt);return e.length!==i.phrases.length&&(i.phrases=e),i.phrases}var z={version:"1.1.4",init:function(e){if(!e){console.warn("[loco] Loco.init() requires a config object");return}if(e.file||e.files){i.fileMode=!0,i.fileReady=new Promise(function(a){i.fileReadyResolve=a});for(var n=e.files?e.files.slice():[e.file],t=0;t<n.length;t++)if(!Qe(n[t])){console.warn("[loco] Blocked unsafe URL: "+n[t]);return}i.fileUrl=n[0],document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){qe(n)}):qe(n);return}if(!e.apiKey){console.warn("[loco] Loco.init() requires { apiKey } or { file }");return}if(!e.apiUrl){console.warn("[loco] Loco.init() requires { apiUrl }");return}i.apiKey=e.apiKey,i.apiBase=e.apiUrl.replace(/\/+$/,""),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",$e):$e()},apply:async function(e){var n=typeof window<"u"&&window.__locoPerfMode;if(n&&(performance.clearMarks(),performance.clearMeasures(),performance.mark("loco-apply-start")),!e){console.warn('[loco] Loco.apply() requires a language code, e.g. Loco.apply("zh-Hans")');return}if(typeof e!="string"||e.length>20||!/^[a-zA-Z0-9\-_]+$/.test(e)){console.warn("[loco] Invalid language code: "+e);return}if(i.fileMode){if(!i.fileData){console.warn("[loco] File not loaded yet. Call Loco.init({ file }) first.");return}if(!i.fileData.translations||!i.fileData.translations[e])try{var t=await pt(e);if(!t||Object.keys(t).length===0){console.warn('[loco] No translations for "'+e+'" in file data or cache');return}return i.fileData.translations||(i.fileData.translations={}),i.fileData.translations[e]=t,i.fileData.languages.indexOf(e)===-1&&i.fileData.languages.push(e),z.apply(e)}catch(p){console.warn('[loco] Failed to load translations for "'+e+'" from cache:',p);return}i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),i.translations=Ke(i.fileData.translations[e]),i.fileData.translations[e]=i.translations,n&&performance.mark("loco-collect-start");var a=Ve();a.length===0&&(i.phrases=await ae(document.body)),n&&(performance.mark("loco-collect-end"),performance.measure("loco-collection-time","loco-collect-start","loco-collect-end"));var r=Object.keys(i.translations);G(i.phrases,r),n&&performance.mark("loco-dom-start");var o=await he(i.phrases,i.translations);return n&&(performance.mark("loco-dom-end"),performance.measure("loco-dom-write-time","loco-dom-start","loco-dom-end"),performance.measure("loco-apply-total","loco-apply-start","loco-dom-end")),i.ariaRules&&Object.keys(i.ariaRules).length>0&&V(i.phrases,i.ariaRules),i.observer=pe(i.phrases.map(function(p){return p.key+"\0"+(p.context||"")}),i.translations),i.currentLang=e,le(e),console.log("[loco] (file) applied "+o.applied+" translation(s), "+o.skipped+" pending"),o}if(!i.apiKey||!i.apiBase){console.warn("[loco] Call Loco.init() first");return}i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases);try{var l=await lt(e);i.translations=l||{},n&&performance.mark("loco-collect-start");var v=Ve();v.length===0&&(i.phrases=await ae(document.body)),n&&(performance.mark("loco-collect-end"),performance.measure("loco-collection-time","loco-collect-start","loco-collect-end")),G(i.phrases,Object.keys(i.translations)),de(i.phrases).then(function(s){s&&s.keyMap&&(ce(i.phrases,s.keyMap),he(i.phrases,i.translations))}).catch(function(){}),n&&performance.mark("loco-dom-start");var o=await he(i.phrases,i.translations);return n&&(performance.mark("loco-dom-end"),performance.measure("loco-dom-write-time","loco-dom-start","loco-dom-end"),performance.measure("loco-apply-total","loco-apply-start","loco-dom-end")),i.ariaRules&&Object.keys(i.ariaRules).length>0&&V(i.phrases,i.ariaRules),i.observer=pe(i.phrases.map(function(s){return s.key+"\0"+(s.context||"")}),i.translations),i.currentLang=e,le(e),console.log("[loco] applied "+o.applied+" translation(s), "+o.skipped+" pending"),o}catch(p){console.warn("[loco] Failed to fetch translations:",p)}},restore:function(){j(i.phrases),i.observer&&i.observer.disconnect(),i.currentLang=null,le(null)},rescan:async function(){var e=Object.keys(i.translations).length>0;e&&j(i.phrases),i.currentLang=null,i.phrases=await ae(document.body),i.fileMode||de(i.phrases).catch(function(){}),i.ariaRules&&Object.keys(i.ariaRules).length>0&&V(i.phrases,i.ariaRules),e&&(G(i.phrases,Object.keys(i.translations)),await he(i.phrases,i.translations))},textnodes:function(){return i.phrases.map(function(e){return{key:e.key,context:e.context||"",element:e.element}})},aria:async function(){var e=await He();i.ariaRules=e||{};var n=V(i.phrases,i.ariaRules);return console.log("[loco] applied ARIA rules to "+n.applied+" element(s)"),n},stopScan:function(){i.scanStopped=!0,i.observer&&(i.observer.disconnect(),i.observer=null),console.log("[loco] scanning stopped, no further nodes will be sent to dashboard")},startScan:function(){i.scanStopped=!1,console.log("[loco] scanning resumed")},isFileMode:function(){return i.fileMode},languages:function(){if(i.fileMode){var e=function(){var n=i.fileData?i.fileData.languages||[]:[],t=i.fileData&&i.fileData.languageNames||{};return n.map(function(a){return{code:a,name:t[a]||a}})};return!i.fileData&&i.fileReady?i.fileReady.then(function(){return ge().then(function(n){return n&&n.languages&&n.languages.length>0?be(n.languages,n.languageNames):e()}).catch(function(){return e()})}):ge().then(function(n){return n&&n.languages&&n.languages.length>0?be(n.languages,n.languageNames):e()}).catch(function(){return e()})}return!i.apiKey||!i.apiBase?Promise.resolve([]):fetch(i.apiBase+"/api/languages",{headers:{"X-API-Key":i.apiKey}}).then(function(n){return n.json()}).then(function(n){return Array.isArray(n)?n:[]}).catch(function(){return[]})},widget:function(e){e=e||{};var n=e.position||"bottom-right";if(i.widgetPosition=n,i.fileMode){let t=function(){ge().then(function(r){var o;if(r&&r.languages&&r.languages.length>0?o=be(r.languages,r.languageNames):o=a(),o.length===0){console.warn("[loco] No languages found in translation file or cache");return}me(o,n)}).catch(function(){var r=a();if(r.length===0){console.warn("[loco] No languages found in translation file");return}me(r,n)})},a=function(){var r=i.fileData?i.fileData.languages||[]:[],o=i.fileData&&i.fileData.languageNames||{};return r.map(function(l){var v=Ge(l,o);return v?{code:l,name:v}:l})};if(!i.fileData&&i.fileReady){i.fileReady.then(t);return}t();return}if(!i.apiKey||!i.apiBase){console.warn("[loco] Call Loco.init() first");return}fetch(i.apiBase+"/api/languages",{headers:{"X-API-Key":i.apiKey}}).then(function(t){return t.json()}).then(function(t){if(!Array.isArray(t)||t.length===0){console.warn("[loco] No languages found — add translations in the dashboard first");return}me(t,n)}).catch(function(t){console.warn("[loco] Failed to fetch languages:",t)})},clearCache:function(){return i.fileMode?vt().then(function(){i.fileData&&(i.fileData.translations={},i.fileData.timestamp=0),i.currentLang=null,i.loadedFromCache=!1,le(null),j(i.phrases),i.observer&&(i.observer.disconnect(),i.observer=null),console.log("[loco] IndexedDB cache cleared — call pullLatest() to re-fetch")}).catch(function(e){console.warn("[loco] Failed to clear cache:",e)}):(console.warn("[loco] clearCache() is only available in file mode"),Promise.resolve())},addFile:function(e){return i.fileMode?e?Qe(e)?(i.fileUrls.indexOf(e)===-1&&i.fileUrls.push(e),fetch(e).then(function(n){if(!n.ok)throw new Error("HTTP "+n.status);return n.text()}).then(function(n){if(!n||!n.trim())throw new Error("Empty file");var t;try{t=JSON.parse(n)}catch{throw new Error("Invalid JSON")}if(t=ye(t),!t)throw new Error("Invalid file schema");var a=!i.fileData||!i.fileData.languages||i.fileData.languages.length===0,r=!a||(t.languages||[]).length===1;return Ee(t,a),ve(e,t,r).catch(function(){}),Ce(),console.log("[loco] added file: "+e+" ("+(t.languages||[]).join(", ")+")"),{status:"added",languages:t.languages||[]}}).catch(function(n){return console.warn("[loco] addFile() failed:",n),{status:"error",reason:n.message}})):(console.warn("[loco] Blocked unsafe URL: "+e),Promise.resolve({status:"error",reason:"unsafe URL"})):Promise.resolve({status:"error",reason:"no URL provided"}):(console.warn("[loco] addFile() is only available in file mode"),Promise.resolve({status:"error",reason:"not in file mode"}))},pullLatest:function(){if(!i.fileMode)return console.warn("[loco] pullLatest() is only available in file mode"),Promise.resolve({status:"skipped",reason:"not in file mode"});var e=i.fileUrls.length>0?i.fileUrls:i.fileUrl?[i.fileUrl]:[];if(e.length===0)return console.warn("[loco] No file URL(s) configured. Call Loco.init({ file }) first."),Promise.resolve({status:"error",reason:"no file URLs"});var n=e.map(function(t){return Promise.all([Xe(t).catch(function(){return null}),fetch(t).then(function(a){if(!a.ok)throw new Error("HTTP "+a.status);return a.text()})]).then(function(a){var r=a[0],o=a[1];if(!o||!o.trim())return{url:t,status:"current",reason:"empty"};var l;try{l=JSON.parse(o)}catch{throw new Error("Invalid JSON in "+t)}if(l=ye(l),!l)throw new Error("Invalid file schema in "+t);var v=l.timestamp||0,p=r&&r.timestamp||0;if(v===p&&p!==0){var s=i.fileData&&i.fileData.translations,f=l.languages||[],h=!s||f.some(function(u){return!i.fileData.translations[u]});if(!h)return{url:t,status:"current",timestamp:p}}var g=!i.fileData||!i.fileData.languages||i.fileData.languages.length===0,c=!g||(l.languages||[]).length===1;return Ee(l,g),ve(t,l,c).catch(function(){}),{url:t,status:"updated",timestamp:v,previousTimestamp:p}}).catch(function(a){return{url:t,status:"error",reason:a.message}})});return Promise.all(n).then(async function(t){var a=t.some(function(f){return f.status==="updated"});if(a){i.loadedFromCache=!1,i.currentLang=null;var r=Y();if(r)i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),await xe("pullLatest");else{i.phrases=Me(document.body);var o=i.fileData.translations||{},l=(i.fileData.languages||[])[0];l&&o[l]&&G(i.phrases,Object.keys(o[l]))}Ce()}if(t.length===1){var v=t[0];return console.log("[loco] pullLatest: "+v.status+(v.timestamp?" (timestamp: "+v.timestamp+")":"")),v}var p=t.filter(function(f){return f.status==="updated"}).map(function(f){return f.url}),s=t.filter(function(f){return f.status==="current"}).map(function(f){return f.url});return console.log("[loco] pullLatest: "+p.length+" updated, "+s.length+" current"),{status:a?"updated":"current",results:t}}).catch(function(t){return console.warn("[loco] pullLatest() failed:",t),{status:"error",reason:t.message}})}};return window.Loco=z,Object.defineProperty(z,"_state",{value:i,writable:!1,enumerable:!1,configurable:!1}),z}();
4
+ Loco.rescan() — re-scan DOM for new nodes`);var n=Y();n?V.apply(n):i.observer=pe(i.phrases.map(function(t){return t.key+"\0"+(t.context||"")}),{})}function bt(e,n){for(var t="\0",r={},a=[],o=0;o<e.length;o++){var l=e[o],v=l.key+t+(l.context||"");r.hasOwnProperty(v)||a.push(v),r[v]=l}for(var p=0;p<n.length;p++){var s=n[p],f=s.key+t+(s.context||"");r.hasOwnProperty(f)||a.push(f),r[f]=s}for(var h=[],g=0;g<a.length;g++)h.push(r[a[g]]);return h}async function xe(e){i.screenshotsEnabled=!1,Le(),i.phrases=await ae(document.body);var n=[],t=i.fileData.translations||{},r=(i.fileData.languages||[])[0];r&&t[r]&&(t[r]=Ue(t[r]),n=Object.keys(t[r]));var a=$(i.phrases,n),o=a?Object.keys(a).length:0,l=(i.fileData.languages||[]).length;console.log("[loco] (file mode) "+i.phrases.length+" text nodes discovered, "+l+" language(s) available"+(o?", "+o+" var-remapped":"")+" ["+e+"]"),console.log(" Languages: "+(i.fileData.languages||[]).join(", "));var v=Y();v?V.apply(v):i.observer=pe(i.phrases.map(function(p){return p.key+"\0"+(p.context||"")}),{}),i.ariaRules=He(i.fileData.aria||[]),Object.keys(i.ariaRules).length>0&&q(i.phrases,i.ariaRules)}async function $e(e){try{indexedDB.deleteDatabase("loco-translations")}catch{}try{indexedDB.deleteDatabase("loco-meta")}catch{}try{indexedDB.databases&&indexedDB.databases().then(function(t){t.forEach(function(r){if(r.name&&r.name.indexOf("loco-tr-")===0)try{indexedDB.deleteDatabase(r.name)}catch{}})}).catch(function(){})}catch{}i.fileUrls=e;var n=null;try{n=await mt()}catch{}n&&n.translations?(i.fileData={languages:n.languages,languageNames:n.languageNames||{},translations:n.translations,aria:n.aria||[],timestamp:0},i.loadedFromCache=!0,await xe("cache"),i.fileReadyResolve&&(i.fileReadyResolve(),i.fileReadyResolve=null),Nt(e)):(await wt(e),await xe("network"),i.fileReadyResolve&&(i.fileReadyResolve(),i.fileReadyResolve=null))}async function wt(e){for(var n=e.map(function(p){return fetch(p).then(function(s){if(!s.ok)throw new Error("HTTP "+s.status+" for "+p);return s.text()}).then(function(s){if(!s||!s.trim())return null;var f;try{f=JSON.parse(s)}catch{return null}var h=ye(f);return h?{url:p,data:h}:(console.warn("[loco] File rejected (invalid schema): "+p),null)}).catch(function(s){return console.warn("[loco] Failed to load "+p+":",s),null})}),t=await Promise.all(n),r=!0,a=0;a<t.length;a++)if(t[a]){var o=t[a].url,l=t[a].data,v=!r||(l.languages||[]).length===1;Ee(l,r),r=!1;try{await ve(o,l,v)}catch{}}i.loadedFromCache=!1}function Ee(e,n){if(!i.fileData||n){i.fileData={languages:(e.languages||[]).slice(),languageNames:Object.assign({},e.languageNames||{}),translations:Object.assign({},e.translations||{}),aria:(e.aria||[]).slice(),timestamp:e.timestamp||0},i.fileData.aria||(i.fileData.aria=[]);var t=e.aria||[];if(t.length>0){for(var r="\0",a={},o=[],l=0;l<i.fileData.aria.length;l++){var v=i.fileData.aria[l];if(!(!v||typeof v.key!="string")){var p=v.key+r+(v.context||"");a.hasOwnProperty(p)||o.push(p),a[p]=v}}for(var s=0;s<t.length;s++){var f=t[s];if(!(!f||typeof f.key!="string")){var h=f.key+r+(f.context||"");a.hasOwnProperty(h)||o.push(h),a[h]=f}}i.fileData.aria=o.map(function(y){return a[y]})}return}for(var g=e.languages||[],c=0;c<g.length;c++)i.fileData.languages.indexOf(g[c])===-1&&i.fileData.languages.push(g[c]);var u=e.languageNames||{};i.fileData.languageNames||(i.fileData.languageNames={});for(var d in u)!u.hasOwnProperty(d)||H[d]||(i.fileData.languageNames[d]=u[d]);var m=e.translations||{};i.fileData.translations||(i.fileData.translations={});for(var x in m)if(!(!m.hasOwnProperty(x)||H[x])){var b=i.fileData.translations[x],w=m[x];!b||!Array.isArray(b)||!Array.isArray(w)?i.fileData.translations[x]=w:i.fileData.translations[x]=bt(b,w)}e.timestamp&&e.timestamp>i.fileData.timestamp&&(i.fileData.timestamp=e.timestamp)}function Nt(e){var n=e.map(function(t){return Promise.all([Qe(t).catch(function(){return null}),fetch(t).then(function(r){return r.ok?r.text():null}).catch(function(){return null})]).then(function(r){var a=r[0],o=r[1];if(!o||!o.trim())return null;var l;try{l=JSON.parse(o)}catch{return null}if(l=ye(l),!l)return null;var v=l.timestamp||0,p=a&&a.timestamp||0;if(v!==p){var s=e.length>1||(l.languages||[]).length===1;return ve(t,l,s).catch(function(){}),l}return null})});Promise.all(n).then(function(t){for(var r=!1,a=0;a<t.length;a++)t[a]&&(Ee(t[a],!1),r=!0);r&&(i.loadedFromCache=!1,i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),xe("network — updated").then(function(){Se()}),console.log("[loco] translations refreshed from file(s) (timestamp changed)"))}).catch(function(){console.log("[loco] using cached translations (network unavailable)")})}function Se(){i.widgetPosition&&ge().then(function(e){if(e){var n=be(e.languages,e.languageNames);Et(n)}}).catch(function(){})}var qe={"zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)"};function Tt(e){var n=String(e||"").trim().replace(/_/g,"-");if(!n)return"";var t=n.split("-").filter(Boolean);if(t.length===0)return"";t[0]=t[0].toLowerCase();for(var r=1;r<t.length;r++)t[r].length===2?t[r]=t[r].toUpperCase():t[r].length===4?t[r]=t[r].charAt(0).toUpperCase()+t[r].slice(1).toLowerCase():t[r]=t[r].toLowerCase();return t.join("-")}function Ve(e){var n=Tt(e);if(!n)return"";if(qe[n])return qe[n];if(n.indexOf("-")===-1)return"";try{if(typeof Intl<"u"&&typeof Intl.DisplayNames=="function"){var t=new Intl.DisplayNames([typeof navigator<"u"&&navigator.language||"en","en"],{type:"language"}),r=t.of(n);if(r&&r!==n)return r}}catch{}return""}function Oe(e,n){if(!e)return"";n=n||{};var t=n[e];if(t)return t;var r=String(e).replace(/_/g,"-");if(n[r])return n[r];var a=r.toLowerCase();if(n[a])return n[a];var o=a.split("-").map(function(l,v){return v===0?l:l.length===2?l.toUpperCase():l.length===4?l.charAt(0).toUpperCase()+l.slice(1):l}).join("-");return n[o]?n[o]:Ve(e)}function be(e,n){return e=e||[],n=n||{},e.map(function(t){var r=Oe(t,n);return r?{code:t,name:r}:t})}function At(e){return e?e.type==="text"?!!(e.textNode&&e.textNode.parentElement&&e.textNode.isConnected):!!(e.element&&e.element.isConnected):!1}function Je(){if(!Array.isArray(i.phrases)||i.phrases.length===0)return[];var e=i.phrases.filter(At);return e.length!==i.phrases.length&&(i.phrases=e),i.phrases}var V={version:"1.1.5",init:function(e){if(!e){console.warn("[loco] Loco.init() requires a config object");return}if(e.file||e.files){i.fileMode=!0,i.fileReady=new Promise(function(r){i.fileReadyResolve=r});for(var n=e.files?e.files.slice():[e.file],t=0;t<n.length;t++)if(!ze(n[t])){console.warn("[loco] Blocked unsafe URL: "+n[t]);return}i.fileUrl=n[0],document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){$e(n)}):$e(n);return}if(!e.apiKey){console.warn("[loco] Loco.init() requires { apiKey } or { file }");return}if(!e.apiUrl){console.warn("[loco] Loco.init() requires { apiUrl }");return}i.apiKey=e.apiKey,i.apiBase=e.apiUrl.replace(/\/+$/,""),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ge):Ge()},apply:async function(e){var n=typeof window<"u"&&window.__locoPerfMode;if(n&&(performance.clearMarks(),performance.clearMeasures(),performance.mark("loco-apply-start")),!e){console.warn('[loco] Loco.apply() requires a language code, e.g. Loco.apply("zh-Hans")');return}if(typeof e!="string"||e.length>20||!/^[a-zA-Z0-9\-_]+$/.test(e)){console.warn("[loco] Invalid language code: "+e);return}if(i.fileMode){if(!i.fileData){console.warn("[loco] File not loaded yet. Call Loco.init({ file }) first.");return}if(!i.fileData.translations||!i.fileData.translations[e])try{var t=await vt(e);if(!t||Object.keys(t).length===0){console.warn('[loco] No translations for "'+e+'" in file data or cache');return}return i.fileData.translations||(i.fileData.translations={}),i.fileData.translations[e]=t,i.fileData.languages.indexOf(e)===-1&&i.fileData.languages.push(e),V.apply(e)}catch(p){console.warn('[loco] Failed to load translations for "'+e+'" from cache:',p);return}i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),i.translations=Ue(i.fileData.translations[e]),i.fileData.translations[e]=i.translations,n&&performance.mark("loco-collect-start");var r=Je();r.length===0&&(i.phrases=await ae(document.body)),n&&(performance.mark("loco-collect-end"),performance.measure("loco-collection-time","loco-collect-start","loco-collect-end"));var a=Object.keys(i.translations);$(i.phrases,a),n&&performance.mark("loco-dom-start");var o=await he(i.phrases,i.translations);return n&&(performance.mark("loco-dom-end"),performance.measure("loco-dom-write-time","loco-dom-start","loco-dom-end"),performance.measure("loco-apply-total","loco-apply-start","loco-dom-end")),i.ariaRules&&Object.keys(i.ariaRules).length>0&&q(i.phrases,i.ariaRules),i.observer=pe(i.phrases.map(function(p){return p.key+"\0"+(p.context||"")}),i.translations),i.currentLang=e,le(e),console.log("[loco] (file) applied "+o.applied+" translation(s), "+o.skipped+" pending"),o}if(!i.apiKey||!i.apiBase){console.warn("[loco] Call Loco.init() first");return}i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases);try{var l=await ct(e);i.translations=l||{},n&&performance.mark("loco-collect-start");var v=Je();v.length===0&&(i.phrases=await ae(document.body)),n&&(performance.mark("loco-collect-end"),performance.measure("loco-collection-time","loco-collect-start","loco-collect-end")),$(i.phrases,Object.keys(i.translations)),de(i.phrases).then(function(s){s&&s.keyMap&&(ce(i.phrases,s.keyMap),he(i.phrases,i.translations))}).catch(function(){}),n&&performance.mark("loco-dom-start");var o=await he(i.phrases,i.translations);return n&&(performance.mark("loco-dom-end"),performance.measure("loco-dom-write-time","loco-dom-start","loco-dom-end"),performance.measure("loco-apply-total","loco-apply-start","loco-dom-end")),i.ariaRules&&Object.keys(i.ariaRules).length>0&&q(i.phrases,i.ariaRules),i.observer=pe(i.phrases.map(function(s){return s.key+"\0"+(s.context||"")}),i.translations),i.currentLang=e,le(e),console.log("[loco] applied "+o.applied+" translation(s), "+o.skipped+" pending"),o}catch(p){console.warn("[loco] Failed to fetch translations:",p)}},restore:function(){j(i.phrases),i.observer&&i.observer.disconnect(),i.currentLang=null,le(null)},rescan:async function(){var e=Object.keys(i.translations).length>0;e&&j(i.phrases),i.currentLang=null,i.phrases=await ae(document.body),i.fileMode||de(i.phrases).catch(function(){}),i.ariaRules&&Object.keys(i.ariaRules).length>0&&q(i.phrases,i.ariaRules),e&&($(i.phrases,Object.keys(i.translations)),await he(i.phrases,i.translations))},textnodes:function(){return i.phrases.map(function(e){return{key:e.key,context:e.context||"",element:e.element}})},aria:async function(){var e=await We();i.ariaRules=e||{};var n=q(i.phrases,i.ariaRules);return console.log("[loco] applied ARIA rules to "+n.applied+" element(s)"),n},stopScan:function(){i.scanStopped=!0,i.observer&&(i.observer.disconnect(),i.observer=null),console.log("[loco] scanning stopped, no further nodes will be sent to dashboard")},startScan:function(){i.scanStopped=!1,console.log("[loco] scanning resumed")},isFileMode:function(){return i.fileMode},languages:function(){if(i.fileMode){var e=function(){var n=i.fileData?i.fileData.languages||[]:[],t=i.fileData&&i.fileData.languageNames||{};return n.map(function(r){return{code:r,name:Oe(r,t)||r}})};return!i.fileData&&i.fileReady?i.fileReady.then(function(){return ge().then(function(n){return n&&n.languages&&n.languages.length>0?be(n.languages,n.languageNames):e()}).catch(function(){return e()})}):ge().then(function(n){return n&&n.languages&&n.languages.length>0?be(n.languages,n.languageNames):e()}).catch(function(){return e()})}return!i.apiKey||!i.apiBase?Promise.resolve([]):fetch(i.apiBase+"/api/languages",{headers:{"X-API-Key":i.apiKey}}).then(function(n){return n.json()}).then(function(n){return Array.isArray(n)?n.map(function(t){if(t&&typeof t=="object"&&t.code){var r=t.name&&t.name!==t.code?t.name:Ve(t.code);return{code:t.code,name:r||t.code}}return t}):[]}).catch(function(){return[]})},widget:function(e){e=e||{};var n=e.position||"bottom-right";if(i.widgetPosition=n,i.fileMode){let t=function(){ge().then(function(a){var o;if(a&&a.languages&&a.languages.length>0?o=be(a.languages,a.languageNames):o=r(),o.length===0){console.warn("[loco] No languages found in translation file or cache");return}me(o,n)}).catch(function(){var a=r();if(a.length===0){console.warn("[loco] No languages found in translation file");return}me(a,n)})},r=function(){var a=i.fileData?i.fileData.languages||[]:[],o=i.fileData&&i.fileData.languageNames||{};return a.map(function(l){var v=Oe(l,o);return v?{code:l,name:v}:l})};if(!i.fileData&&i.fileReady){i.fileReady.then(t);return}t();return}if(!i.apiKey||!i.apiBase){console.warn("[loco] Call Loco.init() first");return}fetch(i.apiBase+"/api/languages",{headers:{"X-API-Key":i.apiKey}}).then(function(t){return t.json()}).then(function(t){if(!Array.isArray(t)||t.length===0){console.warn("[loco] No languages found — add translations in the dashboard first");return}me(t,n)}).catch(function(t){console.warn("[loco] Failed to fetch languages:",t)})},clearCache:function(){return i.fileMode?yt().then(function(){i.fileData&&(i.fileData.translations={},i.fileData.timestamp=0),i.currentLang=null,i.loadedFromCache=!1,le(null),j(i.phrases),i.observer&&(i.observer.disconnect(),i.observer=null),console.log("[loco] IndexedDB cache cleared — call pullLatest() to re-fetch")}).catch(function(e){console.warn("[loco] Failed to clear cache:",e)}):(console.warn("[loco] clearCache() is only available in file mode"),Promise.resolve())},addFile:function(e){return i.fileMode?e?ze(e)?(i.fileUrls.indexOf(e)===-1&&i.fileUrls.push(e),fetch(e).then(function(n){if(!n.ok)throw new Error("HTTP "+n.status);return n.text()}).then(function(n){if(!n||!n.trim())throw new Error("Empty file");var t;try{t=JSON.parse(n)}catch{throw new Error("Invalid JSON")}if(t=ye(t),!t)throw new Error("Invalid file schema");var r=!i.fileData||!i.fileData.languages||i.fileData.languages.length===0,a=!r||(t.languages||[]).length===1;return Ee(t,r),ve(e,t,a).catch(function(){}),Se(),console.log("[loco] added file: "+e+" ("+(t.languages||[]).join(", ")+")"),{status:"added",languages:t.languages||[]}}).catch(function(n){return console.warn("[loco] addFile() failed:",n),{status:"error",reason:n.message}})):(console.warn("[loco] Blocked unsafe URL: "+e),Promise.resolve({status:"error",reason:"unsafe URL"})):Promise.resolve({status:"error",reason:"no URL provided"}):(console.warn("[loco] addFile() is only available in file mode"),Promise.resolve({status:"error",reason:"not in file mode"}))},pullLatest:function(){if(!i.fileMode)return console.warn("[loco] pullLatest() is only available in file mode"),Promise.resolve({status:"skipped",reason:"not in file mode"});var e=i.fileUrls.length>0?i.fileUrls:i.fileUrl?[i.fileUrl]:[];if(e.length===0)return console.warn("[loco] No file URL(s) configured. Call Loco.init({ file }) first."),Promise.resolve({status:"error",reason:"no file URLs"});var n=e.map(function(t){return Promise.all([Qe(t).catch(function(){return null}),fetch(t).then(function(r){if(!r.ok)throw new Error("HTTP "+r.status);return r.text()})]).then(function(r){var a=r[0],o=r[1];if(!o||!o.trim())return{url:t,status:"current",reason:"empty"};var l;try{l=JSON.parse(o)}catch{throw new Error("Invalid JSON in "+t)}if(l=ye(l),!l)throw new Error("Invalid file schema in "+t);var v=l.timestamp||0,p=a&&a.timestamp||0;if(v===p&&p!==0){var s=i.fileData&&i.fileData.translations,f=l.languages||[],h=!s||f.some(function(u){return!i.fileData.translations[u]});if(!h)return{url:t,status:"current",timestamp:p}}var g=!i.fileData||!i.fileData.languages||i.fileData.languages.length===0,c=!g||(l.languages||[]).length===1;return Ee(l,g),ve(t,l,c).catch(function(){}),{url:t,status:"updated",timestamp:v,previousTimestamp:p}}).catch(function(r){return{url:t,status:"error",reason:r.message}})});return Promise.all(n).then(async function(t){var r=t.some(function(f){return f.status==="updated"});if(r){i.loadedFromCache=!1,i.currentLang=null;var a=Y();if(a)i.observer&&(i.observer.disconnect(),i.observer=null),j(i.phrases),await xe("pullLatest");else{i.phrases=Ke(document.body);var o=i.fileData.translations||{},l=(i.fileData.languages||[])[0];l&&o[l]&&$(i.phrases,Object.keys(o[l]))}Se()}if(t.length===1){var v=t[0];return console.log("[loco] pullLatest: "+v.status+(v.timestamp?" (timestamp: "+v.timestamp+")":"")),v}var p=t.filter(function(f){return f.status==="updated"}).map(function(f){return f.url}),s=t.filter(function(f){return f.status==="current"}).map(function(f){return f.url});return console.log("[loco] pullLatest: "+p.length+" updated, "+s.length+" current"),{status:r?"updated":"current",results:t}}).catch(function(t){return console.warn("[loco] pullLatest() failed:",t),{status:"error",reason:t.message}})}};return window.Loco=V,Object.defineProperty(V,"_state",{value:i,writable:!1,enumerable:!1,configurable:!1}),V}();
package/versions.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.1.4"
2
+ "version": "1.1.5"
3
3
  }