@magic-translate/js 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -96,6 +96,49 @@ List the attributes to translate in `data-t-attrs`:
96
96
  <img src="team.jpg" alt="Our team" title="Say hi" data-t-attrs="alt title" />
97
97
  ```
98
98
 
99
+ ### Variables
100
+
101
+ Put values that change, such as names or counts, in `data-v` as a JSON object,
102
+ and reference them as `$name`. The text is translated once as a template,
103
+ `Hi {0}, you have {1} new messages`, and cached, however many different values
104
+ it is shown with. The values themselves are never sent to the API.
105
+
106
+ ```html
107
+ <t data-v='{"name": "Bob", "count": 7}'
108
+ >Hi $name, you have $count new messages</t
109
+ >
110
+
111
+ <input
112
+ placeholder="Search $count products"
113
+ data-t-attrs="placeholder"
114
+ data-v='{"count": 3}'
115
+ />
116
+ ```
117
+
118
+ To show new values, change `data-v`. The cached translation is reused and no
119
+ request is made:
120
+
121
+ ```js
122
+ element.dataset.v = JSON.stringify({ name: 'Bob', count: 8 });
123
+ ```
124
+
125
+ - Only keys of `data-v` are replaced, so text like `$5` stays as it is. If two
126
+ keys start the same way, the longest one wins.
127
+ - Values are inserted as text, never as HTML. Put markup in the text around
128
+ them instead: `Hi <b>$name</b>`.
129
+ - In content, variables are replaced in text only, not in attributes such as
130
+ `href`.
131
+ - If `data-v` is not a valid JSON object, the text is left untranslated and a
132
+ warning is logged. So is a key that is not found in the text.
133
+ - `$name` is visible until the script has loaded. Load it early, or hide the
134
+ elements until then.
135
+
136
+ `translate` takes the values in `v`:
137
+
138
+ ```js
139
+ await magicTranslate.translate('Your order $id has shipped', { v: { id } });
140
+ ```
141
+
99
142
  ### Options per element
100
143
 
101
144
  `data-lang` and `data-formality` override the target language and the
@@ -105,6 +148,15 @@ formality:
105
148
  <t data-lang="fr" data-formality="formal">How are you?</t>
106
149
  ```
107
150
 
151
+ `data-t-id` lets you edit one use of a text on its own in the webapp, e.g. to
152
+ translate the same "Save" differently on two buttons. Its edited translation
153
+ stays when the text changes. Ids are unique within your account and at most 128
154
+ characters. They apply to the element's content, not to its `data-t-attrs`.
155
+
156
+ ```html
157
+ <t data-t-id="checkout-save">Save</t>
158
+ ```
159
+
108
160
  ### Switching languages
109
161
 
