web-internationalization 2.0.42 → 2.0.43
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/index.d.ts +4 -3
- package/index.js +267 -1
- package/package.json +16 -19
- package/type.d.ts +1 -1
package/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { HTMLItem,
|
|
2
|
-
import { WebComponentAPI } from 'web-component-wrapper/type';
|
|
1
|
+
import type { HTMLItem, Mapping } from 'clientnode';
|
|
2
|
+
import type { WebComponentAPI } from 'web-component-wrapper/type';
|
|
3
|
+
import type { DefaultOptions, Options, Replacement } from './type';
|
|
4
|
+
import { Lock, Logger } from 'clientnode';
|
|
3
5
|
import { Web } from 'web-component-wrapper/Web';
|
|
4
|
-
import { DefaultOptions, Options, Replacement } from './type';
|
|
5
6
|
export declare const log: Logger;
|
|
6
7
|
/**
|
|
7
8
|
* This plugin holds all necessary methods to extend a website for
|
package/index.js
CHANGED
|
@@ -1 +1,267 @@
|
|
|
1
|
-
"use strict";if("undefined"!=typeof module&&null!==module&&"undefined"!==eval("typeof require")&&null!==eval("require")&&"main"in eval("require")&&"undefined"!==eval("typeof require.main")&&null!==eval("require.main")){var ORIGINAL_MAIN_MODULE=module;module!==eval("require.main")&&"paths"in module&&"paths"in eval("require.main")&&"undefined"!=typeof __dirname&&null!==__dirname&&(module.paths=eval("require.main.paths").concat(module.paths.filter((function(path){return eval("require.main.paths").includes(path)}))))}if(null==window)var window="undefined"==typeof global||null===global?{}:global;!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("@babel/runtime/helpers/initializerDefineProperty"),require("@babel/runtime/helpers/applyDecoratedDescriptor"),require("@babel/runtime/helpers/initializerWarningHelper"),require("clientnode"),require("clientnode/property-types"),require("web-component-wrapper/decorator"),require("web-component-wrapper/Web"));else if("function"==typeof define&&define.amd)define(["@babel/runtime/helpers/initializerDefineProperty","@babel/runtime/helpers/applyDecoratedDescriptor","@babel/runtime/helpers/initializerWarningHelper","clientnode","clientnode/property-types","web-component-wrapper/decorator","web-component-wrapper/Web"],t);else{var o="object"==typeof exports?t(require("@babel/runtime/helpers/initializerDefineProperty"),require("@babel/runtime/helpers/applyDecoratedDescriptor"),require("@babel/runtime/helpers/initializerWarningHelper"),require("clientnode"),require("clientnode/property-types"),require("web-component-wrapper/decorator"),require("web-component-wrapper/Web")):t(e["@babel/runtime/helpers/initializerDefineProperty"],e["@babel/runtime/helpers/applyDecoratedDescriptor"],e["@babel/runtime/helpers/initializerWarningHelper"],e.clientnode,e["clientnode/property-types"],e["web-component-wrapper/decorator"],e["web-component-wrapper/Web"]);for(var n in o)("object"==typeof exports?exports:e)[n]=o[n]}}(this,((e,t,o,n,i,a,r)=>(()=>{var s=[,t=>{t.exports=e},e=>{e.exports=t},e=>{e.exports=o},e=>{e.exports=n},e=>{e.exports=i},e=>{e.exports=a},e=>{e.exports=r}],l={};function c(e){var t=l[e];if(void 0!==t)return t.exports;var o=l[e]={exports:{}};return s[e](o,o.exports,c),o.exports}c.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return c.d(t,{a:t}),t},c.d=(e,t)=>{for(var o in t)c.o(t,o)&&!c.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var p={};c.r(p),c.d(p,{WebInternationalization:()=>k,api:()=>E,default:()=>R,log:()=>O});var u,d,h,m,g,f,N,b,w,T,_,x,D=c(1),y=c.n(D),L=c(2),C=c.n(L),v=(c(3),c(4)),A=c(5),P=c(6),S=c(7);const O=new v.Logger({name:"web-internationalization"});let k=(u=(0,P.property)({type:A.object}),d=(0,P.property)({type:A.func}),h=(0,P.property)({type:A.func}),m=(0,P.property)({type:A.func}),g=(0,P.property)({type:A.func}),x=class e extends S.Web{constructor(){super(),this.self=e,y()(this,"options",N,this),y()(this,"onEnsure",b,this),y()(this,"onSwitch",w,this),y()(this,"onEnsured",T,this),y()(this,"onSwitched",_,this),this.switchLanguageButtonDomNodes=null,this.currentLanguage="enUS",this.knownTranslations={},this.lock=new v.Lock,this._domNodesToFade=[],this._replacements=[],this._domNodesWithKnownTranslation={},this.defineGetterAndSetterInterface()}async onUpdateAttribute(e,t){await super.onUpdateAttribute(e,t),"options"===e&&this._extendOptions()}async render(e="unknown",t=!0){await super.render(e,!1),0===Object.keys(this.options).length&&this._extendOptions(),this.options.preReplacementLanguagePattern=(0,v.format)(this.options.preReplacementLanguagePattern,this.options.replacementLanguagePattern.substring(1,this.options.replacementLanguagePattern.length-1)),this.options.lockDescription=(0,v.format)(this.options.lockDescription,this.self._name),this.options.sessionDescription=(0,v.format)(this.options.sessionDescription,this.self._name),await this.waitForNestedComponentRendering(),this.switchLanguageButtonDomNodes=this.hostDomNode.querySelectorAll(`a[href^="#${this.options.languageHashPrefix}"]`),this._movePreReplacementNodes(),this.currentLanguage=this._normalizeLanguage(this.options.default);const o=this._determineUsefulLanguage(),n=0===this.options.selection.length;for(const e of this.switchLanguageButtonDomNodes){n&&this.options.selection.push(e.getAttribute("href").substring(`#${this.options.languageHashPrefix}`.length));const t=e=>{e.preventDefault();const t=e.target?.getAttribute("href");t&&this.switch(t.substring(this.options.languageHashPrefix.length+1))};this.addSecureEventListener(e,"click",t)}this.currentLanguage===o?await this.refresh():await this.switch(o,!0),await this.resolveRenderingPromiseIfSet(e,t)}async switch(e,t=!1){if(!0===e||!this.options.selection.length||this.options.selection.includes(e)){if(await this.lock.acquire(this.options.lockDescription),!0===e?(t=!0,e=this.currentLanguage):e=this._normalizeLanguage(e),t||this.currentLanguage!==e){let o="Switch to";return t&&(o="Ensure"),O.debug(`${o} "${e}".`),this._switchCurrentLanguageIndicator(e),t?await this.onEnsure(e):await this.onSwitch(this.currentLanguage,e),this._domNodesToFade=[],this._replacements=[],this._collectDomNodesToReplace(e,t),void await this._handleSwitchEffect(e,t)}O.debug(`"${e}" is already current selected language.`),this.lock.release(this.options.lockDescription)}else O.debug(`"${e}" isn't one of the allowed languages.`)}refresh(){return this._movePreReplacementNodes(),this.switch(!0)}_extendOptions(){this.setPropertyValue("options",(0,v.extend)(!0,{},this.self._defaultOptions,this.options))}async _handleSwitchEffect(e,t){const o=this.currentLanguage;if(!t&&this.options.useEffect&&this._domNodesToFade.length>0)return await Promise.all(this._domNodesToFade.map((e=>{const t=(0,v.fadeOut)(e);return t.then((()=>{t.resetStyles()}))}))),this._switchLanguage(e),await Promise.all(this._domNodesToFade.map((e=>{const t=(0,v.fadeIn)(e);return t.then((()=>{t.resetStyles()}))}))),this.onSwitched(o,e),void this.lock.release(this.options.lockDescription);this._switchLanguage(e),t?this.onEnsured(e):this.onSwitched(o,e),this.lock.release(this.options.lockDescription)}_movePreReplacementNodes(){for(const e of(0,v.getAll)(this.hostDomNode)){const t=e.nodeName.toLowerCase();if(this.options.replacementDomNodeNames.includes(t)){["#comment","#text"].includes(t)||e.classList.add(this.options.selectors.hideClassName);const o=new RegExp(this.options.preReplacementLanguagePattern),n=e.textContent?.match(o);if(e.textContent&&n&&n[0]&&(e.textContent=e.textContent.replace(o,n[1]),e.parentElement)){let t=!1;for(const o of(0,v.getAll)(e.parentElement)){if(t&&(0,v.getText)(o,!0).length>0){o.appendChild(e);break}e===o&&(t=!0)}}}}}_collectDomNodesToReplace(e,t){let o=null,n=null;this.knownTranslations={};for(const i of(0,v.getAll)(this.hostDomNode)){const a=i.nodeName.toLowerCase(),r=(0,v.getText)(i,!0);if(!this._shouldSkipDomNode(i,r,o))if(this.options.replaceDomNodeNames.includes(a))o=i;else if(this.options.alternativeDomNodeNames.includes(a))i.hasAttribute("lang")?i.getAttribute("lang")===e&&this._processAlternativeDomNode(i,e,t,n):this._initializeCurrentLanguageDomNode(i,t);else if(o){if(this.options.replacementDomNodeNames.includes(a)){({domNodeToTranslate:o,languageDomNode:n}=this._processReplacementDomNode(i,a,e,t,o,n));continue}o=null,n=null}}this._registerKnownTextNodes()}_shouldSkipDomNode(e,t,o){return 0===t.length&&(e.nodeType!==Node.COMMENT_NODE||""===(e.nodeValue||"").trim())||Boolean(o?.contains(e))||Boolean((0,v.closest)(e,this.options.replaceDomNodeNames.concat(this.options.replacementDomNodeNames).join(","),!0))}_processAlternativeDomNode(e,t,o,n){let i=null;for(const t of e.parentElement.querySelectorAll(this.options.alternativeDomNodeNames.join(",")))if(t.hasAttribute("active")||!t.hasAttribute("lang")){i=t;break}i&&(this._initializeCurrentLanguageDomNode(i,o),this._registerTextNodeToChange(i,e,e.innerHTML,n))}_initializeCurrentLanguageDomNode(e,t){e.hasAttribute("active")||e.setAttribute("active",""),e.hasAttribute("lang")||e.setAttribute("lang",t&&this.options.default||this.currentLanguage)}_processReplacementDomNode(e,t,o,n,i,a){const r=("#comment"===t?e.textContent:e.innerHTML).match(new RegExp(this.options.replacementLanguagePattern));return Array.isArray(r)&&r[1]===o?(this.knownTranslations[(0,v.getText)(i,!0).join(" ")]=r[2].trim(),a=this._ensureLastTextNodeHavingLanguageIndicator(i,a,n),this._registerTextNodeToChange(i,e,r[2],a),{domNodeToTranslate:null,languageDomNode:null}):(e.textContent.match(new RegExp(this.options.currentLanguagePattern))&&(a=e),{domNodeToTranslate:i,languageDomNode:a})}_registerKnownTextNodes(){this._domNodesWithKnownTranslation={};for(const e of this.hostDomNode.querySelectorAll(this.options.selectors.knownTranslation))for(const t of(0,v.getAll)(e)){const e=(0,v.getText)(t).join(" ");e&&!this.options.replaceDomNodeNames.includes(t.nodeName.toLowerCase())&&!(0,v.closest)(t,this.options.replaceDomNodeNames.join(","),!0)&&Object.prototype.hasOwnProperty.call(this.knownTranslations,e)&&(this._domNodesToFade.push(t.parentElement),Object.prototype.hasOwnProperty.call(this._domNodesWithKnownTranslation,this.knownTranslations[e])?this._domNodesWithKnownTranslation[this.knownTranslations[e]].push(t):this._domNodesWithKnownTranslation[this.knownTranslations[e]]=[t])}}_normalizeLanguage(e){for(const[t,o]of Object.entries(this.options.languageMapping))if(o.includes(t.toLowerCase())||o.push(t.toLowerCase()),o.includes(e.toLowerCase()))return t;return this.options.default}_determineUsefulLanguage(){let e;return this.options.initial?e=this.options.initial:Object.prototype.hasOwnProperty.call(v.globalContext,"window")&&(v.globalContext.window?.localStorage.getItem(this.options.sessionDescription)?(e=v.globalContext.window.localStorage.getItem(this.options.sessionDescription),O.debug(`Determine "${e}", because of local storage`,"information.")):v.globalContext.window?.navigator.language&&(e=v.globalContext.window.navigator.language,O.debug(`Determine "${e}", because of browser settings.`))),e||(e=this.options.default,O.debug(`Determine "${e}", because of default option.`)),e=this._normalizeLanguage(e),this.options.selection.length&&!this.options.selection.includes(e)&&(O.debug(`"${e}" isn't one of the allowed languages. Set`,`language to "${this.options.selection[0]}".`),e=this.options.selection[0]),v.globalContext.window?.localStorage&&v.globalContext.window.localStorage.setItem(this.options.sessionDescription,e),e}_registerTextNodeToChange(e,t,o,n){this._domNodesToFade.push(e.parentElement),t&&this._replacements.push({domNodeToTranslate:e,domNodeToReplaceWith:t,textToReplaceWith:o,currentLanguageDomNode:n})}_ensureLastTextNodeHavingLanguageIndicator(e,t,o){if(e&&!t){let n=this.currentLanguage;o&&(n=this.options.default||this.currentLanguage),(t=v.globalContext.document?.createComment(n)||null)&&e.after(t)}return t}_switchLanguage(e){for(const t of this._replacements){const o=this._getCurrentNodeText(t.domNodeToTranslate),n=o.trim();if(!this.options.templateDelimiter||!n.endsWith(this.options.templateDelimiter.post)&&this.options.templateDelimiter.post){const n=this._resolveCurrentLanguageDomNode(t),i=n.textContent;i&&e===i&&O.warn(`Text node "${t.textToReplaceWith}" is`,`marked as "${i}" and has same`,"translation language as it already is.");const a=t.domNodeToReplaceWith.nodeName.toLowerCase();if(this.options.alternativeDomNodeNames.includes(a)){t.domNodeToReplaceWith.setAttribute("active",""),t.domNodeToTranslate.removeAttribute("active");continue}const r=this._createBackupNode(a,i,o,t.domNodeToTranslate);t.domNodeToTranslate.after(r),t.domNodeToTranslate.after(v.globalContext.document.createComment(e)),this._applyTextReplacement(t),n.remove(),t.domNodeToReplaceWith.remove()}}this._updateKnownTextNodes(),v.globalContext.localStorage&&v.globalContext.localStorage.setItem(this.options.sessionDescription,e),this.currentLanguage=e}_getCurrentNodeText(e){return"innerHTML"in e?e.innerHTML:e.textContent}_resolveCurrentLanguageDomNode(e){if(e.currentLanguageDomNode)return e.currentLanguageDomNode;let t=document.body,o=!1;for(const n of(0,v.getAll)(e.domNodeToTranslate.parentElement)){if(o){e.currentLanguageDomNode=t=n;break}n===e.domNodeToTranslate&&(o=!0)}return t}_createBackupNode(e,t,o,n){if("#comment"===e)return v.globalContext.document.createComment(`${t}:${o}`);const i=v.globalContext.document.createElement(e);i.appendChild(v.globalContext.document.createTextNode(`${t}:`)),i.classList.add(this.options.selectors.hideClassName);for(const e of Array.from(n.childNodes))i.appendChild(e);return i}_applyTextReplacement(e){if("innerHTML"in e.domNodeToTranslate)if("#comment"===e.domNodeToReplaceWith.nodeName.toLowerCase())e.domNodeToTranslate.innerHTML=e.textToReplaceWith;else{let t=!1;for(const o of Array.from(e.domNodeToReplaceWith.childNodes))t||(o.textContent=o.textContent.replace(/^[a-z]{2}[A-Z]{2}:/,""),t=!0),e.domNodeToTranslate.appendChild(o)}else e.domNodeToTranslate.textContent=e.textToReplaceWith}_updateKnownTextNodes(){for(const[e,t]of Object.entries(this._domNodesWithKnownTranslation))for(const o of t)o.textContent=e}_switchCurrentLanguageIndicator(e){for(const e of this.hostDomNode.querySelectorAll(`a[href="#${this.options.languageHashPrefix}${this.currentLanguage}"].`+this.options.currentLanguageIndicatorClassName))e.classList.remove(this.options.currentLanguageIndicatorClassName);for(const t of this.hostDomNode.querySelectorAll(`a[href="#${this.options.languageHashPrefix}${e}"]`))t.classList.add(this.options.currentLanguageIndicatorClassName)}},x._name="WebInternationalization",x._defaultOptions={currentLanguageIndicatorClassName:"current",currentLanguagePattern:"^[a-z]{2}[A-Z]{2}$",default:"enUS",useEffect:!0,initial:null,languageHashPrefix:"lang-",languageMapping:{deDE:["de","de_de","de-de","german","deutsch"],enUS:["en","en_us","en-us"],enEN:["en_en","en-en","english"],frFR:["fr","fr_fr","fr-fr","french"]},lockDescription:"{1}Switch",preReplacementLanguagePattern:"^\\|({1})$",alternativeDomNodeNames:["lang-alternative"],replaceDomNodeNames:["#text","lang-replace"],replacementDomNodeNames:["#comment","lang-replacement"],replacementLanguagePattern:"^([a-z]{2}[A-Z]{2}):((.|\\s)*)$",selection:[],selectors:{knownTranslation:".web-internationalization-generated-content",hideClassName:"wi-hide"},sessionDescription:"{1}",templateDelimiter:{pre:"{{",post:"}}"}},f=x,N=C()(f.prototype,"options",[u],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return{}}}),b=C()(f.prototype,"onEnsure",[d],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return v.NOOP}}),w=C()(f.prototype,"onSwitch",[h],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return v.NOOP}}),T=C()(f.prototype,"onEnsured",[m],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return v.NOOP}}),_=C()(f.prototype,"onSwitched",[g],{configurable:!0,enumerable:!0,writable:!0,initializer:function(){return v.NOOP}}),f);const E={component:k,register:(e=(0,v.camelCaseToDelimited)(k._name))=>{customElements.define(e,k)}},R=k;return v.globalContext.AUTO_DEFINE_WEB_INTERNATIONALIZATION&&E.register(),p})()));
|
|
1
|
+
if(typeof window==='undefined'||window===null)var window=(typeof global==='undefined'||global===null)?{}:global;import { Lock as __WEBPACK_EXTERNAL_MODULE_clientnode_Lock__, Logger as __WEBPACK_EXTERNAL_MODULE_clientnode_Logger__, NOOP as __WEBPACK_EXTERNAL_MODULE_clientnode_NOOP__, camelCaseToDelimited as __WEBPACK_EXTERNAL_MODULE_clientnode_camelCaseToDelimited__, closest as __WEBPACK_EXTERNAL_MODULE_clientnode_closest__, extend as __WEBPACK_EXTERNAL_MODULE_clientnode_extend__, fadeIn as __WEBPACK_EXTERNAL_MODULE_clientnode_fadeIn__, fadeOut as __WEBPACK_EXTERNAL_MODULE_clientnode_fadeOut__, format as __WEBPACK_EXTERNAL_MODULE_clientnode_format__, getAll as __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__, getText as __WEBPACK_EXTERNAL_MODULE_clientnode_getText__, globalContext as __WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__ } from "clientnode";
|
|
2
|
+
import { func as __WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_func__, object as __WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_object__ } from "clientnode/property-types";
|
|
3
|
+
import { property as __WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__ } from "web-component-wrapper/decorator";
|
|
4
|
+
import { Web as __WEBPACK_EXTERNAL_MODULE_web_component_wrapper_Web_aacc6608_Web__ } from "web-component-wrapper/Web";
|
|
5
|
+
|
|
6
|
+
;// external "clientnode"
|
|
7
|
+
|
|
8
|
+
;// external "clientnode/property-types"
|
|
9
|
+
|
|
10
|
+
;// external "web-component-wrapper/decorator"
|
|
11
|
+
|
|
12
|
+
;// external "web-component-wrapper/Web"
|
|
13
|
+
|
|
14
|
+
;// ./index.ts
|
|
15
|
+
// #!/usr/bin/env babel-node
|
|
16
|
+
// -*- coding: utf-8 -*-
|
|
17
|
+
/** @module web-internationalization *//* !
|
|
18
|
+
region header
|
|
19
|
+
[Project page](https://torben.website/web-internationalization)
|
|
20
|
+
|
|
21
|
+
Copyright Torben Sickert (info["~at~"]torben.website) 16.12.2012
|
|
22
|
+
|
|
23
|
+
License
|
|
24
|
+
-------
|
|
25
|
+
|
|
26
|
+
This library written by Torben Sickert stands under a creative commons
|
|
27
|
+
naming 3.0 unported license.
|
|
28
|
+
See https://creativecommons.org/licenses/by/3.0/deed.de
|
|
29
|
+
endregion
|
|
30
|
+
*/// region imports
|
|
31
|
+
var _dec,_dec2,_dec3,_dec4,_dec5,_class,_descriptor,_descriptor2,_descriptor3,_descriptor4,_descriptor5,_WebInternationalization;function _initializerDefineProperty(e,i,r,l){r&&Object.defineProperty(e,i,{enumerable:r.enumerable,configurable:r.configurable,writable:r.writable,value:r.initializer?r.initializer.call(l):void 0})}function _defineProperty(e,r,t){return(r=_toPropertyKey(r))in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function _toPropertyKey(t){var i=_toPrimitive(t,"string");return"symbol"==typeof i?i:i+""}function _toPrimitive(t,r){if("object"!=typeof t||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,r||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===r?String:Number)(t)}function _applyDecoratedDescriptor(i,e,r,n,l){var a={};return Object.keys(n).forEach(function(i){a[i]=n[i]}),a.enumerable=!!a.enumerable,a.configurable=!!a.configurable,("value"in a||a.initializer)&&(a.writable=!0),a=r.slice().reverse().reduce(function(r,n){return n(i,e,r)||r},a),l&&void 0!==a.initializer&&(a.value=a.initializer?a.initializer.call(l):void 0,a.initializer=void 0),void 0===a.initializer?(Object.defineProperty(i,e,a),null):a}function _initializerWarningHelper(r,e){throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform.")};// endregion
|
|
32
|
+
const log=new __WEBPACK_EXTERNAL_MODULE_clientnode_Logger__({name:"web-internationalization"});// region plugins/classes
|
|
33
|
+
/**
|
|
34
|
+
* This plugin holds all necessary methods to extend a website for
|
|
35
|
+
* internationalization.
|
|
36
|
+
* @property _defaultOptions - Options extended by the options given to the
|
|
37
|
+
* initializer method.
|
|
38
|
+
* @property _defaultOptions.currentLanguageIndicatorClassName - Class name
|
|
39
|
+
* which marks current language switcher button or link.
|
|
40
|
+
* @property _defaultOptions.currentLanguagePattern - Saves a pattern to
|
|
41
|
+
* recognize current language marker.
|
|
42
|
+
* @property _defaultOptions.default - Initial language to use.
|
|
43
|
+
* @property _defaultOptions.useEffect - Indicates whether a fade effect
|
|
44
|
+
* should be performed.
|
|
45
|
+
* @property _defaultOptions.initial - Initial set language (if omitted it will
|
|
46
|
+
* be determined based on environment information).
|
|
47
|
+
* @property _defaultOptions.languageHashPrefix - Hash prefix to determine
|
|
48
|
+
* current active language by url.
|
|
49
|
+
* @property _defaultOptions.languageMapping - A mapping of alternate language
|
|
50
|
+
* descriptions.
|
|
51
|
+
* @property _defaultOptions.lockDescription - Lock description.
|
|
52
|
+
* @property _defaultOptions.preReplacementLanguagePattern - Pattern to
|
|
53
|
+
* introduce a pre-replacement language node.
|
|
54
|
+
* @property _defaultOptions.replaceDomNodeNames - Tag names which indicates
|
|
55
|
+
* dom nodes which should be replaced.
|
|
56
|
+
* @property _defaultOptions.replacementDomNodeNames - Dom node tag name which
|
|
57
|
+
* should be interpreted as a hidden alternate language node (contains text in
|
|
58
|
+
* another language).
|
|
59
|
+
* @property _defaultOptions.replacementLanguagePattern - Text pattern to
|
|
60
|
+
* introduce a post-replacement node.
|
|
61
|
+
* @property _defaultOptions.selection - List of all supported languages.
|
|
62
|
+
* @property _defaultOptions.selectors - Mapping of necessary dom node
|
|
63
|
+
* selectors.
|
|
64
|
+
* @property _defaultOptions.selectors.knownTranslation - Selector to find
|
|
65
|
+
* known translation sections.
|
|
66
|
+
* @property _defaultOptions.sessionDescription - Description to save current
|
|
67
|
+
* language in session storage.
|
|
68
|
+
* @property _defaultOptions.templateDelimiter - Template delimiter to
|
|
69
|
+
* recognize dynamic content.
|
|
70
|
+
* @property _defaultOptions.templateDelimiter.pre - Delimiter that introduces
|
|
71
|
+
* a dynamic expression.
|
|
72
|
+
* @property _defaultOptions.templateDelimiter.post - Delimiter which finishes
|
|
73
|
+
* a dynamic expression.
|
|
74
|
+
* @property options - Finally configured given options.
|
|
75
|
+
* @property currentLanguage - Saves the current language.
|
|
76
|
+
* @property knownTranslations - Saves a mapping of known language strings and
|
|
77
|
+
* their corresponding translations, to boost language replacements or saves
|
|
78
|
+
* redundant replacements in a dom tree.
|
|
79
|
+
* @property lock - Lock instance when updating dom noes.
|
|
80
|
+
* @property _domNodesToFade - Saves all dom nodes that should be animated.
|
|
81
|
+
* @property _replacements - Saves all text nodes that should be replaced.
|
|
82
|
+
* @property _domNodesWithKnownTranslation - Saves a mapping of known text
|
|
83
|
+
* snippets to their corresponding $-extended dom nodes.
|
|
84
|
+
*/let WebInternationalization=(_dec=__WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__({type:__WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_object__}),_dec2=__WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__({type:__WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_func__}),_dec3=__WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__({type:__WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_func__}),_dec4=__WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__({type:__WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_func__}),_dec5=__WEBPACK_EXTERNAL_MODULE_web_component_wrapper_decorator_a680de5c_property__({type:__WEBPACK_EXTERNAL_MODULE_clientnode_property_types_4789ebe2_func__}),_class=(_WebInternationalization=class WebInternationalization extends __WEBPACK_EXTERNAL_MODULE_web_component_wrapper_Web_aacc6608_Web__{// region public methods
|
|
85
|
+
/// region live-cycle
|
|
86
|
+
/**
|
|
87
|
+
* Defines dynamic getter and setter interface and resolves a configuration
|
|
88
|
+
* object. Initializes the map implementation.
|
|
89
|
+
*/constructor(){super();/*
|
|
90
|
+
Babel property declaration transformation overwrites defined
|
|
91
|
+
properties at the end of an implicit constructor. So we have to
|
|
92
|
+
redefine them as long as we want to declare expected component
|
|
93
|
+
interface properties to enable static type checks.
|
|
94
|
+
*/_defineProperty(this,"self",WebInternationalization);// region api properties
|
|
95
|
+
_initializerDefineProperty(this,"options",_descriptor,this);_initializerDefineProperty(this,"onEnsure",_descriptor2,this);_initializerDefineProperty(this,"onSwitch",_descriptor3,this);_initializerDefineProperty(this,"onEnsured",_descriptor4,this);_initializerDefineProperty(this,"onSwitched",_descriptor5,this);// endregion
|
|
96
|
+
_defineProperty(this,"switchLanguageButtonDomNodes",null);_defineProperty(this,"currentLanguage","enUS");_defineProperty(this,"knownTranslations",{});_defineProperty(this,"lock",new __WEBPACK_EXTERNAL_MODULE_clientnode_Lock__);_defineProperty(this,"_domNodesToFade",[]);_defineProperty(this,"_replacements",[]);_defineProperty(this,"_domNodesWithKnownTranslation",{});this.defineGetterAndSetterInterface()}/**
|
|
97
|
+
* Triggered when ever a given attribute has changed and triggers to update
|
|
98
|
+
* configured dom content.
|
|
99
|
+
* @param name - Attribute name which was updates.
|
|
100
|
+
* @param newValue - New updated value.
|
|
101
|
+
* @returns Returns when attribute has been updated.
|
|
102
|
+
*/async onUpdateAttribute(name,newValue){await super.onUpdateAttribute(name,newValue);if(name==="options")this._extendOptions()}/**
|
|
103
|
+
* Updates controlled dom elements.
|
|
104
|
+
* @param reason - Why an update has been triggered.
|
|
105
|
+
* @param resolveRendering - Indicates whether rendering should be resolved
|
|
106
|
+
* finally. Should be set to "false" via super calls in inherited render
|
|
107
|
+
* methods which do further dom manipulations afterward and resolve the
|
|
108
|
+
* rendering process by their own.
|
|
109
|
+
* @returns A promise resolving when rendering has finished. A promise may
|
|
110
|
+
* be needed for classes inheriting from this class.
|
|
111
|
+
*/async render(reason="unknown",resolveRendering=true){await super.render(reason,false);if(Object.keys(this.options).length===0)this._extendOptions();this.options.preReplacementLanguagePattern=__WEBPACK_EXTERNAL_MODULE_clientnode_format__(this.options.preReplacementLanguagePattern,this.options.replacementLanguagePattern.substring(1,this.options.replacementLanguagePattern.length-1));this.options.lockDescription=__WEBPACK_EXTERNAL_MODULE_clientnode_format__(this.options.lockDescription,this.self._name);this.options.sessionDescription=__WEBPACK_EXTERNAL_MODULE_clientnode_format__(this.options.sessionDescription,this.self._name);await this.waitForNestedComponentRendering();this.switchLanguageButtonDomNodes=this.hostDomNode.querySelectorAll(`a[href^="#${this.options.languageHashPrefix}"]`);this._movePreReplacementNodes();this.currentLanguage=this._normalizeLanguage(this.options.default);/*
|
|
112
|
+
NOTE: Only switch current language indicator if we haven't an
|
|
113
|
+
initial language switch which will perform the indicator switch.
|
|
114
|
+
*/const newLanguage=this._determineUsefulLanguage();const determineSelection=this.options.selection.length===0;for(const domNode of this.switchLanguageButtonDomNodes){if(determineSelection)this.options.selection.push(domNode.getAttribute("href").substring(`#${this.options.languageHashPrefix}`.length));const handler=event=>{event.preventDefault();const url=event.target?.getAttribute("href");if(url)void this.switch(url.substring(this.options.languageHashPrefix.length+1))};this.addSecureEventListener(domNode,"click",handler)}if(this.currentLanguage===newLanguage)await this.refresh();else await this.switch(newLanguage,true);await this.resolveRenderingPromiseIfSet(reason,resolveRendering)}/// endregion
|
|
115
|
+
/**
|
|
116
|
+
* Switches the current language to a given language. This method is
|
|
117
|
+
* mutually synchronized.
|
|
118
|
+
* @param language - New language as string or "true". If set to "true" it
|
|
119
|
+
* indicates that the dom tree should be checked again current language to
|
|
120
|
+
* ensure every text node has the right content.
|
|
121
|
+
* @param ensure - Indicates if a switch effect should be avoided.
|
|
122
|
+
* @returns Returns the current instance wrapped in a promise.
|
|
123
|
+
*/async switch(language,ensure=false){if(language!==true&&this.options.selection.length&&!this.options.selection.includes(language)){log.debug(`"${language}" isn't one of the allowed languages.`);return}await this.lock.acquire(this.options.lockDescription);if(language===true){ensure=true;language=this.currentLanguage}else language=this._normalizeLanguage(language);if(ensure||this.currentLanguage!==language){let actionDescription="Switch to";if(ensure)actionDescription="Ensure";log.debug(`${actionDescription} "${language}".`);this._switchCurrentLanguageIndicator(language);if(ensure)await this.onEnsure(language);else await this.onSwitch(this.currentLanguage,language);this._domNodesToFade=[];this._replacements=[];this._collectDomNodesToReplace(language,ensure);await this._handleSwitchEffect(language,ensure);return}log.debug(`"${language}" is already current selected language.`);void this.lock.release(this.options.lockDescription)}/**
|
|
124
|
+
* Ensures current selected language.
|
|
125
|
+
* @returns Promise resolving to nothing when switching as finished.
|
|
126
|
+
*/refresh(){this._movePreReplacementNodes();return this.switch(true)}/// endregion
|
|
127
|
+
// region protected methods
|
|
128
|
+
/**
|
|
129
|
+
* Extends given options by default options.
|
|
130
|
+
*/_extendOptions(){/*
|
|
131
|
+
NOTE: Using the internal setter avoids triggering an additional
|
|
132
|
+
rendering.
|
|
133
|
+
*/this.setPropertyValue("options",__WEBPACK_EXTERNAL_MODULE_clientnode_extend__(true,{},this.self._defaultOptions,this.options))}/**
|
|
134
|
+
* Depending on activated switching effect this method initialized the
|
|
135
|
+
* effect of replace all text string directly.
|
|
136
|
+
* @param language - New language to use.
|
|
137
|
+
* @param ensure - Indicates if current language should be ensured again
|
|
138
|
+
* every text node content.
|
|
139
|
+
* @returns Returns the current instance wrapped in a promise.
|
|
140
|
+
*/async _handleSwitchEffect(language,ensure){const oldLanguage=this.currentLanguage;if(!ensure&&this.options.useEffect&&this._domNodesToFade.length>0){await Promise.all(this._domNodesToFade.map(domNode=>{const handler=__WEBPACK_EXTERNAL_MODULE_clientnode_fadeOut__(domNode);return handler.then(()=>{handler.resetStyles()})}));this._switchLanguage(language);await Promise.all(this._domNodesToFade.map(domNode=>{const handler=__WEBPACK_EXTERNAL_MODULE_clientnode_fadeIn__(domNode);return handler.then(()=>{handler.resetStyles()})}));this.onSwitched(oldLanguage,language);void this.lock.release(this.options.lockDescription);return}this._switchLanguage(language);if(ensure)this.onEnsured(language);else this.onSwitched(oldLanguage,language);void this.lock.release(this.options.lockDescription)}/**
|
|
141
|
+
* Moves pre-replacement dom nodes into the next dom node behind the
|
|
142
|
+
* translation text to use the same translation algorithm for both.
|
|
143
|
+
*/_movePreReplacementNodes(){for(const domNode of __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__(this.hostDomNode)){const nodeName=domNode.nodeName.toLowerCase();if(this.options.replacementDomNodeNames.includes(nodeName)){if(!["#comment","#text"].includes(nodeName))// NOTE: Hide replacement dom nodes.
|
|
144
|
+
domNode.classList.add(this.options.selectors.hideClassName);const regularExpression=new RegExp(this.options.preReplacementLanguagePattern);const match=domNode.textContent?.match(regularExpression);if(domNode.textContent&&match&&match[0]){domNode.textContent=domNode.textContent.replace(regularExpression,match[1]);if(domNode.parentElement){let selfFound=false;for(const subDomNode of __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__(domNode.parentElement)){if(selfFound&&__WEBPACK_EXTERNAL_MODULE_clientnode_getText__(subDomNode,true).length>0){subDomNode.appendChild(domNode);break}if(domNode===subDomNode)selfFound=true}}}}}}/**
|
|
145
|
+
* Collects all text nodes that should be replaced later.
|
|
146
|
+
* @param language - New language to use.
|
|
147
|
+
* @param ensure - Indicates if the whole dom should be checked again
|
|
148
|
+
* current language to ensure every text node has right content.
|
|
149
|
+
*/_collectDomNodesToReplace(language,ensure){let currentDomNodeToTranslate=null;let currentLanguageDomNode=null;this.knownTranslations={};for(const domNode of __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__(this.hostDomNode)){const nodeName=domNode.nodeName.toLowerCase();const nodeTextContent=__WEBPACK_EXTERNAL_MODULE_clientnode_getText__(domNode,true);// NOTE: We skip empty and nested nodes.
|
|
150
|
+
if(this._shouldSkipDomNode(domNode,nodeTextContent,currentDomNodeToTranslate))continue;if(this.options.replaceDomNodeNames.includes(nodeName))currentDomNodeToTranslate=domNode;else if(this.options.alternativeDomNodeNames.includes(nodeName)){if(!domNode.hasAttribute("lang"))this._initializeCurrentLanguageDomNode(domNode,ensure);else if(domNode.getAttribute("lang")===language)this._processAlternativeDomNode(domNode,language,ensure,currentLanguageDomNode)}else if(currentDomNodeToTranslate){if(this.options.replacementDomNodeNames.includes(nodeName)){;({domNodeToTranslate:currentDomNodeToTranslate,languageDomNode:currentLanguageDomNode}=this._processReplacementDomNode(domNode,nodeName,language,ensure,currentDomNodeToTranslate,currentLanguageDomNode));continue}currentDomNodeToTranslate=null;currentLanguageDomNode=null}}this._registerKnownTextNodes()}/**
|
|
151
|
+
* Determines whether a given dom node should be skipped during
|
|
152
|
+
* translation collection.
|
|
153
|
+
* @param domNode - The dom node to evaluate.
|
|
154
|
+
* @param nodeTextContent - Pre-computed text content of the node.
|
|
155
|
+
* @param currentDomNodeToTranslate - The currently tracked translation
|
|
156
|
+
* ancestor node.
|
|
157
|
+
* @returns Returns true if the node should be skipped.
|
|
158
|
+
*/_shouldSkipDomNode(domNode,nodeTextContent,currentDomNodeToTranslate){return nodeTextContent.length===0&&(domNode.nodeType!==Node.COMMENT_NODE||(domNode.nodeValue||"").trim()==="")||Boolean(currentDomNodeToTranslate?.contains(domNode))||Boolean(__WEBPACK_EXTERNAL_MODULE_clientnode_closest__(domNode,this.options.replaceDomNodeNames.concat(this.options.replacementDomNodeNames).join(","),true))}/**
|
|
159
|
+
* Processes an alternative dom node by finding its active sibling,
|
|
160
|
+
* ensuring it has the necessary attributes and registering it for
|
|
161
|
+
* replacement.
|
|
162
|
+
* @param domNode - The alternative language dom node.
|
|
163
|
+
* @param language - New language to use.
|
|
164
|
+
* @param ensure - Indicates if current language should be ensured again
|
|
165
|
+
* every text node content.
|
|
166
|
+
* @param currentLanguageDomNode - The currently tracked language indicator
|
|
167
|
+
* node.
|
|
168
|
+
*/_processAlternativeDomNode(domNode,language,ensure,currentLanguageDomNode){/*
|
|
169
|
+
When dealing with alternative dom nodes we do not rely on dom node
|
|
170
|
+
positions to keep them stable. Therefore, we identify the current
|
|
171
|
+
dom node to translate by going through all siblings.
|
|
172
|
+
*/let activeSibling=null;for(const candidate of domNode.parentElement.querySelectorAll(this.options.alternativeDomNodeNames.join(",")))if(candidate.hasAttribute("active")||!candidate.hasAttribute("lang")){activeSibling=candidate;break}if(!activeSibling)return;this._initializeCurrentLanguageDomNode(activeSibling,ensure);this._registerTextNodeToChange(activeSibling,domNode,domNode.innerHTML,currentLanguageDomNode)}_initializeCurrentLanguageDomNode(domNode,ensure){if(!domNode.hasAttribute("active"))domNode.setAttribute("active","");if(!domNode.hasAttribute("lang"))domNode.setAttribute("lang",ensure?this.options.default||this.currentLanguage:this.currentLanguage)}/**
|
|
173
|
+
* Processes a replacement dom node like comment or lang-replacement
|
|
174
|
+
* element and updates translation state accordingly.
|
|
175
|
+
* @param domNode - The replacement dom node.
|
|
176
|
+
* @param nodeName - Lowercase node name of the replacement node.
|
|
177
|
+
* @param language - New language to use.
|
|
178
|
+
* @param ensure - Indicates if current language should be ensured again
|
|
179
|
+
* every text node content.
|
|
180
|
+
* @param currentDomNodeToTranslate - The currently tracked node whose
|
|
181
|
+
* content is to be replaced.
|
|
182
|
+
* @param currentLanguageDomNode - The currently tracked language indicator
|
|
183
|
+
* node.
|
|
184
|
+
* @returns Updated references for the tracked translation and language
|
|
185
|
+
* indicator nodes.
|
|
186
|
+
*/_processReplacementDomNode(domNode,nodeName,language,ensure,currentDomNodeToTranslate,currentLanguageDomNode){const content=nodeName==="#comment"?domNode.textContent:domNode.innerHTML;const match=content.match(new RegExp(this.options.replacementLanguagePattern));if(Array.isArray(match)&&match[1]===language){// Save known text translations.
|
|
187
|
+
this.knownTranslations[__WEBPACK_EXTERNAL_MODULE_clientnode_getText__(currentDomNodeToTranslate,true).join(" ")]=match[2].trim();currentLanguageDomNode=this._ensureLastTextNodeHavingLanguageIndicator(currentDomNodeToTranslate,currentLanguageDomNode,ensure);this._registerTextNodeToChange(currentDomNodeToTranslate,domNode,match[2],currentLanguageDomNode);return{domNodeToTranslate:null,languageDomNode:null}}if(domNode.textContent.match(new RegExp(this.options.currentLanguagePattern)))currentLanguageDomNode=domNode;return{domNodeToTranslate:currentDomNodeToTranslate,languageDomNode:currentLanguageDomNode}}/**
|
|
188
|
+
* Iterates all text nodes in language known area with known translations.
|
|
189
|
+
*/_registerKnownTextNodes(){this._domNodesWithKnownTranslation={};for(const domNode of this.hostDomNode.querySelectorAll(this.options.selectors.knownTranslation))for(const node of __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__(domNode)){const content=__WEBPACK_EXTERNAL_MODULE_clientnode_getText__(node).join(" ");// NOTE: We skip empty and nested text nodes.
|
|
190
|
+
if(content&&!this.options.replaceDomNodeNames.includes(node.nodeName.toLowerCase())&&!__WEBPACK_EXTERNAL_MODULE_clientnode_closest__(node,this.options.replaceDomNodeNames.join(","),true)&&Object.prototype.hasOwnProperty.call(this.knownTranslations,content)){this._domNodesToFade.push(node.parentElement);if(Object.prototype.hasOwnProperty.call(this._domNodesWithKnownTranslation,this.knownTranslations[content]))this._domNodesWithKnownTranslation[this.knownTranslations[content]].push(node);else this._domNodesWithKnownTranslation[this.knownTranslations[content]]=[node]}}}/**
|
|
191
|
+
* Normalizes a given language string.
|
|
192
|
+
* @param language - New language to use.
|
|
193
|
+
* @returns Returns the normalized version of given language.
|
|
194
|
+
*/_normalizeLanguage(language){for(const[otherLanguage,aliases]of Object.entries(this.options.languageMapping)){if(!aliases.includes(otherLanguage.toLowerCase()))aliases.push(otherLanguage.toLowerCase());if(aliases.includes(language.toLowerCase()))return otherLanguage}return this.options.default}/**
|
|
195
|
+
* Determines a useful initial language depending on session and browser
|
|
196
|
+
* settings.
|
|
197
|
+
* @returns Returns the determined language.
|
|
198
|
+
*/_determineUsefulLanguage(){let result;if(this.options.initial)result=this.options.initial;else if(Object.prototype.hasOwnProperty.call(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__,"window"))if(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window?.localStorage.getItem(this.options.sessionDescription)){result=__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window.localStorage.getItem(this.options.sessionDescription);log.debug(`Determine "${result}", because of local storage`,"information.")}else if(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window?.navigator.language){result=__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window.navigator.language;log.debug(`Determine "${result}", because of browser settings.`)}if(!result){result=this.options.default;log.debug(`Determine "${result}", because of default option.`)}result=this._normalizeLanguage(result);if(this.options.selection.length&&!this.options.selection.includes(result)){log.debug(`"${result}" isn't one of the allowed languages. Set`,`language to "${this.options.selection[0]}".`);result=this.options.selection[0]}if(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window?.localStorage)__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.window.localStorage.setItem(this.options.sessionDescription,result);return result}/**
|
|
199
|
+
* Registers a text node to change its content with a given replacement.
|
|
200
|
+
* @param domNodeToTranslate - Text node with content to
|
|
201
|
+
* translate.
|
|
202
|
+
* @param domNodeToReplaceWith - A node with replacement content.
|
|
203
|
+
* @param textToReplaceWith - Text content to use as replacement.
|
|
204
|
+
* @param currentLanguageDomNode - A potential given text node indicating
|
|
205
|
+
* the language of given text node.
|
|
206
|
+
*/_registerTextNodeToChange(domNodeToTranslate,domNodeToReplaceWith,textToReplaceWith,currentLanguageDomNode){this._domNodesToFade.push(domNodeToTranslate.parentElement);if(domNodeToReplaceWith)this._replacements.push({domNodeToTranslate,domNodeToReplaceWith,textToReplaceWith,currentLanguageDomNode})}/**
|
|
207
|
+
* Checks if the last text node has a language indication comment node.
|
|
208
|
+
* This function is called after each parsed dom text node.
|
|
209
|
+
* @param lastTextNodeToTranslate - Last text node to check.
|
|
210
|
+
* @param lastLanguageDomNode - A potential given language indication
|
|
211
|
+
* commend node.
|
|
212
|
+
* @param ensure - Indicates if current language should be ensured again
|
|
213
|
+
* every text node content.
|
|
214
|
+
* @returns Returns the retrieved or newly created language indicating
|
|
215
|
+
* comment node.
|
|
216
|
+
*/_ensureLastTextNodeHavingLanguageIndicator(lastTextNodeToTranslate,lastLanguageDomNode,ensure){if(lastTextNodeToTranslate&&!lastLanguageDomNode){/*
|
|
217
|
+
Last text node doesn't have a current language indicating dom
|
|
218
|
+
node.
|
|
219
|
+
*/let currentLocalLanguage=this.currentLanguage;if(ensure)currentLocalLanguage=this.options.default||this.currentLanguage;lastLanguageDomNode=__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.document?.createComment(currentLocalLanguage)||null;if(lastLanguageDomNode)lastTextNodeToTranslate.after(lastLanguageDomNode)}return lastLanguageDomNode}/**
|
|
220
|
+
* Performs the low-level text replacements for switching to a given
|
|
221
|
+
* language.
|
|
222
|
+
* @param language - The new language to switch to.
|
|
223
|
+
*/_switchLanguage(language){for(const replacement of this._replacements){const currentText=this._getCurrentNodeText(replacement.domNodeToTranslate);const trimmedText=currentText.trim();if(!this.options.templateDelimiter||!trimmedText.endsWith(this.options.templateDelimiter.post)&&this.options.templateDelimiter.post){const currentLanguageDomNode=this._resolveCurrentLanguageDomNode(replacement);const currentLanguage=currentLanguageDomNode.textContent;if(currentLanguage&&language===currentLanguage)log.warn(`Text node "${replacement.textToReplaceWith}" is`,`marked as "${currentLanguage}" and has same`,"translation language as it already is.");// Move markup to be replaced next its parent node.
|
|
224
|
+
const nodeName=replacement.domNodeToReplaceWith.nodeName.toLowerCase();if(this.options.alternativeDomNodeNames.includes(nodeName)){;replacement.domNodeToReplaceWith.setAttribute("active","");replacement.domNodeToTranslate.removeAttribute("active");continue}const newNode=this._createBackupNode(nodeName,currentLanguage,currentText,replacement.domNodeToTranslate);replacement.domNodeToTranslate.after(newNode);replacement.domNodeToTranslate.after(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.document.createComment(language));this._applyTextReplacement(replacement);currentLanguageDomNode.remove();replacement.domNodeToReplaceWith.remove()}}this._updateKnownTextNodes();if(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.localStorage)__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.localStorage.setItem(this.options.sessionDescription,language);this.currentLanguage=language}/**
|
|
225
|
+
* Returns the current text content of a dom node, preferring innerHTML
|
|
226
|
+
* over textContent when available.
|
|
227
|
+
* @param domNode - The dom node to read the text content from.
|
|
228
|
+
* @returns The current text content of the dom node.
|
|
229
|
+
*/_getCurrentNodeText(domNode){return"innerHTML"in domNode?domNode.innerHTML:domNode.textContent}/**
|
|
230
|
+
* Resolves the current language dom node for a given replacement. If the
|
|
231
|
+
* node was not set initially it is determined by iterating through the
|
|
232
|
+
* siblings and cached on the replacement object.
|
|
233
|
+
* @param replacement - The replacement whose language dom node should be
|
|
234
|
+
* resolved.
|
|
235
|
+
* @returns The resolved language indicator dom node or null.
|
|
236
|
+
*/_resolveCurrentLanguageDomNode(replacement){if(replacement.currentLanguageDomNode)return replacement.currentLanguageDomNode;/*
|
|
237
|
+
Language dom node wasn't present initially. So we have to
|
|
238
|
+
determine it now.
|
|
239
|
+
*/let currentLanguageDomNode=document.body;let currentDomNodeFound=false;for(const domNode of __WEBPACK_EXTERNAL_MODULE_clientnode_getAll__(replacement.domNodeToTranslate.parentElement)){if(currentDomNodeFound){replacement.currentLanguageDomNode=currentLanguageDomNode=domNode;break}if(domNode===replacement.domNodeToTranslate)currentDomNodeFound=true}return currentLanguageDomNode}/**
|
|
240
|
+
* Creates a backup node for the current dom node content before the
|
|
241
|
+
* replacement is applied. Returns either a comment node or an element
|
|
242
|
+
* node depending on `nodeName`.
|
|
243
|
+
* @param nodeName - Lowercase node name of the replacement node.
|
|
244
|
+
* @param currentLanguage - Current language string used as prefix.
|
|
245
|
+
* @param currentText - Text content of the node to back up.
|
|
246
|
+
* @param domNodeToTranslate - The dom node whose children are moved into
|
|
247
|
+
* the backup element (for non-comment nodes).
|
|
248
|
+
* @returns The created backup node.
|
|
249
|
+
*/_createBackupNode(nodeName,currentLanguage,currentText,domNodeToTranslate){if(nodeName==="#comment")return __WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.document.createComment(`${currentLanguage}:${currentText}`);const newNode=__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.document.createElement(nodeName);newNode.appendChild(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.document.createTextNode(`${currentLanguage}:`));newNode.classList.add(this.options.selectors.hideClassName);// NOTE: We need to use "Array.from" to copy the list.
|
|
250
|
+
for(const childNode of Array.from(domNodeToTranslate.childNodes))newNode.appendChild(childNode);return newNode}/**
|
|
251
|
+
* Applies the actual text replacement to the target dom node. Moves
|
|
252
|
+
* child nodes from the replacement node or sets innerHTML/textContent
|
|
253
|
+
* directly depending on the node type.
|
|
254
|
+
* @param replacement - Replacement object containing source, target and
|
|
255
|
+
* replacement text information.
|
|
256
|
+
*/_applyTextReplacement(replacement){if("innerHTML"in replacement.domNodeToTranslate){if(replacement.domNodeToReplaceWith.nodeName.toLowerCase()==="#comment")replacement.domNodeToTranslate.innerHTML=replacement.textToReplaceWith;else{let languageRemoved=false;// NOTE: We need to use "Array.from" to copy the list.
|
|
257
|
+
for(const childNode of Array.from(replacement.domNodeToReplaceWith.childNodes)){if(!languageRemoved){childNode.textContent=childNode.textContent.replace(/^[a-z]{2}[A-Z]{2}:/,"");languageRemoved=true}replacement.domNodeToTranslate.appendChild(childNode)}}}else replacement.domNodeToTranslate.textContent=replacement.textToReplaceWith}/**
|
|
258
|
+
* Updates all dom nodes that have a known translation to their translated
|
|
259
|
+
* text content.
|
|
260
|
+
*/_updateKnownTextNodes(){for(const[content,domNodes]of Object.entries(this._domNodesWithKnownTranslation))for(const domNode of domNodes)domNode.textContent=content}/**
|
|
261
|
+
* Switches the current language indicator in language switch triggered dom
|
|
262
|
+
* nodes.
|
|
263
|
+
* @param language - The new language to switch to.
|
|
264
|
+
*/_switchCurrentLanguageIndicator(language){for(const domNode of this.hostDomNode.querySelectorAll(`a[href="#${this.options.languageHashPrefix}`+`${this.currentLanguage}"].`+this.options.currentLanguageIndicatorClassName))domNode.classList.remove(this.options.currentLanguageIndicatorClassName);for(const domNode of this.hostDomNode.querySelectorAll(`a[href="#${this.options.languageHashPrefix}${language}"]`))domNode.classList.add(this.options.currentLanguageIndicatorClassName)}// endregion
|
|
265
|
+
},_defineProperty(_WebInternationalization,"_name","WebInternationalization"),_defineProperty(_WebInternationalization,"_defaultOptions",{currentLanguageIndicatorClassName:"current",currentLanguagePattern:"^[a-z]{2}[A-Z]{2}$",default:"enUS",useEffect:true,initial:null,languageHashPrefix:"lang-",languageMapping:{deDE:["de","de_de","de-de","german","deutsch"],enUS:["en","en_us","en-us"],enEN:["en_en","en-en","english"],frFR:["fr","fr_fr","fr-fr","french"]},lockDescription:"{1}Switch",preReplacementLanguagePattern:"^\\|({1})$",alternativeDomNodeNames:["lang-alternative"],replaceDomNodeNames:["#text","lang-replace"],replacementDomNodeNames:["#comment","lang-replacement"],replacementLanguagePattern:"^([a-z]{2}[A-Z]{2}):((.|\\s)*)$",selection:[],selectors:{knownTranslation:".web-internationalization-generated-content",hideClassName:"wi-hide"},sessionDescription:"{1}",templateDelimiter:{pre:"{{",post:"}}"}}),_WebInternationalization),_descriptor=_applyDecoratedDescriptor(_class.prototype,"options",[_dec],{configurable:true,enumerable:true,writable:true,initializer:function(){return{}}}),_descriptor2=_applyDecoratedDescriptor(_class.prototype,"onEnsure",[_dec2],{configurable:true,enumerable:true,writable:true,initializer:function(){return __WEBPACK_EXTERNAL_MODULE_clientnode_NOOP__}}),_descriptor3=_applyDecoratedDescriptor(_class.prototype,"onSwitch",[_dec3],{configurable:true,enumerable:true,writable:true,initializer:function(){return __WEBPACK_EXTERNAL_MODULE_clientnode_NOOP__}}),_descriptor4=_applyDecoratedDescriptor(_class.prototype,"onEnsured",[_dec4],{configurable:true,enumerable:true,writable:true,initializer:function(){return __WEBPACK_EXTERNAL_MODULE_clientnode_NOOP__}}),_descriptor5=_applyDecoratedDescriptor(_class.prototype,"onSwitched",[_dec5],{configurable:true,enumerable:true,writable:true,initializer:function(){return __WEBPACK_EXTERNAL_MODULE_clientnode_NOOP__}}),_class);// endregion
|
|
266
|
+
const api={component:WebInternationalization,register:(tagName=__WEBPACK_EXTERNAL_MODULE_clientnode_camelCaseToDelimited__(WebInternationalization._name))=>{customElements.define(tagName,WebInternationalization)}};/* harmony default export */ const index = (WebInternationalization);if(__WEBPACK_EXTERNAL_MODULE_clientnode_globalContext__.AUTO_DEFINE_WEB_INTERNATIONALIZATION)api.register();
|
|
267
|
+
export { WebInternationalization, api, index as default, log };
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.0.
|
|
2
|
+
"version": "2.0.43",
|
|
3
3
|
"name": "web-internationalization",
|
|
4
4
|
"description": "Expand your audience",
|
|
5
5
|
"keywords": [
|
|
@@ -49,34 +49,34 @@
|
|
|
49
49
|
"watch": "weboptimizer build --watch"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@babel/eslint-parser": "^
|
|
53
|
-
"@babel/plugin-transform-proto-to-assign": "^
|
|
54
|
-
"@babel/runtime": "^
|
|
52
|
+
"@babel/eslint-parser": "^8.0.1",
|
|
53
|
+
"@babel/plugin-transform-proto-to-assign": "^8.0.1",
|
|
54
|
+
"@babel/runtime": "^8.0.0",
|
|
55
55
|
"@eslint/js": "^10.0.1",
|
|
56
56
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
57
57
|
"@types/ejs": "^3.1.5",
|
|
58
58
|
"@types/html-minifier": "^4.0.6",
|
|
59
59
|
"@types/imagemin": "^9.0.1",
|
|
60
60
|
"@types/jsdom": "^28.0.3",
|
|
61
|
-
"@types/node": "^
|
|
61
|
+
"@types/node": "^26.1.1",
|
|
62
62
|
"@types/webpack-env": "^1.18.8",
|
|
63
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
64
|
-
"@typescript-eslint/parser": "^8.
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
|
64
|
+
"@typescript-eslint/parser": "^8.65.0",
|
|
65
65
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
|
66
|
-
"clientnode": "^4.0.
|
|
67
|
-
"eslint": "^10.
|
|
66
|
+
"clientnode": "^4.0.1469",
|
|
67
|
+
"eslint": "^10.7.0",
|
|
68
68
|
"eslint-config-google": "^0.14.0",
|
|
69
|
-
"eslint-plugin-jsdoc": "^63.
|
|
69
|
+
"eslint-plugin-jsdoc": "^63.2.2",
|
|
70
70
|
"favicons-webpack-plugin": "^6.0.1",
|
|
71
71
|
"image-minimizer-webpack-plugin": "^5.0.0",
|
|
72
72
|
"jest": "^30.4.2",
|
|
73
73
|
"jsdoc": "^4.0.5",
|
|
74
74
|
"prop-types": "^15.8.1",
|
|
75
|
-
"typescript-eslint": "^8.
|
|
76
|
-
"web-component-wrapper": "^0.0.
|
|
77
|
-
"web-documentation": "^1.0.
|
|
78
|
-
"weboptimizer": "^
|
|
79
|
-
"webpack-dev-server": "^
|
|
75
|
+
"typescript-eslint": "^8.65.0",
|
|
76
|
+
"web-component-wrapper": "^0.0.605",
|
|
77
|
+
"web-documentation": "^1.0.42",
|
|
78
|
+
"weboptimizer": "^4.0.36",
|
|
79
|
+
"webpack-dev-server": "^6.0.0"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"@babel/runtime": "*",
|
|
@@ -101,6 +101,7 @@
|
|
|
101
101
|
"globals@npm:^9.18.0": "patch:globals@npm%3A11.12.0#~/.yarn/patches/globals-npm-11.12.0-1fa7f41a6c.patch"
|
|
102
102
|
},
|
|
103
103
|
"sideEffects": false,
|
|
104
|
+
"type": "module",
|
|
104
105
|
"webDocumentation": {
|
|
105
106
|
"languages": [
|
|
106
107
|
"deDE",
|
|
@@ -134,10 +135,6 @@
|
|
|
134
135
|
}
|
|
135
136
|
},
|
|
136
137
|
"optimizer": {
|
|
137
|
-
"babelMinify": {
|
|
138
|
-
"#": "Avoids TypeError: Cannot read properties of undefined (reading 'add')",
|
|
139
|
-
"module": null
|
|
140
|
-
},
|
|
141
138
|
"htmlMinifier": {
|
|
142
139
|
"ignoreCustomComments": [
|
|
143
140
|
{
|
package/type.d.ts
CHANGED