{"version":3,"file":"translationCache.mjs","names":["CACHE_PREFIX","cacheKey","language","unityUserId","readCachedBundle","raw","localStorage","getItem","JSON","parse","writeCachedBundle","bundle","setItem","stringify","clearCachedTranslations","includeSystem","doomed","i","length","key","startsWith","scope","split","push","forEach","removeItem"],"sources":["../../../src/utilities/i18n/translationCache.js"],"sourcesContent":["/**\n * localStorage-backed stale-while-revalidate cache for translation bundles.\n *\n * One entry per scope+language: the FINAL bundle that was applied last session\n * (user-scoped entries include the user's personal overrides). Hydrating it\n * synchronously at startup means first paint is already translated - the\n * network loads then revalidate in the background and are visually no-ops\n * unless a translation actually changed.\n *\n * All operations are best-effort: quota errors / private browsing / disabled\n * storage silently degrade to the uncached (fetch-only) behavior.\n */\n\n// Bump the version segment to invalidate every cached bundle on format changes.\nconst CACHE_PREFIX = 'udpI18n.v1';\n\nconst cacheKey = (language, unityUserId) =>\n  `${CACHE_PREFIX}:${unityUserId || 'anon'}:${language}`;\n\n/**\n * @param {string} language\n * @param {string|null} [unityUserId] null/undefined reads the anonymous (system) entry.\n * @returns {Record<string, string>|null}\n */\nexport const readCachedBundle = (language, unityUserId) => {\n  try {\n    const raw = localStorage.getItem(cacheKey(language, unityUserId));\n    return raw ? JSON.parse(raw) : null;\n  } catch {\n    return null;\n  }\n};\n\n/**\n * @param {string} language\n * @param {string|null} unityUserId null writes the anonymous (system) entry.\n * @param {Record<string, string>} bundle\n */\nexport const writeCachedBundle = (language, unityUserId, bundle) => {\n  try {\n    localStorage.setItem(cacheKey(language, unityUserId), JSON.stringify(bundle));\n  } catch {\n    // best-effort cache; ignore quota/private-mode failures\n  }\n};\n\n/**\n * Remove cached bundles. By default only user-scoped entries are cleared\n * (call on logout so a shared machine never hydrates another user's\n * overrides); pass includeSystem to also drop the anonymous entries.\n * @param {{includeSystem?: boolean}} [options]\n */\nexport const clearCachedTranslations = ({ includeSystem = false } = {}) => {\n  try {\n    const doomed = [];\n    for (let i = 0; i < localStorage.length; i++) {\n      const key = localStorage.key(i);\n      if (!key || !key.startsWith(`${CACHE_PREFIX}:`)) continue;\n      const scope = key.split(':')[1];\n      if (!includeSystem && scope === 'anon') continue;\n      doomed.push(key);\n    }\n    doomed.forEach((key) => localStorage.removeItem(key));\n  } catch {\n    // best-effort cache; ignore storage failures\n  }\n};\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAMA,eAAe;AAErB,MAAMC,YAAYC,UAAUC,gBAC1B,GAAGH,aAAY,GAAIG,eAAe,OAAM,GAAID;;;;;;AAO9C,MAAaE,oBAAoBF,UAAUC,gBAAgB;AACzD,KAAI;EACF,MAAME,MAAMC,aAAaC,QAAQN,SAASC,UAAUC,YAAY,CAAC;AACjE,SAAOE,MAAMG,KAAKC,MAAMJ,IAAI,GAAG;SACzB;AACN,SAAO;;;;;;;;AASX,MAAaK,qBAAqBR,UAAUC,aAAaQ,WAAW;AAClE,KAAI;AACFL,eAAaM,QAAQX,SAASC,UAAUC,YAAY,EAAEK,KAAKK,UAAUF,OAAO,CAAC;SACvE;;;;;;;;AAWV,MAAaG,2BAA2B,EAAEC,gBAAgB,UAAU,EAAE,KAAK;AACzE,KAAI;EACF,MAAMC,SAAS,EAAE;AACjB,OAAK,IAAIC,IAAI,GAAGA,IAAIX,aAAaY,QAAQD,KAAK;GAC5C,MAAME,MAAMb,aAAaa,IAAIF,EAAE;AAC/B,OAAI,CAACE,OAAO,CAACA,IAAIC,WAAW,GAAGpB,aAAY,GAAI,CAAE;GACjD,MAAMqB,QAAQF,IAAIG,MAAM,IAAI,CAAC;AAC7B,OAAI,CAACP,iBAAiBM,UAAU,OAAQ;AACxCL,UAAOO,KAAKJ,IAAI;;AAElBH,SAAOQ,SAASL,QAAQb,aAAamB,WAAWN,IAAI,CAAC;SAC/C"}