110
162
  Call `setLanguage` to translate the page to another language:
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@magic-translate/core");var t=`t, mt-translate, [data-t]`,n=`[data-t-attrs]`;function r(e){let n=e;for(let e=n.parentElement?.closest(t);e;e=n.parentElement?.closest(t))n=e;return n}function i(e){let t={},n=e.getAttribute(`data-lang`),r=e.getAttribute(`data-formality`);return n&&(t.lang=n),r&&(t.formality=r),t}var a=class{constructor(t){if(this.options=t,this.contents=new Map,this.attributes=new Map,this.listeners=new Set,!t.apiKey)throw Error(`Missing API key. Please get one at ${e.libraryWebsite}`);this.currentLanguage=t.language??(0,e.utsLocaleToLanguage)(typeof navigator>`u`?void 0:navigator.language),this.dataLoader=this.createDataLoader(),typeof document<`u`&&(this.root=t.root??document.documentElement,this.start(this.root))}get language(){return this.currentLanguage}setLanguage(e){e!==this.currentLanguage&&(this.currentLanguage=e,this.dataLoader=this.createDataLoader(),this.forget(e=>!e.isConnected||!this.root?.contains(e)),this.contents.forEach((e,t)=>this.translateContent(t,!0)),this.attributes.forEach((e,t)=>this.translateAttributes(t,!0)),this.listeners.forEach(t=>t(e)))}onLanguageChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}translate(e,t={}){return this.dataLoader.load({text:e,...t})}destroy(){this.observer?.disconnect(),this.contents.clear(),this.attributes.clear(),this.listeners.clear()}createDataLoader(){let{debug:t,apiKey:n,sourceLanguage:r,_apiUrl:i,formality:a}=this.options,o=this.options._loaderFactory??e.defaultLoaderFactory;return new e.DataLoader(o({debug:!!t,apiKey:n,lang:this.currentLanguage,sourceLang:r,apiUrl:i,formality:a}),{cacheKeyFn:(0,e.cacheKeyFn)(n,r,this.currentLanguage)})}start(e){let t=new Set,n=new Set;this.collect(e,t,n),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e)),this.observer=new MutationObserver(e=>this.handleMutations(e)),this.observer.observe(e,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}collect(e,t,n){let i=[e,...Array.from(e.querySelectorAll(`*`))];for(let e of i)e.matches(`t, mt-translate, [data-t]`)?t.add(r(e)):e.matches(`[data-t-attrs]`)&&!e.closest(`t, mt-translate, [data-t]`)&&n.add(e)}handleMutations(e){let n=new Set,i=new Set;for(let a of e){let e=a.target.nodeType===Node.ELEMENT_NODE?a.target:a.target.parentElement;if(!e)continue;let o=e.closest(t);o?n.add(r(o)):(a.type===`attributes`&&e.matches(`[data-t-attrs]`)&&i.add(e),a.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&this.collect(e,n,i)}))}e.some(e=>e.removedNodes.length>0)&&this.forget(e=>!e.isConnected),n.forEach(e=>this.translateContent(e)),i.forEach(e=>this.translateAttributes(e))}forget(e){for(let t of this.contents.keys())e(t)&&this.contents.delete(t);for(let t of this.attributes.keys())e(t)&&this.attributes.delete(t)}translateContent(e,t=!1){let n=e.innerHTML,r=this.contents.get(e);if(!r)r={source:n,requestId:0},this.contents.set(e,r);else if(n!==r.rendered&&n!==r.source)r.source=n,r.rendered=void 0;else if(!t)return;let[,a,o,s]=/^(\s*)([\s\S]*?)(\s*)$/.exec(r.source.replace(/<!--[\s\S]*?-->/g,``));if(!o)return;let c=++r.requestId,l=r;this.translate(o,i(e)).then(t=>{if(c!==l.requestId||!e.isConnected)return;let n=`${a}${t}${s}`;e.innerHTML!==n&&(e.innerHTML=n),l.rendered=e.innerHTML})}translateAttributes(e,t=!1){let n=(e.getAttribute(`data-t-attrs`)??``).split(/[\s,]+/).filter(Boolean),r=this.attributes.get(e);r||(r=new Map,this.attributes.set(e,r));for(let a of n){let n=e.getAttribute(a);if(!n?.trim())continue;let o=r.get(a);if(!o)o={source:n,requestId:0},r.set(a,o);else if(n!==o.rendered&&n!==o.source)o.source=n,o.rendered=void 0;else if(!t)continue;let s=++o.requestId,c=o;this.translate(c.source,i(e)).then(t=>{s===c.requestId&&e.isConnected&&(c.rendered=t,e.getAttribute(a)!==t&&e.setAttribute(a,t))})}}};function o(e){return new a(e)}exports.ATTRIBUTES_SELECTOR=n,exports.CONTENT_SELECTOR=t,exports.MagicTranslate=a,exports.createMagicTranslate=o,Object.keys(e).forEach(function(t){t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@magic-translate/core");var t=`t, mt-translate, [data-t]`,n=`[data-t-attrs]`;function r(e){let n=e;for(let e=n.parentElement?.closest(t);e;e=n.parentElement?.closest(t))n=e;return n}function i(e){let t={},n=e.getAttribute(`data-lang`),r=e.getAttribute(`data-formality`),i=e.getAttribute(`data-t-id`);return n&&(t.lang=n),r&&(t.formality=r),i&&(t.id=i),t}function a(t){let n=t.getAttribute(`data-v`);if(n!==null){try{let e=JSON.parse(n);if(e&&typeof e==`object`&&!Array.isArray(e))return e}catch{}return console.warn(`[${e.libraryName}]: data-v must be a JSON object, such as data-v='{"name": "Bob"}', but is ${n}`),null}}function o(t,n){if(n.length===0)return t;let r=document.createElement(`template`);return r.innerHTML=t,(0,e.fillElement)(r.content,n),r.innerHTML}var s=class{constructor(t){if(this.options=t,this.contents=new Map,this.attributes=new Map,this.listeners=new Set,!t.apiKey)throw Error(`Missing API key. Please get one at ${e.libraryWebsite}`);this.currentLanguage=t.language??(0,e.utsLocaleToLanguage)(typeof navigator>`u`?void 0:navigator.language),this.dataLoader=this.createDataLoader(),typeof document<`u`&&(this.root=t.root??document.documentElement,this.start(this.root))}get language(){return this.currentLanguage}setLanguage(e){e!==this.currentLanguage&&(this.currentLanguage=e,this.dataLoader=this.createDataLoader(),this.forget(e=>!e.isConnected||!this.root?.contains(e)),this.contents.forEach((e,t)=>this.translateContent(t,!0)),this.attributes.forEach((e,t)=>this.translateAttributes(t,!0)),this.listeners.forEach(t=>t(e)))}onLanguageChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}translate(t,{v:n,...r}={}){if(!n)return this.dataLoader.load({text:t,...r});let{template:i,values:a,unused:o}=(0,e.toTemplate)(t,n);return(0,e.warnAboutUnused)(o),this.dataLoader.load({text:i,...r}).then(t=>(0,e.fillPlaceholders)(t,a))}destroy(){this.observer?.disconnect(),this.contents.clear(),this.attributes.clear(),this.listeners.clear()}createDataLoader(){let{debug:t,apiKey:n,sourceLanguage:r,_apiUrl:i,formality:a}=this.options,o=this.options._loaderFactory??e.defaultLoaderFactory;return new e.DataLoader(o({debug:!!t,apiKey:n,lang:this.currentLanguage,sourceLang:r,apiUrl:i,formality:a}),{cacheKeyFn:(0,e.cacheKeyFn)(n,r,this.currentLanguage)})}start(e){let t=new Set,n=new Set;this.collect(e,t,n),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e)),this.observer=new MutationObserver(e=>this.handleMutations(e)),this.observer.observe(e,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}collect(e,t,n){let i=[e,...Array.from(e.querySelectorAll(`*`))];for(let e of i)e.matches(`t, mt-translate, [data-t]`)?t.add(r(e)):e.matches(`[data-t-attrs]`)&&!e.closest(`t, mt-translate, [data-t]`)&&n.add(e)}handleMutations(e){let n=new Set,i=new Set;for(let a of e){let e=a.target.nodeType===Node.ELEMENT_NODE?a.target:a.target.parentElement;if(!e)continue;let o=e.closest(t);o?n.add(r(o)):(a.type===`attributes`&&e.matches(`[data-t-attrs]`)&&i.add(e),a.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&this.collect(e,n,i)}))}e.some(e=>e.removedNodes.length>0)&&this.forget(e=>!e.isConnected),n.forEach(e=>this.translateContent(e)),i.forEach(e=>this.translateAttributes(e))}forget(e){for(let t of this.contents.keys())e(t)&&this.contents.delete(t);for(let t of this.attributes.keys())e(t)&&this.attributes.delete(t)}translateContent(t,n=!1){let r=t.innerHTML,s=t.getAttribute(`data-v`),c=this.contents.get(t);if(!c)c={source:r,requestId:0,variables:s},this.contents.set(t,c);else if(r!==c.rendered&&r!==c.source)c.source=r,c.rendered=void 0,c.variables=s;else if(s!==c.variables)c.variables=s;else if(!n)return;let[,l,u,d]=/^(\s*)([\s\S]*?)(\s*)$/.exec(c.source.replace(/<!--[\s\S]*?-->/g,``));if(!u)return;let f=a(t);if(f===null)return;let{template:p,values:m,unused:h}=f?(0,e.toHtmlTemplate)(u,f):{template:u,values:[],unused:[]};p!==c.template&&(c.template=p,(0,e.warnAboutUnused)(h));let g=c,_=e=>{let n=`${l}${o(e,m)}${d}`;t.innerHTML!==n&&(t.innerHTML=n),g.rendered=t.innerHTML};f&&g.rendered===void 0&&_(p);let v=++g.requestId;this.translate(p,i(t)).then(e=>{v===g.requestId&&t.isConnected&&_(e)})}translateAttributes(t,n=!1){let r=(t.getAttribute(`data-t-attrs`)??``).split(/[\s,]+/).filter(Boolean),o=t.getAttribute(`data-v`),s=this.attributes.get(t);s||(s=new Map,this.attributes.set(t,s));for(let c of r){let r=t.getAttribute(c);if(!r?.trim())continue;let l=s.get(c);if(!l)l={source:r,requestId:0,variables:o},s.set(c,l);else if(r!==l.rendered&&r!==l.source)l.source=r,l.rendered=void 0,l.variables=o;else if(o!==l.variables)l.variables=o;else if(!n)continue;let u=a(t);if(u===null)continue;let{template:d,values:f,unused:p}=u?(0,e.toTemplate)(l.source,u):{template:l.source,values:[],unused:[]};d!==l.template&&(l.template=d,(0,e.warnAboutUnused)(p));let m=l,h=n=>{let r=(0,e.fillPlaceholders)(n,f);m.rendered=r,t.getAttribute(c)!==r&&t.setAttribute(c,r)};u&&m.rendered===void 0&&h(d);let g=++m.requestId,{id:_,...v}=i(t);this.translate(d,v).then(e=>{g===m.requestId&&t.isConnected&&h(e)})}}};function c(e){return new s(e)}exports.ATTRIBUTES_SELECTOR=n,exports.CONTENT_SELECTOR=t,exports.MagicTranslate=s,exports.createMagicTranslate=c,Object.keys(e).forEach(function(t){t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["libraryWebsite","utsLocaleToLanguage","defaultLoaderFactory","DataLoader","cacheKeyFn","_magic_translate_core","CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","MagicTranslate","language","listener","params","loaderFactory","debug","sourceLanguage","_apiUrl","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","html","translation","force","leadingWhitespace","text","trailingWhitespace","requestId","rendered","translated","names","translations","name","value","createMagicTranslate","k"],"sources":["../src/magic-translate.ts"],"sourcesContent":["import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n Language,\n libraryWebsite,\n MagicTranslateConfig,\n TranslateOptions,\n utsLocaleToLanguage,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TranslateOptions {\n const options: TranslateOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n return options;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(text: string, params: TranslateParams = {}): Promise<string> {\n return this.dataLoader.load({ text, ...params });\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n let translation = this.contents.get(element);\n\n if (!translation) {\n translation = { source: html, requestId: 0 };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(text, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n const rendered = `${leadingWhitespace}${translated}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0 };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n } else if (!force) {\n continue;\n }\n\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(current.source, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n current.rendered = translated;\n if (element.getAttribute(name) !== translated) {\n element.setAttribute(name, translated);\n }\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n"],"mappings":"A,0GAmCA,IAAaM,EAAmB,4BAEnBC,EAAsB,iBASnC,SAASC,EAAU,EAA2B,CAC5C,IAAIC,EAAUC,EACd,IACE,IAAIC,EAASF,EAAQ,eAAe,QAAQH,CAAgB,EAC5DK,EACA,EAASF,EAAQ,eAAe,QAAQH,CAAgB,EAExD,EAAUK,EAEZ,OAAOF,CACT,CAEA,SAASG,EAAU,EAAoC,CACrD,IAAMC,EAA4B,CAAC,EAC7BC,EAAOJ,EAAQ,aAAa,WAAW,EACvCK,EAAYL,EAAQ,aAAa,gBAAgB,EAOvD,OANII,IACF,EAAQ,KAAOA,GAEbC,IACF,EAAQ,UAAYA,GAEfF,CACT,CAEA,IAAaG,EAAb,KAA4B,CAS1B,YAAY,EAAiD,CAC3D,GAD2B,KAAA,QAAAH,EALD,KAAA,SAAA,IAAI,IACF,KAAA,WAAA,IAAI,IACL,KAAA,UAAA,IAAI,IAI3B,CAACA,EAAQ,OACX,MAAU,MAAM,sCAAsCb,EAAAA,gBAAgB,EAGxE,KAAK,gBACHa,EAAQ,WAAA,EACRZ,EAAAA,oBAAAA,CACE,OAAO,UAAc,IAAc,IAAA,GAAY,UAAU,QAC3D,EACF,KAAK,WAAa,KAAK,iBAAiB,EAEpC,OAAO,SAAa,MACtB,KAAK,KAAOY,EAAQ,MAAQ,SAAS,gBACrC,KAAK,MAAM,KAAK,IAAI,EAExB,CAKA,IAAI,UAAsB,CACxB,OAAO,KAAK,eACd,CAKA,YAAY,EAA2B,CACjCI,IAAa,KAAK,kBAItB,KAAK,gBAAkBA,EACvB,KAAK,WAAa,KAAK,iBAAiB,EAExC,KAAK,OACF,GAAY,CAACP,EAAQ,aAAe,CAAC,KAAK,MAAM,SAASA,CAAO,CACnE,EACA,KAAK,SAAS,SAAS,EAAG,IAAY,KAAK,iBAAiBA,EAAS,EAAI,CAAC,EAC1E,KAAK,WAAW,SAAS,EAAG,IAC1B,KAAK,oBAAoBA,EAAS,EAAI,CACxC,EACA,KAAK,UAAU,QAAS,GAAaQ,EAASD,CAAQ,CAAC,EACzD,CAMA,iBAAiB,EAAqD,CAEpE,OADA,KAAK,UAAU,IAAIC,CAAQ,MACd,KAAK,UAAU,OAAOA,CAAQ,CAC7C,CAKA,UAAU,EAAc,EAA0B,CAAC,EAAoB,CACrE,OAAO,KAAK,WAAW,KAAK,CAAE,OAAM,GAAGC,CAAO,CAAC,CACjD,CAMA,SAAgB,CACd,KAAK,UAAU,WAAW,EAC1B,KAAK,SAAS,MAAM,EACpB,KAAK,WAAW,MAAM,EACtB,KAAK,UAAU,MAAM,CACvB,CAEA,kBAA2B,CACzB,GAAM,CAAE,QAAO,SAAQ,iBAAgB,UAAS,aAAc,KAAK,QAC7DC,EAAgB,KAAK,QAAQ,gBAAkBlB,EAAAA,qBAErD,OAAO,IAAIC,EAAAA,WACTiB,EAAc,CACZ,MAAO,CAAC,CAACC,EACT,SACA,KAAM,KAAK,gBACX,WAAYC,EACZ,OAAQC,EACR,WACF,CAAC,EACD,CACE,YAAA,EAAYnB,EAAAA,WAAAA,CAAWoB,EAAQF,EAAgB,KAAK,eAAe,CACrE,CACF,CACF,CAEA,MAAc,EAAe,CAC3B,IAAMG,EAAW,IAAI,IACfC,EAAa,IAAI,IACvB,KAAK,QAAQC,EAAMF,EAAUC,CAAU,EACvCD,EAAS,QAAS,GAAY,KAAK,iBAAiBf,CAAO,CAAC,EAC5DgB,EAAW,QAAS,GAAY,KAAK,oBAAoBhB,CAAO,CAAC,EAGjE,KAAK,SAAW,IAAI,iBAAkB,GACpC,KAAK,gBAAgBkB,CAAO,CAC9B,EACA,KAAK,SAAS,QAAQD,EAAM,CAC1B,QAAS,GACT,UAAW,GACX,cAAe,GACf,WAAY,EACd,CAAC,CACH,CAEA,QACE,EACA,EACA,EACA,CACA,IAAME,EAAM,CAACF,EAAM,GAAG,MAAM,KAAKA,EAAK,iBAAiB,GAAG,CAAC,CAAC,EAC5D,IAAK,IAAMjB,KAAWmB,EAChBnB,EAAQ,QAAA,2BAAwB,EAClCe,EAAS,IAAIjB,EAAUE,CAAO,CAAC,EAE/BA,EAAQ,QAAA,gBAA2B,GACnC,CAACA,EAAQ,QAAA,2BAAwB,GAEjCgB,EAAW,IAAIhB,CAAO,CAG5B,CAEA,gBAAwB,EAA2B,CACjD,IAAMe,EAAW,IAAI,IACfC,EAAa,IAAI,IAEvB,IAAK,IAAMI,KAAUF,EAAS,CAC5B,IAAMG,EACJD,EAAO,OAAO,WAAa,KAAK,aAC3BA,EAAO,OACRA,EAAO,OAAO,cACpB,GAAI,CAACC,EACH,SAGF,IAAMC,EAAUD,EAAO,QAAQzB,CAAgB,EAC3C0B,EACFP,EAAS,IAAIjB,EAAUwB,CAAO,CAAC,GAI7BF,EAAO,OAAS,cAAgBC,EAAO,QAAA,gBAA2B,GACpEL,EAAW,IAAIK,CAAM,EAEvBD,EAAO,WAAW,QAAS,GAAS,CAC9BG,EAAK,WAAa,KAAK,cACzB,KAAK,QAAQA,EAAiBR,EAAUC,CAAU,CAEtD,CAAC,EACH,CAEIE,EAAQ,KAAM,GAAWE,EAAO,aAAa,OAAS,CAAC,GACzD,KAAK,OAAQ,GAAY,CAACpB,EAAQ,WAAW,EAE/Ce,EAAS,QAAS,GAAY,KAAK,iBAAiBf,CAAO,CAAC,EAC5DgB,EAAW,QAAS,GAAY,KAAK,oBAAoBhB,CAAO,CAAC,CACnE,CAEA,OAAe,EAA0C,CACvD,IAAK,IAAMA,KAAW,KAAK,SAAS,KAAK,EACnCwB,EAAUxB,CAAO,GACnB,KAAK,SAAS,OAAOA,CAAO,EAGhC,IAAK,IAAMA,KAAW,KAAK,WAAW,KAAK,EACrCwB,EAAUxB,CAAO,GACnB,KAAK,WAAW,OAAOA,CAAO,CAGpC,CAEA,iBAAyB,EAAkB,EAAQ,GAAO,CACxD,IAAMyB,EAAOzB,EAAQ,UACjB0B,EAAc,KAAK,SAAS,IAAI1B,CAAO,EAE3C,GAAI,CAAC0B,EACH,EAAc,CAAE,OAAQD,EAAM,UAAW,CAAE,EAC3C,KAAK,SAAS,IAAIzB,EAAS0B,CAAW,OACjC,GAAID,IAASC,EAAY,UAAYD,IAASC,EAAY,OAE/D,EAAY,OAASD,EACrB,EAAY,SAAW,IAAA,QAClB,GAAI,CAACE,EACV,OAGF,GAAM,EAAGC,EAAmBC,EAAMC,GAChC,yBAAyB,KACvBJ,EAAY,OAAO,QAAQ,mBAAoB,EAAE,CACnD,EACF,GAAI,CAACG,EACH,OAIF,IAAME,EAAY,EAAEL,EAAY,UAC1B3B,EAAU2B,EAChB,KAAK,UAAUG,EAAM3B,EAAUF,CAAO,CAAC,CAAC,CAAC,KAAM,GAAe,CAC5D,GAAI+B,IAAchC,EAAQ,WAAa,CAACC,EAAQ,YAC9C,OAEF,IAAMgC,EAAW,GAAGJ,IAAoBK,IAAaH,IACjD9B,EAAQ,YAAcgC,IACxB,EAAQ,UAAYA,GAEtB,EAAQ,SAAWhC,EAAQ,SAC7B,CAAC,CACH,CAEA,oBAA4B,EAAkB,EAAQ,GAAO,CAC3D,IAAMkC,GAASlC,EAAQ,aAAa,cAAc,GAAK,GAAA,CACpD,MAAM,QAAQ,CAAC,CACf,OAAO,OAAO,EACbmC,EAAe,KAAK,WAAW,IAAInC,CAAO,EACzCmC,IACH,EAAe,IAAI,IACnB,KAAK,WAAW,IAAInC,EAASmC,CAAY,GAG3C,IAAK,IAAMC,KAAQF,EAAO,CACxB,IAAMG,EAAQrC,EAAQ,aAAaoC,CAAI,EACvC,GAAI,CAACC,GAAO,KAAK,EACf,SAGF,IAAIX,EAAcS,EAAa,IAAIC,CAAI,EACvC,GAAI,CAACV,EACH,EAAc,CAAE,OAAQW,EAAO,UAAW,CAAE,EAC5CF,EAAa,IAAIC,EAAMV,CAAW,OAC7B,GACLW,IAAUX,EAAY,UACtBW,IAAUX,EAAY,OAEtB,EAAY,OAASW,EACrB,EAAY,SAAW,IAAA,QAClB,GAAI,CAACV,EACV,SAGF,IAAMI,EAAY,EAAEL,EAAY,UAC1B3B,EAAU2B,EAChB,KAAK,UAAU3B,EAAQ,OAAQG,EAAUF,CAAO,CAAC,CAAC,CAAC,KAAM,GAAe,CAClE+B,IAAchC,EAAQ,WAAcC,EAAQ,cAGhD,EAAQ,SAAWiC,EACfjC,EAAQ,aAAaoC,CAAI,IAAMH,GACjCjC,EAAQ,aAAaoC,EAAMH,CAAU,EAEzC,CAAC,CACH,CACF,CACF,EAOA,SAAgBK,EACd,EACgB,CAChB,OAAO,IAAIhC,EAAeH,CAAO,CACnC,C"}
1
+ {"version":3,"file":"index.cjs","names":["libraryName","libraryWebsite","utsLocaleToLanguage","toTemplate","fillPlaceholders","defaultLoaderFactory","DataLoader","cacheKeyFn","toHtmlTemplate","_magic_translate_core","CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","id","variablesOf","json","variables","fillHtml","values","html","container","MagicTranslate","language","listener","params","v","text","unused","template","translation","loaderFactory","debug","sourceLanguage","_apiUrl","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","variablesJson","force","leadingWhitespace","trailingWhitespace","show","rendered","translated","requestId","names","translations","name","value","_id","createMagicTranslate","k"],"sources":["../src/magic-translate.ts"],"sourcesContent":["import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n fillElement,\n fillPlaceholders,\n Language,\n libraryName,\n libraryWebsite,\n MagicTranslateConfig,\n toHtmlTemplate,\n toTemplate,\n TextOptions,\n TranslateOptions,\n utsLocaleToLanguage,\n Variables,\n warnAboutUnused,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {\n /**\n * Values that are not translated, referenced as `$name` in the text. The text\n * is translated once as a template and cached, whatever the values are.\n */\n v?: Variables;\n}\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n // the `data-v` attribute the source was last translated with\n variables: string | null;\n // to warn about unused variables once per text, not on every render\n template?: string;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TextOptions {\n const options: TextOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n const id = element.getAttribute('data-t-id');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n if (id) {\n options.id = id;\n }\n return options;\n}\n\n/**\n * Reads the values in `data-v`, a JSON object such as `{\"name\": \"Bob\"}`.\n * Returns `null` if the attribute is not valid, so the text is left as it is\n * rather than translated with `$name` in it.\n */\nfunction variablesOf(element: Element): Variables | undefined | null {\n const json = element.getAttribute('data-v');\n if (json === null) {\n return undefined;\n }\n try {\n const variables: unknown = JSON.parse(json);\n if (\n variables &&\n typeof variables === 'object' &&\n !Array.isArray(variables)\n ) {\n return variables as Variables;\n }\n } catch {\n // reported below\n }\n console.warn(\n `[${libraryName}]: data-v must be a JSON object, such as data-v='{\"name\": \"Bob\"}', but is ${json}`\n );\n return null;\n}\n\nfunction fillHtml(html: string, values: readonly string[]): string {\n if (values.length === 0) {\n return html;\n }\n const container = document.createElement('template');\n container.innerHTML = html;\n fillElement(container.content, values);\n return container.innerHTML;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(\n text: string,\n { v, ...params }: TranslateParams = {}\n ): Promise<string> {\n if (!v) {\n return this.dataLoader.load({ text, ...params });\n }\n const { template, values, unused } = toTemplate(text, v);\n warnAboutUnused(unused);\n return this.dataLoader\n .load({ text: template, ...params })\n .then((translation) => fillPlaceholders(translation, values));\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n const variablesJson = element.getAttribute('data-v');\n let translation = this.contents.get(element);\n if (!translation) {\n translation = { source: html, requestId: 0, variables: variablesJson };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n // only the values changed, so the cached translation is reused\n translation.variables = variablesJson;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n return;\n }\n const { template, values, unused } = variables\n ? toHtmlTemplate(text, variables)\n : { template: text, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = `${leadingWhitespace}${fillHtml(translated, values)}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n };\n // Until the first translation arrives, show the values instead of `$name`.\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++current.requestId;\n this.translate(template, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n const variablesJson = element.getAttribute('data-v');\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0, variables: variablesJson };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n translation.variables = variablesJson;\n } else if (!force) {\n continue;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n continue;\n }\n const { template, values, unused } = variables\n ? toTemplate(translation.source, variables)\n : { template: translation.source, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = fillPlaceholders(translated, values);\n current.rendered = rendered;\n if (element.getAttribute(name) !== rendered) {\n element.setAttribute(name, rendered);\n }\n };\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n const requestId = ++current.requestId;\n // An id stands for one text, and an element's attributes are several.\n const { id: _id, ...options } = optionsOf(element);\n this.translate(template, options).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,20 +1,35 @@
1
- import { DataLoader as e, cacheKeyFn as t, defaultLoaderFactory as n, libraryWebsite as r, utsLocaleToLanguage as i } from "@magic-translate/core";
1
+ import { DataLoader as e, cacheKeyFn as t, defaultLoaderFactory as n, fillElement as r, fillPlaceholders as i, libraryName as a, libraryWebsite as o, toHtmlTemplate as s, toTemplate as c, utsLocaleToLanguage as l, warnAboutUnused as u } from "@magic-translate/core";
2
2
  export * from "@magic-translate/core";
3
3
  // src/magic-translate.ts
4
- var a = "t, mt-translate, [data-t]", o = "[data-t-attrs]";
5
- function s(e) {
4
+ var d = "t, mt-translate, [data-t]", f = "[data-t-attrs]";
5
+ function p(e) {
6
6
  let t = e;
7
- for (let e = t.parentElement?.closest(a); e; e = t.parentElement?.closest(a)) t = e;
7
+ for (let e = t.parentElement?.closest(d); e; e = t.parentElement?.closest(d)) t = e;
8
8
  return t;
9
9
  }
10
- function c(e) {
11
- let t = {}, n = e.getAttribute("data-lang"), r = e.getAttribute("data-formality");
12
- return n && (t.lang = n), r && (t.formality = r), t;
10
+ function m(e) {
11
+ let t = {}, n = e.getAttribute("data-lang"), r = e.getAttribute("data-formality"), i = e.getAttribute("data-t-id");
12
+ return n && (t.lang = n), r && (t.formality = r), i && (t.id = i), t;
13
13
  }
14
- var l = class {
14
+ function h(e) {
15
+ let t = e.getAttribute("data-v");
16
+ if (t !== null) {
17
+ try {
18
+ let e = JSON.parse(t);
19
+ if (e && typeof e == "object" && !Array.isArray(e)) return e;
20
+ } catch {}
21
+ return console.warn(`[${a}]: data-v must be a JSON object, such as data-v='{"name": "Bob"}', but is ${t}`), null;
22
+ }
23
+ }
24
+ function g(e, t) {
25
+ if (t.length === 0) return e;
26
+ let n = document.createElement("template");
27
+ return n.innerHTML = e, r(n.content, t), n.innerHTML;
28
+ }
29
+ var _ = class {
15
30
  constructor(e) {
16
- if (this.options = e, this.contents = /* @__PURE__ */ new Map(), this.attributes = /* @__PURE__ */ new Map(), this.listeners = /* @__PURE__ */ new Set(), !e.apiKey) throw Error(`Missing API key. Please get one at ${r}`);
17
- this.currentLanguage = e.language ?? i(typeof navigator > "u" ? void 0 : navigator.language), this.dataLoader = this.createDataLoader(), typeof document < "u" && (this.root = e.root ?? document.documentElement, this.start(this.root));
31
+ if (this.options = e, this.contents = /* @__PURE__ */ new Map(), this.attributes = /* @__PURE__ */ new Map(), this.listeners = /* @__PURE__ */ new Set(), !e.apiKey) throw Error(`Missing API key. Please get one at ${o}`);
32
+ this.currentLanguage = e.language ?? l(typeof navigator > "u" ? void 0 : navigator.language), this.dataLoader = this.createDataLoader(), typeof document < "u" && (this.root = e.root ?? document.documentElement, this.start(this.root));
18
33
  }
19
34
  get language() {
20
35
  return this.currentLanguage;
@@ -25,11 +40,16 @@ var l = class {
25
40
  onLanguageChange(e) {
26
41
  return this.listeners.add(e), () => this.listeners.delete(e);
27
42
  }
28
- translate(e, t = {}) {
29
- return this.dataLoader.load({
43
+ translate(e, { v: t, ...n } = {}) {
44
+ if (!t) return this.dataLoader.load({
30
45
  text: e,
31
- ...t
46
+ ...n
32
47
  });
48
+ let { template: r, values: a, unused: o } = c(e, t);
49
+ return u(o), this.dataLoader.load({
50
+ text: r,
51
+ ...n
52
+ }).then((e) => i(e, a));
33
53
  }
34
54
  destroy() {
35
55
  this.observer?.disconnect(), this.contents.clear(), this.attributes.clear(), this.listeners.clear();
@@ -56,15 +76,15 @@ var l = class {
56
76
  }
57
77
  collect(e, t, n) {
58
78
  let r = [e, ...Array.from(e.querySelectorAll("*"))];
59
- for (let e of r) e.matches("t, mt-translate, [data-t]") ? t.add(s(e)) : e.matches("[data-t-attrs]") && !e.closest("t, mt-translate, [data-t]") && n.add(e);
79
+ for (let e of r) e.matches("t, mt-translate, [data-t]") ? t.add(p(e)) : e.matches("[data-t-attrs]") && !e.closest("t, mt-translate, [data-t]") && n.add(e);
60
80
  }
61
81
  handleMutations(e) {
62
82
  let t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set();
63
83
  for (let r of e) {
64
84
  let e = r.target.nodeType === Node.ELEMENT_NODE ? r.target : r.target.parentElement;
65
85
  if (!e) continue;
66
- let i = e.closest(a);
67
- i ? t.add(s(i)) : (r.type === "attributes" && e.matches("[data-t-attrs]") && n.add(e), r.addedNodes.forEach((e) => {
86
+ let i = e.closest(d);
87
+ i ? t.add(p(i)) : (r.type === "attributes" && e.matches("[data-t-attrs]") && n.add(e), r.addedNodes.forEach((e) => {
68
88
  e.nodeType === Node.ELEMENT_NODE && this.collect(e, t, n);
69
89
  }));
70
90
  }
@@ -75,45 +95,73 @@ var l = class {
75
95
  for (let t of this.attributes.keys()) e(t) && this.attributes.delete(t);
76
96
  }
77
97
  translateContent(e, t = !1) {
78
- let n = e.innerHTML, r = this.contents.get(e);
79
- if (!r) r = {
98
+ let n = e.innerHTML, r = e.getAttribute("data-v"), i = this.contents.get(e);
99
+ if (!i) i = {
80
100
  source: n,
81
- requestId: 0
82
- }, this.contents.set(e, r);
83
- else if (n !== r.rendered && n !== r.source) r.source = n, r.rendered = void 0;
101
+ requestId: 0,
102
+ variables: r
103
+ }, this.contents.set(e, i);
104
+ else if (n !== i.rendered && n !== i.source) i.source = n, i.rendered = void 0, i.variables = r;
105
+ else if (r !== i.variables) i.variables = r;
84
106
  else if (!t) return;
85
- let [, i, a, o] = /^(\s*)([\s\S]*?)(\s*)$/.exec(r.source.replace(/<!--[\s\S]*?-->/g, ""));
86
- if (!a) return;
87
- let s = ++r.requestId, l = r;
88
- this.translate(a, c(e)).then((t) => {
89
- if (s !== l.requestId || !e.isConnected) return;
90
- let n = `${i}${t}${o}`;
91
- e.innerHTML !== n && (e.innerHTML = n), l.rendered = e.innerHTML;
107
+ let [, a, o, c] = /^(\s*)([\s\S]*?)(\s*)$/.exec(i.source.replace(/<!--[\s\S]*?-->/g, ""));
108
+ if (!o) return;
109
+ let l = h(e);
110
+ if (l === null) return;
111
+ let { template: d, values: f, unused: p } = l ? s(o, l) : {
112
+ template: o,
113
+ values: [],
114
+ unused: []
115
+ };
116
+ d !== i.template && (i.template = d, u(p));
117
+ let _ = i, v = (t) => {
118
+ let n = `${a}${g(t, f)}${c}`;
119
+ e.innerHTML !== n && (e.innerHTML = n), _.rendered = e.innerHTML;
120
+ };
121
+ l && _.rendered === void 0 && v(d);
122
+ let y = ++_.requestId;
123
+ this.translate(d, m(e)).then((t) => {
124
+ y === _.requestId && e.isConnected && v(t);
92
125
  });
93
126
  }
94
127
  translateAttributes(e, t = !1) {
95
- let n = (e.getAttribute("data-t-attrs") ?? "").split(/[\s,]+/).filter(Boolean), r = this.attributes.get(e);
96
- r || (r = /* @__PURE__ */ new Map(), this.attributes.set(e, r));
97
- for (let i of n) {
98
- let n = e.getAttribute(i);
128
+ let n = (e.getAttribute("data-t-attrs") ?? "").split(/[\s,]+/).filter(Boolean), r = e.getAttribute("data-v"), a = this.attributes.get(e);
129
+ a || (a = /* @__PURE__ */ new Map(), this.attributes.set(e, a));
130
+ for (let o of n) {
131
+ let n = e.getAttribute(o);
99
132
  if (!n?.trim()) continue;
100
- let a = r.get(i);
101
- if (!a) a = {
133
+ let s = a.get(o);
134
+ if (!s) s = {
102
135
  source: n,
103
- requestId: 0
104
- }, r.set(i, a);
105
- else if (n !== a.rendered && n !== a.source) a.source = n, a.rendered = void 0;
136
+ requestId: 0,
137
+ variables: r
138
+ }, a.set(o, s);
139
+ else if (n !== s.rendered && n !== s.source) s.source = n, s.rendered = void 0, s.variables = r;
140
+ else if (r !== s.variables) s.variables = r;
106
141
  else if (!t) continue;
107
- let o = ++a.requestId, s = a;
108
- this.translate(s.source, c(e)).then((t) => {
109
- o === s.requestId && e.isConnected && (s.rendered = t, e.getAttribute(i) !== t && e.setAttribute(i, t));
142
+ let l = h(e);
143
+ if (l === null) continue;
144
+ let { template: d, values: f, unused: p } = l ? c(s.source, l) : {
145
+ template: s.source,
146
+ values: [],
147
+ unused: []
148
+ };
149
+ d !== s.template && (s.template = d, u(p));
150
+ let g = s, _ = (t) => {
151
+ let n = i(t, f);
152
+ g.rendered = n, e.getAttribute(o) !== n && e.setAttribute(o, n);
153
+ };
154
+ l && g.rendered === void 0 && _(d);
155
+ let v = ++g.requestId, { id: y, ...b } = m(e);
156
+ this.translate(d, b).then((t) => {
157
+ v === g.requestId && e.isConnected && _(t);
110
158
  });
111
159
  }
112
160
  }
113
161
  };
114
- function u(e) {
115
- return new l(e);
162
+ function v(e) {
163
+ return new _(e);
116
164
  }
117
- export { o as ATTRIBUTES_SELECTOR, a as CONTENT_SELECTOR, l as MagicTranslate, u as createMagicTranslate };
165
+ export { f as ATTRIBUTES_SELECTOR, d as CONTENT_SELECTOR, _ as MagicTranslate, v as createMagicTranslate };
118
166
 
119
167
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","MagicTranslate","libraryWebsite","utsLocaleToLanguage","language","listener","params","loaderFactory","defaultLoaderFactory","DataLoader","debug","sourceLanguage","_apiUrl","cacheKeyFn","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","html","translation","force","leadingWhitespace","text","trailingWhitespace","requestId","rendered","translated","names","translations","name","value","createMagicTranslate"],"sources":["../src/magic-translate.ts"],"sourcesContent":["import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n Language,\n libraryWebsite,\n MagicTranslateConfig,\n TranslateOptions,\n utsLocaleToLanguage,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TranslateOptions {\n const options: TranslateOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n return options;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(text: string, params: TranslateParams = {}): Promise<string> {\n return this.dataLoader.load({ text, ...params });\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n let translation = this.contents.get(element);\n\n if (!translation) {\n translation = { source: html, requestId: 0 };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(text, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n const rendered = `${leadingWhitespace}${translated}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0 };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n } else if (!force) {\n continue;\n }\n\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(current.source, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n current.rendered = translated;\n if (element.getAttribute(name) !== translated) {\n element.setAttribute(name, translated);\n }\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","id","variablesOf","json","variables","libraryName","fillHtml","values","html","container","fillElement","MagicTranslate","libraryWebsite","utsLocaleToLanguage","language","listener","params","v","toTemplate","text","warnAboutUnused","unused","template","fillPlaceholders","translation","loaderFactory","defaultLoaderFactory","DataLoader","debug","sourceLanguage","_apiUrl","cacheKeyFn","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","variablesJson","force","leadingWhitespace","trailingWhitespace","toHtmlTemplate","show","rendered","translated","requestId","names","translations","name","value","_id","createMagicTranslate"],"sources":["../src/magic-translate.ts"],"sourcesContent":["import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n fillElement,\n fillPlaceholders,\n Language,\n libraryName,\n libraryWebsite,\n MagicTranslateConfig,\n toHtmlTemplate,\n toTemplate,\n TextOptions,\n TranslateOptions,\n utsLocaleToLanguage,\n Variables,\n warnAboutUnused,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {\n /**\n * Values that are not translated, referenced as `$name` in the text. The text\n * is translated once as a template and cached, whatever the values are.\n */\n v?: Variables;\n}\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n // the `data-v` attribute the source was last translated with\n variables: string | null;\n // to warn about unused variables once per text, not on every render\n template?: string;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TextOptions {\n const options: TextOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n const id = element.getAttribute('data-t-id');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n if (id) {\n options.id = id;\n }\n return options;\n}\n\n/**\n * Reads the values in `data-v`, a JSON object such as `{\"name\": \"Bob\"}`.\n * Returns `null` if the attribute is not valid, so the text is left as it is\n * rather than translated with `$name` in it.\n */\nfunction variablesOf(element: Element): Variables | undefined | null {\n const json = element.getAttribute('data-v');\n if (json === null) {\n return undefined;\n }\n try {\n const variables: unknown = JSON.parse(json);\n if (\n variables &&\n typeof variables === 'object' &&\n !Array.isArray(variables)\n ) {\n return variables as Variables;\n }\n } catch {\n // reported below\n }\n console.warn(\n `[${libraryName}]: data-v must be a JSON object, such as data-v='{\"name\": \"Bob\"}', but is ${json}`\n );\n return null;\n}\n\nfunction fillHtml(html: string, values: readonly string[]): string {\n if (values.length === 0) {\n return html;\n }\n const container = document.createElement('template');\n container.innerHTML = html;\n fillElement(container.content, values);\n return container.innerHTML;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(\n text: string,\n { v, ...params }: TranslateParams = {}\n ): Promise<string> {\n if (!v) {\n return this.dataLoader.load({ text, ...params });\n }\n const { template, values, unused } = toTemplate(text, v);\n warnAboutUnused(unused);\n return this.dataLoader\n .load({ text: template, ...params })\n .then((translation) => fillPlaceholders(translation, values));\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n const variablesJson = element.getAttribute('data-v');\n let translation = this.contents.get(element);\n if (!translation) {\n translation = { source: html, requestId: 0, variables: variablesJson };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n // only the values changed, so the cached translation is reused\n translation.variables = variablesJson;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n return;\n }\n const { template, values, unused } = variables\n ? toHtmlTemplate(text, variables)\n : { template: text, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = `${leadingWhitespace}${fillHtml(translated, values)}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n };\n // Until the first translation arrives, show the values instead of `$name`.\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++current.requestId;\n this.translate(template, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n const variablesJson = element.getAttribute('data-v');\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0, variables: variablesJson };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n translation.variables = variablesJson;\n } else if (!force) {\n continue;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n continue;\n }\n const { template, values, unused } = variables\n ? toTemplate(translation.source, variables)\n : { template: translation.source, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = fillPlaceholders(translated, values);\n current.rendered = rendered;\n if (element.getAttribute(name) !== rendered) {\n element.setAttribute(name, rendered);\n }\n };\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n const requestId = ++current.requestId;\n // An id stands for one text, and an element's attributes are several.\n const { id: _id, ...options } = optionsOf(element);\n this.translate(template, options).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n"],"mappings":"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"}
@@ -1,10 +1,16 @@
1
- import { DataLoaderLoadParams, Language, MagicTranslateConfig } from '@magic-translate/core';
1
+ import { DataLoaderLoadParams, Language, MagicTranslateConfig, Variables } from '@magic-translate/core';
2
2
  /**
3
3
  * Type alias to make the language enum more flexible to also allow passing language strings
4
4
  * instead of just the enum.
5
5
  */
6
6
  export type Languages = `${Language}`;
7
- export type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;
7
+ export interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {
8
+ /**
9
+ * Values that are not translated, referenced as `$name` in the text. The text
10
+ * is translated once as a template and cached, whatever the values are.
11
+ */
12
+ v?: Variables;
13
+ }
8
14
  export interface MagicTranslateOptions extends Omit<MagicTranslateConfig, 'language'> {
9
15
  /**
10
16
  * The language content is translated to. Defaults to the browser's language.
@@ -45,7 +51,7 @@ export declare class MagicTranslate {
45
51
  /**
46
52
  * Translates a string to the current language.
47
53
  */
48
- translate(text: string, params?: TranslateParams): Promise<string>;
54
+ translate(text: string, { v, ...params }?: TranslateParams): Promise<string>;
49
55
  /**
50
56
  * Stops translating the page. Content that is already translated stays
51
57
  * translated.
@@ -1,8 +1,8 @@
1
- var MagicTranslate=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=`Magic Translate`,n=`https://magictranslate.io`,r;function i(e){return Object.keys(e).filter(t=>e[t]!==void 0).reduce((t,n)=>({...t,[n]:e[n]}),{})}function a(e){let t=new URLSearchParams,n=(e,r=``)=>{Array.isArray(e)?e.forEach((e,t)=>{n(e,r?`${r}[${t}]`:`[${t}]`)}):typeof e==`object`&&e?Object.entries(e).forEach(([e,t])=>{n(t,r?`${r}.${e}`:e)}):t.append(r,e)};return n(e),t}(function(e){e.AF=`af`,e.SQ=`sq`,e.AM=`am`,e.AR=`ar`,e.HY=`hy`,e.AZ=`az`,e.BN=`bn`,e.BS=`bs`,e.BG=`bg`,e.CA=`ca`,e.ZH=`zh`,e.ZH_TW=`zh-TW`,e.HR=`hr`,e.CS=`cs`,e.DA=`da`,e.FA_AF=`fa-AF`,e.NL=`nl`,e.EN=`en`,e.ET=`et`,e.FA=`fa`,e.TL=`tl`,e.FI=`fi`,e.FR=`fr`,e.FR_CA=`fr-CA`,e.KA=`ka`,e.DE=`de`,e.EL=`el`,e.GU=`gu`,e.HT=`ht`,e.HA=`ha`,e.HE=`he`,e.HI=`hi`,e.HU=`hu`,e.IS=`is`,e.ID=`id`,e.GA=`ga`,e.IT=`it`,e.JA=`ja`,e.KN=`kn`,e.KK=`kk`,e.KO=`ko`,e.LV=`lv`,e.LT=`lt`,e.MK=`mk`,e.MS=`ms`,e.ML=`ml`,e.MT=`mt`,e.MR=`mr`,e.MN=`mn`,e.NO=`no`,e.PS=`ps`,e.PL=`pl`,e.PT=`pt`,e.PT_PT=`pt-PT`,e.PA=`pa`,e.RO=`ro`,e.RU=`ru`,e.SR=`sr`,e.SI=`si`,e.SK=`sk`,e.SL=`sl`,e.SO=`so`,e.ES=`es`,e.ES_MX=`es-MX`,e.SW=`sw`,e.SV=`sv`,e.TA=`ta`,e.TE=`te`,e.TH=`th`,e.TR=`tr`,e.UK=`uk`,e.UR=`ur`,e.UZ=`uz`,e.VI=`vi`,e.CY=`cy`})(r||={});var o={debug:!1,apiUrl:`https://api.magictranslate.io`,lang:r.DE},s;(function(e){e.QUOTA_EXCEEDED_ERROR=`QUOTA_EXCEEDED_ERROR`})(s||={});var c=(e,t,n)=>r=>Object.entries(i({apiKey:e,language:n,sourceLanguage:r.sourceLang??t??`auto`,...r})).sort(([e])=>e.localeCompare(e)).reduce((e,t)=>`${e};${t.join(`=`)}`,``),l=e=>async n=>{if(e.debug&&console.debug(`[Magic Translate]: batch function called with: `,n),e.lang===e.sourceLang)return n.map(e=>e.text);let{apiKey:r,lang:s,formality:c}=e,l=i({apiKey:r,lang:s,formality:c,items:n.map(({text:e,sourceLang:t,lang:n,...r})=>i({text:e,lang:n,sourceLang:t,...r}))});return fetch(`${e.apiUrl??o.apiUrl}/v1/translate`,{method:`POST`,body:e.useJson?JSON.stringify(l):a(l),headers:{"Content-Type":e.useJson?`application/json`:`application/x-www-form-urlencoded`}}).then(e=>e.json()).then(e=>`results`in e?e.results:(`code`in e?console.error(`[${t}]: ${e.message}`):console.error(`[${t}]: Unexpected payload from magic translate server: ${JSON.stringify(e)}`),n.map(e=>e.text))).catch(e=>(console.error(`[${t}]: Error while loading translations: `,e),n.map(e=>e.text)))};function u(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,`default`)?e.default:e}var d,f,p=u(function(){if(f)return d;f=1;var e,t=function(){function e(e,t){if(typeof e!=`function`)throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but got: `+e+`.`);this._batchLoadFn=e,this._maxBatchSize=function(e){if(e&&!1===e.batch)return 1;var t=e&&e.maxBatchSize;if(t===void 0)return 1/0;if(typeof t!=`number`||t<1)throw TypeError(`maxBatchSize must be a positive number: `+t);return t}(t),this._batchScheduleFn=function(e){var t=e&&e.batchScheduleFn;if(t===void 0)return n;if(typeof t!=`function`)throw TypeError(`batchScheduleFn must be a function: `+t);return t}(t),this._cacheKeyFn=function(e){var t=e&&e.cacheKeyFn;if(t===void 0)return function(e){return e};if(typeof t!=`function`)throw TypeError(`cacheKeyFn must be a function: `+t);return t}(t),this._cacheMap=function(e){if(e&&!1===e.cache)return null;var t=e&&e.cacheMap;if(t===void 0)return new Map;if(t!==null){var n=[`get`,`set`,`delete`,`clear`].filter(function(e){return t&&typeof t[e]!=`function`});if(n.length!==0)throw TypeError(`Custom cacheMap missing methods: `+n.join(`, `))}return t}(t),this._batch=null,this.name=function(e){return e&&e.name?e.name:null}(t)}var t=e.prototype;return t.load=function(e){if(e==null)throw TypeError(`The loader.load() function must be called with a value, but got: `+String(e)+`.`);var t,n=function(e){var t=e._batch;if(t!==null&&!t.hasDispatched&&t.keys.length<e._maxBatchSize)return t;var n={hasDispatched:!1,keys:[],callbacks:[]};return e._batch=n,e._batchScheduleFn(function(){(function(e,t){if(t.hasDispatched=!0,t.keys.length===0)return void i(t);var n;try{n=e._batchLoadFn(t.keys)}catch(n){return r(e,t,TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function errored synchronously: `+String(n)+`.`))}if(!n||typeof n.then!=`function`)return r(e,t,TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise: `+String(n)+`.`));n.then(function(e){if(!a(e))throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array: `+String(e)+`.`);if(e.length!==t.keys.length)throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.
1
+ var MagicTranslate=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=`Magic Translate`,n=`https://magictranslate.io`,r;function i(e){return Object.keys(e).filter(t=>e[t]!==void 0).reduce((t,n)=>({...t,[n]:e[n]}),{})}function a(e){let t=new URLSearchParams,n=(e,r=``)=>{Array.isArray(e)?e.forEach((e,t)=>{n(e,r?`${r}[${t}]`:`[${t}]`)}):typeof e==`object`&&e?Object.entries(e).forEach(([e,t])=>{n(t,r?`${r}.${e}`:e)}):t.append(r,e)};return n(e),t}(function(e){e.AF=`af`,e.SQ=`sq`,e.AM=`am`,e.AR=`ar`,e.HY=`hy`,e.AZ=`az`,e.BN=`bn`,e.BS=`bs`,e.BG=`bg`,e.CA=`ca`,e.ZH=`zh`,e.ZH_TW=`zh-TW`,e.HR=`hr`,e.CS=`cs`,e.DA=`da`,e.FA_AF=`fa-AF`,e.NL=`nl`,e.EN=`en`,e.ET=`et`,e.FA=`fa`,e.TL=`tl`,e.FI=`fi`,e.FR=`fr`,e.FR_CA=`fr-CA`,e.KA=`ka`,e.DE=`de`,e.EL=`el`,e.GU=`gu`,e.HT=`ht`,e.HA=`ha`,e.HE=`he`,e.HI=`hi`,e.HU=`hu`,e.IS=`is`,e.ID=`id`,e.GA=`ga`,e.IT=`it`,e.JA=`ja`,e.KN=`kn`,e.KK=`kk`,e.KO=`ko`,e.LV=`lv`,e.LT=`lt`,e.MK=`mk`,e.MS=`ms`,e.ML=`ml`,e.MT=`mt`,e.MR=`mr`,e.MN=`mn`,e.NO=`no`,e.PS=`ps`,e.PL=`pl`,e.PT=`pt`,e.PT_PT=`pt-PT`,e.PA=`pa`,e.RO=`ro`,e.RU=`ru`,e.SR=`sr`,e.SI=`si`,e.SK=`sk`,e.SL=`sl`,e.SO=`so`,e.ES=`es`,e.ES_MX=`es-MX`,e.SW=`sw`,e.SV=`sv`,e.TA=`ta`,e.TE=`te`,e.TH=`th`,e.TR=`tr`,e.UK=`uk`,e.UR=`ur`,e.UZ=`uz`,e.VI=`vi`,e.CY=`cy`})(r||={});var o=`MAGIC_TRANSLATE_SECRET_KEY`,s=e=>!!e?.startsWith(`p-`);function c(){let{process:e}=globalThis;return e?.env?.MAGIC_TRANSLATE_SECRET_KEY||void 0}var l=!1;function u({apiKey:e,secretKey:t}){return typeof window>`u`?t||c()||e:(!t&&!s(e)||l||(l=!0,console.error(`[Magic Translate]: Secret keys only work on servers, so this one was not sent. Use your public API key in the browser, and regenerate your secret key at https://magictranslate.io/account since it is exposed.`)),s(e)?void 0:e)}var d=128,f={debug:!1,apiUrl:`https://api.magictranslate.io`,lang:r.DE},p;function m(e){if(e!==void 0)return e.trim()&&e.length<=128?e:void console.error(`[${t}]: Ignoring the id "${e}". Ids must be 1 to 128 characters.`)}(function(e){e.QUOTA_EXCEEDED_ERROR=`QUOTA_EXCEEDED_ERROR`,e.SECRET_KEY_REQUIRED=`SECRET_KEY_REQUIRED`,e.SECRET_KEY_IN_BROWSER=`SECRET_KEY_IN_BROWSER`})(p||={});var h=(e,t,n)=>r=>Object.entries(i({apiKey:e,language:n,sourceLanguage:r.sourceLang??t??`auto`,...r})).sort(([e])=>e.localeCompare(e)).reduce((e,t)=>`${e};${t.join(`=`)}`,``),g=e=>async n=>{if(e.debug&&console.debug(`[Magic Translate]: batch function called with: `,n),e.lang===e.sourceLang)return n.map(e=>e.text);let{lang:r,formality:o}=e,s=u(e);if(!s)return e.apiKey||e.secretKey||console.error(`[Magic Translate]: Missing API key. Please get one at https://magictranslate.io`),n.map(e=>e.text);let c=i({apiKey:s,lang:r,formality:o,items:n.map(({text:e,sourceLang:t,lang:n,id:r,...a})=>i({text:e,lang:n,sourceLang:t,...a,id:m(r)}))});return fetch(`${e.apiUrl??f.apiUrl}/v1/translate`,{method:`POST`,body:e.useJson?JSON.stringify(c):a(c),headers:{"Content-Type":e.useJson?`application/json`:`application/x-www-form-urlencoded`}}).then(e=>e.json()).then(e=>`results`in e?e.results:(`code`in e?console.error(`[${t}]: ${e.message}`):console.error(`[${t}]: Unexpected payload from magic translate server: ${JSON.stringify(e)}`),n.map(e=>e.text))).catch(e=>(console.error(`[${t}]: Error while loading translations: `,e),n.map(e=>e.text)))};function _(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,`default`)?e.default:e}var v,y,b=_(function(){if(y)return v;y=1;var e,t=function(){function e(e,t){if(typeof e!=`function`)throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but got: `+e+`.`);this._batchLoadFn=e,this._maxBatchSize=function(e){if(e&&!1===e.batch)return 1;var t=e&&e.maxBatchSize;if(t===void 0)return 1/0;if(typeof t!=`number`||t<1)throw TypeError(`maxBatchSize must be a positive number: `+t);return t}(t),this._batchScheduleFn=function(e){var t=e&&e.batchScheduleFn;if(t===void 0)return n;if(typeof t!=`function`)throw TypeError(`batchScheduleFn must be a function: `+t);return t}(t),this._cacheKeyFn=function(e){var t=e&&e.cacheKeyFn;if(t===void 0)return function(e){return e};if(typeof t!=`function`)throw TypeError(`cacheKeyFn must be a function: `+t);return t}(t),this._cacheMap=function(e){if(e&&!1===e.cache)return null;var t=e&&e.cacheMap;if(t===void 0)return new Map;if(t!==null){var n=[`get`,`set`,`delete`,`clear`].filter(function(e){return t&&typeof t[e]!=`function`});if(n.length!==0)throw TypeError(`Custom cacheMap missing methods: `+n.join(`, `))}return t}(t),this._batch=null,this.name=function(e){return e&&e.name?e.name:null}(t)}var t=e.prototype;return t.load=function(e){if(e==null)throw TypeError(`The loader.load() function must be called with a value, but got: `+String(e)+`.`);var t,n=function(e){var t=e._batch;if(t!==null&&!t.hasDispatched&&t.keys.length<e._maxBatchSize)return t;var n={hasDispatched:!1,keys:[],callbacks:[]};return e._batch=n,e._batchScheduleFn(function(){(function(e,t){if(t.hasDispatched=!0,t.keys.length===0)return void i(t);var n;try{n=e._batchLoadFn(t.keys)}catch(n){return r(e,t,TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function errored synchronously: `+String(n)+`.`))}if(!n||typeof n.then!=`function`)return r(e,t,TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise: `+String(n)+`.`));n.then(function(e){if(!a(e))throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array: `+String(e)+`.`);if(e.length!==t.keys.length)throw TypeError(`DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.
2
2
 
3
3
  Keys:
4
4
  `+String(t.keys)+`
5
5
 
6
6
  Values:
7
- `+String(e));i(t);for(var n=0;n<t.callbacks.length;n++){var r=e[n];r instanceof Error?t.callbacks[n].reject(r):t.callbacks[n].resolve(r)}}).catch(function(n){r(e,t,n)})})(e,n)}),n}(this),o=this._cacheMap;if(o){t=this._cacheKeyFn(e);var s=o.get(t);if(s){var c=n.cacheHits||=[];return new Promise(function(e){c.push(function(){e(s)})})}}n.keys.push(e);var l=new Promise(function(e,t){n.callbacks.push({resolve:e,reject:t})});return o&&o.set(t,l),l},t.loadMany=function(e){if(!a(e))throw TypeError(`The loader.loadMany() function must be called with Array<key> but got: `+e+`.`);for(var t=[],n=0;n<e.length;n++)t.push(this.load(e[n]).catch(function(e){return e}));return Promise.all(t)},t.clear=function(e){var t=this._cacheMap;if(t){var n=this._cacheKeyFn(e);t.delete(n)}return this},t.clearAll=function(){var e=this._cacheMap;return e&&e.clear(),this},t.prime=function(e,t){var n=this._cacheMap;if(n){var r,i=this._cacheKeyFn(e);n.get(i)===void 0&&(t instanceof Error?(r=Promise.reject(t)).catch(function(){}):r=Promise.resolve(t),n.set(i,r))}return this},e}(),n=typeof process==`object`&&typeof process.nextTick==`function`?function(t){e||=Promise.resolve(),e.then(function(){process.nextTick(t)})}:typeof setImmediate==`function`?function(e){setImmediate(e)}:function(e){setTimeout(e)};function r(e,t,n){i(t);for(var r=0;r<t.keys.length;r++)e.clear(t.keys[r]),t.callbacks[r].reject(n)}function i(e){if(e.cacheHits)for(var t=0;t<e.cacheHits.length;t++)e.cacheHits[t]()}function a(e){return typeof e==`object`&&!!e&&typeof e.length==`number`&&(e.length===0||e.length>0&&Object.prototype.hasOwnProperty.call(e,e.length-1))}return d=t}());function m({debug:e,apiKey:t,sourceLanguage:n,_apiUrl:i,formality:a,_loaderFactory:o}){let s={debug:!!e,apiKey:t,lang:r.EN,sourceLang:n,apiUrl:i,formality:a},u=new p((o??l)(s),{cacheKeyFn:c(t,n)});return(e,t,n)=>u.load({text:t,...n,lang:e})}var h=m,g=r.EN;function _(e,t){if(!e)return t??g;if([r.FA_AF,r.FR_CA,r.PT_PT,r.ES_MX].includes(e))return e;let n=e.includes(`-`)?e.split(`-`)[0]:e;return Object.values(r).includes(n)?n:t||(console.warn(`Language not found for UTS locale "${e}" and no fallback provided was provided. Falling back to "${g}"`),g)}var v=`t, mt-translate, [data-t]`,y=`[data-t-attrs]`;function b(e){let t=e;for(let e=t.parentElement?.closest(v);e;e=t.parentElement?.closest(v))t=e;return t}function x(e){let t={},n=e.getAttribute(`data-lang`),r=e.getAttribute(`data-formality`);return n&&(t.lang=n),r&&(t.formality=r),t}var S=class{constructor(e){if(this.options=e,this.contents=new Map,this.attributes=new Map,this.listeners=new Set,!e.apiKey)throw Error(`Missing API key. Please get one at ${n}`);this.currentLanguage=e.language??_(typeof navigator>`u`?void 0:navigator.language),this.dataLoader=this.createDataLoader(),typeof document<`u`&&(this.root=e.root??document.documentElement,this.start(this.root))}get language(){return this.currentLanguage}setLanguage(e){e!==this.currentLanguage&&(this.currentLanguage=e,this.dataLoader=this.createDataLoader(),this.forget(e=>!e.isConnected||!this.root?.contains(e)),this.contents.forEach((e,t)=>this.translateContent(t,!0)),this.attributes.forEach((e,t)=>this.translateAttributes(t,!0)),this.listeners.forEach(t=>t(e)))}onLanguageChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}translate(e,t={}){return this.dataLoader.load({text:e,...t})}destroy(){this.observer?.disconnect(),this.contents.clear(),this.attributes.clear(),this.listeners.clear()}createDataLoader(){let{debug:e,apiKey:t,sourceLanguage:n,_apiUrl:r,formality:i}=this.options;return new p((this.options._loaderFactory??l)({debug:!!e,apiKey:t,lang:this.currentLanguage,sourceLang:n,apiUrl:r,formality:i}),{cacheKeyFn:c(t,n,this.currentLanguage)})}start(e){let t=new Set,n=new Set;this.collect(e,t,n),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e)),this.observer=new MutationObserver(e=>this.handleMutations(e)),this.observer.observe(e,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}collect(e,t,n){let r=[e,...Array.from(e.querySelectorAll(`*`))];for(let e of r)e.matches(`t, mt-translate, [data-t]`)?t.add(b(e)):e.matches(`[data-t-attrs]`)&&!e.closest(`t, mt-translate, [data-t]`)&&n.add(e)}handleMutations(e){let t=new Set,n=new Set;for(let r of e){let e=r.target.nodeType===Node.ELEMENT_NODE?r.target:r.target.parentElement;if(!e)continue;let i=e.closest(v);i?t.add(b(i)):(r.type===`attributes`&&e.matches(`[data-t-attrs]`)&&n.add(e),r.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&this.collect(e,t,n)}))}e.some(e=>e.removedNodes.length>0)&&this.forget(e=>!e.isConnected),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e))}forget(e){for(let t of this.contents.keys())e(t)&&this.contents.delete(t);for(let t of this.attributes.keys())e(t)&&this.attributes.delete(t)}translateContent(e,t=!1){let n=e.innerHTML,r=this.contents.get(e);if(!r)r={source:n,requestId:0},this.contents.set(e,r);else if(n!==r.rendered&&n!==r.source)r.source=n,r.rendered=void 0;else if(!t)return;let[,i,a,o]=/^(\s*)([\s\S]*?)(\s*)$/.exec(r.source.replace(/<!--[\s\S]*?-->/g,``));if(!a)return;let s=++r.requestId,c=r;this.translate(a,x(e)).then(t=>{if(s!==c.requestId||!e.isConnected)return;let n=`${i}${t}${o}`;e.innerHTML!==n&&(e.innerHTML=n),c.rendered=e.innerHTML})}translateAttributes(e,t=!1){let n=(e.getAttribute(`data-t-attrs`)??``).split(/[\s,]+/).filter(Boolean),r=this.attributes.get(e);r||(r=new Map,this.attributes.set(e,r));for(let i of n){let n=e.getAttribute(i);if(!n?.trim())continue;let a=r.get(i);if(!a)a={source:n,requestId:0},r.set(i,a);else if(n!==a.rendered&&n!==a.source)a.source=n,a.rendered=void 0;else if(!t)continue;let o=++a.requestId,s=a;this.translate(s.source,x(e)).then(t=>{o===s.requestId&&e.isConnected&&(s.rendered=t,e.getAttribute(i)!==t&&e.setAttribute(i,t))})}}};function C(e){return new S(e)}var w=`magic-translate-language`;function T(){try{return localStorage.getItem(w)??void 0}catch{return}}var E=document.currentScript,D=E?.dataset.apiKey;if(E&&D){let{language:e,sourceLanguage:t,formality:n}=E.dataset,r=()=>{let r=C({apiKey:D,language:T()??e,sourceLanguage:t,formality:n,debug:E.hasAttribute(`data-debug`)});r.onLanguageChange(e=>{try{localStorage.setItem(w,e)}catch{}}),window.magicTranslate=r,document.dispatchEvent(new CustomEvent(`magictranslate:ready`,{detail:r}))};document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,r):r()}return e.ATTRIBUTES_SELECTOR=y,e.CONTENT_SELECTOR=v,e.DataLoader=p,Object.defineProperty(e,"Language",{enumerable:!0,get:function(){return r}}),e.MagicTranslate=S,e.cacheKeyFn=c,e.createMagicTranslate=C,e.defaultDataLoaderOptions=o,e.defaultLoaderFactory=l,e.libraryName=t,e.libraryWebsite=n,e.setupT=h,e.setupTranslate=m,e.utsLocaleToLanguage=_,e})({});
7
+ `+String(e));i(t);for(var n=0;n<t.callbacks.length;n++){var r=e[n];r instanceof Error?t.callbacks[n].reject(r):t.callbacks[n].resolve(r)}}).catch(function(n){r(e,t,n)})})(e,n)}),n}(this),o=this._cacheMap;if(o){t=this._cacheKeyFn(e);var s=o.get(t);if(s){var c=n.cacheHits||=[];return new Promise(function(e){c.push(function(){e(s)})})}}n.keys.push(e);var l=new Promise(function(e,t){n.callbacks.push({resolve:e,reject:t})});return o&&o.set(t,l),l},t.loadMany=function(e){if(!a(e))throw TypeError(`The loader.loadMany() function must be called with Array<key> but got: `+e+`.`);for(var t=[],n=0;n<e.length;n++)t.push(this.load(e[n]).catch(function(e){return e}));return Promise.all(t)},t.clear=function(e){var t=this._cacheMap;if(t){var n=this._cacheKeyFn(e);t.delete(n)}return this},t.clearAll=function(){var e=this._cacheMap;return e&&e.clear(),this},t.prime=function(e,t){var n=this._cacheMap;if(n){var r,i=this._cacheKeyFn(e);n.get(i)===void 0&&(t instanceof Error?(r=Promise.reject(t)).catch(function(){}):r=Promise.resolve(t),n.set(i,r))}return this},e}(),n=typeof process==`object`&&typeof process.nextTick==`function`?function(t){e||=Promise.resolve(),e.then(function(){process.nextTick(t)})}:typeof setImmediate==`function`?function(e){setImmediate(e)}:function(e){setTimeout(e)};function r(e,t,n){i(t);for(var r=0;r<t.keys.length;r++)e.clear(t.keys[r]),t.callbacks[r].reject(n)}function i(e){if(e.cacheHits)for(var t=0;t<e.cacheHits.length;t++)e.cacheHits[t]()}function a(e){return typeof e==`object`&&!!e&&typeof e.length==`number`&&(e.length===0||e.length>0&&Object.prototype.hasOwnProperty.call(e,e.length-1))}return v=t}());function x({debug:e,apiKey:t,secretKey:n,sourceLanguage:i,_apiUrl:a,formality:o,_loaderFactory:s}){let c={debug:!!e,apiKey:t,secretKey:n,lang:r.EN,sourceLang:i,apiUrl:a,formality:o},l=new b((s??g)(c),{cacheKeyFn:h(t,i)});return(e,t,n)=>l.load({text:t,...n,lang:e})}var S=x,C=r.EN;function w(e,t){if(!e)return t??C;if([r.FA_AF,r.FR_CA,r.PT_PT,r.ES_MX].includes(e))return e;let n=e.includes(`-`)?e.split(`-`)[0]:e;return Object.values(r).includes(n)?n:t||(console.warn(`Language not found for UTS locale "${e}" and no fallback provided was provided. Falling back to "${C}"`),C)}var T=/\{(\d+)\}/g,E=e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);function D(e){let t=Object.keys(e).sort((e,t)=>t.length-e.length),n=t.length>0?RegExp(`\\$(${t.map(E).join(`|`)})`,`g`):null,r=new Map,i=[];return{values:i,replace:t=>n?t.replace(n,(t,n)=>{let a=r.get(n);return a===void 0&&(a=i.push(String(e[n]??``))-1,r.set(n,a)),`{${a}}`}):t,unused:()=>t.filter(e=>!r.has(e))}}function O(e){e.length>0&&console.warn(`[Magic Translate]: ${e.map(e=>`$${e}`).join(`, `)} not found in the text. Check the spelling, or remove ${e.length===1?`it`:`them`} from the variables.`)}function k(e,t){let{replace:n,values:r,unused:i}=D(t);return{template:n(e),values:r,unused:i()}}function A(e,t){return e.replace(T,(e,n)=>Number(n)<t.length?t[Number(n)]:e)}function j(e){let t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(let e=t.nextNode();e;e=t.nextNode())n.push(e);return n}function M(e,t){let n=document.createElement(`template`);n.innerHTML=e;let{replace:r,values:i,unused:a}=D(t);return j(n.content).forEach(e=>{e.data=r(e.data)}),{template:n.innerHTML,values:i,unused:a()}}function N(e,t){j(e).forEach(e=>{let n=A(e.data,t);n!==e.data&&(e.data=n)})}var P=`t, mt-translate, [data-t]`,F=`[data-t-attrs]`;function I(e){let t=e;for(let e=t.parentElement?.closest(P);e;e=t.parentElement?.closest(P))t=e;return t}function L(e){let t={},n=e.getAttribute(`data-lang`),r=e.getAttribute(`data-formality`),i=e.getAttribute(`data-t-id`);return n&&(t.lang=n),r&&(t.formality=r),i&&(t.id=i),t}function R(e){let n=e.getAttribute(`data-v`);if(n!==null){try{let e=JSON.parse(n);if(e&&typeof e==`object`&&!Array.isArray(e))return e}catch{}return console.warn(`[${t}]: data-v must be a JSON object, such as data-v='{"name": "Bob"}', but is ${n}`),null}}function z(e,t){if(t.length===0)return e;let n=document.createElement(`template`);return n.innerHTML=e,N(n.content,t),n.innerHTML}var B=class{constructor(e){if(this.options=e,this.contents=new Map,this.attributes=new Map,this.listeners=new Set,!e.apiKey)throw Error(`Missing API key. Please get one at ${n}`);this.currentLanguage=e.language??w(typeof navigator>`u`?void 0:navigator.language),this.dataLoader=this.createDataLoader(),typeof document<`u`&&(this.root=e.root??document.documentElement,this.start(this.root))}get language(){return this.currentLanguage}setLanguage(e){e!==this.currentLanguage&&(this.currentLanguage=e,this.dataLoader=this.createDataLoader(),this.forget(e=>!e.isConnected||!this.root?.contains(e)),this.contents.forEach((e,t)=>this.translateContent(t,!0)),this.attributes.forEach((e,t)=>this.translateAttributes(t,!0)),this.listeners.forEach(t=>t(e)))}onLanguageChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}translate(e,{v:t,...n}={}){if(!t)return this.dataLoader.load({text:e,...n});let{template:r,values:i,unused:a}=k(e,t);return O(a),this.dataLoader.load({text:r,...n}).then(e=>A(e,i))}destroy(){this.observer?.disconnect(),this.contents.clear(),this.attributes.clear(),this.listeners.clear()}createDataLoader(){let{debug:e,apiKey:t,sourceLanguage:n,_apiUrl:r,formality:i}=this.options;return new b((this.options._loaderFactory??g)({debug:!!e,apiKey:t,lang:this.currentLanguage,sourceLang:n,apiUrl:r,formality:i}),{cacheKeyFn:h(t,n,this.currentLanguage)})}start(e){let t=new Set,n=new Set;this.collect(e,t,n),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e)),this.observer=new MutationObserver(e=>this.handleMutations(e)),this.observer.observe(e,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}collect(e,t,n){let r=[e,...Array.from(e.querySelectorAll(`*`))];for(let e of r)e.matches(`t, mt-translate, [data-t]`)?t.add(I(e)):e.matches(`[data-t-attrs]`)&&!e.closest(`t, mt-translate, [data-t]`)&&n.add(e)}handleMutations(e){let t=new Set,n=new Set;for(let r of e){let e=r.target.nodeType===Node.ELEMENT_NODE?r.target:r.target.parentElement;if(!e)continue;let i=e.closest(P);i?t.add(I(i)):(r.type===`attributes`&&e.matches(`[data-t-attrs]`)&&n.add(e),r.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&this.collect(e,t,n)}))}e.some(e=>e.removedNodes.length>0)&&this.forget(e=>!e.isConnected),t.forEach(e=>this.translateContent(e)),n.forEach(e=>this.translateAttributes(e))}forget(e){for(let t of this.contents.keys())e(t)&&this.contents.delete(t);for(let t of this.attributes.keys())e(t)&&this.attributes.delete(t)}translateContent(e,t=!1){let n=e.innerHTML,r=e.getAttribute(`data-v`),i=this.contents.get(e);if(!i)i={source:n,requestId:0,variables:r},this.contents.set(e,i);else if(n!==i.rendered&&n!==i.source)i.source=n,i.rendered=void 0,i.variables=r;else if(r!==i.variables)i.variables=r;else if(!t)return;let[,a,o,s]=/^(\s*)([\s\S]*?)(\s*)$/.exec(i.source.replace(/<!--[\s\S]*?-->/g,``));if(!o)return;let c=R(e);if(c===null)return;let{template:l,values:u,unused:d}=c?M(o,c):{template:o,values:[],unused:[]};l!==i.template&&(i.template=l,O(d));let f=i,p=t=>{let n=`${a}${z(t,u)}${s}`;e.innerHTML!==n&&(e.innerHTML=n),f.rendered=e.innerHTML};c&&f.rendered===void 0&&p(l);let m=++f.requestId;this.translate(l,L(e)).then(t=>{m===f.requestId&&e.isConnected&&p(t)})}translateAttributes(e,t=!1){let n=(e.getAttribute(`data-t-attrs`)??``).split(/[\s,]+/).filter(Boolean),r=e.getAttribute(`data-v`),i=this.attributes.get(e);i||(i=new Map,this.attributes.set(e,i));for(let a of n){let n=e.getAttribute(a);if(!n?.trim())continue;let o=i.get(a);if(!o)o={source:n,requestId:0,variables:r},i.set(a,o);else if(n!==o.rendered&&n!==o.source)o.source=n,o.rendered=void 0,o.variables=r;else if(r!==o.variables)o.variables=r;else if(!t)continue;let s=R(e);if(s===null)continue;let{template:c,values:l,unused:u}=s?k(o.source,s):{template:o.source,values:[],unused:[]};c!==o.template&&(o.template=c,O(u));let d=o,f=t=>{let n=A(t,l);d.rendered=n,e.getAttribute(a)!==n&&e.setAttribute(a,n)};s&&d.rendered===void 0&&f(c);let p=++d.requestId,{id:m,...h}=L(e);this.translate(c,h).then(t=>{p===d.requestId&&e.isConnected&&f(t)})}}};function V(e){return new B(e)}var H=`magic-translate-language`;function U(){try{return localStorage.getItem(H)??void 0}catch{return}}var W=document.currentScript,G=W?.dataset.apiKey;if(W&&G){let{language:e,sourceLanguage:t,formality:n}=W.dataset,r=()=>{let r=V({apiKey:G,language:U()??e,sourceLanguage:t,formality:n,debug:W.hasAttribute(`data-debug`)});r.onLanguageChange(e=>{try{localStorage.setItem(H,e)}catch{}}),window.magicTranslate=r,document.dispatchEvent(new CustomEvent(`magictranslate:ready`,{detail:r}))};document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,r):r()}return e.ATTRIBUTES_SELECTOR=F,e.CONTENT_SELECTOR=P,e.DataLoader=b,Object.defineProperty(e,"Language",{enumerable:!0,get:function(){return r}}),e.MagicTranslate=B,e.cacheKeyFn=h,e.createMagicTranslate=V,e.defaultDataLoaderOptions=f,e.defaultLoaderFactory=g,e.fillElement=N,e.fillPlaceholders=A,e.isSecretKey=s,e.libraryName=t,e.libraryWebsite=n,e.maxIdLength=d,e.resolveApiKey=u,e.secretKeyEnvVariable=o,e.secretKeyFromEnv=c,e.setupT=S,e.setupTranslate=x,e.templater=D,e.toHtmlTemplate=M,e.toTemplate=k,e.utsLocaleToLanguage=w,e.warnAboutUnused=O,e})({});
8
8
  //# sourceMappingURL=magic-translate.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"magic-translate.min.js","names":["libraryWebsite","utsLocaleToLanguage","defaultLoaderFactory","DataLoader","cacheKeyFn","exports","e","t","n","r","c","i","a","u","s","l","h","o","y","d","m","g","CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","MagicTranslate","language","listener","params","debug","sourceLanguage","_apiUrl","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","html","translation","force","leadingWhitespace","text","trailingWhitespace","requestId","rendered","translated","names","translations","name","value","createMagicTranslate","STORAGE_KEY","storedLanguage","script","start","magicTranslate"],"sources":["../../core/dist/index.es.js","../src/magic-translate.ts","../src/script.ts"],"sourcesContent":["/*\n * 'Magic Translate Core'\n * {@link https://https://magictranslate.io\n * @copyright i42 GmbH\n */\nconst e=\"Magic Translate\",t=\"https://magictranslate.io\";var r;function n(e){return Object.keys(e).filter(t=>void 0!==e[t]).reduce((t,r)=>({...t,[r]:e[r]}),{})}function a(e){const t=new URLSearchParams,r=(e,n=\"\")=>{Array.isArray(e)?e.forEach((e,t)=>{r(e,n?`${n}[${t}]`:`[${t}]`)}):\"object\"==typeof e&&null!==e?Object.entries(e).forEach(([e,t])=>{r(t,n?`${n}.${e}`:e)}):t.append(n,e)};return r(e),t}!function(e){e.AF=\"af\",e.SQ=\"sq\",e.AM=\"am\",e.AR=\"ar\",e.HY=\"hy\",e.AZ=\"az\",e.BN=\"bn\",e.BS=\"bs\",e.BG=\"bg\",e.CA=\"ca\",e.ZH=\"zh\",e.ZH_TW=\"zh-TW\",e.HR=\"hr\",e.CS=\"cs\",e.DA=\"da\",e.FA_AF=\"fa-AF\",e.NL=\"nl\",e.EN=\"en\",e.ET=\"et\",e.FA=\"fa\",e.TL=\"tl\",e.FI=\"fi\",e.FR=\"fr\",e.FR_CA=\"fr-CA\",e.KA=\"ka\",e.DE=\"de\",e.EL=\"el\",e.GU=\"gu\",e.HT=\"ht\",e.HA=\"ha\",e.HE=\"he\",e.HI=\"hi\",e.HU=\"hu\",e.IS=\"is\",e.ID=\"id\",e.GA=\"ga\",e.IT=\"it\",e.JA=\"ja\",e.KN=\"kn\",e.KK=\"kk\",e.KO=\"ko\",e.LV=\"lv\",e.LT=\"lt\",e.MK=\"mk\",e.MS=\"ms\",e.ML=\"ml\",e.MT=\"mt\",e.MR=\"mr\",e.MN=\"mn\",e.NO=\"no\",e.PS=\"ps\",e.PL=\"pl\",e.PT=\"pt\",e.PT_PT=\"pt-PT\",e.PA=\"pa\",e.RO=\"ro\",e.RU=\"ru\",e.SR=\"sr\",e.SI=\"si\",e.SK=\"sk\",e.SL=\"sl\",e.SO=\"so\",e.ES=\"es\",e.ES_MX=\"es-MX\",e.SW=\"sw\",e.SV=\"sv\",e.TA=\"ta\",e.TE=\"te\",e.TH=\"th\",e.TR=\"tr\",e.UK=\"uk\",e.UR=\"ur\",e.UZ=\"uz\",e.VI=\"vi\",e.CY=\"cy\"}(r||(r={}));const o={debug:!1,apiUrl:\"https://api.magictranslate.io\",lang:r.DE};var c;!function(e){e.QUOTA_EXCEEDED_ERROR=\"QUOTA_EXCEEDED_ERROR\"}(c||(c={}));const i=(e,t,r)=>a=>Object.entries(n({apiKey:e,language:r,sourceLanguage:a.sourceLang??t??\"auto\",...a})).sort(([e])=>e.localeCompare(e)).reduce((e,t)=>`${e};${t.join(\"=\")}`,\"\"),u=t=>async r=>{if(t.debug&&console.debug(`[${e}]: batch function called with: `,r),t.lang===t.sourceLang)return r.map(e=>e.text);const{apiKey:c,lang:i,formality:u}=t,s=n({apiKey:c,lang:i,formality:u,items:r.map(({text:e,sourceLang:t,lang:r,...a})=>n({text:e,lang:r,sourceLang:t,...a}))});return fetch(`${t.apiUrl??o.apiUrl}/v1/translate`,{method:\"POST\",body:t.useJson?JSON.stringify(s):a(s),headers:{\"Content-Type\":t.useJson?\"application/json\":\"application/x-www-form-urlencoded\"}}).then(e=>e.json()).then(t=>\"results\"in t?t.results:(\"code\"in t?console.error(`[${e}]: ${t.message}`):console.error(`[${e}]: Unexpected payload from magic translate server: ${JSON.stringify(t)}`),r.map(e=>e.text))).catch(t=>(console.error(`[${e}]: Error while loading translations: `,t),r.map(e=>e.text)))};function s(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,\"default\")?e.default:e}var l,h;var f=function(){if(h)return l;h=1;var e,t=function(){function e(e,t){if(\"function\"!=typeof e)throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but got: \"+e+\".\");this._batchLoadFn=e,this._maxBatchSize=function(e){var t=!e||!1!==e.batch;if(!t)return 1;var r=e&&e.maxBatchSize;if(void 0===r)return 1/0;if(\"number\"!=typeof r||r<1)throw new TypeError(\"maxBatchSize must be a positive number: \"+r);return r}(t),this._batchScheduleFn=function(e){var t=e&&e.batchScheduleFn;if(void 0===t)return r;if(\"function\"!=typeof t)throw new TypeError(\"batchScheduleFn must be a function: \"+t);return t}(t),this._cacheKeyFn=function(e){var t=e&&e.cacheKeyFn;if(void 0===t)return function(e){return e};if(\"function\"!=typeof t)throw new TypeError(\"cacheKeyFn must be a function: \"+t);return t}(t),this._cacheMap=function(e){var t=!e||!1!==e.cache;if(!t)return null;var r=e&&e.cacheMap;if(void 0===r)return new Map;if(null!==r){var n=[\"get\",\"set\",\"delete\",\"clear\"].filter(function(e){return r&&\"function\"!=typeof r[e]});if(0!==n.length)throw new TypeError(\"Custom cacheMap missing methods: \"+n.join(\", \"))}return r}(t),this._batch=null,this.name=function(e){if(e&&e.name)return e.name;return null}(t)}var t=e.prototype;return t.load=function(e){if(null==e)throw new TypeError(\"The loader.load() function must be called with a value, but got: \"+String(e)+\".\");var t,r=function(e){var t=e._batch;if(null!==t&&!t.hasDispatched&&t.keys.length<e._maxBatchSize)return t;var r={hasDispatched:!1,keys:[],callbacks:[]};return e._batch=r,e._batchScheduleFn(function(){!function(e,t){if(t.hasDispatched=!0,0===t.keys.length)return void a(t);var r;try{r=e._batchLoadFn(t.keys)}catch(r){return n(e,t,new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function errored synchronously: \"+String(r)+\".\"))}if(!r||\"function\"!=typeof r.then)return n(e,t,new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise: \"+String(r)+\".\"));r.then(function(e){if(!o(e))throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array: \"+String(e)+\".\");if(e.length!==t.keys.length)throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.\\n\\nKeys:\\n\"+String(t.keys)+\"\\n\\nValues:\\n\"+String(e));a(t);for(var r=0;r<t.callbacks.length;r++){var n=e[r];n instanceof Error?t.callbacks[r].reject(n):t.callbacks[r].resolve(n)}}).catch(function(r){n(e,t,r)})}(e,r)}),r}(this),c=this._cacheMap;if(c){t=this._cacheKeyFn(e);var i=c.get(t);if(i){var u=r.cacheHits||(r.cacheHits=[]);return new Promise(function(e){u.push(function(){e(i)})})}}r.keys.push(e);var s=new Promise(function(e,t){r.callbacks.push({resolve:e,reject:t})});return c&&c.set(t,s),s},t.loadMany=function(e){if(!o(e))throw new TypeError(\"The loader.loadMany() function must be called with Array<key> but got: \"+e+\".\");for(var t=[],r=0;r<e.length;r++)t.push(this.load(e[r]).catch(function(e){return e}));return Promise.all(t)},t.clear=function(e){var t=this._cacheMap;if(t){var r=this._cacheKeyFn(e);t.delete(r)}return this},t.clearAll=function(){var e=this._cacheMap;return e&&e.clear(),this},t.prime=function(e,t){var r=this._cacheMap;if(r){var n,a=this._cacheKeyFn(e);if(void 0===r.get(a))t instanceof Error?(n=Promise.reject(t)).catch(function(){}):n=Promise.resolve(t),r.set(a,n)}return this},e}(),r=\"object\"==typeof process&&\"function\"==typeof process.nextTick?function(t){e||(e=Promise.resolve()),e.then(function(){process.nextTick(t)})}:\"function\"==typeof setImmediate?function(e){setImmediate(e)}:function(e){setTimeout(e)};function n(e,t,r){a(t);for(var n=0;n<t.keys.length;n++)e.clear(t.keys[n]),t.callbacks[n].reject(r)}function a(e){if(e.cacheHits)for(var t=0;t<e.cacheHits.length;t++)e.cacheHits[t]()}function o(e){return\"object\"==typeof e&&null!==e&&\"number\"==typeof e.length&&(0===e.length||e.length>0&&Object.prototype.hasOwnProperty.call(e,e.length-1))}return l=t}(),p=s(f);function y({debug:e,apiKey:t,sourceLanguage:n,_apiUrl:a,formality:o,_loaderFactory:c}){const s={debug:!!e,apiKey:t,lang:r.EN,sourceLang:n,apiUrl:a,formality:o},l=new p((c??u)(s),{cacheKeyFn:i(t,n)});return(e,t,r)=>l.load({text:t,...r,lang:e})}const d=y,m=r.EN;function g(e,t){if(!e)return t??m;if([r.FA_AF,r.FR_CA,r.PT_PT,r.ES_MX].includes(e))return e;const n=e.includes(\"-\")?e.split(\"-\")[0]:e;return Object.values(r).includes(n)?n:t||(console.warn(`Language not found for UTS locale \"${e}\" and no fallback provided was provided. Falling back to \"${m}\"`),m)}export{p as DataLoader,r as Language,i as cacheKeyFn,o as defaultDataLoaderOptions,u as defaultLoaderFactory,e as libraryName,t as libraryWebsite,d as setupT,y as setupTranslate,g as utsLocaleToLanguage};\n//# sourceMappingURL=index.es.js.map\n","import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n Language,\n libraryWebsite,\n MagicTranslateConfig,\n TranslateOptions,\n utsLocaleToLanguage,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TranslateOptions {\n const options: TranslateOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n return options;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(text: string, params: TranslateParams = {}): Promise<string> {\n return this.dataLoader.load({ text, ...params });\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n let translation = this.contents.get(element);\n\n if (!translation) {\n translation = { source: html, requestId: 0 };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(text, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n const rendered = `${leadingWhitespace}${translated}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0 };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n } else if (!force) {\n continue;\n }\n\n const requestId = ++translation.requestId;\n const current = translation;\n this.translate(current.source, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n current.rendered = translated;\n if (element.getAttribute(name) !== translated) {\n element.setAttribute(name, translated);\n }\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n","import {\n createMagicTranslate,\n Languages,\n MagicTranslate,\n TranslateParams,\n} from './magic-translate';\n\nexport * from './index';\n\ndeclare global {\n interface Window {\n magicTranslate?: MagicTranslate;\n }\n}\n\nconst STORAGE_KEY = 'magic-translate-language';\n\nfunction storedLanguage(): Languages | undefined {\n try {\n return (localStorage.getItem(STORAGE_KEY) as Languages | null) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n// `<script src=\".../magic-translate.min.js\" data-api-key=\"...\"></script>`\n// starts translating the page without any further code.\nconst script = document.currentScript as HTMLScriptElement | null;\nconst apiKey = script?.dataset.apiKey;\n\nif (script && apiKey) {\n const { language, sourceLanguage, formality } = script.dataset;\n\n const start = () => {\n const magicTranslate = createMagicTranslate({\n apiKey,\n // a language picked with the language switcher outlives page loads\n language: storedLanguage() ?? (language as Languages | undefined),\n sourceLanguage: sourceLanguage as Languages | undefined,\n formality: formality as TranslateParams['formality'],\n debug: script.hasAttribute('data-debug'),\n });\n magicTranslate.onLanguageChange((language) => {\n try {\n localStorage.setItem(STORAGE_KEY, language);\n } catch {\n // storage is unavailable, e.g. in some private windows\n }\n });\n window.magicTranslate = magicTranslate;\n document.dispatchEvent(\n new CustomEvent('magictranslate:ready', { detail: magicTranslate })\n );\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', start);\n } else {\n start();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"magic-translate.min.js","names":["libraryName","libraryWebsite","utsLocaleToLanguage","toTemplate","fillPlaceholders","defaultLoaderFactory","DataLoader","cacheKeyFn","toHtmlTemplate","exports","e","t","n","r","c","i","\"MAGIC_TRANSLATE_SECRET_KEY\"","s","l","h","f","d","p","a","y","o","g","m","v","E","u","w","T","_","S","A","k","R","$","K","P","F","L","M","CONTENT_SELECTOR","ATTRIBUTES_SELECTOR","outermost","current","element","parent","optionsOf","options","lang","formality","id","variablesOf","json","variables","fillHtml","values","html","container","MagicTranslate","language","listener","params","text","unused","template","translation","debug","sourceLanguage","_apiUrl","apiKey","contents","attributes","root","records","all","record","target","content","node","predicate","variablesJson","force","leadingWhitespace","trailingWhitespace","show","rendered","translated","requestId","names","translations","name","value","_id","createMagicTranslate","STORAGE_KEY","storedLanguage","script","start","magicTranslate"],"sources":["../../core/dist/index.es.js","../src/magic-translate.ts","../src/script.ts"],"sourcesContent":["/*\n * 'Magic Translate Core'\n * {@link https://https://magictranslate.io\n * @copyright i42 GmbH\n */\nconst e=\"Magic Translate\",t=\"https://magictranslate.io\";var n;function r(e){return Object.keys(e).filter(t=>void 0!==e[t]).reduce((t,n)=>({...t,[n]:e[n]}),{})}function a(e){const t=new URLSearchParams,n=(e,r=\"\")=>{Array.isArray(e)?e.forEach((e,t)=>{n(e,r?`${r}[${t}]`:`[${t}]`)}):\"object\"==typeof e&&null!==e?Object.entries(e).forEach(([e,t])=>{n(t,r?`${r}.${e}`:e)}):t.append(r,e)};return n(e),t}!function(e){e.AF=\"af\",e.SQ=\"sq\",e.AM=\"am\",e.AR=\"ar\",e.HY=\"hy\",e.AZ=\"az\",e.BN=\"bn\",e.BS=\"bs\",e.BG=\"bg\",e.CA=\"ca\",e.ZH=\"zh\",e.ZH_TW=\"zh-TW\",e.HR=\"hr\",e.CS=\"cs\",e.DA=\"da\",e.FA_AF=\"fa-AF\",e.NL=\"nl\",e.EN=\"en\",e.ET=\"et\",e.FA=\"fa\",e.TL=\"tl\",e.FI=\"fi\",e.FR=\"fr\",e.FR_CA=\"fr-CA\",e.KA=\"ka\",e.DE=\"de\",e.EL=\"el\",e.GU=\"gu\",e.HT=\"ht\",e.HA=\"ha\",e.HE=\"he\",e.HI=\"hi\",e.HU=\"hu\",e.IS=\"is\",e.ID=\"id\",e.GA=\"ga\",e.IT=\"it\",e.JA=\"ja\",e.KN=\"kn\",e.KK=\"kk\",e.KO=\"ko\",e.LV=\"lv\",e.LT=\"lt\",e.MK=\"mk\",e.MS=\"ms\",e.ML=\"ml\",e.MT=\"mt\",e.MR=\"mr\",e.MN=\"mn\",e.NO=\"no\",e.PS=\"ps\",e.PL=\"pl\",e.PT=\"pt\",e.PT_PT=\"pt-PT\",e.PA=\"pa\",e.RO=\"ro\",e.RU=\"ru\",e.SR=\"sr\",e.SI=\"si\",e.SK=\"sk\",e.SL=\"sl\",e.SO=\"so\",e.ES=\"es\",e.ES_MX=\"es-MX\",e.SW=\"sw\",e.SV=\"sv\",e.TA=\"ta\",e.TE=\"te\",e.TH=\"th\",e.TR=\"tr\",e.UK=\"uk\",e.UR=\"ur\",e.UZ=\"uz\",e.VI=\"vi\",e.CY=\"cy\"}(n||(n={}));const o=\"MAGIC_TRANSLATE_SECRET_KEY\",c=e=>!!e?.startsWith(\"p-\");function i(){const{process:e}=globalThis;return e?.env?.[o]||void 0}let s=!1;function u({apiKey:n,secretKey:r}){return\"undefined\"==typeof window?r||i()||n:(!r&&!c(n)||s||(s=!0,console.error(`[${e}]: Secret keys only work on servers, so this one was not sent. Use your public API key in the browser, and regenerate your secret key at ${t}/account since it is exposed.`)),c(n)?void 0:n)}const l=128,h={debug:!1,apiUrl:\"https://api.magictranslate.io\",lang:n.DE};var f;function d(t){if(void 0!==t)return t.trim()&&t.length<=128?t:void console.error(`[${e}]: Ignoring the id \"${t}\". Ids must be 1 to 128 characters.`)}!function(e){e.QUOTA_EXCEEDED_ERROR=\"QUOTA_EXCEEDED_ERROR\",e.SECRET_KEY_REQUIRED=\"SECRET_KEY_REQUIRED\",e.SECRET_KEY_IN_BROWSER=\"SECRET_KEY_IN_BROWSER\"}(f||(f={}));const p=(e,t,n)=>a=>Object.entries(r({apiKey:e,language:n,sourceLanguage:a.sourceLang??t??\"auto\",...a})).sort(([e])=>e.localeCompare(e)).reduce((e,t)=>`${e};${t.join(\"=\")}`,\"\"),y=n=>async o=>{if(n.debug&&console.debug(`[${e}]: batch function called with: `,o),n.lang===n.sourceLang)return o.map(e=>e.text);const{lang:c,formality:i}=n,s=u(n);if(!s)return n.apiKey||n.secretKey||console.error(`[${e}]: Missing API key. Please get one at ${t}`),o.map(e=>e.text);const l=r({apiKey:s,lang:c,formality:i,items:o.map(({text:e,sourceLang:t,lang:n,id:a,...o})=>r({text:e,lang:n,sourceLang:t,...o,id:d(a)}))});return fetch(`${n.apiUrl??h.apiUrl}/v1/translate`,{method:\"POST\",body:n.useJson?JSON.stringify(l):a(l),headers:{\"Content-Type\":n.useJson?\"application/json\":\"application/x-www-form-urlencoded\"}}).then(e=>e.json()).then(t=>\"results\"in t?t.results:(\"code\"in t?console.error(`[${e}]: ${t.message}`):console.error(`[${e}]: Unexpected payload from magic translate server: ${JSON.stringify(t)}`),o.map(e=>e.text))).catch(t=>(console.error(`[${e}]: Error while loading translations: `,t),o.map(e=>e.text)))};function g(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,\"default\")?e.default:e}var m,v;var b=function(){if(v)return m;v=1;var e,t=function(){function e(e,t){if(\"function\"!=typeof e)throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but got: \"+e+\".\");this._batchLoadFn=e,this._maxBatchSize=function(e){var t=!e||!1!==e.batch;if(!t)return 1;var n=e&&e.maxBatchSize;if(void 0===n)return 1/0;if(\"number\"!=typeof n||n<1)throw new TypeError(\"maxBatchSize must be a positive number: \"+n);return n}(t),this._batchScheduleFn=function(e){var t=e&&e.batchScheduleFn;if(void 0===t)return n;if(\"function\"!=typeof t)throw new TypeError(\"batchScheduleFn must be a function: \"+t);return t}(t),this._cacheKeyFn=function(e){var t=e&&e.cacheKeyFn;if(void 0===t)return function(e){return e};if(\"function\"!=typeof t)throw new TypeError(\"cacheKeyFn must be a function: \"+t);return t}(t),this._cacheMap=function(e){var t=!e||!1!==e.cache;if(!t)return null;var n=e&&e.cacheMap;if(void 0===n)return new Map;if(null!==n){var r=[\"get\",\"set\",\"delete\",\"clear\"].filter(function(e){return n&&\"function\"!=typeof n[e]});if(0!==r.length)throw new TypeError(\"Custom cacheMap missing methods: \"+r.join(\", \"))}return n}(t),this._batch=null,this.name=function(e){if(e&&e.name)return e.name;return null}(t)}var t=e.prototype;return t.load=function(e){if(null==e)throw new TypeError(\"The loader.load() function must be called with a value, but got: \"+String(e)+\".\");var t,n=function(e){var t=e._batch;if(null!==t&&!t.hasDispatched&&t.keys.length<e._maxBatchSize)return t;var n={hasDispatched:!1,keys:[],callbacks:[]};return e._batch=n,e._batchScheduleFn(function(){!function(e,t){if(t.hasDispatched=!0,0===t.keys.length)return void a(t);var n;try{n=e._batchLoadFn(t.keys)}catch(n){return r(e,t,new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function errored synchronously: \"+String(n)+\".\"))}if(!n||\"function\"!=typeof n.then)return r(e,t,new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise: \"+String(n)+\".\"));n.then(function(e){if(!o(e))throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array: \"+String(e)+\".\");if(e.length!==t.keys.length)throw new TypeError(\"DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.\\n\\nKeys:\\n\"+String(t.keys)+\"\\n\\nValues:\\n\"+String(e));a(t);for(var n=0;n<t.callbacks.length;n++){var r=e[n];r instanceof Error?t.callbacks[n].reject(r):t.callbacks[n].resolve(r)}}).catch(function(n){r(e,t,n)})}(e,n)}),n}(this),c=this._cacheMap;if(c){t=this._cacheKeyFn(e);var i=c.get(t);if(i){var s=n.cacheHits||(n.cacheHits=[]);return new Promise(function(e){s.push(function(){e(i)})})}}n.keys.push(e);var u=new Promise(function(e,t){n.callbacks.push({resolve:e,reject:t})});return c&&c.set(t,u),u},t.loadMany=function(e){if(!o(e))throw new TypeError(\"The loader.loadMany() function must be called with Array<key> but got: \"+e+\".\");for(var t=[],n=0;n<e.length;n++)t.push(this.load(e[n]).catch(function(e){return e}));return Promise.all(t)},t.clear=function(e){var t=this._cacheMap;if(t){var n=this._cacheKeyFn(e);t.delete(n)}return this},t.clearAll=function(){var e=this._cacheMap;return e&&e.clear(),this},t.prime=function(e,t){var n=this._cacheMap;if(n){var r,a=this._cacheKeyFn(e);if(void 0===n.get(a))t instanceof Error?(r=Promise.reject(t)).catch(function(){}):r=Promise.resolve(t),n.set(a,r)}return this},e}(),n=\"object\"==typeof process&&\"function\"==typeof process.nextTick?function(t){e||(e=Promise.resolve()),e.then(function(){process.nextTick(t)})}:\"function\"==typeof setImmediate?function(e){setImmediate(e)}:function(e){setTimeout(e)};function r(e,t,n){a(t);for(var r=0;r<t.keys.length;r++)e.clear(t.keys[r]),t.callbacks[r].reject(n)}function a(e){if(e.cacheHits)for(var t=0;t<e.cacheHits.length;t++)e.cacheHits[t]()}function o(e){return\"object\"==typeof e&&null!==e&&\"number\"==typeof e.length&&(0===e.length||e.length>0&&Object.prototype.hasOwnProperty.call(e,e.length-1))}return m=t}(),E=g(b);function w({debug:e,apiKey:t,secretKey:r,sourceLanguage:a,_apiUrl:o,formality:c,_loaderFactory:i}){const s={debug:!!e,apiKey:t,secretKey:r,lang:n.EN,sourceLang:a,apiUrl:o,formality:c},u=new E((i??y)(s),{cacheKeyFn:p(t,a)});return(e,t,n)=>u.load({text:t,...n,lang:e})}const T=w,_=n.EN;function S(e,t){if(!e)return t??_;if([n.FA_AF,n.FR_CA,n.PT_PT,n.ES_MX].includes(e))return e;const r=e.includes(\"-\")?e.split(\"-\")[0]:e;return Object.values(n).includes(r)?r:t||(console.warn(`Language not found for UTS locale \"${e}\" and no fallback provided was provided. Falling back to \"${_}\"`),_)}const A=/\\{(\\d+)\\}/g,k=e=>e.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\");function R(e){const t=Object.keys(e).sort((e,t)=>t.length-e.length),n=t.length>0?new RegExp(`\\\\$(${t.map(k).join(\"|\")})`,\"g\"):null,r=new Map,a=[];return{values:a,replace:t=>n?t.replace(n,(t,n)=>{let o=r.get(n);return void 0===o&&(o=a.push(String(e[n]??\"\"))-1,r.set(n,o)),`{${o}}`}):t,unused:()=>t.filter(e=>!r.has(e))}}function $(t){t.length>0&&console.warn(`[${e}]: ${t.map(e=>`$${e}`).join(\", \")} not found in the text. Check the spelling, or remove ${1===t.length?\"it\":\"them\"} from the variables.`)}function K(e,t){const{replace:n,values:r,unused:a}=R(t);return{template:n(e),values:r,unused:a()}}function P(e,t){return e.replace(A,(e,n)=>Number(n)<t.length?t[Number(n)]:e)}function F(e){const t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(let e=t.nextNode();e;e=t.nextNode())n.push(e);return n}function L(e,t){const n=document.createElement(\"template\");n.innerHTML=e;const{replace:r,values:a,unused:o}=R(t);return F(n.content).forEach(e=>{e.data=r(e.data)}),{template:n.innerHTML,values:a,unused:o()}}function M(e,t){F(e).forEach(e=>{const n=P(e.data,t);n!==e.data&&(e.data=n)})}export{E as DataLoader,n as Language,p as cacheKeyFn,h as defaultDataLoaderOptions,y as defaultLoaderFactory,M as fillElement,P as fillPlaceholders,c as isSecretKey,e as libraryName,t as libraryWebsite,l as maxIdLength,u as resolveApiKey,o as secretKeyEnvVariable,i as secretKeyFromEnv,T as setupT,w as setupTranslate,R as templater,L as toHtmlTemplate,K as toTemplate,S as utsLocaleToLanguage,$ as warnAboutUnused};\n//# sourceMappingURL=index.es.js.map\n","import {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n fillElement,\n fillPlaceholders,\n Language,\n libraryName,\n libraryWebsite,\n MagicTranslateConfig,\n toHtmlTemplate,\n toTemplate,\n TextOptions,\n TranslateOptions,\n utsLocaleToLanguage,\n Variables,\n warnAboutUnused,\n} from '@magic-translate/core';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {\n /**\n * Values that are not translated, referenced as `$name` in the text. The text\n * is translated once as a template and cached, whatever the values are.\n */\n v?: Variables;\n}\n\nexport interface MagicTranslateOptions extends Omit<\n MagicTranslateConfig,\n 'language'\n> {\n /**\n * The language content is translated to. Defaults to the browser's language.\n */\n language?: Languages;\n /**\n * The element whose content is translated. Defaults to the whole document.\n */\n root?: Element;\n}\n\n/** Elements whose content is translated. */\nexport const CONTENT_SELECTOR = 't, mt-translate, [data-t]';\n/** Elements with attributes to translate, e.g. `data-t-attrs=\"placeholder title\"`. */\nexport const ATTRIBUTES_SELECTOR = '[data-t-attrs]';\n\ninterface Translation {\n source: string;\n // what was last written to the DOM, to tell our own changes from others\n rendered?: string;\n requestId: number;\n // the `data-v` attribute the source was last translated with\n variables: string | null;\n // to warn about unused variables once per text, not on every render\n template?: string;\n}\n\nfunction outermost(element: Element): Element {\n let current = element;\n for (\n let parent = current.parentElement?.closest(CONTENT_SELECTOR);\n parent;\n parent = current.parentElement?.closest(CONTENT_SELECTOR)\n ) {\n current = parent;\n }\n return current;\n}\n\nfunction optionsOf(element: Element): TextOptions {\n const options: TextOptions = {};\n const lang = element.getAttribute('data-lang');\n const formality = element.getAttribute('data-formality');\n const id = element.getAttribute('data-t-id');\n if (lang) {\n options.lang = lang as Languages;\n }\n if (formality) {\n options.formality = formality as TranslateOptions['formality'];\n }\n if (id) {\n options.id = id;\n }\n return options;\n}\n\n/**\n * Reads the values in `data-v`, a JSON object such as `{\"name\": \"Bob\"}`.\n * Returns `null` if the attribute is not valid, so the text is left as it is\n * rather than translated with `$name` in it.\n */\nfunction variablesOf(element: Element): Variables | undefined | null {\n const json = element.getAttribute('data-v');\n if (json === null) {\n return undefined;\n }\n try {\n const variables: unknown = JSON.parse(json);\n if (\n variables &&\n typeof variables === 'object' &&\n !Array.isArray(variables)\n ) {\n return variables as Variables;\n }\n } catch {\n // reported below\n }\n console.warn(\n `[${libraryName}]: data-v must be a JSON object, such as data-v='{\"name\": \"Bob\"}', but is ${json}`\n );\n return null;\n}\n\nfunction fillHtml(html: string, values: readonly string[]): string {\n if (values.length === 0) {\n return html;\n }\n const container = document.createElement('template');\n container.innerHTML = html;\n fillElement(container.content, values);\n return container.innerHTML;\n}\n\nexport class MagicTranslate {\n private currentLanguage: Languages;\n private dataLoader: DataLoader<DataLoaderLoadParams, string, string>;\n private readonly root?: Element;\n private readonly contents = new Map<Element, Translation>();\n private readonly attributes = new Map<Element, Map<string, Translation>>();\n private readonly listeners = new Set<(language: Languages) => void>();\n private observer?: MutationObserver;\n\n constructor(private readonly options: MagicTranslateOptions) {\n if (!options.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n\n this.currentLanguage =\n options.language ??\n utsLocaleToLanguage(\n typeof navigator === 'undefined' ? undefined : navigator.language\n );\n this.dataLoader = this.createDataLoader();\n\n if (typeof document !== 'undefined') {\n this.root = options.root ?? document.documentElement;\n this.start(this.root);\n }\n }\n\n /**\n * The language content is currently translated to.\n */\n get language(): Languages {\n return this.currentLanguage;\n }\n\n /**\n * Translates the page to another language.\n */\n setLanguage(language: Languages): void {\n if (language === this.currentLanguage) {\n return;\n }\n\n this.currentLanguage = language;\n this.dataLoader = this.createDataLoader();\n\n this.forget(\n (element) => !element.isConnected || !this.root?.contains(element)\n );\n this.contents.forEach((_, element) => this.translateContent(element, true));\n this.attributes.forEach((_, element) =>\n this.translateAttributes(element, true)\n );\n this.listeners.forEach((listener) => listener(language));\n }\n\n /**\n * Calls `listener` whenever the language changes. Returns a function that\n * removes the listener again.\n */\n onLanguageChange(listener: (language: Languages) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Translates a string to the current language.\n */\n translate(\n text: string,\n { v, ...params }: TranslateParams = {}\n ): Promise<string> {\n if (!v) {\n return this.dataLoader.load({ text, ...params });\n }\n const { template, values, unused } = toTemplate(text, v);\n warnAboutUnused(unused);\n return this.dataLoader\n .load({ text: template, ...params })\n .then((translation) => fillPlaceholders(translation, values));\n }\n\n /**\n * Stops translating the page. Content that is already translated stays\n * translated.\n */\n destroy(): void {\n this.observer?.disconnect();\n this.contents.clear();\n this.attributes.clear();\n this.listeners.clear();\n }\n\n private createDataLoader() {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.options;\n const loaderFactory = this.options._loaderFactory ?? defaultLoaderFactory;\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: this.currentLanguage,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n {\n cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, this.currentLanguage),\n }\n );\n }\n\n private start(root: Element) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n this.collect(root, contents, attributes);\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n\n // Picks up content that is added or changed later.\n this.observer = new MutationObserver((records) =>\n this.handleMutations(records)\n );\n this.observer.observe(root, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private collect(\n root: Element,\n contents: Set<Element>,\n attributes: Set<Element>\n ) {\n const all = [root, ...Array.from(root.querySelectorAll('*'))];\n for (const element of all) {\n if (element.matches(CONTENT_SELECTOR)) {\n contents.add(outermost(element));\n } else if (\n element.matches(ATTRIBUTES_SELECTOR) &&\n !element.closest(CONTENT_SELECTOR)\n ) {\n attributes.add(element);\n }\n }\n }\n\n private handleMutations(records: MutationRecord[]) {\n const contents = new Set<Element>();\n const attributes = new Set<Element>();\n\n for (const record of records) {\n const target =\n record.target.nodeType === Node.ELEMENT_NODE\n ? (record.target as Element)\n : record.target.parentElement;\n if (!target) {\n continue;\n }\n\n const content = target.closest(CONTENT_SELECTOR);\n if (content) {\n contents.add(outermost(content));\n continue;\n }\n\n if (record.type === 'attributes' && target.matches(ATTRIBUTES_SELECTOR)) {\n attributes.add(target);\n }\n record.addedNodes.forEach((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.collect(node as Element, contents, attributes);\n }\n });\n }\n\n if (records.some((record) => record.removedNodes.length > 0)) {\n this.forget((element) => !element.isConnected);\n }\n contents.forEach((element) => this.translateContent(element));\n attributes.forEach((element) => this.translateAttributes(element));\n }\n\n private forget(predicate: (element: Element) => boolean) {\n for (const element of this.contents.keys()) {\n if (predicate(element)) {\n this.contents.delete(element);\n }\n }\n for (const element of this.attributes.keys()) {\n if (predicate(element)) {\n this.attributes.delete(element);\n }\n }\n }\n\n private translateContent(element: Element, force = false) {\n const html = element.innerHTML;\n const variablesJson = element.getAttribute('data-v');\n let translation = this.contents.get(element);\n if (!translation) {\n translation = { source: html, requestId: 0, variables: variablesJson };\n this.contents.set(element, translation);\n } else if (html !== translation.rendered && html !== translation.source) {\n // changed by someone else, e.g. the page's own scripts\n translation.source = html;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n // only the values changed, so the cached translation is reused\n translation.variables = variablesJson;\n } else if (!force) {\n return;\n }\n\n const [, leadingWhitespace, text, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(\n translation.source.replace(/<!--[\\s\\S]*?-->/g, '')\n )!;\n if (!text) {\n return;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n return;\n }\n const { template, values, unused } = variables\n ? toHtmlTemplate(text, variables)\n : { template: text, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = `${leadingWhitespace}${fillHtml(translated, values)}${trailingWhitespace}`;\n if (element.innerHTML !== rendered) {\n element.innerHTML = rendered;\n }\n current.rendered = element.innerHTML;\n };\n // Until the first translation arrives, show the values instead of `$name`.\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++current.requestId;\n this.translate(template, optionsOf(element)).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n\n private translateAttributes(element: Element, force = false) {\n const names = (element.getAttribute('data-t-attrs') ?? '')\n .split(/[\\s,]+/)\n .filter(Boolean);\n const variablesJson = element.getAttribute('data-v');\n let translations = this.attributes.get(element);\n if (!translations) {\n translations = new Map();\n this.attributes.set(element, translations);\n }\n\n for (const name of names) {\n const value = element.getAttribute(name);\n if (!value?.trim()) {\n continue;\n }\n\n let translation = translations.get(name);\n if (!translation) {\n translation = { source: value, requestId: 0, variables: variablesJson };\n translations.set(name, translation);\n } else if (\n value !== translation.rendered &&\n value !== translation.source\n ) {\n translation.source = value;\n translation.rendered = undefined;\n translation.variables = variablesJson;\n } else if (variablesJson !== translation.variables) {\n translation.variables = variablesJson;\n } else if (!force) {\n continue;\n }\n\n const variables = variablesOf(element);\n if (variables === null) {\n continue;\n }\n const { template, values, unused } = variables\n ? toTemplate(translation.source, variables)\n : { template: translation.source, values: [], unused: [] };\n if (template !== translation.template) {\n translation.template = template;\n warnAboutUnused(unused);\n }\n\n const current = translation;\n const show = (translated: string) => {\n const rendered = fillPlaceholders(translated, values);\n current.rendered = rendered;\n if (element.getAttribute(name) !== rendered) {\n element.setAttribute(name, rendered);\n }\n };\n if (variables && current.rendered === undefined) {\n show(template);\n }\n\n const requestId = ++current.requestId;\n // An id stands for one text, and an element's attributes are several.\n const { id: _id, ...options } = optionsOf(element);\n this.translate(template, options).then((translated) => {\n if (requestId !== current.requestId || !element.isConnected) {\n return;\n }\n show(translated);\n });\n }\n }\n}\n\n/**\n * Starts translating the page: the content of every `<t>` element (or element\n * with a `data-t` attribute), and the attributes listed in `data-t-attrs`.\n * Content added later is translated as well.\n */\nexport function createMagicTranslate(\n options: MagicTranslateOptions\n): MagicTranslate {\n return new MagicTranslate(options);\n}\n","import {\n createMagicTranslate,\n Languages,\n MagicTranslate,\n TranslateParams,\n} from './magic-translate';\n\nexport * from './index';\n\ndeclare global {\n interface Window {\n magicTranslate?: MagicTranslate;\n }\n}\n\nconst STORAGE_KEY = 'magic-translate-language';\n\nfunction storedLanguage(): Languages | undefined {\n try {\n return (localStorage.getItem(STORAGE_KEY) as Languages | null) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n// `<script src=\".../magic-translate.min.js\" data-api-key=\"...\"></script>`\n// starts translating the page without any further code.\nconst script = document.currentScript as HTMLScriptElement | null;\nconst apiKey = script?.dataset.apiKey;\n\nif (script && apiKey) {\n const { language, sourceLanguage, formality } = script.dataset;\n\n const start = () => {\n const magicTranslate = createMagicTranslate({\n apiKey,\n // a language picked with the language switcher outlives page loads\n language: storedLanguage() ?? (language as Languages | undefined),\n sourceLanguage: sourceLanguage as Languages | undefined,\n formality: formality as TranslateParams['formality'],\n debug: script.hasAttribute('data-debug'),\n });\n magicTranslate.onLanguageChange((language) => {\n try {\n localStorage.setItem(STORAGE_KEY, language);\n } catch {\n // storage is unavailable, e.g. in some private windows\n }\n });\n window.magicTranslate = magicTranslate;\n document.dispatchEvent(\n new CustomEvent('magictranslate:ready', { detail: magicTranslate })\n );\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', start);\n } else {\n start();\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magic-translate/js",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "keywords": [
5
5
  "javascript",
6
6
  "vanilla-js",
@@ -48,7 +48,7 @@
48
48
  "node": ">=22.22.1"
49
49
  },
50
50
  "dependencies": {
51
- "@magic-translate/core": "^1.4.2"
51
+ "@magic-translate/core": "^1.6.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^26.6.5",