mi-intl 0.6.3 → 0.6.6

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
@@ -3,7 +3,7 @@
3
3
 
4
4
  # mi-intl
5
5
 
6
- Formats strings using [ICU Message Syntax][icu-syntax] for [mi-element][].
6
+ > Formats strings using [ICU Message Syntax][icu-syntax] for [mi-element][].
7
7
 
8
8
  **Table of contents**
9
9
 
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- import{cached as s}from"intl-messageformat-tiny";import{MiElement as t,ContextProvider as e,ContextConsumer as n}from"mi-element";function o(s=""){const t=s.split(/\s*;\s*/),e={};for(const s of t){const[t,n]=s.split("=");if(t){const s=decodeURIComponent(n);e[t]=s}}return e}const a=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function i(s,t,e){const{maxAge:n,domain:o,path:i,expires:g,httpOnly:r=!1,secure:l=!1,sameSite:u="Strict"}=e||{};if(!s||!a.test(s))throw TypeError("invalid name");const c=[`${s}=${encodeURIComponent(t)}`];return!isNaN(n-0)&&isFinite(n)&&c.push(`Max-Age=${n}`),o&&a.test(o)&&c.push(`Domain=${o}`),i&&a.test(i)&&c.push(`Path=${i}`),isNaN(new Date(g).getTime())||c.push(`Expires=${new Date(g).toUTCString()}`),r&&c.push("HttpOnly"),l&&c.push("Secure"),u&&c.push(`SameSite=${u}`),c.join("; ")}const g=s(),r=globalThis?.navigator?.language&&globalThis?.document,l="translations",u={supportedLngs:[],version:"",ns:[l],defaultNs:l,localesPath:"/locales/{lng}/{ns}.json?v={version}",useLabel:!1,debug:!1,cookie:{name:"lc",path:"/"}};let c={debug:(...s)=>{},error:(...s)=>{}};const h=s=>[...new Set(s.filter(Boolean))],d=s=>(s||"").split("-",1)[0];class p{constructor(s){const{supportedLngs:t,lng:e,defaultNs:n,fallbackLng:o=t[0],resources:a={},debug:i,...g}={...u,...s};if(!t?.length)throw new Error("no supportedLngs");this.options=g,this.defaultNs=n,this.fallbackLng=o,this.lng=e||this.fallbackLng,this.supportedLngs=t,this.userLng=e,this.resources=a,i&&(c=g.log||console),this.t=this.t.bind(this),this.getLanguages=this.getLanguages.bind(this),this._setLanguage()}t(s,t={}){const{lng:e,fallbackLng:n,defaultNs:o}=this,{lng:a=e,ns:i=o,...r}=t,l=this.resources[a]?.[i]?.[s]||this.resources[n]?.[i]?.[s]||(this.options.useLabel?s:"");return g(l,r,a)}getUserLanguage(){if(!r)return this.fallbackLng;const[s,t]=this._getSettings();return c.debug("getUserLanguage: cookieLng:%s browserLng:%s",s,t),s||t}resetUserLanguage(){if(!r)return;const{name:s,...t}=this.options.cookie;c.debug("reset cookie"),document.cookie=i(s,"",{...t,expires:0}),this._setLanguage()}_getSettings(){const{name:s}=this.options.cookie,t=o(document.cookie)[s],e=globalThis?.navigator?.language;return console.log(document.cookie,t,e),[t,e]}_setCookie(){if(!r)return;const[s,t]=this._getSettings(),{userLng:e=""}=this;if(s===e)return;let n,o=e;[t,d(t)].includes(e)&&(n=0,o="");const{name:a,...g}=this.options.cookie;c.debug("_setCookie: %s:%s",0===n?"reset":"set",e),document.cookie=i(a,o,{...g,expires:n})}_setLanguage(s){const t=s||this.getUserLanguage(),{supportedLngs:e}=this,n=((s,t,e=[])=>h([s,...e].filter(Boolean).reduce((s,t)=>(s.push(t,d(t)),s),[])).reduce((s,e)=>(t.includes(e)&&s.push(e),s),[]))(t,e,globalThis?.navigator?.languages||[]);if(n.length)this.userLng=t,this.lng=n[0];else{this.userLng=this.lng=this.fallbackLng;const[s]=this.lng.split("-");n.push(...h([this.lng,s]))}return this._setCookie(),n}getLanguages(){return this.supportedLngs}async changeLanguage(s){const t=this._setLanguage(s);c.debug("changeLanguage: lng:%s variants:%s",s,t),await this.loadLanguages(t);let e=this.fallbackLng;for(const s of t)if(this.resources[s]?.[this.defaultNs]){e=s;break}c.debug("changeLanguage: loadedLng:%s",e);const n=d(e);if(d(s||t[0])!==n){const s=t.find(s=>d(s)===n);this._setLanguage(s||e)}this._setCookie()}async changeNamespace(s){this.defaultNs=s,await this.loadLanguages([this.lng,this.fallbackLng])}async loadLanguages(s=[],t=[]){const e=h(s),n=h([...t,this.defaultNs]);if(!e.length||!n.length)return c.error("can't load without languages or namespaces"),[];const o=[];for(const s of e)for(const t of n)this.resources[s]?.[t]||o.push(this._load({lng:s,ns:t}).catch(s=>c.error(s)));return await Promise.all(o)}async _load({lng:s,ns:t}){const{version:e}=this.options,n=g(this.options.localesPath,{lng:s,ns:t,version:e}),o=await fetch(n).catch(s=>c.error(s));this.resources[s]=this.resources[s]||{};const{ok:a=!1,status:i=-1}=o||{};if(a&&o){c.debug("_load: lng=%s ns=%s",s,t);const e=await o.json();this.resources[s][t]=e}else c.error("_load: error loading url=%s",n);return{ok:a,status:i,lng:s,ns:t}}}const L="mi-intl",f=()=>new Promise(s=>requestAnimationFrame(s));class m extends t{static get attributes(){return{version:"",lng:String,defaultNs:"translations",ns:"translations",supportedLngs:"",localesPath:"/locales/{lng}/{ns}.json?v={version}",useLabel:Boolean,debug:!1}}static get properties(){return{loading:!1}}static template="<slot></slot>";set options(s){this.i18n=new p(s),this.changeLanguage(s?.lng).catch(console.error)}_contextValue(){const{t:s,lng:t,getLanguages:e}=this.i18n??{t:()=>"",lng:"",getLanguages:()=>[]};return{t:s,lng:t,getLanguages:e,changeLanguage:this.changeLanguage.bind(this),loading:this.loading??!1}}async changeLanguage(s){this.loading=!0,await(this.i18n?.changeLanguage(s).finally(()=>{this.requestUpdate()})),await f(),await f(),this.loading=!1}render(){const s=this.supportedLngs.split(","),t=this.ns.split(",");this.i18n=new p({...this,supportedLngs:s,ns:t}),this.provider=new e(this,L,this._contextValue()),this.changeLanguage(this.lng).catch(console.error)}update(){this.provider?.set(this._contextValue())}}class b extends n{constructor(s,t=!0){super(s,L,{subscribe:t})}}class k extends t{#s;constructor(){super(),this.#s=new b(this)}t(s,t){return this.#s.value.t(s,t)}}export{p as I18n,L as INTL_CONTEXT,b as IntlConsumer,k as MiIntlMessage,m as MiIntlProvider,o as cookieParse,i as cookieSerialize};
1
+ import{cached as s}from"intl-messageformat-tiny";import{MiElement as t,ContextProvider as e,ContextConsumer as n}from"mi-element";function o(s=""){const t=s.split(/\s*;\s*/),e={};for(const s of t){const[t,n]=s.split("=");if(t){const s=decodeURIComponent(n);e[t]=s}}return e}const a=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function i(s,t,e){const{maxAge:n,domain:o,path:i,expires:g,httpOnly:r=!1,secure:l=!1,sameSite:u="Strict"}=e||{};if(!s||!a.test(s))throw TypeError("invalid name");const c=[`${s}=${encodeURIComponent(t)}`];return!isNaN(n-0)&&isFinite(n)&&c.push(`Max-Age=${n}`),o&&a.test(o)&&c.push(`Domain=${o}`),i&&a.test(i)&&c.push(`Path=${i}`),isNaN(new Date(g).getTime())||c.push(`Expires=${new Date(g).toUTCString()}`),r&&c.push("HttpOnly"),l&&c.push("Secure"),u&&c.push(`SameSite=${u}`),c.join("; ")}const g=s(),r=globalThis?.navigator?.language&&globalThis?.document,l="translations",u={supportedLngs:[],version:"",ns:[l],defaultNs:l,localesPath:"/locales/{lng}/{ns}.json?v={version}",useLabel:!1,debug:!1,cookie:{name:"lc",path:"/"}};let c={debug:(...s)=>{},error:(...s)=>{}};const h=s=>[...new Set(s.filter(Boolean))],d=s=>(s||"").split("-",1)[0];class p{constructor(s){const{supportedLngs:t,lng:e,defaultNs:n,fallbackLng:o=t[0],resources:a={},debug:i,...g}={...u,...s};if(!t?.length)throw new Error("no supportedLngs");this.options=g,this.defaultNs=n,this.fallbackLng=o,this.lng=e||this.fallbackLng,this.supportedLngs=t,this.userLng=e,this.resources=a,i&&(c=g.log||console),this.t=this.t.bind(this),this.getLanguages=this.getLanguages.bind(this),this._setLanguage()}t(s,t={}){const{lng:e,fallbackLng:n,defaultNs:o}=this,{lng:a=e,ns:i=o,...r}=t,l=this.resources[a]?.[i]?.[s]||this.resources[n]?.[i]?.[s]||(this.options.useLabel?s:"");return g(l,r,a)}getUserLanguage(){if(!r)return this.fallbackLng;const[s,t]=this._getSettings();return c.debug("getUserLanguage: cookieLng:%s browserLng:%s",s,t),s||t}resetUserLanguage(){if(!r)return;const{name:s,...t}=this.options.cookie;c.debug("reset cookie"),document.cookie=i(s,"",{...t,expires:0}),this._setLanguage()}_getSettings(){const{name:s}=this.options.cookie,t=o(document.cookie)[s],e=globalThis?.navigator?.language;return console.log(document.cookie,t,e),[t,e]}_setCookie(){if(!r)return;const[s,t]=this._getSettings(),{userLng:e=""}=this;if(s===e)return;let n,o=e;[t,d(t)].includes(e)&&(n=0,o="");const{name:a,...g}=this.options.cookie;c.debug("_setCookie: %s:%s",0===n?"reset":"set",e),document.cookie=i(a,o,{...g,expires:n})}_setLanguage(s){const t=s||this.getUserLanguage(),{supportedLngs:e}=this,n=((s,t,e=[])=>h([s,...e].filter(Boolean).reduce((s,t)=>(s.push(t,d(t)),s),[])).reduce((s,e)=>(t.includes(e)&&s.push(e),s),[]))(t,e,globalThis?.navigator?.languages||[]);if(n.length)this.userLng=t,this.lng=n[0];else{this.userLng=this.lng=this.fallbackLng;const[s]=this.lng.split("-");n.push(...h([this.lng,s]))}return this._setCookie(),n}getLanguages(){return this.supportedLngs}async changeLanguage(s){const t=this._setLanguage(s);c.debug("changeLanguage: lng:%s variants:%s",s,t),await this.loadLanguages(t);let e=this.fallbackLng;for(const s of t)if(this.resources[s]?.[this.defaultNs]){e=s;break}c.debug("changeLanguage: loadedLng:%s",e);const n=d(e);if(d(s||t[0])!==n){const s=t.find(s=>d(s)===n);this._setLanguage(s||e)}this._setCookie()}async changeNamespace(s){this.defaultNs=s,await this.loadLanguages([this.lng,this.fallbackLng])}async loadLanguages(s=[],t=[]){const e=h(s),n=h([...t,this.defaultNs]);if(!e.length||!n.length)return c.error("can't load without languages or namespaces"),[];const o=[];for(const s of e)for(const t of n)this.resources[s]?.[t]||o.push(this._load({lng:s,ns:t}).catch(s=>c.error(s)));return await Promise.all(o)}async _load({lng:s,ns:t}){const{version:e}=this.options,n=g(this.options.localesPath,{lng:s,ns:t,version:e}),o=await fetch(n).catch(s=>c.error(s));this.resources[s]=this.resources[s]||{};const{ok:a=!1,status:i=-1}=o||{};if(a&&o){c.debug("_load: lng=%s ns=%s",s,t);const e=await o.json();this.resources[s][t]=e}else c.error("_load: error loading url=%s",n);return{ok:a,status:i,lng:s,ns:t}}}const L="mi-intl",f=()=>new Promise(s=>requestAnimationFrame(s));class b extends t{version="";lng="";defaultNs="";ns="";supportedLngs="";localesPath="";useLabel=!1;debug=!1;static get attributes(){return{version:"",lng:String,defaultNs:"translations",ns:"translations",supportedLngs:"",localesPath:"/locales/{lng}/{ns}.json?v={version}",useLabel:Boolean,debug:!1}}static get properties(){return{loading:!1}}static template="<slot></slot>";set options(s){this.i18n=new p(s),this.changeLanguage(s?.lng).catch(console.error)}_contextValue(){const{t:s,lng:t,getLanguages:e}=this.i18n??{t:()=>"",lng:"",getLanguages:()=>[]};return{t:s,lng:t,getLanguages:e,changeLanguage:this.changeLanguage.bind(this),loading:this.loading??!1}}async changeLanguage(s){this.loading=!0,await(this.i18n?.changeLanguage(s).finally(()=>{this.requestUpdate()})),await f(),await f(),this.loading=!1}render(){const s=this.supportedLngs.split(","),t=this.ns.split(",");this.i18n=new p({...this,supportedLngs:s,ns:t}),this.provider=new e(this,L,this._contextValue()),this.changeLanguage(this.lng).catch(console.error)}update(){this.provider?.set(this._contextValue())}}class m extends n{constructor(s,t=!0){super(s,L,{subscribe:t})}}class k extends t{#s;constructor(){super(),this.#s=new m(this)}t(s,t){return this.#s.value.t(s,t)}}export{p as I18n,L as INTL_CONTEXT,m as IntlConsumer,k as MiIntlMessage,b as MiIntlProvider,o as cookieParse,i as cookieSerialize};
@@ -5,6 +5,14 @@ import { I18n } from './i18n.js';
5
5
  const INTL_CONTEXT = 'mi-intl', requestAnimationFrameP = () => new Promise(resolve => requestAnimationFrame(resolve));
6
6
 
7
7
  class MiIntlProvider extends MiElement {
8
+ version='';
9
+ lng='';
10
+ defaultNs='';
11
+ ns='';
12
+ supportedLngs='';
13
+ localesPath='';
14
+ useLabel=!1;
15
+ debug=!1;
8
16
  static get attributes() {
9
17
  return {
10
18
  version: '',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mi-intl",
3
- "version": "0.6.3",
4
- "description": "Translations",
3
+ "version": "0.6.6",
4
+ "description": "i18n for mi-element",
5
5
  "keywords": [
6
6
  "i18n",
7
7
  "translations"
@@ -41,26 +41,26 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "intl-messageformat-tiny": "^1.1.0",
44
- "mi-element": "0.6.3"
44
+ "mi-element": "0.6.6"
45
45
  },
46
46
  "devDependencies": {
47
- "@eslint/js": "^9.34.0",
47
+ "@eslint/js": "^9.39.1",
48
48
  "@rollup/plugin-terser": "^0.4.4",
49
49
  "@testing-library/dom": "^10.4.1",
50
- "@types/node": "^24.3.0",
51
- "@vitest/browser": "^3.2.4",
52
- "@vitest/coverage-istanbul": "^3.2.4",
53
- "eslint": "^9.34.0",
54
- "globals": "^16.3.0",
50
+ "@types/node": "^24.10.0",
51
+ "@vitest/browser": "^4.0.8",
52
+ "@vitest/browser-playwright": "^4.0.8",
53
+ "@vitest/coverage-istanbul": "^4.0.8",
54
+ "eslint": "^9.39.1",
55
+ "globals": "^16.5.0",
55
56
  "npm-run-all2": "^8.0.4",
56
- "playwright": "^1.55.0",
57
+ "playwright": "^1.56.1",
57
58
  "prettier": "^3.6.2",
58
- "rimraf": "^6.0.1",
59
- "rollup": "^4.48.1",
60
- "typescript": "^5.9.2",
61
- "vite": "^7.1.3",
62
- "vitest": "^3.2.4",
63
- "mi-html": "0.6.3"
59
+ "rimraf": "^6.1.0",
60
+ "rollup": "^4.53.1",
61
+ "typescript": "^5.9.3",
62
+ "vite": "^7.2.2",
63
+ "vitest": "^4.0.8"
64
64
  },
65
65
  "scripts": {
66
66
  "all": "npm-run-all pretty lint test build types",
@@ -10,6 +10,23 @@ const requestAnimationFrameP = () =>
10
10
  new Promise((resolve) => requestAnimationFrame(resolve))
11
11
 
12
12
  export class MiIntlProvider extends MiElement {
13
+ /** @type {string} */
14
+ version = ''
15
+ /** @type {string} */
16
+ lng = ''
17
+ /** @type {string} */
18
+ defaultNs = ''
19
+ /** @type {string} */
20
+ ns = ''
21
+ /** @type {string} */
22
+ supportedLngs = ''
23
+ /** @type {string} */
24
+ localesPath = ''
25
+ /** @type {boolean} */
26
+ useLabel = false
27
+ /** @type {boolean} */
28
+ debug = false
29
+
13
30
  static get attributes() {
14
31
  return {
15
32
  /** translation version */
@@ -24,6 +24,22 @@ export class MiIntlProvider extends MiElement {
24
24
  loading: boolean;
25
25
  };
26
26
  static template: string;
27
+ /** @type {string} */
28
+ version: string;
29
+ /** @type {string} */
30
+ lng: string;
31
+ /** @type {string} */
32
+ defaultNs: string;
33
+ /** @type {string} */
34
+ ns: string;
35
+ /** @type {string} */
36
+ supportedLngs: string;
37
+ /** @type {string} */
38
+ localesPath: string;
39
+ /** @type {boolean} */
40
+ useLabel: boolean;
41
+ /** @type {boolean} */
42
+ debug: boolean;
27
43
  /**
28
44
  * @param {I18nOptions} options
29
45
  */