sugarcube-i18n 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sugarcube-i18n.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
1
|
!function(){"use strict";const t="lang",e={debug:!0,fallbackLng:"en",resources:{}};async function a(){var a;await(a="https://unpkg.com/i18next@latest/i18next.min.js",new Promise((t,e)=>{if(window.i18next)return t();const n=document.createElement("script");n.src=a,n.onload=t,n.onerror=()=>e(new Error(`Failed to load ${a}`)),document.head.appendChild(n)}));let n="en";State.variables[t]?n=State.variables[t]:navigator.language&&(n=navigator.language.split("-")[0]),await i18next.init({...e,lng:n,interpolation:{escapeValue:!1}}),State.variables[t]||(State.variables[t]=i18next.language),console.log(`[i18n] Initialized (${i18next.language})`)}function n(t,e={}){return window.i18next?i18next.t(t,e):t}Macro.add("loadTranslations",{handler:function(){if(this.args.length<2)return this.error("Usage: <<loadTranslations 'path' 'langCode'>>");const t=this.args[0],e=this.args[1];fetch(t).then(t=>{if(!t.ok)throw new Error(`HTTP error! status: ${t.status}`);return t.json()}).then(a=>{window.i18next&&(i18next.addResourceBundle(e,"translation",a,!0,!0),console.log(`[i18n] Loaded translations for ${e} from ${t}`),i18next.language===e&&Engine.show())}).catch(e=>{console.error(`[i18n] Failed to load ${t}:`,e),$(this.output).append(`<span class="error">i18n Error: Failed to load ${t}</span>`)})}}),Macro.add("setLang",{handler(){(function(e){return i18next.changeLanguage(e).then(()=>{State.variables[t]=e})})(this.args[0]).then(()=>Engine.show())}}),Macro.add("t",{handler(){if(0===this.args.length)return this.error("Usage: <<t 'key' [options]>>");const t=this.args[0];let e={};const a=this.args[1];if(this.args.length>1&&"object"==typeof a&&!Array.isArray(a))e=a;else{if((this.args.length-1)%2!=0)return this.error("<<t>> expects key-value pairs or an options object");for(let t=1;t<this.args.length;t+=2)e[this.args[t]]=this.args[t+1]}const r=n(t,e);$(this.output).append($("<span>").html(r))}}),Macro.add("tlink",{handler(){const t=this.args[0],e=this.args[1];let a={};if(this.args.length>2){const t=this.args[2];if(t&&"object"==typeof t)a=t;else for(let t=2;t<this.args.length;t+=2)a[this.args[t]]=this.args[t+1]}const r=n(t,a);new Wikifier(this.output,`<<link "${r}" "${e}">><</link>>`)}}),async function(){try{var t=LoadScreen.lock();await a(),LoadScreen.unlock(t)}catch(t){console.error("[i18n] Init failed",t)}}(),Save.onLoad.add(e=>{const a=e?.state?.history?.[e.state.index],n=a?.variables?.[t];n&&window.i18next&&i18next.changeLanguage(n)}),$(document).on(":storyready",()=>{window.i18next&&State.variables[t]&&i18next.changeLanguage(State.variables[t])})}();
|
|
2
|
-
//# sourceMappingURL=sugarcube-i18n.js.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sugarcube-i18n.js","sources":["../src/core.js","../src/macros.js","../src/index.js"],"sourcesContent":["\"use strict\";\r\n\r\nexport const STATE_VAR_NAME = \"lang\";\r\nconst I18NEXT_CDN = \"https://unpkg.com/i18next@latest/i18next.min.js\";\r\n\r\nconst i18nOptions = {\r\n debug: true,\r\n fallbackLng: \"en\",\r\n resources: {}\r\n};\r\n\r\nfunction loadScript(src) {\r\n // Load the script\r\n return new Promise((resolve, reject) => {\r\n // If i18next is already loaded, return it\r\n if (window.i18next) return resolve(); \r\n const script = document.createElement(\"script\");\r\n script.src = src;\r\n script.onload = resolve;\r\n script.onerror = () => reject(new Error(`Failed to load ${src}`));\r\n document.head.appendChild(script);\r\n });\r\n}\r\n\r\nexport async function initI18n() {\r\n await loadScript(I18NEXT_CDN);\r\n\r\n let initialLang = \"en\";\r\n if (State.variables[STATE_VAR_NAME]) {\r\n initialLang = State.variables[STATE_VAR_NAME];\r\n } else if (navigator.language) {\r\n initialLang = navigator.language.split(\"-\")[0];\r\n }\r\n\r\n await i18next.init({\r\n ...i18nOptions,\r\n lng: initialLang,\r\n interpolation: { escapeValue: false }\r\n });\r\n\r\n if (!State.variables[STATE_VAR_NAME]) {\r\n State.variables[STATE_VAR_NAME] = i18next.language;\r\n }\r\n\r\n console.log(`[i18n] Initialized (${i18next.language})`);\r\n}\r\n\r\nexport function setLang(lang) {\r\n return i18next.changeLanguage(lang).then(() => {\r\n State.variables[STATE_VAR_NAME] = lang;\r\n });\r\n}\r\n\r\nexport function translate(key, options = {}) {\r\n return window.i18next ? i18next.t(key, options) : key;\r\n}\r\n","import { translate, setLang } from \"./core.js\";\r\n\r\nexport function registerMacros() {\r\n\r\n /**\r\n * Macro: <<loadTranslations \"path/to/file.json\" [namespace]>>\r\n * Loads a JSON file and adds it to i18next resources.\r\n *\r\n * Convention:\r\n * The JSON file should be structured as:\r\n * {\r\n * \"key\": \"translation\"\r\n * }\r\n *\r\n * Usage: <<loadTranslations \"locales/en.json\" \"en\">>\r\n */\r\n Macro.add('loadTranslations', {\r\n handler: function () {\r\n if (this.args.length < 2) {\r\n return this.error(\"Usage: <<loadTranslations 'path' 'langCode'>>\");\r\n }\r\n\r\n const path = this.args[0];\r\n const lang = this.args[1];\r\n const ns = 'translation'; // default namespace\r\n\r\n // fetch is async, but macros in Init/StoryInit are synchronous. \r\n // SugarCube doesn't pause for async macros in Init usually, but content won't render till ready if used in Passages.\r\n \r\n fetch(path)\r\n .then(response => {\r\n if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\r\n return response.json();\r\n })\r\n .then(data => {\r\n if (window.i18next) {\r\n i18next.addResourceBundle(lang, ns, data, true, true);\r\n console.log(`[i18n] Loaded translations for ${lang} from ${path}`);\r\n // If this is the current language, trigger a refresh might be needed if passage is already shown?\r\n // Usually this is done in StoryInit so no passage is shown yet.\r\n \r\n // Force update engine if we are currently looking at this language\r\n if (i18next.language === lang) {\r\n Engine.show(); // Refreshes current passage if needed, though be careful in Init\r\n }\r\n }\r\n })\r\n .catch(err => {\r\n console.error(`[i18n] Failed to load ${path}:`, err);\r\n $(this.output).append(`<span class=\"error\">i18n Error: Failed to load ${path}</span>`);\r\n });\r\n }\r\n });\r\n\r\n /**\r\n * Macro: <<setLang \"code\">>\r\n * Changes the current language and updates persistence.\r\n */\r\n Macro.add('setLang', {\r\n handler() { \r\n const lang = this.args[0]; \r\n setLang(lang).then(() => Engine.show()); \r\n } \r\n });\r\n\r\n /**\r\n * Macro: <<t \"key\" [options]>>\r\n * Translates a key. Supports interpolation.\r\n * Options can be an object or key-value pairs.\r\n * Example:\r\n * - Object options: \r\n * <<set $opts to { name: $name }>>\r\n * <<t \"greeting\" $opts>>\r\n * - Key-Value pairs options:\r\n * <<t \"greeting\" \"name\" $name>>\r\n */\r\n Macro.add('t', {\r\n handler() {\r\n if (this.args.length === 0) {\r\n return this.error(\"Usage: <<t 'key' [options]>>\");\r\n }\r\n\r\n const key = this.args[0];\r\n let options = {};\r\n const second = this.args[1];\r\n if (this.args.length > 1 && typeof second === \"object\" && !Array.isArray(second)) {\r\n // Object form\r\n options = second;\r\n } else {\r\n // Key-value pairs form\r\n if ((this.args.length - 1) % 2 !== 0) {\r\n return this.error(\r\n \"<<t>> expects key-value pairs or an options object\"\r\n );\r\n }\r\n\r\n for (let i = 1; i < this.args.length; i += 2) {\r\n options[this.args[i]] = this.args[i + 1];\r\n }\r\n }\r\n\r\n const text = translate(key, options);\r\n $(this.output).append($(\"<span>\").html(text));\r\n }\r\n });\r\n\r\n /**\r\n * Macro: <<tlink \"key\" \"passage\" [options]>>\r\n * Translates a key and creates a link to a passage. Supports interpolation.\r\n * Options can be an object or key-value pairs.\r\n * Example:\r\n * <<tlink \"go-to-forest\" \"ForestPassage\">>\r\n * <<tlink \"go-to-forest\" \"ForestPassage\" { name: $name }>>\r\n * <<tlink \"go-to-forest\" \"ForestPassage\" \"name\" $name>>\r\n */\r\n Macro.add(\"tlink\", {\r\n handler() {\r\n const key = this.args[0];\r\n const passage = this.args[1];\r\n let options = {}; \r\n\r\n if (this.args.length > 2) {\r\n const second = this.args[2];\r\n if (second && typeof second === \"object\") {\r\n options = second;\r\n } else {\r\n for (let i = 2; i < this.args.length; i += 2) {\r\n options[this.args[i]] = this.args[i + 1];\r\n }\r\n }\r\n }\r\n const label = translate(key, options);\r\n new Wikifier(this.output, `<<link \"${label}\" \"${passage}\">><</link>>`);\r\n }\r\n });\r\n\r\n}\r\n","import { initI18n, STATE_VAR_NAME } from \"./core.js\";\r\nimport { registerMacros } from \"./macros.js\";\r\n\r\nregisterMacros();\r\n\r\n(async function () {\r\n try {\r\n\r\n // Lock the loading screen.\r\n var lockId = LoadScreen.lock();\r\n\r\n // Initialize i18n plugin configuration\r\n await initI18n();\r\n \r\n // Release the loading screen.\r\n LoadScreen.unlock(lockId);\r\n \r\n } catch (err) {\r\n console.error(\"[i18n] Init failed\", err);\r\n }\r\n})();\r\n\r\n// Save / Load hooks\r\nSave.onLoad.add(save => {\r\n const moment = save?.state?.history?.[save.state.index];\r\n const lang = moment?.variables?.[STATE_VAR_NAME];\r\n if (lang && window.i18next) {\r\n i18next.changeLanguage(lang);\r\n }\r\n});\r\n\r\n$(document).on(\":storyready\", () => {\r\n if (window.i18next && State.variables[STATE_VAR_NAME]) {\r\n i18next.changeLanguage(State.variables[STATE_VAR_NAME]);\r\n }\r\n});\r\n"],"names":["STATE_VAR_NAME","i18nOptions","debug","fallbackLng","resources","async","initI18n","src","Promise","resolve","reject","window","i18next","script","document","createElement","onload","onerror","Error","head","appendChild","initialLang","State","variables","navigator","language","split","init","lng","interpolation","escapeValue","console","log","translate","key","options","t","Macro","add","handler","this","args","length","error","path","lang","fetch","then","response","ok","status","json","data","addResourceBundle","Engine","show","catch","err","$","output","append","changeLanguage","setLang","second","Array","isArray","i","text","html","passage","label","Wikifier","lockId","LoadScreen","lock","unlock","Save","onLoad","save","moment","state","history","index","on"],"mappings":"yBAEO,MAAMA,EAAiB,OAGxBC,EAAc,CAClBC,OAAO,EACPC,YAAa,KACbC,UAAW,CAAA,GAgBNC,eAAeC,IAbtB,IAAoBC,UARA,kDAUX,IAAIC,QAAQ,CAACC,EAASC,KAE3B,GAAIC,OAAOC,QAAS,OAAOH,IAC3B,MAAMI,EAASC,SAASC,cAAc,UACtCF,EAAON,IAAMA,EACbM,EAAOG,OAASP,EAChBI,EAAOI,QAAU,IAAMP,EAAO,IAAIQ,MAAM,kBAAkBX,MAC1DO,SAASK,KAAKC,YAAYP,MAO5B,IAAIQ,EAAc,KACdC,MAAMC,UAAUvB,GAClBqB,EAAcC,MAAMC,UAAUvB,GACrBwB,UAAUC,WACnBJ,EAAcG,UAAUC,SAASC,MAAM,KAAK,UAGxCd,QAAQe,KAAK,IACd1B,EACH2B,IAAKP,EACLQ,cAAe,CAAEC,aAAa,KAG3BR,MAAMC,UAAUvB,KACnBsB,MAAMC,UAAUvB,GAAkBY,QAAQa,UAG5CM,QAAQC,IAAI,uBAAuBpB,QAAQa,YAC7C,CAQO,SAASQ,EAAUC,EAAKC,EAAU,IACvC,OAAOxB,OAAOC,QAAUA,QAAQwB,EAAEF,EAAKC,GAAWD,CACpD,CCvCIG,MAAMC,IAAI,mBAAoB,CAC1BC,QAAS,WACL,GAAIC,KAAKC,KAAKC,OAAS,EACnB,OAAOF,KAAKG,MAAM,iDAGtB,MAAMC,EAAOJ,KAAKC,KAAK,GACjBI,EAAOL,KAAKC,KAAK,GAMvBK,MAAMF,GACDG,KAAKC,IACF,IAAKA,EAASC,GAAI,MAAM,IAAI/B,MAAM,uBAAuB8B,EAASE,UAClE,OAAOF,EAASG,SAEnBJ,KAAKK,IACEzC,OAAOC,UACPA,QAAQyC,kBAAkBR,EAZ3B,cAYqCO,GAAM,GAAM,GAChDrB,QAAQC,IAAI,kCAAkCa,UAAaD,KAKvDhC,QAAQa,WAAaoB,GACtBS,OAAOC,UAIjBC,MAAMC,IACH1B,QAAQY,MAAM,yBAAyBC,KAASa,GAChDC,EAAElB,KAAKmB,QAAQC,OAAO,kDAAkDhB,aAEpF,IAOJP,MAAMC,IAAI,UAAW,CAClB,OAAAC,IDZA,SAAiBM,GACtB,OAAOjC,QAAQiD,eAAehB,GAAME,KAAK,KACvCzB,MAAMC,UAAUvB,GAAkB6C,GAEtC,ECUQiB,CADatB,KAAKC,KAAK,IACTM,KAAK,IAAMO,OAAOC,OACjC,IAcHlB,MAAMC,IAAI,IAAK,CACX,OAAAC,GACI,GAAyB,IAArBC,KAAKC,KAAKC,OACV,OAAOF,KAAKG,MAAM,gCAGtB,MAAMT,EAAMM,KAAKC,KAAK,GACtB,IAAIN,EAAU,CAAA,EACd,MAAM4B,EAASvB,KAAKC,KAAK,GACzB,GAAID,KAAKC,KAAKC,OAAS,GAAuB,iBAAXqB,IAAwBC,MAAMC,QAAQF,GAEvE5B,EAAU4B,MACL,CAEL,IAAKvB,KAAKC,KAAKC,OAAS,GAAK,GAAM,EACjC,OAAOF,KAAKG,MACV,sDAIJ,IAAK,IAAIuB,EAAI,EAAGA,EAAI1B,KAAKC,KAAKC,OAAQwB,GAAK,EACzC/B,EAAQK,KAAKC,KAAKyB,IAAM1B,KAAKC,KAAKyB,EAAI,EAE1C,CAEA,MAAMC,EAAOlC,EAAUC,EAAKC,GAC5BuB,EAAElB,KAAKmB,QAAQC,OAAOF,EAAE,UAAUU,KAAKD,GAC3C,IAYJ9B,MAAMC,IAAI,QAAS,CACjB,OAAAC,GACE,MAAML,EAAMM,KAAKC,KAAK,GAChB4B,EAAU7B,KAAKC,KAAK,GAC1B,IAAIN,EAAU,CAAA,EAEd,GAAIK,KAAKC,KAAKC,OAAS,EAAG,CACxB,MAAMqB,EAASvB,KAAKC,KAAK,GACzB,GAAIsB,GAA4B,iBAAXA,EACnB5B,EAAU4B,OAEV,IAAK,IAAIG,EAAI,EAAGA,EAAI1B,KAAKC,KAAKC,OAAQwB,GAAK,EACzC/B,EAAQK,KAAKC,KAAKyB,IAAM1B,KAAKC,KAAKyB,EAAI,EAG5C,CACA,MAAMI,EAAQrC,EAAUC,EAAKC,GAC7B,IAAIoC,SAAS/B,KAAKmB,OAAQ,WAAWW,OAAWD,gBAClD,IChIN,iBACE,IAGE,IAAIG,EAASC,WAAWC,aAGlBpE,IAGNmE,WAAWE,OAAOH,EAEpB,CAAE,MAAOf,GACP1B,QAAQY,MAAM,qBAAsBc,EACtC,CACD,CAfD,GAkBAmB,KAAKC,OAAOvC,IAAIwC,IACd,MAAMC,EAASD,GAAME,OAAOC,UAAUH,EAAKE,MAAME,OAC3CrC,EAAOkC,GAAQxD,YAAYvB,GAC7B6C,GAAQlC,OAAOC,SACjBA,QAAQiD,eAAehB,KAI3Ba,EAAE5C,UAAUqE,GAAG,cAAe,KACxBxE,OAAOC,SAAWU,MAAMC,UAAUvB,IACpCY,QAAQiD,eAAevC,MAAMC,UAAUvB"}
|