@fluenti/vue 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`),t=require(`@fluenti/core`);function n(){let t=(0,e.inject)(T);if(!t)throw Error(`[fluenti] useI18n() requires createFluentVue plugin`);return t}function r(e,t){return t===0?e:e.replace(/<(\d+)(\/?>)/g,(e,n,r)=>`<${Number(n)+t}${r}`).replace(/<\/(\d+)>/g,(e,n)=>`</${Number(n)+t}>`)}function i(t){let n=[],a=``;function o(t){if(t==null||typeof t==`boolean`)return;if(Array.isArray(t)){for(let e of t)o(e);return}if(typeof t==`string`||typeof t==`number`){a+=String(t);return}if(!(0,e.isVNode)(t)||t.type===e.Comment)return;if(t.type===e.Text){a+=typeof t.children==`string`?t.children:``;return}let s=n.length,c=i(t.children);n.push(t),n.push(...c.components),a+=`<${s}>${r(c.message,s+1)}</${s}>`}return o(t),{message:a,components:n}}function a(t,n){let r=/<(\d+)>([\s\S]*?)<\/\1>/g,i=[],o=0,s;for(r.lastIndex=0,s=r.exec(t);s!==null;){s.index>o&&i.push(t.slice(o,s.index));let c=n[Number(s[1])],l=a(s[2],n);c?i.push((0,e.h)(c.type,c.props??{},Array.isArray(l)?l:[l])):i.push(s[2]),o=r.lastIndex,s=r.exec(t)}return o<t.length&&i.push(t.slice(o)),i.length<=1?i[0]??``:i}function o(e,t){let n={},a=[];for(let o of e){let e=t[o];if(e===void 0)continue;let s=i(e);n[o]=r(s.message,a.length),a.push(...s.components)}for(let[o,s]of Object.entries(t)){if(e.includes(o)||s===void 0)continue;let t=i(s);n[o]=r(t.message,a.length),a.push(...t.components)}return{messages:n,components:a}}function s(e){return`{value, select, ${Object.entries(e).map(([e,t])=>`${e} {${t}}`).join(` `)}}`}function c(e){let t={},n={},r=0;for(let[i,a]of Object.entries(e)){if(i===`other`){t.other=a;continue}let e=/^[A-Za-z0-9_]+$/.test(i)?i:`case_${r++}`;t[e]=a,n[i]=e}return t.other===void 0&&(t.other=``),{forms:t,valueMap:n}}var l={id:String,context:String,comment:String,tag:{type:String,default:`span`}},u=(0,e.defineComponent)({name:`Trans`,props:l,setup(t,{slots:r}){let{t:o}=n();return()=>{let n=r.default?.();if(!n)return null;let{message:s,components:c}=i(n),l=o({...t.id===void 0?{}:{id:t.id},message:s,...t.context===void 0?{}:{context:t.context},...t.comment===void 0?{}:{comment:t.comment}}),u=c.length>0?a(l,c):l;return Array.isArray(u)?u.length===1?u[0]:(0,e.h)(t.tag,null,u):u}}}),d=[`zero`,`one`,`two`,`few`,`many`,`other`];function f(e,t){let n=[];for(let t of d){let r=e[t];if(r!==void 0){let e=t===`zero`?`=0`:t;n.push(`${e} {${r}}`)}}return`{count, plural, ${t?`offset:${t} `:``}${n.join(` `)}}`}var p={value:{type:Number,required:!0},id:String,context:String,comment:String,zero:String,one:String,two:String,few:String,many:String,other:{type:String,default:void 0},offset:Number,tag:{type:String,default:`span`}},m=(0,e.defineComponent)({name:`Plural`,props:p,setup(r,{slots:i}){let{t:s}=n();return()=>{let n={zero:r.zero,one:r.one,two:r.two,few:r.few,many:r.many,other:r.other??``};for(let e of d){let t=i[e];t&&(n[e]=t({count:`#`}))}let{messages:c,components:l}=o(d,n),u=f({...c.zero!==void 0&&{zero:c.zero},...c.one!==void 0&&{one:c.one},...c.two!==void 0&&{two:c.two},...c.few!==void 0&&{few:c.few},...c.many!==void 0&&{many:c.many},other:c.other??``},r.offset),p=s({id:r.id??(r.context===void 0?u:(0,t.hashMessage)(u,r.context)),message:u,...r.context===void 0?{}:{context:r.context},...r.comment===void 0?{}:{comment:r.comment}},{count:r.value}),m=l.length>0?a(p,l):p;return(0,e.h)(r.tag,void 0,m??void 0)}}}),h={value:{type:String,required:!0},id:String,context:String,comment:String,other:{type:String,default:void 0},options:{type:Object,default:void 0},tag:{type:String,default:`span`}},g=(0,e.defineComponent)({name:`Select`,inheritAttrs:!1,props:h,setup(r,{attrs:i,slots:l}){let{t:u}=n();return()=>{let n={};if(r.options!==void 0){for(let[e,t]of Object.entries(r.options))n[e]=t;n.other=r.other??``}else{for(let[e,t]of Object.entries(i))typeof t==`string`&&(n[e]=t);n.other=r.other??``}for(let[e,t]of Object.entries(l))e===`default`||!t||(n[e]=t({value:`{value}`}));let d=[...Object.keys(n).filter(e=>e!==`other`),`other`],{messages:f,components:p}=o(d,n),m=c(Object.fromEntries([...d].map(e=>[e,f[e]??``]))),h=s(m.forms),g=u({id:r.id??(r.context===void 0?h:(0,t.hashMessage)(h,r.context)),message:h,...r.context===void 0?{}:{context:r.context},...r.comment===void 0?{}:{comment:r.comment}},{value:m.valueMap[r.value]??`other`}),_=p.length>0?a(g,p):g;return(0,e.h)(r.tag,void 0,_??void 0)}}}),_={value:{type:[Date,Number],required:!0},style:{type:String,default:void 0},tag:{type:String,default:`span`}},v=(0,e.defineComponent)({name:`DateTime`,props:_,setup(t){let{d:r}=n();return()=>(0,e.h)(t.tag,r(t.value,t.style))}}),y={value:{type:Number,required:!0},style:{type:String,default:void 0},tag:{type:String,default:`span`}},b=(0,e.defineComponent)({name:`NumberFormat`,props:y,setup(t){let{n:r}=n();return()=>(0,e.h)(t.tag,r(t.value,t.style))}});function x(e){return e.replace(/&/g,`&`).replace(/"/g,`"`).replace(/'/g,`'`).replace(/</g,`<`).replace(/>/g,`>`)}var S=Symbol.for(`fluenti.runtime.vue`);function C(){let e=globalThis[S];return typeof e==`object`&&e?e:null}function w(e){return typeof e==`object`&&e&&`default`in e?e.default:e}var T=Symbol(`fluenti`);function E(e,n,r){return typeof e==`function`?e(n):(0,t.interpolate)(e,n,r)}function D(e){let t=Object.keys(e).filter(e=>e!==`plural`);return t.length>0?t[0]:void 0}function O(n){let r=n.lazyLocaleLoading??n.splitting??!1,i=(0,e.ref)(n.locale),a=(0,e.shallowReactive)({...n.messages}),o=(0,e.ref)(!1),s=new Set([n.locale]),c=(0,e.ref)(new Set(s));function l(e,t){let n=a[e];if(n)return n[t]}function d(e,...r){if(Array.isArray(e)&&`raw`in e)return d((0,t.buildICUMessage)(e,r),Object.fromEntries(r.map((e,t)=>[String(t),e])));let a=e,o=r[0],s,c;typeof a==`object`&&a?(s=(0,t.resolveDescriptorId)(a)??``,c=a.message):s=a;let u=i.value,f=[u];if(n.fallbackLocale&&!f.includes(n.fallbackLocale)&&f.push(n.fallbackLocale),n.fallbackChain?.[u])for(let e of n.fallbackChain[u])f.includes(e)||f.push(e);else if(n.fallbackChain?.[`*`])for(let e of n.fallbackChain[`*`])f.includes(e)||f.push(e);for(let e of f){let t=l(e,s);if(t!==void 0)return E(t,o,e)}if(n.missing){let e=n.missing(u,s);if(e!==void 0)return e}return c?(0,t.interpolate)(c,o,u):s.includes(`{`)?(0,t.interpolate)(s,o,u):s}async function f(e){if(!r||!n.chunkLoader){i.value=e;return}let t=C();if(s.has(e)){t?.__switchLocale&&await t.__switchLocale(e),i.value=e;return}o.value=!0;try{let r=w(await n.chunkLoader(e));a[e]={...a[e],...r},s.add(e),c.value=new Set(s),t?.__switchLocale&&await t.__switchLocale(e),i.value=e}finally{o.value=!1}}function p(e,t){a[e]={...a[e],...t},s.add(e),c.value=new Set(s)}function h(e){if(!r||s.has(e)||!n.chunkLoader)return;let t=C();n.chunkLoader(e).then(async n=>{let r=w(n);a[e]={...a[e],...r},s.add(e),c.value=new Set(s),t?.__preloadLocale&&await t.__preloadLocale(e)}).catch(()
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`),t=require(`@fluenti/core`);function n(){let t=(0,e.inject)(T);if(!t)throw Error(`[fluenti] useI18n() requires createFluentVue plugin`);return t}function r(e,t){return t===0?e:e.replace(/<(\d+)(\/?>)/g,(e,n,r)=>`<${Number(n)+t}${r}`).replace(/<\/(\d+)>/g,(e,n)=>`</${Number(n)+t}>`)}function i(t){let n=[],a=``;function o(t){if(t==null||typeof t==`boolean`)return;if(Array.isArray(t)){for(let e of t)o(e);return}if(typeof t==`string`||typeof t==`number`){a+=String(t);return}if(!(0,e.isVNode)(t)||t.type===e.Comment)return;if(t.type===e.Text){a+=typeof t.children==`string`?t.children:``;return}let s=n.length,c=i(t.children);n.push(t),n.push(...c.components),a+=`<${s}>${r(c.message,s+1)}</${s}>`}return o(t),{message:a,components:n}}function a(t,n){let r=/<(\d+)>([\s\S]*?)<\/\1>/g,i=[],o=0,s;for(r.lastIndex=0,s=r.exec(t);s!==null;){s.index>o&&i.push(t.slice(o,s.index));let c=n[Number(s[1])],l=a(s[2],n);c?i.push((0,e.h)(c.type,c.props??{},Array.isArray(l)?l:[l])):i.push(s[2]),o=r.lastIndex,s=r.exec(t)}return o<t.length&&i.push(t.slice(o)),i.length<=1?i[0]??``:i}function o(e,t){let n={},a=[];for(let o of e){let e=t[o];if(e===void 0)continue;let s=i(e);n[o]=r(s.message,a.length),a.push(...s.components)}for(let[o,s]of Object.entries(t)){if(e.includes(o)||s===void 0)continue;let t=i(s);n[o]=r(t.message,a.length),a.push(...t.components)}return{messages:n,components:a}}function s(e){return`{value, select, ${Object.entries(e).map(([e,t])=>`${e} {${t}}`).join(` `)}}`}function c(e){let t={},n={},r=0;for(let[i,a]of Object.entries(e)){if(i===`other`){t.other=a;continue}let e=/^[A-Za-z0-9_]+$/.test(i)?i:`case_${r++}`;t[e]=a,n[i]=e}return t.other===void 0&&(t.other=``),{forms:t,valueMap:n}}var l={id:String,context:String,comment:String,tag:{type:String,default:`span`}},u=(0,e.defineComponent)({name:`Trans`,props:l,setup(t,{slots:r}){let{t:o}=n();return()=>{let n=r.default?.();if(!n)return null;let{message:s,components:c}=i(n),l=o({...t.id===void 0?{}:{id:t.id},message:s,...t.context===void 0?{}:{context:t.context},...t.comment===void 0?{}:{comment:t.comment}}),u=c.length>0?a(l,c):l;return Array.isArray(u)?u.length===1?u[0]:(0,e.h)(t.tag,null,u):u}}}),d=[`zero`,`one`,`two`,`few`,`many`,`other`];function f(e,t){let n=[];for(let t of d){let r=e[t];if(r!==void 0){let e=t===`zero`?`=0`:t;n.push(`${e} {${r}}`)}}return`{count, plural, ${t?`offset:${t} `:``}${n.join(` `)}}`}var p={value:{type:Number,required:!0},id:String,context:String,comment:String,zero:String,one:String,two:String,few:String,many:String,other:{type:String,default:void 0},offset:Number,tag:{type:String,default:`span`}},m=(0,e.defineComponent)({name:`Plural`,props:p,setup(r,{slots:i}){let{t:s}=n();return()=>{let n={zero:r.zero,one:r.one,two:r.two,few:r.few,many:r.many,other:r.other??``};for(let e of d){let t=i[e];t&&(n[e]=t({count:`#`}))}let{messages:c,components:l}=o(d,n),u=f({...c.zero!==void 0&&{zero:c.zero},...c.one!==void 0&&{one:c.one},...c.two!==void 0&&{two:c.two},...c.few!==void 0&&{few:c.few},...c.many!==void 0&&{many:c.many},other:c.other??``},r.offset),p=s({id:r.id??(r.context===void 0?u:(0,t.hashMessage)(u,r.context)),message:u,...r.context===void 0?{}:{context:r.context},...r.comment===void 0?{}:{comment:r.comment}},{count:r.value}),m=l.length>0?a(p,l):p;return(0,e.h)(r.tag,void 0,m??void 0)}}}),h={value:{type:String,required:!0},id:String,context:String,comment:String,other:{type:String,default:void 0},options:{type:Object,default:void 0},tag:{type:String,default:`span`}},g=(0,e.defineComponent)({name:`Select`,inheritAttrs:!1,props:h,setup(r,{attrs:i,slots:l}){let{t:u}=n();return()=>{let n={};if(r.options!==void 0){for(let[e,t]of Object.entries(r.options))n[e]=t;n.other=r.other??``}else{for(let[e,t]of Object.entries(i))typeof t==`string`&&(n[e]=t);n.other=r.other??``}for(let[e,t]of Object.entries(l))e===`default`||!t||(n[e]=t({value:`{value}`}));let d=[...Object.keys(n).filter(e=>e!==`other`),`other`],{messages:f,components:p}=o(d,n),m=c(Object.fromEntries([...d].map(e=>[e,f[e]??``]))),h=s(m.forms),g=u({id:r.id??(r.context===void 0?h:(0,t.hashMessage)(h,r.context)),message:h,...r.context===void 0?{}:{context:r.context},...r.comment===void 0?{}:{comment:r.comment}},{value:m.valueMap[r.value]??`other`}),_=p.length>0?a(g,p):g;return(0,e.h)(r.tag,void 0,_??void 0)}}}),_={value:{type:[Date,Number],required:!0},style:{type:String,default:void 0},tag:{type:String,default:`span`}},v=(0,e.defineComponent)({name:`DateTime`,props:_,setup(t){let{d:r}=n();return()=>(0,e.h)(t.tag,r(t.value,t.style))}}),y={value:{type:Number,required:!0},style:{type:String,default:void 0},tag:{type:String,default:`span`}},b=(0,e.defineComponent)({name:`NumberFormat`,props:y,setup(t){let{n:r}=n();return()=>(0,e.h)(t.tag,r(t.value,t.style))}});function x(e){return e.replace(/&/g,`&`).replace(/"/g,`"`).replace(/'/g,`'`).replace(/</g,`<`).replace(/>/g,`>`)}var S=Symbol.for(`fluenti.runtime.vue`);function C(){let e=globalThis[S];return typeof e==`object`&&e?e:null}function w(e){return typeof e==`object`&&e&&`default`in e?e.default:e}var T=Symbol(`fluenti`);function E(e,n,r){return typeof e==`function`?e(n):(0,t.interpolate)(e,n,r)}function D(e){let t=Object.keys(e).filter(e=>e!==`plural`);return t.length>0?t[0]:void 0}function O(n){let r=n.lazyLocaleLoading??n.splitting??!1,i=(0,e.ref)(n.locale),a=(0,e.shallowReactive)({...n.messages}),o=(0,e.ref)(!1),s=new Set([n.locale]),c=(0,e.ref)(new Set(s));function l(e,t){let n=a[e];if(n)return n[t]}function d(e,...r){if(Array.isArray(e)&&`raw`in e)return d((0,t.buildICUMessage)(e,r),Object.fromEntries(r.map((e,t)=>[String(t),e])));let a=e,o=r[0],s,c;typeof a==`object`&&a?(s=(0,t.resolveDescriptorId)(a)??``,c=a.message):s=a;let u=i.value,f=[u];if(n.fallbackLocale&&!f.includes(n.fallbackLocale)&&f.push(n.fallbackLocale),n.fallbackChain?.[u])for(let e of n.fallbackChain[u])f.includes(e)||f.push(e);else if(n.fallbackChain?.[`*`])for(let e of n.fallbackChain[`*`])f.includes(e)||f.push(e);for(let e of f){let t=l(e,s);if(t!==void 0)return E(t,o,e)}if(n.missing){let e=n.missing(u,s);if(e!==void 0)return e}return c?(0,t.interpolate)(c,o,u):s.includes(`{`)?(0,t.interpolate)(s,o,u):s}async function f(e){if(!r||!n.chunkLoader){i.value=e;return}let t=C();if(s.has(e)){t?.__switchLocale&&await t.__switchLocale(e),i.value=e;return}o.value=!0;try{let r=w(await n.chunkLoader(e));a[e]={...a[e],...r},s.add(e),c.value=new Set(s),t?.__switchLocale&&await t.__switchLocale(e),i.value=e}finally{o.value=!1}}function p(e,t){a[e]={...a[e],...t},s.add(e),c.value=new Set(s)}function h(e){if(!r||s.has(e)||!n.chunkLoader)return;let t=C();n.chunkLoader(e).then(async n=>{let r=w(n);a[e]={...a[e],...r},s.add(e),c.value=new Set(s),t?.__preloadLocale&&await t.__preloadLocale(e)}).catch(t=>{console.warn(`[fluenti] preload failed:`,e,t)})}function _(){return Object.keys(a)}function y(e,r){let a=i.value;return(0,t.formatDate)(e,a,r,n.dateFormats)}function S(e,r){let a=i.value;return(0,t.formatNumber)(e,a,r,n.numberFormats)}function O(e,t){return E(e,t,i.value)}function k(e,t,n){return x(n?d(e,n):d(e)).replace(/<(\d+)>([\s\S]*?)<\/\1>/g,(e,n,r)=>{let i=t[Number(n)];if(!i)return r;let a=Object.entries(i.attrs).map(([e,t])=>t?`${x(e)}="${x(t)}"`:x(e)).join(` `),o=x(i.tag);return`<${o}${a?` `+a:``}>${r}</${o}>`})}function A(e,t){return l(t??i.value,e)!==void 0}function j(e,t){return l(t??i.value,e)}let M={t:d,locale:i,setLocale:f,loadMessages:p,getLocales:_,d:y,n:S,format:O,isLoading:o,loadedLocales:c,preloadLocale:h,te:A,tm:j};return{install(e){e.provide(T,M);let t=n.componentPrefix??``;e.component(`${t}Trans`,u),e.component(`${t}Plural`,m),e.component(`${t}Select`,g),e.component(`${t}DateTime`,v),e.component(`${t}NumberFormat`,b),e.config.globalProperties.$t=d,e.config.globalProperties.$d=y,e.config.globalProperties.$n=S,e.config.globalProperties.$vtRich=k;let r=new WeakMap;e.directive(`t`,{mounted(e,t){let n=D(t.modifiers);if(n){let t=e.getAttribute(n)??``;r.set(e,t),e.setAttribute(n,d(t))}else{let n=t.arg??e.textContent??``;r.set(e,n.trim()),e.textContent=d(n.trim(),t.value==null?void 0:{...t.value})}},updated(e,t){let n=D(t.modifiers);if(n){let t=r.get(e)??e.getAttribute(n)??``;e.setAttribute(n,d(t))}else e.textContent=d((t.arg??r.get(e)??``).trim(),t.value==null?void 0:{...t.value})}})},global:M}}var k=((...e)=>{throw Error("[fluenti] `t` imported from '@fluenti/vue' is a compile-time API. Use it only with the Fluenti build transform inside <script setup> or setup(). For runtime lookups, use useI18n().t(...).")});exports.DateTime=v,exports.FLUENTI_KEY=T,exports.NumberFormat=b,exports.Plural=m,exports.Select=g,exports.Trans=u,exports.createFluentVue=O,Object.defineProperty(exports,`msg`,{enumerable:!0,get:function(){return t.msg}}),exports.t=k,exports.useI18n=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/use-i18n.ts","../src/components/rich-text.ts","../src/components/Trans.ts","../src/components/Plural.ts","../src/components/Select.ts","../src/components/DateTime.ts","../src/components/NumberFormat.ts","../src/plugin.ts","../src/compile-time-t.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { FLUENTI_KEY, type FluentVueContext } from './plugin'\n\n/**\n * Composable that returns the Fluenti i18n context.\n *\n * Must be called inside a component whose ancestor app has installed the\n * `createFluentVue()` plugin.\n *\n * @throws If the plugin has not been installed\n */\nexport function useI18n(): FluentVueContext {\n const ctx = inject(FLUENTI_KEY)\n if (!ctx) {\n throw new Error('[fluenti] useI18n() requires createFluentVue plugin')\n }\n return ctx\n}\n","import { Comment, Text, h, isVNode, type VNode, type VNodeChild } from 'vue'\n\nexport function offsetIndices(message: string, offset: number): string {\n if (offset === 0) return message\n return message\n .replace(/<(\\d+)(\\/?>)/g, (_match, index: string, suffix: string) => `<${Number(index) + offset}${suffix}`)\n .replace(/<\\/(\\d+)>/g, (_match, index: string) => `</${Number(index) + offset}>`)\n}\n\nexport function extractMessage(children: VNodeChild | VNodeChild[] | undefined): {\n message: string\n components: VNode[]\n} {\n const components: VNode[] = []\n let message = ''\n\n function visit(node: VNodeChild | VNodeChild[] | undefined): void {\n if (node === null || node === undefined || typeof node === 'boolean') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n if (typeof node === 'string' || typeof node === 'number') {\n message += String(node)\n return\n }\n if (!isVNode(node) || node.type === Comment) return\n if (node.type === Text) {\n message += typeof node.children === 'string' ? node.children : ''\n return\n }\n\n const idx = components.length\n const inner = extractMessage(node.children as VNodeChild | VNodeChild[] | undefined)\n components.push(node)\n components.push(...inner.components)\n message += `<${idx}>${offsetIndices(inner.message, idx + 1)}</${idx}>`\n }\n\n visit(children)\n return { message, components }\n}\n\nexport function reconstruct(\n translated: string,\n components: VNode[],\n): VNodeChild {\n const tagRe = /<(\\d+)>([\\s\\S]*?)<\\/\\1>/g\n const result: VNodeChild[] = []\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n tagRe.lastIndex = 0\n match = tagRe.exec(translated)\n while (match !== null) {\n if (match.index > lastIndex) {\n result.push(translated.slice(lastIndex, match.index))\n }\n\n const idx = Number(match[1])\n const component = components[idx]\n const innerContent = reconstruct(match[2]!, components)\n if (component) {\n result.push(h(component.type as never, component.props ?? {}, Array.isArray(innerContent) ? innerContent : [innerContent]))\n } else {\n result.push(match[2]!)\n }\n\n lastIndex = tagRe.lastIndex\n match = tagRe.exec(translated)\n }\n\n if (lastIndex < translated.length) {\n result.push(translated.slice(lastIndex))\n }\n\n return result.length <= 1 ? (result[0] ?? '') : result\n}\n\nexport function serializeRichForms<T extends string>(\n keys: readonly T[],\n forms: Partial<Record<T, VNodeChild>> & Record<string, VNodeChild | undefined>,\n): {\n messages: Record<string, string>\n components: VNode[]\n} {\n const messages: Record<string, string> = {}\n const components: VNode[] = []\n\n for (const key of keys) {\n const value = forms[key]\n if (value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n for (const [key, value] of Object.entries(forms)) {\n if (keys.includes(key as T) || value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n return { messages, components }\n}\n\nexport function buildICUSelectMessage(forms: Record<string, string>): string {\n return `{value, select, ${Object.entries(forms).map(([key, text]) => `${key} {${text}}`).join(' ')}}`\n}\n\nexport function normalizeSelectForms(forms: Record<string, string>): {\n forms: Record<string, string>\n valueMap: Record<string, string>\n} {\n const normalized: Record<string, string> = {}\n const valueMap: Record<string, string> = {}\n let index = 0\n\n for (const [key, text] of Object.entries(forms)) {\n if (key === 'other') {\n normalized['other'] = text\n continue\n }\n\n const safeKey = /^[A-Za-z0-9_]+$/.test(key) ? key : `case_${index++}`\n normalized[safeKey] = text\n valueMap[key] = safeKey\n }\n\n if (normalized['other'] === undefined) {\n normalized['other'] = ''\n }\n\n return { forms: normalized, valueMap }\n}\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\nimport { extractMessage, reconstruct } from './rich-text'\n\n/**\n * `<Trans>` component for rich text with Vue components.\n *\n * @example\n * ```vue\n * <Trans>\n * Visit our <a href=\"/docs\">documentation</a> to learn more.\n * </Trans>\n * ```\n *\n * @example\n * ```vue\n * <Trans>\n * Click <RouterLink to=\"/next\">here</RouterLink> to continue.\n * </Trans>\n * ```\n */\nconst transProps = {\n /** Override auto-generated hash ID */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type TransProps = Readonly<ExtractPropTypes<typeof transProps>>\n\nexport const Trans = defineComponent({\n name: 'Trans',\n props: transProps,\n setup(props, { slots }) {\n const { t } = useI18n()\n\n return () => {\n const defaultSlot = slots['default']?.()\n if (!defaultSlot) return null\n const { message, components } = extractMessage(defaultSlot)\n const translated = t({\n ...(props.id !== undefined ? { id: props.id } : {}),\n message,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n })\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n if (Array.isArray(result)) {\n return result.length === 1 ? result[0]! : h(props.tag, null, result)\n }\n return result\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { reconstruct, serializeRichForms } from './rich-text'\n\n/** Plural category names in a stable order for ICU message building. */\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n\ntype PluralCategory = (typeof PLURAL_CATEGORIES)[number]\n\n/**\n * Build an ICU plural message string from individual category props.\n *\n * Given `{ zero: \"No items\", one: \"# item\", other: \"# items\" }`,\n * produces `\"{count, plural, =0 {No items} one {# item} other {# items}}\"`.\n *\n * @internal\n */\nfunction buildICUPluralMessage(\n forms: Partial<Record<PluralCategory, string>> & { other: string },\n offset?: number,\n): string {\n const parts: string[] = []\n for (const cat of PLURAL_CATEGORIES) {\n const text = forms[cat]\n if (text !== undefined) {\n // Map the `zero` prop to ICU `=0` exact match. In ICU MessageFormat,\n // `zero` is a CLDR plural category that only activates in languages\n // with a grammatical zero form (e.g. Arabic). The `=0` exact match\n // works universally for the common \"show this when count is 0\" intent.\n const key = cat === 'zero' ? '=0' : cat\n parts.push(`${key} {${text}}`)\n }\n }\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{count, plural, ${offsetPrefix}${parts.join(' ')}}`\n}\n\n/**\n * `<Plural>` component — shorthand for ICU plural patterns.\n *\n * Plural form props (`zero`, `one`, `two`, `few`, `many`, `other`) are treated\n * as source-language messages. The component builds an ICU plural message,\n * looks it up via `t()` in the catalog, and interpolates the translated result.\n *\n * When no catalog translation exists, the component falls back to interpolating\n * the source-language ICU message directly via the `message` field of the\n * MessageDescriptor.\n *\n * Rich text is supported via named slots:\n * ```vue\n * <Plural :value=\"count\">\n * <template #zero>No <strong>items</strong></template>\n * <template #one><em>1</em> item</template>\n * <template #other><strong>{{ count }}</strong> items</template>\n * </Plural>\n * ```\n *\n * String props still work (backward compatible):\n * ```vue\n * <Plural :value=\"count\" zero=\"No items\" one=\"# item\" other=\"# items\" />\n * ```\n */\nconst pluralProps = {\n /** The numeric value to pluralise on */\n value: { type: Number, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Text for zero items (maps to `=0`) */\n zero: String,\n /** Text for singular (maps to `one`) */\n one: String,\n /** Text for dual (maps to `two`) */\n two: String,\n /** Text for few (maps to `few`) */\n few: String,\n /** Text for many (maps to `many`) */\n many: String,\n /** Text for the default/other category */\n other: { type: String, default: undefined },\n /** Offset from value before selecting form */\n offset: Number,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type PluralProps = Readonly<ExtractPropTypes<typeof pluralProps>>\n\nexport const Plural = defineComponent({\n name: 'Plural',\n props: pluralProps,\n setup(props, { slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Partial<Record<PluralCategory, VNodeChild>> & Record<string, VNodeChild | undefined> = {\n zero: props.zero,\n one: props.one,\n two: props.two,\n few: props.few,\n many: props.many,\n other: props.other ?? '',\n }\n\n for (const cat of PLURAL_CATEGORIES) {\n const slot = slots[cat]\n if (slot) {\n forms[cat] = slot({ count: '#' })\n }\n }\n\n const { messages, components } = serializeRichForms(PLURAL_CATEGORIES, forms)\n const icuMessage = buildICUPluralMessage(\n {\n ...(messages['zero'] !== undefined && { zero: messages['zero'] }),\n ...(messages['one'] !== undefined && { one: messages['one'] }),\n ...(messages['two'] !== undefined && { two: messages['two'] }),\n ...(messages['few'] !== undefined && { few: messages['few'] }),\n ...(messages['many'] !== undefined && { many: messages['many'] }),\n other: messages['other'] ?? '',\n },\n props.offset,\n )\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { count: props.value },\n )\n\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { buildICUSelectMessage, normalizeSelectForms, reconstruct, serializeRichForms } from './rich-text'\n\n/**\n * `<Select>` component — shorthand for ICU select patterns.\n *\n * Accepts a `value` string that selects among named options. Options can be\n * provided via the type-safe `options` prop (recommended), as direct attrs\n * (convenience), or as named slots (rich text).\n *\n * Falls back to `other` when no match is found.\n *\n * @example Type-safe usage (recommended):\n * ```vue\n * <Select\n * :value=\"gender\"\n * :options=\"{ male: 'He liked it', female: 'She liked it' }\"\n * other=\"They liked it\"\n * />\n * ```\n *\n * @example Rich text via named slots:\n * ```vue\n * <Select :value=\"gender\">\n * <template #male><strong>He</strong> liked this</template>\n * <template #female><strong>She</strong> liked this</template>\n * <template #other><em>They</em> liked this</template>\n * </Select>\n * ```\n */\nconst selectProps = {\n /** The value to select on (e.g. `\"male\"`, `\"female\"`) */\n value: { type: String, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Fallback text when no option matches `value` */\n other: { type: String, default: undefined },\n /**\n * Named options map. Keys are match values, values are display strings.\n * Takes precedence over attrs when both are provided.\n *\n * @example `{ male: 'He', female: 'She' }`\n */\n options: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type SelectProps = Readonly<ExtractPropTypes<typeof selectProps>>\n\nexport const Select = defineComponent({\n name: 'Select',\n inheritAttrs: false,\n props: selectProps,\n setup(props, { attrs, slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Record<string, VNodeChild | undefined> = {}\n\n if (props.options !== undefined) {\n for (const [key, value] of Object.entries(props.options)) {\n forms[key] = value\n }\n forms['other'] = props.other ?? ''\n } else {\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'string') {\n forms[key] = value\n }\n }\n forms['other'] = props.other ?? ''\n }\n\n for (const [key, slot] of Object.entries(slots)) {\n if (key === 'default' || !slot) continue\n forms[key] = slot({ value: '{value}' })\n }\n\n const orderedKeys = [...Object.keys(forms).filter(key => key !== 'other'), 'other'] as const\n const { messages, components } = serializeRichForms(orderedKeys, forms)\n const normalized = normalizeSelectForms(\n Object.fromEntries(\n [...orderedKeys].map((key) => [key, messages[key] ?? '']),\n ),\n )\n const icuMessage = buildICUSelectMessage(normalized.forms)\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { value: normalized.valueMap[props.value] ?? 'other' },\n )\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<DateTime>` component for formatting dates according to locale.\n *\n * @example\n * ```vue\n * <DateTime :value=\"new Date()\" />\n * <DateTime :value=\"Date.now()\" style=\"short\" />\n * <DateTime :value=\"event.date\" style=\"long\" tag=\"time\" />\n * ```\n */\nconst dateTimeProps = {\n value: { type: [Date, Number] as PropType<Date | number>, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type DateTimeProps = Readonly<ExtractPropTypes<typeof dateTimeProps>>\n\nexport const DateTime = defineComponent({\n name: 'DateTime',\n props: dateTimeProps,\n setup(props) {\n const { d } = useI18n()\n return () => h(props.tag, d(props.value as Date | number, props.style))\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<NumberFormat>` component for formatting numbers according to locale.\n *\n * @example\n * ```vue\n * <NumberFormat :value=\"1234.56\" />\n * <NumberFormat :value=\"0.75\" style=\"percent\" />\n * <NumberFormat :value=\"99.99\" style=\"currency\" tag=\"strong\" />\n * ```\n */\nconst numberFormatProps = {\n value: { type: Number, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type NumberFormatProps = Readonly<ExtractPropTypes<typeof numberFormatProps>>\n\nexport const NumberFormat = defineComponent({\n name: 'NumberFormat',\n props: numberFormatProps,\n setup(props) {\n const { n } = useI18n()\n return () => h(props.tag, n(props.value, props.style))\n },\n})\n","import { type App, type InjectionKey, type Ref, ref, shallowReactive } from 'vue'\nimport type { AllMessages, Locale, Messages, CompiledMessage, MessageDescriptor } from '@fluenti/core'\nimport { interpolate, formatDate, formatNumber, buildICUMessage, resolveDescriptorId } from '@fluenti/core'\nimport { Trans } from './components/Trans'\nimport { Plural } from './components/Plural'\nimport { Select } from './components/Select'\nimport { DateTime } from './components/DateTime'\nimport { NumberFormat } from './components/NumberFormat'\n\n/** Escape HTML special characters to prevent XSS. @internal */\nfunction escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(/\"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Compiled message chunk loader for lazy locale loading */\nexport type ChunkLoader = (\n locale: string,\n) => Promise<Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> }>\n\ninterface SplitRuntimeModule {\n __switchLocale?: (locale: string) => Promise<void>\n __preloadLocale?: (locale: string) => Promise<void>\n}\n\nconst SPLIT_RUNTIME_KEY = Symbol.for('fluenti.runtime.vue')\n\nfunction getSplitRuntimeModule(): SplitRuntimeModule | null {\n const runtime = (globalThis as Record<PropertyKey, unknown>)[SPLIT_RUNTIME_KEY]\n return typeof runtime === 'object' && runtime !== null\n ? runtime as SplitRuntimeModule\n : null\n}\n\nfunction resolveChunkMessages(\n loaded: Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> },\n): Record<string, CompiledMessage> {\n return typeof loaded === 'object' && loaded !== null && 'default' in loaded\n ? (loaded as { default: Record<string, CompiledMessage> }).default\n : loaded\n}\n\n/** Context object returned by `useI18n()` and available as `$t` etc. on globalProperties */\nexport interface FluentVueContext {\n /** Translate a message by id or MessageDescriptor, with optional interpolation values */\n t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n /** Tagged template form: t`Hello ${name}` */\n t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n /** Reactive ref for current locale */\n locale: Readonly<Ref<Locale>>\n /** Change the active locale (async when lazy locale loading is enabled) */\n setLocale(locale: Locale): Promise<void>\n /** Dynamically load messages for a locale */\n loadMessages(locale: Locale, messages: Messages): void\n /** Get all locales that have loaded messages */\n getLocales(): Locale[]\n /** Format a date value according to locale */\n d(value: Date | number, style?: string): string\n /** Format a number according to locale */\n n(value: number, style?: string): string\n /** Format an ICU message string directly (no catalog lookup) */\n format(message: string, values?: Record<string, unknown>): string\n /** Whether a locale chunk is currently being loaded */\n isLoading: Readonly<Ref<boolean>>\n /** Set of locales whose messages have been loaded */\n loadedLocales: Readonly<Ref<ReadonlySet<string>>>\n /** Preload a locale in the background without switching to it */\n preloadLocale(locale: string): void\n /** Check if a translation key exists in the catalog */\n te(key: string, locale?: string): boolean\n /** Get the raw compiled message without interpolation */\n tm(key: string, locale?: string): CompiledMessage | undefined\n}\n\n/** Injection key for providing/injecting fluenti context */\nexport const FLUENTI_KEY: InjectionKey<FluentVueContext> = Symbol('fluenti')\n\n/** Options for creating the FluentVue plugin */\nexport interface FluentVueOptions {\n locale: string\n fallbackLocale?: string\n messages: AllMessages\n missing?: (locale: string, id: string) => string | undefined\n dateFormats?: Record<string, Intl.DateTimeFormatOptions | 'relative'>\n numberFormats?: Record<string, Intl.NumberFormatOptions | ((locale: string) => Intl.NumberFormatOptions)>\n fallbackChain?: Record<string, string[]>\n /** Async chunk loader for lazy locale loading */\n chunkLoader?: ChunkLoader\n /** Enable lazy locale loading through chunkLoader */\n lazyLocaleLoading?: boolean\n /**\n * Prefix for globally registered components (Trans, Plural, Select).\n *\n * Set this to avoid naming conflicts with other libraries.\n *\n * @example\n * componentPrefix: 'I18n'\n * // Registers: I18nTrans, I18nPlural, I18nSelect\n *\n * @example\n * componentPrefix: 'Fluenti'\n * // Registers: FluentiTrans, FluentiPlural, FluentiSelect\n *\n * @default '' (no prefix — Trans, Plural, Select)\n */\n componentPrefix?: string\n}\n\n/** Return value of `createFluentVue()` */\nexport interface FluentVuePlugin {\n /** Vue plugin install method */\n install(app: App): void\n /** The global fluenti context (same as what useI18n returns) */\n global: FluentVueContext\n}\n\n/**\n * Resolve a compiled message to a string, applying values if needed.\n * @internal\n */\nfunction resolveMessage(\n compiled: CompiledMessage,\n values?: Record<string, unknown>,\n locale?: string,\n): string {\n if (typeof compiled === 'function') {\n return compiled(values)\n }\n // Use core interpolate for ICU message parsing (handles plural, select, etc.)\n return interpolate(compiled, values, locale)\n}\n\n/** Extract the attribute name from v-t modifiers (e.g., v-t.alt → 'alt') */\nfunction getModifierAttr(modifiers: Partial<Record<string, boolean>>): string | undefined {\n const keys = Object.keys(modifiers).filter((k) => k !== 'plural')\n return keys.length > 0 ? keys[0] : undefined\n}\n\n/**\n * Create a Fluenti Vue plugin (SSR-safe, per-request instance).\n *\n * Each invocation creates entirely fresh state — no module-level singletons —\n * so it is safe to call once per SSR request.\n */\nexport function createFluentVue(options: FluentVueOptions): FluentVuePlugin {\n const lazyLocaleLoading = options.lazyLocaleLoading\n ?? (options as FluentVueOptions & { splitting?: boolean }).splitting\n ?? false\n const locale = ref(options.locale)\n const catalogs = shallowReactive<AllMessages>({ ...options.messages })\n const isLoading = ref(false)\n const loadedLocalesSet = new Set<string>([options.locale])\n const loadedLocales = ref<ReadonlySet<string>>(new Set(loadedLocalesSet))\n\n function lookup(\n loc: Locale,\n id: string,\n ): CompiledMessage | undefined {\n const msgs = catalogs[loc]\n if (!msgs) return undefined\n return msgs[id]\n }\n\n function t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n function t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n function t(idOrStrings: string | MessageDescriptor | TemplateStringsArray, ...rest: unknown[]): string {\n // Tagged template form: t`Hello ${name}`\n if (Array.isArray(idOrStrings) && 'raw' in idOrStrings) {\n const strings = idOrStrings as TemplateStringsArray\n const icu = buildICUMessage(strings, rest)\n const values = Object.fromEntries(rest.map((v, i) => [String(i), v]))\n // Delegate to the function-call path with the ICU string as the id\n return t(icu, values)\n }\n\n // Function call form\n const id = idOrStrings as string | MessageDescriptor\n const values = rest[0] as Record<string, unknown> | undefined\n\n // Handle MessageDescriptor objects (from msg``)\n let messageId: string\n let fallbackMessage: string | undefined\n if (typeof id === 'object' && id !== null) {\n messageId = resolveDescriptorId(id) ?? ''\n fallbackMessage = id.message\n } else {\n messageId = id\n }\n\n // Read locale.value to register a Vue reactive dependency\n const currentLocale = locale.value\n\n // Build the chain of locales to try\n const chain: Locale[] = [currentLocale]\n\n if (options.fallbackLocale && !chain.includes(options.fallbackLocale)) {\n chain.push(options.fallbackLocale)\n }\n\n if (options.fallbackChain?.[currentLocale]) {\n for (const fallback of options.fallbackChain[currentLocale]) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n } else if (options.fallbackChain?.['*']) {\n for (const fallback of options.fallbackChain['*']) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n }\n\n for (const loc of chain) {\n const compiled = lookup(loc, messageId)\n if (compiled !== undefined) {\n return resolveMessage(compiled, values, loc)\n }\n }\n\n // Try the missing handler\n if (options.missing) {\n const result = options.missing(currentLocale, messageId)\n if (result !== undefined) return result\n }\n\n // If we have a fallback message from a MessageDescriptor, interpolate it\n if (fallbackMessage) {\n return interpolate(fallbackMessage, values, currentLocale)\n }\n\n // Final fallback — if the id looks like an ICU message, interpolate it\n // (compile-time transforms like <Plural> emit inline ICU as t() arguments)\n if (messageId.includes('{')) {\n return interpolate(messageId, values, currentLocale)\n }\n return messageId\n }\n\n async function setLocale(newLocale: Locale): Promise<void> {\n if (!lazyLocaleLoading || !options.chunkLoader) {\n locale.value = newLocale\n return\n }\n\n const splitRuntime = getSplitRuntimeModule()\n\n if (loadedLocalesSet.has(newLocale)) {\n // Already loaded, instant switch\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n return\n }\n\n // Async load\n isLoading.value = true\n try {\n const messages = resolveChunkMessages(await options.chunkLoader(newLocale))\n catalogs[newLocale] = { ...catalogs[newLocale], ...messages }\n loadedLocalesSet.add(newLocale)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n } finally {\n isLoading.value = false\n }\n }\n\n function loadMessages(loc: Locale, messages: Messages): void {\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n }\n\n function preloadLocale(loc: string): void {\n if (!lazyLocaleLoading || loadedLocalesSet.has(loc) || !options.chunkLoader) return\n const splitRuntime = getSplitRuntimeModule()\n options.chunkLoader(loc).then(async (loaded) => {\n const messages = resolveChunkMessages(loaded)\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__preloadLocale) {\n await splitRuntime.__preloadLocale(loc)\n }\n }).catch(() => {\n // Silent failure for preload\n })\n }\n\n function getLocales(): Locale[] {\n return Object.keys(catalogs)\n }\n\n function d(value: Date | number, style?: string): string {\n const currentLocale = locale.value\n return formatDate(value, currentLocale, style, options.dateFormats)\n }\n\n function n(value: number, style?: string): string {\n const currentLocale = locale.value\n return formatNumber(value, currentLocale, style, options.numberFormats)\n }\n\n function format(message: string, values?: Record<string, unknown>): string {\n return resolveMessage(message, values, locale.value)\n }\n\n /**\n * Rich text helper for v-t with child elements.\n * Translates the message (which contains `<0>content</0>` placeholders),\n * then replaces each placeholder with the original HTML element.\n * Used via `v-html=\"$vtRich('msg', elements)\"` in compile-time transforms.\n * @internal\n */\n function vtRich(\n message: string | MessageDescriptor,\n elements: Array<{ tag: string; attrs: Record<string, string> }>,\n values?: Record<string, unknown>,\n ): string {\n const translated = values ? t(message, values) : t(message)\n // Escape the entire translated string first to neutralise any injected HTML\n const escaped = escapeHtml(translated)\n // Restore numbered placeholders (now escaped as <0>...</0>) back to real HTML\n return escaped.replace(/<(\\d+)>([\\s\\S]*?)<\\/\\1>/g, (_match, idxStr: string, content: string) => {\n const el = elements[Number(idxStr)]\n if (!el) return content\n const attrs = Object.entries(el.attrs)\n .map(([k, v]) => v ? `${escapeHtml(k)}=\"${escapeHtml(v)}\"` : escapeHtml(k))\n .join(' ')\n const tag = escapeHtml(el.tag)\n return `<${tag}${attrs ? ' ' + attrs : ''}>${content}</${tag}>`\n })\n }\n\n function te(key: string, loc?: string): boolean {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key) !== undefined\n }\n\n function tm(key: string, loc?: string): CompiledMessage | undefined {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key)\n }\n\n const context: FluentVueContext = {\n t,\n locale,\n setLocale,\n loadMessages,\n getLocales,\n d,\n n,\n format,\n isLoading,\n loadedLocales,\n preloadLocale,\n te,\n tm,\n }\n\n return {\n install(app: App) {\n app.provide(FLUENTI_KEY, context)\n const prefix = options.componentPrefix ?? ''\n app.component(`${prefix}Trans`, Trans)\n app.component(`${prefix}Plural`, Plural)\n app.component(`${prefix}Select`, Select)\n app.component(`${prefix}DateTime`, DateTime)\n app.component(`${prefix}NumberFormat`, NumberFormat)\n app.config.globalProperties['$t'] = t\n app.config.globalProperties['$d'] = d\n app.config.globalProperties['$n'] = n\n app.config.globalProperties['$vtRich'] = vtRich\n\n // Runtime v-t directive (fallback when compile-time transform is not used)\n app.directive('t', {\n mounted(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n // v-t.alt, v-t.placeholder, etc. — translate the attribute\n const original = el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n // v-t or v-t:id — translate text content\n const id = binding.arg ?? el.textContent ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n updated(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n const original = el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n const id = binding.arg ?? el.textContent ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n })\n },\n global: context,\n }\n}\n","import type { CompileTimeT } from '@fluenti/core'\n\nexport const t: CompileTimeT = ((..._args: unknown[]) => {\n throw new Error(\n \"[fluenti] `t` imported from '@fluenti/vue' is a compile-time API. \" +\n 'Use it only with the Fluenti build transform inside <script setup> or setup(). ' +\n 'For runtime lookups, use useI18n().t(...).',\n )\n}) as CompileTimeT\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/use-i18n.ts","../src/components/rich-text.ts","../src/components/Trans.ts","../src/components/Plural.ts","../src/components/Select.ts","../src/components/DateTime.ts","../src/components/NumberFormat.ts","../src/plugin.ts","../src/compile-time-t.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { FLUENTI_KEY, type FluentVueContext } from './plugin'\n\n/**\n * Composable that returns the Fluenti i18n context.\n *\n * Must be called inside a component whose ancestor app has installed the\n * `createFluentVue()` plugin.\n *\n * @throws If the plugin has not been installed\n */\nexport function useI18n(): FluentVueContext {\n const ctx = inject(FLUENTI_KEY)\n if (!ctx) {\n throw new Error('[fluenti] useI18n() requires createFluentVue plugin')\n }\n return ctx\n}\n","import { Comment, Text, h, isVNode, type VNode, type VNodeChild } from 'vue'\n\nexport function offsetIndices(message: string, offset: number): string {\n if (offset === 0) return message\n return message\n .replace(/<(\\d+)(\\/?>)/g, (_match, index: string, suffix: string) => `<${Number(index) + offset}${suffix}`)\n .replace(/<\\/(\\d+)>/g, (_match, index: string) => `</${Number(index) + offset}>`)\n}\n\nexport function extractMessage(children: VNodeChild | VNodeChild[] | undefined): {\n message: string\n components: VNode[]\n} {\n const components: VNode[] = []\n let message = ''\n\n function visit(node: VNodeChild | VNodeChild[] | undefined): void {\n if (node === null || node === undefined || typeof node === 'boolean') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n if (typeof node === 'string' || typeof node === 'number') {\n message += String(node)\n return\n }\n if (!isVNode(node) || node.type === Comment) return\n if (node.type === Text) {\n message += typeof node.children === 'string' ? node.children : ''\n return\n }\n\n const idx = components.length\n const inner = extractMessage(node.children as VNodeChild | VNodeChild[] | undefined)\n components.push(node)\n components.push(...inner.components)\n message += `<${idx}>${offsetIndices(inner.message, idx + 1)}</${idx}>`\n }\n\n visit(children)\n return { message, components }\n}\n\nexport function reconstruct(\n translated: string,\n components: VNode[],\n): VNodeChild {\n const tagRe = /<(\\d+)>([\\s\\S]*?)<\\/\\1>/g\n const result: VNodeChild[] = []\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n tagRe.lastIndex = 0\n match = tagRe.exec(translated)\n while (match !== null) {\n if (match.index > lastIndex) {\n result.push(translated.slice(lastIndex, match.index))\n }\n\n const idx = Number(match[1])\n const component = components[idx]\n const innerContent = reconstruct(match[2]!, components)\n if (component) {\n result.push(h(component.type as never, component.props ?? {}, Array.isArray(innerContent) ? innerContent : [innerContent]))\n } else {\n result.push(match[2]!)\n }\n\n lastIndex = tagRe.lastIndex\n match = tagRe.exec(translated)\n }\n\n if (lastIndex < translated.length) {\n result.push(translated.slice(lastIndex))\n }\n\n return result.length <= 1 ? (result[0] ?? '') : result\n}\n\nexport function serializeRichForms<T extends string>(\n keys: readonly T[],\n forms: Partial<Record<T, VNodeChild>> & Record<string, VNodeChild | undefined>,\n): {\n messages: Record<string, string>\n components: VNode[]\n} {\n const messages: Record<string, string> = {}\n const components: VNode[] = []\n\n for (const key of keys) {\n const value = forms[key]\n if (value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n for (const [key, value] of Object.entries(forms)) {\n if (keys.includes(key as T) || value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n return { messages, components }\n}\n\nexport function buildICUSelectMessage(forms: Record<string, string>): string {\n return `{value, select, ${Object.entries(forms).map(([key, text]) => `${key} {${text}}`).join(' ')}}`\n}\n\nexport function normalizeSelectForms(forms: Record<string, string>): {\n forms: Record<string, string>\n valueMap: Record<string, string>\n} {\n const normalized: Record<string, string> = {}\n const valueMap: Record<string, string> = {}\n let index = 0\n\n for (const [key, text] of Object.entries(forms)) {\n if (key === 'other') {\n normalized['other'] = text\n continue\n }\n\n const safeKey = /^[A-Za-z0-9_]+$/.test(key) ? key : `case_${index++}`\n normalized[safeKey] = text\n valueMap[key] = safeKey\n }\n\n if (normalized['other'] === undefined) {\n normalized['other'] = ''\n }\n\n return { forms: normalized, valueMap }\n}\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\nimport { extractMessage, reconstruct } from './rich-text'\n\n/**\n * `<Trans>` component for rich text with Vue components.\n *\n * @example\n * ```vue\n * <Trans>\n * Visit our <a href=\"/docs\">documentation</a> to learn more.\n * </Trans>\n * ```\n *\n * @example\n * ```vue\n * <Trans>\n * Click <RouterLink to=\"/next\">here</RouterLink> to continue.\n * </Trans>\n * ```\n */\nconst transProps = {\n /** Override auto-generated hash ID */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type TransProps = Readonly<ExtractPropTypes<typeof transProps>>\n\nexport const Trans = defineComponent({\n name: 'Trans',\n props: transProps,\n setup(props, { slots }) {\n const { t } = useI18n()\n\n return () => {\n const defaultSlot = slots['default']?.()\n if (!defaultSlot) return null\n const { message, components } = extractMessage(defaultSlot)\n const translated = t({\n ...(props.id !== undefined ? { id: props.id } : {}),\n message,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n })\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n if (Array.isArray(result)) {\n return result.length === 1 ? result[0]! : h(props.tag, null, result)\n }\n return result\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { reconstruct, serializeRichForms } from './rich-text'\n\n/** Plural category names in a stable order for ICU message building. */\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n\ntype PluralCategory = (typeof PLURAL_CATEGORIES)[number]\n\n/**\n * Build an ICU plural message string from individual category props.\n *\n * Given `{ zero: \"No items\", one: \"# item\", other: \"# items\" }`,\n * produces `\"{count, plural, =0 {No items} one {# item} other {# items}}\"`.\n *\n * @internal\n */\nfunction buildICUPluralMessage(\n forms: Partial<Record<PluralCategory, string>> & { other: string },\n offset?: number,\n): string {\n const parts: string[] = []\n for (const cat of PLURAL_CATEGORIES) {\n const text = forms[cat]\n if (text !== undefined) {\n // Map the `zero` prop to ICU `=0` exact match. In ICU MessageFormat,\n // `zero` is a CLDR plural category that only activates in languages\n // with a grammatical zero form (e.g. Arabic). The `=0` exact match\n // works universally for the common \"show this when count is 0\" intent.\n const key = cat === 'zero' ? '=0' : cat\n parts.push(`${key} {${text}}`)\n }\n }\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{count, plural, ${offsetPrefix}${parts.join(' ')}}`\n}\n\n/**\n * `<Plural>` component — shorthand for ICU plural patterns.\n *\n * Plural form props (`zero`, `one`, `two`, `few`, `many`, `other`) are treated\n * as source-language messages. The component builds an ICU plural message,\n * looks it up via `t()` in the catalog, and interpolates the translated result.\n *\n * When no catalog translation exists, the component falls back to interpolating\n * the source-language ICU message directly via the `message` field of the\n * MessageDescriptor.\n *\n * Rich text is supported via named slots:\n * ```vue\n * <Plural :value=\"count\">\n * <template #zero>No <strong>items</strong></template>\n * <template #one><em>1</em> item</template>\n * <template #other><strong>{{ count }}</strong> items</template>\n * </Plural>\n * ```\n *\n * String props still work (backward compatible):\n * ```vue\n * <Plural :value=\"count\" zero=\"No items\" one=\"# item\" other=\"# items\" />\n * ```\n */\nconst pluralProps = {\n /** The numeric value to pluralise on */\n value: { type: Number, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Text for zero items (maps to `=0`) */\n zero: String,\n /** Text for singular (maps to `one`) */\n one: String,\n /** Text for dual (maps to `two`) */\n two: String,\n /** Text for few (maps to `few`) */\n few: String,\n /** Text for many (maps to `many`) */\n many: String,\n /** Text for the default/other category */\n other: { type: String, default: undefined },\n /** Offset from value before selecting form */\n offset: Number,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type PluralProps = Readonly<ExtractPropTypes<typeof pluralProps>>\n\nexport const Plural = defineComponent({\n name: 'Plural',\n props: pluralProps,\n setup(props, { slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Partial<Record<PluralCategory, VNodeChild>> & Record<string, VNodeChild | undefined> = {\n zero: props.zero,\n one: props.one,\n two: props.two,\n few: props.few,\n many: props.many,\n other: props.other ?? '',\n }\n\n for (const cat of PLURAL_CATEGORIES) {\n const slot = slots[cat]\n if (slot) {\n forms[cat] = slot({ count: '#' })\n }\n }\n\n const { messages, components } = serializeRichForms(PLURAL_CATEGORIES, forms)\n const icuMessage = buildICUPluralMessage(\n {\n ...(messages['zero'] !== undefined && { zero: messages['zero'] }),\n ...(messages['one'] !== undefined && { one: messages['one'] }),\n ...(messages['two'] !== undefined && { two: messages['two'] }),\n ...(messages['few'] !== undefined && { few: messages['few'] }),\n ...(messages['many'] !== undefined && { many: messages['many'] }),\n other: messages['other'] ?? '',\n },\n props.offset,\n )\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { count: props.value },\n )\n\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { buildICUSelectMessage, normalizeSelectForms, reconstruct, serializeRichForms } from './rich-text'\n\n/**\n * `<Select>` component — shorthand for ICU select patterns.\n *\n * Accepts a `value` string that selects among named options. Options can be\n * provided via the type-safe `options` prop (recommended), as direct attrs\n * (convenience), or as named slots (rich text).\n *\n * Falls back to `other` when no match is found.\n *\n * @example Type-safe usage (recommended):\n * ```vue\n * <Select\n * :value=\"gender\"\n * :options=\"{ male: 'He liked it', female: 'She liked it' }\"\n * other=\"They liked it\"\n * />\n * ```\n *\n * @example Rich text via named slots:\n * ```vue\n * <Select :value=\"gender\">\n * <template #male><strong>He</strong> liked this</template>\n * <template #female><strong>She</strong> liked this</template>\n * <template #other><em>They</em> liked this</template>\n * </Select>\n * ```\n */\nconst selectProps = {\n /** The value to select on (e.g. `\"male\"`, `\"female\"`) */\n value: { type: String, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Fallback text when no option matches `value` */\n other: { type: String, default: undefined },\n /**\n * Named options map. Keys are match values, values are display strings.\n * Takes precedence over attrs when both are provided.\n *\n * @example `{ male: 'He', female: 'She' }`\n */\n options: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type SelectProps = Readonly<ExtractPropTypes<typeof selectProps>>\n\nexport const Select = defineComponent({\n name: 'Select',\n inheritAttrs: false,\n props: selectProps,\n setup(props, { attrs, slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Record<string, VNodeChild | undefined> = {}\n\n if (props.options !== undefined) {\n for (const [key, value] of Object.entries(props.options)) {\n forms[key] = value\n }\n forms['other'] = props.other ?? ''\n } else {\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'string') {\n forms[key] = value\n }\n }\n forms['other'] = props.other ?? ''\n }\n\n for (const [key, slot] of Object.entries(slots)) {\n if (key === 'default' || !slot) continue\n forms[key] = slot({ value: '{value}' })\n }\n\n const orderedKeys = [...Object.keys(forms).filter(key => key !== 'other'), 'other'] as const\n const { messages, components } = serializeRichForms(orderedKeys, forms)\n const normalized = normalizeSelectForms(\n Object.fromEntries(\n [...orderedKeys].map((key) => [key, messages[key] ?? '']),\n ),\n )\n const icuMessage = buildICUSelectMessage(normalized.forms)\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { value: normalized.valueMap[props.value] ?? 'other' },\n )\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<DateTime>` component for formatting dates according to locale.\n *\n * @example\n * ```vue\n * <DateTime :value=\"new Date()\" />\n * <DateTime :value=\"Date.now()\" style=\"short\" />\n * <DateTime :value=\"event.date\" style=\"long\" tag=\"time\" />\n * ```\n */\nconst dateTimeProps = {\n value: { type: [Date, Number] as PropType<Date | number>, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type DateTimeProps = Readonly<ExtractPropTypes<typeof dateTimeProps>>\n\nexport const DateTime = defineComponent({\n name: 'DateTime',\n props: dateTimeProps,\n setup(props) {\n const { d } = useI18n()\n return () => h(props.tag, d(props.value as Date | number, props.style))\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<NumberFormat>` component for formatting numbers according to locale.\n *\n * @example\n * ```vue\n * <NumberFormat :value=\"1234.56\" />\n * <NumberFormat :value=\"0.75\" style=\"percent\" />\n * <NumberFormat :value=\"99.99\" style=\"currency\" tag=\"strong\" />\n * ```\n */\nconst numberFormatProps = {\n value: { type: Number, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type NumberFormatProps = Readonly<ExtractPropTypes<typeof numberFormatProps>>\n\nexport const NumberFormat = defineComponent({\n name: 'NumberFormat',\n props: numberFormatProps,\n setup(props) {\n const { n } = useI18n()\n return () => h(props.tag, n(props.value, props.style))\n },\n})\n","import { type App, type InjectionKey, type Ref, ref, shallowReactive } from 'vue'\nimport type { AllMessages, Locale, Messages, CompiledMessage, MessageDescriptor } from '@fluenti/core'\nimport { interpolate, formatDate, formatNumber, buildICUMessage, resolveDescriptorId } from '@fluenti/core'\nimport { Trans } from './components/Trans'\nimport { Plural } from './components/Plural'\nimport { Select } from './components/Select'\nimport { DateTime } from './components/DateTime'\nimport { NumberFormat } from './components/NumberFormat'\n\n/** Escape HTML special characters to prevent XSS. @internal */\nfunction escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(/\"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Compiled message chunk loader for lazy locale loading */\nexport type ChunkLoader = (\n locale: string,\n) => Promise<Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> }>\n\ninterface SplitRuntimeModule {\n __switchLocale?: (locale: string) => Promise<void>\n __preloadLocale?: (locale: string) => Promise<void>\n}\n\nconst SPLIT_RUNTIME_KEY = Symbol.for('fluenti.runtime.vue')\n\nfunction getSplitRuntimeModule(): SplitRuntimeModule | null {\n const runtime = (globalThis as Record<PropertyKey, unknown>)[SPLIT_RUNTIME_KEY]\n return typeof runtime === 'object' && runtime !== null\n ? runtime as SplitRuntimeModule\n : null\n}\n\nfunction resolveChunkMessages(\n loaded: Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> },\n): Record<string, CompiledMessage> {\n return typeof loaded === 'object' && loaded !== null && 'default' in loaded\n ? (loaded as { default: Record<string, CompiledMessage> }).default\n : loaded\n}\n\n/** Context object returned by `useI18n()` and available as `$t` etc. on globalProperties */\nexport interface FluentVueContext {\n /** Translate a message by id or MessageDescriptor, with optional interpolation values */\n t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n /** Tagged template form: t`Hello ${name}` */\n t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n /** Reactive ref for current locale */\n locale: Readonly<Ref<Locale>>\n /** Change the active locale (async when lazy locale loading is enabled) */\n setLocale(locale: Locale): Promise<void>\n /** Dynamically load messages for a locale */\n loadMessages(locale: Locale, messages: Messages): void\n /** Get all locales that have loaded messages */\n getLocales(): Locale[]\n /** Format a date value according to locale */\n d(value: Date | number, style?: string): string\n /** Format a number according to locale */\n n(value: number, style?: string): string\n /** Format an ICU message string directly (no catalog lookup) */\n format(message: string, values?: Record<string, unknown>): string\n /** Whether a locale chunk is currently being loaded */\n isLoading: Readonly<Ref<boolean>>\n /** Set of locales whose messages have been loaded */\n loadedLocales: Readonly<Ref<ReadonlySet<string>>>\n /** Preload a locale in the background without switching to it */\n preloadLocale(locale: string): void\n /** Check if a translation key exists in the catalog */\n te(key: string, locale?: string): boolean\n /** Get the raw compiled message without interpolation */\n tm(key: string, locale?: string): CompiledMessage | undefined\n}\n\n/** Injection key for providing/injecting fluenti context */\nexport const FLUENTI_KEY: InjectionKey<FluentVueContext> = Symbol('fluenti')\n\n/** Options for creating the FluentVue plugin */\nexport interface FluentVueOptions {\n locale: string\n fallbackLocale?: string\n messages: AllMessages\n missing?: (locale: string, id: string) => string | undefined\n dateFormats?: Record<string, Intl.DateTimeFormatOptions | 'relative'>\n numberFormats?: Record<string, Intl.NumberFormatOptions | ((locale: string) => Intl.NumberFormatOptions)>\n fallbackChain?: Record<string, string[]>\n /** Async chunk loader for lazy locale loading */\n chunkLoader?: ChunkLoader\n /** Enable lazy locale loading through chunkLoader */\n lazyLocaleLoading?: boolean\n /**\n * Prefix for globally registered components (Trans, Plural, Select).\n *\n * Set this to avoid naming conflicts with other libraries.\n *\n * @example\n * componentPrefix: 'I18n'\n * // Registers: I18nTrans, I18nPlural, I18nSelect\n *\n * @example\n * componentPrefix: 'Fluenti'\n * // Registers: FluentiTrans, FluentiPlural, FluentiSelect\n *\n * @default '' (no prefix — Trans, Plural, Select)\n */\n componentPrefix?: string\n}\n\n/** Return value of `createFluentVue()` */\nexport interface FluentVuePlugin {\n /** Vue plugin install method */\n install(app: App): void\n /** The global fluenti context (same as what useI18n returns) */\n global: FluentVueContext\n}\n\n/**\n * Resolve a compiled message to a string, applying values if needed.\n * @internal\n */\nfunction resolveMessage(\n compiled: CompiledMessage,\n values?: Record<string, unknown>,\n locale?: string,\n): string {\n if (typeof compiled === 'function') {\n return compiled(values)\n }\n // Use core interpolate for ICU message parsing (handles plural, select, etc.)\n return interpolate(compiled, values, locale)\n}\n\n/** Extract the attribute name from v-t modifiers (e.g., v-t.alt → 'alt') */\nfunction getModifierAttr(modifiers: Partial<Record<string, boolean>>): string | undefined {\n const keys = Object.keys(modifiers).filter((k) => k !== 'plural')\n return keys.length > 0 ? keys[0] : undefined\n}\n\n/**\n * Create a Fluenti Vue plugin (SSR-safe, per-request instance).\n *\n * Each invocation creates entirely fresh state — no module-level singletons —\n * so it is safe to call once per SSR request.\n */\nexport function createFluentVue(options: FluentVueOptions): FluentVuePlugin {\n const lazyLocaleLoading = options.lazyLocaleLoading\n ?? (options as FluentVueOptions & { splitting?: boolean }).splitting\n ?? false\n const locale = ref(options.locale)\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n const catalogs = shallowReactive<AllMessages>({ ...options.messages })\n const isLoading = ref(false)\n const loadedLocalesSet = new Set<string>([options.locale])\n const loadedLocales = ref<ReadonlySet<string>>(new Set(loadedLocalesSet))\n\n function lookup(\n loc: Locale,\n id: string,\n ): CompiledMessage | undefined {\n const msgs = catalogs[loc]\n if (!msgs) return undefined\n return msgs[id]\n }\n\n function t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n function t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n function t(idOrStrings: string | MessageDescriptor | TemplateStringsArray, ...rest: unknown[]): string {\n // Tagged template form: t`Hello ${name}`\n if (Array.isArray(idOrStrings) && 'raw' in idOrStrings) {\n const strings = idOrStrings as TemplateStringsArray\n const icu = buildICUMessage(strings, rest)\n const values = Object.fromEntries(rest.map((v, i) => [String(i), v]))\n // Delegate to the function-call path with the ICU string as the id\n return t(icu, values)\n }\n\n // Function call form\n const id = idOrStrings as string | MessageDescriptor\n const values = rest[0] as Record<string, unknown> | undefined\n\n // Handle MessageDescriptor objects (from msg``)\n let messageId: string\n let fallbackMessage: string | undefined\n if (typeof id === 'object' && id !== null) {\n messageId = resolveDescriptorId(id) ?? ''\n fallbackMessage = id.message\n } else {\n messageId = id\n }\n\n // Read locale.value to register a Vue reactive dependency\n const currentLocale = locale.value\n\n // Build the chain of locales to try\n const chain: Locale[] = [currentLocale]\n\n if (options.fallbackLocale && !chain.includes(options.fallbackLocale)) {\n chain.push(options.fallbackLocale)\n }\n\n if (options.fallbackChain?.[currentLocale]) {\n for (const fallback of options.fallbackChain[currentLocale]) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n } else if (options.fallbackChain?.['*']) {\n for (const fallback of options.fallbackChain['*']) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n }\n\n for (const loc of chain) {\n const compiled = lookup(loc, messageId)\n if (compiled !== undefined) {\n return resolveMessage(compiled, values, loc)\n }\n }\n\n // Try the missing handler\n if (options.missing) {\n const result = options.missing(currentLocale, messageId)\n if (result !== undefined) return result\n }\n\n // If we have a fallback message from a MessageDescriptor, interpolate it\n if (fallbackMessage) {\n return interpolate(fallbackMessage, values, currentLocale)\n }\n\n // Final fallback — if the id looks like an ICU message, interpolate it\n // (compile-time transforms like <Plural> emit inline ICU as t() arguments)\n if (messageId.includes('{')) {\n return interpolate(messageId, values, currentLocale)\n }\n return messageId\n }\n\n async function setLocale(newLocale: Locale): Promise<void> {\n if (!lazyLocaleLoading || !options.chunkLoader) {\n locale.value = newLocale\n return\n }\n\n const splitRuntime = getSplitRuntimeModule()\n\n if (loadedLocalesSet.has(newLocale)) {\n // Already loaded, instant switch\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n return\n }\n\n // Async load\n isLoading.value = true\n try {\n const messages = resolveChunkMessages(await options.chunkLoader(newLocale))\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[newLocale] = { ...catalogs[newLocale], ...messages }\n loadedLocalesSet.add(newLocale)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n } finally {\n isLoading.value = false\n }\n }\n\n function loadMessages(loc: Locale, messages: Messages): void {\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n }\n\n function preloadLocale(loc: string): void {\n if (!lazyLocaleLoading || loadedLocalesSet.has(loc) || !options.chunkLoader) return\n const splitRuntime = getSplitRuntimeModule()\n options.chunkLoader(loc).then(async (loaded) => {\n const messages = resolveChunkMessages(loaded)\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__preloadLocale) {\n await splitRuntime.__preloadLocale(loc)\n }\n }).catch((e: unknown) => {\n console.warn('[fluenti] preload failed:', loc, e)\n })\n }\n\n function getLocales(): Locale[] {\n return Object.keys(catalogs)\n }\n\n function d(value: Date | number, style?: string): string {\n const currentLocale = locale.value\n return formatDate(value, currentLocale, style, options.dateFormats)\n }\n\n function n(value: number, style?: string): string {\n const currentLocale = locale.value\n return formatNumber(value, currentLocale, style, options.numberFormats)\n }\n\n function format(message: string, values?: Record<string, unknown>): string {\n return resolveMessage(message, values, locale.value)\n }\n\n /**\n * Rich text helper for v-t with child elements.\n * Translates the message (which contains `<0>content</0>` placeholders),\n * then replaces each placeholder with the original HTML element.\n * Used via `v-html=\"$vtRich('msg', elements)\"` in compile-time transforms.\n * @internal\n */\n function vtRich(\n message: string | MessageDescriptor,\n elements: Array<{ tag: string; attrs: Record<string, string> }>,\n values?: Record<string, unknown>,\n ): string {\n const translated = values ? t(message, values) : t(message)\n // Escape the entire translated string first to neutralise any injected HTML\n const escaped = escapeHtml(translated)\n // Restore numbered placeholders (now escaped as <0>...</0>) back to real HTML\n return escaped.replace(/<(\\d+)>([\\s\\S]*?)<\\/\\1>/g, (_match, idxStr: string, content: string) => {\n const el = elements[Number(idxStr)]\n if (!el) return content\n const attrs = Object.entries(el.attrs)\n .map(([k, v]) => v ? `${escapeHtml(k)}=\"${escapeHtml(v)}\"` : escapeHtml(k))\n .join(' ')\n const tag = escapeHtml(el.tag)\n return `<${tag}${attrs ? ' ' + attrs : ''}>${content}</${tag}>`\n })\n }\n\n function te(key: string, loc?: string): boolean {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key) !== undefined\n }\n\n function tm(key: string, loc?: string): CompiledMessage | undefined {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key)\n }\n\n const context: FluentVueContext = {\n t,\n locale,\n setLocale,\n loadMessages,\n getLocales,\n d,\n n,\n format,\n isLoading,\n loadedLocales,\n preloadLocale,\n te,\n tm,\n }\n\n return {\n install(app: App) {\n app.provide(FLUENTI_KEY, context)\n const prefix = options.componentPrefix ?? ''\n app.component(`${prefix}Trans`, Trans)\n app.component(`${prefix}Plural`, Plural)\n app.component(`${prefix}Select`, Select)\n app.component(`${prefix}DateTime`, DateTime)\n app.component(`${prefix}NumberFormat`, NumberFormat)\n app.config.globalProperties['$t'] = t\n app.config.globalProperties['$d'] = d\n app.config.globalProperties['$n'] = n\n app.config.globalProperties['$vtRich'] = vtRich\n\n // Runtime v-t directive (fallback when compile-time transform is not used)\n const vtOriginalIds = new WeakMap<HTMLElement, string>()\n app.directive('t', {\n mounted(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n // v-t.alt, v-t.placeholder, etc. — translate the attribute\n const original = el.getAttribute(attrName) ?? ''\n vtOriginalIds.set(el, original)\n el.setAttribute(attrName, t(original))\n } else {\n // v-t or v-t:id — translate text content\n const id = binding.arg ?? el.textContent ?? ''\n vtOriginalIds.set(el, id.trim())\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n updated(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n const original = vtOriginalIds.get(el) ?? el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n const id = binding.arg ?? vtOriginalIds.get(el) ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n })\n },\n global: context,\n }\n}\n","import type { CompileTimeT } from '@fluenti/core'\n\nexport const t: CompileTimeT = ((..._args: unknown[]) => {\n throw new Error(\n \"[fluenti] `t` imported from '@fluenti/vue' is a compile-time API. \" +\n 'Use it only with the Fluenti build transform inside <script setup> or setup(). ' +\n 'For runtime lookups, use useI18n().t(...).',\n )\n}) as CompileTimeT\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -347,7 +347,9 @@ function I(e) {
|
|
|
347
347
|
...r[n],
|
|
348
348
|
...t
|
|
349
349
|
}, a.add(n), d.value = new Set(a), i?.__preloadLocale && await i.__preloadLocale(n);
|
|
350
|
-
}).catch(() => {
|
|
350
|
+
}).catch((e) => {
|
|
351
|
+
console.warn("[fluenti] preload failed:", n, e);
|
|
352
|
+
});
|
|
351
353
|
}
|
|
352
354
|
function y() {
|
|
353
355
|
return Object.keys(r);
|
|
@@ -396,20 +398,25 @@ function I(e) {
|
|
|
396
398
|
install(t) {
|
|
397
399
|
t.provide(N, L);
|
|
398
400
|
let n = e.componentPrefix ?? "";
|
|
399
|
-
t.component(`${n}Trans`, S), t.component(`${n}Plural`, T), t.component(`${n}Select`, E), t.component(`${n}DateTime`, D), t.component(`${n}NumberFormat`, O), t.config.globalProperties.$t = h, t.config.globalProperties.$d = b, t.config.globalProperties.$n = x, t.config.globalProperties.$vtRich = w
|
|
401
|
+
t.component(`${n}Trans`, S), t.component(`${n}Plural`, T), t.component(`${n}Select`, E), t.component(`${n}DateTime`, D), t.component(`${n}NumberFormat`, O), t.config.globalProperties.$t = h, t.config.globalProperties.$d = b, t.config.globalProperties.$n = x, t.config.globalProperties.$vtRich = w;
|
|
402
|
+
let r = /* @__PURE__ */ new WeakMap();
|
|
403
|
+
t.directive("t", {
|
|
400
404
|
mounted(e, t) {
|
|
401
405
|
let n = F(t.modifiers);
|
|
402
406
|
if (n) {
|
|
403
407
|
let t = e.getAttribute(n) ?? "";
|
|
404
|
-
e.setAttribute(n, h(t));
|
|
405
|
-
} else
|
|
408
|
+
r.set(e, t), e.setAttribute(n, h(t));
|
|
409
|
+
} else {
|
|
410
|
+
let n = t.arg ?? e.textContent ?? "";
|
|
411
|
+
r.set(e, n.trim()), e.textContent = h(n.trim(), t.value == null ? void 0 : { ...t.value });
|
|
412
|
+
}
|
|
406
413
|
},
|
|
407
414
|
updated(e, t) {
|
|
408
415
|
let n = F(t.modifiers);
|
|
409
416
|
if (n) {
|
|
410
|
-
let t = e.getAttribute(n) ?? "";
|
|
417
|
+
let t = r.get(e) ?? e.getAttribute(n) ?? "";
|
|
411
418
|
e.setAttribute(n, h(t));
|
|
412
|
-
} else e.textContent = h((t.arg ?? e
|
|
419
|
+
} else e.textContent = h((t.arg ?? r.get(e) ?? "").trim(), t.value == null ? void 0 : { ...t.value });
|
|
413
420
|
}
|
|
414
421
|
});
|
|
415
422
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/use-i18n.ts","../src/components/rich-text.ts","../src/components/Trans.ts","../src/components/Plural.ts","../src/components/Select.ts","../src/components/DateTime.ts","../src/components/NumberFormat.ts","../src/plugin.ts","../src/compile-time-t.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { FLUENTI_KEY, type FluentVueContext } from './plugin'\n\n/**\n * Composable that returns the Fluenti i18n context.\n *\n * Must be called inside a component whose ancestor app has installed the\n * `createFluentVue()` plugin.\n *\n * @throws If the plugin has not been installed\n */\nexport function useI18n(): FluentVueContext {\n const ctx = inject(FLUENTI_KEY)\n if (!ctx) {\n throw new Error('[fluenti] useI18n() requires createFluentVue plugin')\n }\n return ctx\n}\n","import { Comment, Text, h, isVNode, type VNode, type VNodeChild } from 'vue'\n\nexport function offsetIndices(message: string, offset: number): string {\n if (offset === 0) return message\n return message\n .replace(/<(\\d+)(\\/?>)/g, (_match, index: string, suffix: string) => `<${Number(index) + offset}${suffix}`)\n .replace(/<\\/(\\d+)>/g, (_match, index: string) => `</${Number(index) + offset}>`)\n}\n\nexport function extractMessage(children: VNodeChild | VNodeChild[] | undefined): {\n message: string\n components: VNode[]\n} {\n const components: VNode[] = []\n let message = ''\n\n function visit(node: VNodeChild | VNodeChild[] | undefined): void {\n if (node === null || node === undefined || typeof node === 'boolean') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n if (typeof node === 'string' || typeof node === 'number') {\n message += String(node)\n return\n }\n if (!isVNode(node) || node.type === Comment) return\n if (node.type === Text) {\n message += typeof node.children === 'string' ? node.children : ''\n return\n }\n\n const idx = components.length\n const inner = extractMessage(node.children as VNodeChild | VNodeChild[] | undefined)\n components.push(node)\n components.push(...inner.components)\n message += `<${idx}>${offsetIndices(inner.message, idx + 1)}</${idx}>`\n }\n\n visit(children)\n return { message, components }\n}\n\nexport function reconstruct(\n translated: string,\n components: VNode[],\n): VNodeChild {\n const tagRe = /<(\\d+)>([\\s\\S]*?)<\\/\\1>/g\n const result: VNodeChild[] = []\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n tagRe.lastIndex = 0\n match = tagRe.exec(translated)\n while (match !== null) {\n if (match.index > lastIndex) {\n result.push(translated.slice(lastIndex, match.index))\n }\n\n const idx = Number(match[1])\n const component = components[idx]\n const innerContent = reconstruct(match[2]!, components)\n if (component) {\n result.push(h(component.type as never, component.props ?? {}, Array.isArray(innerContent) ? innerContent : [innerContent]))\n } else {\n result.push(match[2]!)\n }\n\n lastIndex = tagRe.lastIndex\n match = tagRe.exec(translated)\n }\n\n if (lastIndex < translated.length) {\n result.push(translated.slice(lastIndex))\n }\n\n return result.length <= 1 ? (result[0] ?? '') : result\n}\n\nexport function serializeRichForms<T extends string>(\n keys: readonly T[],\n forms: Partial<Record<T, VNodeChild>> & Record<string, VNodeChild | undefined>,\n): {\n messages: Record<string, string>\n components: VNode[]\n} {\n const messages: Record<string, string> = {}\n const components: VNode[] = []\n\n for (const key of keys) {\n const value = forms[key]\n if (value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n for (const [key, value] of Object.entries(forms)) {\n if (keys.includes(key as T) || value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n return { messages, components }\n}\n\nexport function buildICUSelectMessage(forms: Record<string, string>): string {\n return `{value, select, ${Object.entries(forms).map(([key, text]) => `${key} {${text}}`).join(' ')}}`\n}\n\nexport function normalizeSelectForms(forms: Record<string, string>): {\n forms: Record<string, string>\n valueMap: Record<string, string>\n} {\n const normalized: Record<string, string> = {}\n const valueMap: Record<string, string> = {}\n let index = 0\n\n for (const [key, text] of Object.entries(forms)) {\n if (key === 'other') {\n normalized['other'] = text\n continue\n }\n\n const safeKey = /^[A-Za-z0-9_]+$/.test(key) ? key : `case_${index++}`\n normalized[safeKey] = text\n valueMap[key] = safeKey\n }\n\n if (normalized['other'] === undefined) {\n normalized['other'] = ''\n }\n\n return { forms: normalized, valueMap }\n}\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\nimport { extractMessage, reconstruct } from './rich-text'\n\n/**\n * `<Trans>` component for rich text with Vue components.\n *\n * @example\n * ```vue\n * <Trans>\n * Visit our <a href=\"/docs\">documentation</a> to learn more.\n * </Trans>\n * ```\n *\n * @example\n * ```vue\n * <Trans>\n * Click <RouterLink to=\"/next\">here</RouterLink> to continue.\n * </Trans>\n * ```\n */\nconst transProps = {\n /** Override auto-generated hash ID */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type TransProps = Readonly<ExtractPropTypes<typeof transProps>>\n\nexport const Trans = defineComponent({\n name: 'Trans',\n props: transProps,\n setup(props, { slots }) {\n const { t } = useI18n()\n\n return () => {\n const defaultSlot = slots['default']?.()\n if (!defaultSlot) return null\n const { message, components } = extractMessage(defaultSlot)\n const translated = t({\n ...(props.id !== undefined ? { id: props.id } : {}),\n message,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n })\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n if (Array.isArray(result)) {\n return result.length === 1 ? result[0]! : h(props.tag, null, result)\n }\n return result\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { reconstruct, serializeRichForms } from './rich-text'\n\n/** Plural category names in a stable order for ICU message building. */\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n\ntype PluralCategory = (typeof PLURAL_CATEGORIES)[number]\n\n/**\n * Build an ICU plural message string from individual category props.\n *\n * Given `{ zero: \"No items\", one: \"# item\", other: \"# items\" }`,\n * produces `\"{count, plural, =0 {No items} one {# item} other {# items}}\"`.\n *\n * @internal\n */\nfunction buildICUPluralMessage(\n forms: Partial<Record<PluralCategory, string>> & { other: string },\n offset?: number,\n): string {\n const parts: string[] = []\n for (const cat of PLURAL_CATEGORIES) {\n const text = forms[cat]\n if (text !== undefined) {\n // Map the `zero` prop to ICU `=0` exact match. In ICU MessageFormat,\n // `zero` is a CLDR plural category that only activates in languages\n // with a grammatical zero form (e.g. Arabic). The `=0` exact match\n // works universally for the common \"show this when count is 0\" intent.\n const key = cat === 'zero' ? '=0' : cat\n parts.push(`${key} {${text}}`)\n }\n }\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{count, plural, ${offsetPrefix}${parts.join(' ')}}`\n}\n\n/**\n * `<Plural>` component — shorthand for ICU plural patterns.\n *\n * Plural form props (`zero`, `one`, `two`, `few`, `many`, `other`) are treated\n * as source-language messages. The component builds an ICU plural message,\n * looks it up via `t()` in the catalog, and interpolates the translated result.\n *\n * When no catalog translation exists, the component falls back to interpolating\n * the source-language ICU message directly via the `message` field of the\n * MessageDescriptor.\n *\n * Rich text is supported via named slots:\n * ```vue\n * <Plural :value=\"count\">\n * <template #zero>No <strong>items</strong></template>\n * <template #one><em>1</em> item</template>\n * <template #other><strong>{{ count }}</strong> items</template>\n * </Plural>\n * ```\n *\n * String props still work (backward compatible):\n * ```vue\n * <Plural :value=\"count\" zero=\"No items\" one=\"# item\" other=\"# items\" />\n * ```\n */\nconst pluralProps = {\n /** The numeric value to pluralise on */\n value: { type: Number, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Text for zero items (maps to `=0`) */\n zero: String,\n /** Text for singular (maps to `one`) */\n one: String,\n /** Text for dual (maps to `two`) */\n two: String,\n /** Text for few (maps to `few`) */\n few: String,\n /** Text for many (maps to `many`) */\n many: String,\n /** Text for the default/other category */\n other: { type: String, default: undefined },\n /** Offset from value before selecting form */\n offset: Number,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type PluralProps = Readonly<ExtractPropTypes<typeof pluralProps>>\n\nexport const Plural = defineComponent({\n name: 'Plural',\n props: pluralProps,\n setup(props, { slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Partial<Record<PluralCategory, VNodeChild>> & Record<string, VNodeChild | undefined> = {\n zero: props.zero,\n one: props.one,\n two: props.two,\n few: props.few,\n many: props.many,\n other: props.other ?? '',\n }\n\n for (const cat of PLURAL_CATEGORIES) {\n const slot = slots[cat]\n if (slot) {\n forms[cat] = slot({ count: '#' })\n }\n }\n\n const { messages, components } = serializeRichForms(PLURAL_CATEGORIES, forms)\n const icuMessage = buildICUPluralMessage(\n {\n ...(messages['zero'] !== undefined && { zero: messages['zero'] }),\n ...(messages['one'] !== undefined && { one: messages['one'] }),\n ...(messages['two'] !== undefined && { two: messages['two'] }),\n ...(messages['few'] !== undefined && { few: messages['few'] }),\n ...(messages['many'] !== undefined && { many: messages['many'] }),\n other: messages['other'] ?? '',\n },\n props.offset,\n )\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { count: props.value },\n )\n\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { buildICUSelectMessage, normalizeSelectForms, reconstruct, serializeRichForms } from './rich-text'\n\n/**\n * `<Select>` component — shorthand for ICU select patterns.\n *\n * Accepts a `value` string that selects among named options. Options can be\n * provided via the type-safe `options` prop (recommended), as direct attrs\n * (convenience), or as named slots (rich text).\n *\n * Falls back to `other` when no match is found.\n *\n * @example Type-safe usage (recommended):\n * ```vue\n * <Select\n * :value=\"gender\"\n * :options=\"{ male: 'He liked it', female: 'She liked it' }\"\n * other=\"They liked it\"\n * />\n * ```\n *\n * @example Rich text via named slots:\n * ```vue\n * <Select :value=\"gender\">\n * <template #male><strong>He</strong> liked this</template>\n * <template #female><strong>She</strong> liked this</template>\n * <template #other><em>They</em> liked this</template>\n * </Select>\n * ```\n */\nconst selectProps = {\n /** The value to select on (e.g. `\"male\"`, `\"female\"`) */\n value: { type: String, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Fallback text when no option matches `value` */\n other: { type: String, default: undefined },\n /**\n * Named options map. Keys are match values, values are display strings.\n * Takes precedence over attrs when both are provided.\n *\n * @example `{ male: 'He', female: 'She' }`\n */\n options: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type SelectProps = Readonly<ExtractPropTypes<typeof selectProps>>\n\nexport const Select = defineComponent({\n name: 'Select',\n inheritAttrs: false,\n props: selectProps,\n setup(props, { attrs, slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Record<string, VNodeChild | undefined> = {}\n\n if (props.options !== undefined) {\n for (const [key, value] of Object.entries(props.options)) {\n forms[key] = value\n }\n forms['other'] = props.other ?? ''\n } else {\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'string') {\n forms[key] = value\n }\n }\n forms['other'] = props.other ?? ''\n }\n\n for (const [key, slot] of Object.entries(slots)) {\n if (key === 'default' || !slot) continue\n forms[key] = slot({ value: '{value}' })\n }\n\n const orderedKeys = [...Object.keys(forms).filter(key => key !== 'other'), 'other'] as const\n const { messages, components } = serializeRichForms(orderedKeys, forms)\n const normalized = normalizeSelectForms(\n Object.fromEntries(\n [...orderedKeys].map((key) => [key, messages[key] ?? '']),\n ),\n )\n const icuMessage = buildICUSelectMessage(normalized.forms)\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { value: normalized.valueMap[props.value] ?? 'other' },\n )\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<DateTime>` component for formatting dates according to locale.\n *\n * @example\n * ```vue\n * <DateTime :value=\"new Date()\" />\n * <DateTime :value=\"Date.now()\" style=\"short\" />\n * <DateTime :value=\"event.date\" style=\"long\" tag=\"time\" />\n * ```\n */\nconst dateTimeProps = {\n value: { type: [Date, Number] as PropType<Date | number>, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type DateTimeProps = Readonly<ExtractPropTypes<typeof dateTimeProps>>\n\nexport const DateTime = defineComponent({\n name: 'DateTime',\n props: dateTimeProps,\n setup(props) {\n const { d } = useI18n()\n return () => h(props.tag, d(props.value as Date | number, props.style))\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<NumberFormat>` component for formatting numbers according to locale.\n *\n * @example\n * ```vue\n * <NumberFormat :value=\"1234.56\" />\n * <NumberFormat :value=\"0.75\" style=\"percent\" />\n * <NumberFormat :value=\"99.99\" style=\"currency\" tag=\"strong\" />\n * ```\n */\nconst numberFormatProps = {\n value: { type: Number, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type NumberFormatProps = Readonly<ExtractPropTypes<typeof numberFormatProps>>\n\nexport const NumberFormat = defineComponent({\n name: 'NumberFormat',\n props: numberFormatProps,\n setup(props) {\n const { n } = useI18n()\n return () => h(props.tag, n(props.value, props.style))\n },\n})\n","import { type App, type InjectionKey, type Ref, ref, shallowReactive } from 'vue'\nimport type { AllMessages, Locale, Messages, CompiledMessage, MessageDescriptor } from '@fluenti/core'\nimport { interpolate, formatDate, formatNumber, buildICUMessage, resolveDescriptorId } from '@fluenti/core'\nimport { Trans } from './components/Trans'\nimport { Plural } from './components/Plural'\nimport { Select } from './components/Select'\nimport { DateTime } from './components/DateTime'\nimport { NumberFormat } from './components/NumberFormat'\n\n/** Escape HTML special characters to prevent XSS. @internal */\nfunction escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(/\"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Compiled message chunk loader for lazy locale loading */\nexport type ChunkLoader = (\n locale: string,\n) => Promise<Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> }>\n\ninterface SplitRuntimeModule {\n __switchLocale?: (locale: string) => Promise<void>\n __preloadLocale?: (locale: string) => Promise<void>\n}\n\nconst SPLIT_RUNTIME_KEY = Symbol.for('fluenti.runtime.vue')\n\nfunction getSplitRuntimeModule(): SplitRuntimeModule | null {\n const runtime = (globalThis as Record<PropertyKey, unknown>)[SPLIT_RUNTIME_KEY]\n return typeof runtime === 'object' && runtime !== null\n ? runtime as SplitRuntimeModule\n : null\n}\n\nfunction resolveChunkMessages(\n loaded: Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> },\n): Record<string, CompiledMessage> {\n return typeof loaded === 'object' && loaded !== null && 'default' in loaded\n ? (loaded as { default: Record<string, CompiledMessage> }).default\n : loaded\n}\n\n/** Context object returned by `useI18n()` and available as `$t` etc. on globalProperties */\nexport interface FluentVueContext {\n /** Translate a message by id or MessageDescriptor, with optional interpolation values */\n t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n /** Tagged template form: t`Hello ${name}` */\n t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n /** Reactive ref for current locale */\n locale: Readonly<Ref<Locale>>\n /** Change the active locale (async when lazy locale loading is enabled) */\n setLocale(locale: Locale): Promise<void>\n /** Dynamically load messages for a locale */\n loadMessages(locale: Locale, messages: Messages): void\n /** Get all locales that have loaded messages */\n getLocales(): Locale[]\n /** Format a date value according to locale */\n d(value: Date | number, style?: string): string\n /** Format a number according to locale */\n n(value: number, style?: string): string\n /** Format an ICU message string directly (no catalog lookup) */\n format(message: string, values?: Record<string, unknown>): string\n /** Whether a locale chunk is currently being loaded */\n isLoading: Readonly<Ref<boolean>>\n /** Set of locales whose messages have been loaded */\n loadedLocales: Readonly<Ref<ReadonlySet<string>>>\n /** Preload a locale in the background without switching to it */\n preloadLocale(locale: string): void\n /** Check if a translation key exists in the catalog */\n te(key: string, locale?: string): boolean\n /** Get the raw compiled message without interpolation */\n tm(key: string, locale?: string): CompiledMessage | undefined\n}\n\n/** Injection key for providing/injecting fluenti context */\nexport const FLUENTI_KEY: InjectionKey<FluentVueContext> = Symbol('fluenti')\n\n/** Options for creating the FluentVue plugin */\nexport interface FluentVueOptions {\n locale: string\n fallbackLocale?: string\n messages: AllMessages\n missing?: (locale: string, id: string) => string | undefined\n dateFormats?: Record<string, Intl.DateTimeFormatOptions | 'relative'>\n numberFormats?: Record<string, Intl.NumberFormatOptions | ((locale: string) => Intl.NumberFormatOptions)>\n fallbackChain?: Record<string, string[]>\n /** Async chunk loader for lazy locale loading */\n chunkLoader?: ChunkLoader\n /** Enable lazy locale loading through chunkLoader */\n lazyLocaleLoading?: boolean\n /**\n * Prefix for globally registered components (Trans, Plural, Select).\n *\n * Set this to avoid naming conflicts with other libraries.\n *\n * @example\n * componentPrefix: 'I18n'\n * // Registers: I18nTrans, I18nPlural, I18nSelect\n *\n * @example\n * componentPrefix: 'Fluenti'\n * // Registers: FluentiTrans, FluentiPlural, FluentiSelect\n *\n * @default '' (no prefix — Trans, Plural, Select)\n */\n componentPrefix?: string\n}\n\n/** Return value of `createFluentVue()` */\nexport interface FluentVuePlugin {\n /** Vue plugin install method */\n install(app: App): void\n /** The global fluenti context (same as what useI18n returns) */\n global: FluentVueContext\n}\n\n/**\n * Resolve a compiled message to a string, applying values if needed.\n * @internal\n */\nfunction resolveMessage(\n compiled: CompiledMessage,\n values?: Record<string, unknown>,\n locale?: string,\n): string {\n if (typeof compiled === 'function') {\n return compiled(values)\n }\n // Use core interpolate for ICU message parsing (handles plural, select, etc.)\n return interpolate(compiled, values, locale)\n}\n\n/** Extract the attribute name from v-t modifiers (e.g., v-t.alt → 'alt') */\nfunction getModifierAttr(modifiers: Partial<Record<string, boolean>>): string | undefined {\n const keys = Object.keys(modifiers).filter((k) => k !== 'plural')\n return keys.length > 0 ? keys[0] : undefined\n}\n\n/**\n * Create a Fluenti Vue plugin (SSR-safe, per-request instance).\n *\n * Each invocation creates entirely fresh state — no module-level singletons —\n * so it is safe to call once per SSR request.\n */\nexport function createFluentVue(options: FluentVueOptions): FluentVuePlugin {\n const lazyLocaleLoading = options.lazyLocaleLoading\n ?? (options as FluentVueOptions & { splitting?: boolean }).splitting\n ?? false\n const locale = ref(options.locale)\n const catalogs = shallowReactive<AllMessages>({ ...options.messages })\n const isLoading = ref(false)\n const loadedLocalesSet = new Set<string>([options.locale])\n const loadedLocales = ref<ReadonlySet<string>>(new Set(loadedLocalesSet))\n\n function lookup(\n loc: Locale,\n id: string,\n ): CompiledMessage | undefined {\n const msgs = catalogs[loc]\n if (!msgs) return undefined\n return msgs[id]\n }\n\n function t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n function t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n function t(idOrStrings: string | MessageDescriptor | TemplateStringsArray, ...rest: unknown[]): string {\n // Tagged template form: t`Hello ${name}`\n if (Array.isArray(idOrStrings) && 'raw' in idOrStrings) {\n const strings = idOrStrings as TemplateStringsArray\n const icu = buildICUMessage(strings, rest)\n const values = Object.fromEntries(rest.map((v, i) => [String(i), v]))\n // Delegate to the function-call path with the ICU string as the id\n return t(icu, values)\n }\n\n // Function call form\n const id = idOrStrings as string | MessageDescriptor\n const values = rest[0] as Record<string, unknown> | undefined\n\n // Handle MessageDescriptor objects (from msg``)\n let messageId: string\n let fallbackMessage: string | undefined\n if (typeof id === 'object' && id !== null) {\n messageId = resolveDescriptorId(id) ?? ''\n fallbackMessage = id.message\n } else {\n messageId = id\n }\n\n // Read locale.value to register a Vue reactive dependency\n const currentLocale = locale.value\n\n // Build the chain of locales to try\n const chain: Locale[] = [currentLocale]\n\n if (options.fallbackLocale && !chain.includes(options.fallbackLocale)) {\n chain.push(options.fallbackLocale)\n }\n\n if (options.fallbackChain?.[currentLocale]) {\n for (const fallback of options.fallbackChain[currentLocale]) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n } else if (options.fallbackChain?.['*']) {\n for (const fallback of options.fallbackChain['*']) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n }\n\n for (const loc of chain) {\n const compiled = lookup(loc, messageId)\n if (compiled !== undefined) {\n return resolveMessage(compiled, values, loc)\n }\n }\n\n // Try the missing handler\n if (options.missing) {\n const result = options.missing(currentLocale, messageId)\n if (result !== undefined) return result\n }\n\n // If we have a fallback message from a MessageDescriptor, interpolate it\n if (fallbackMessage) {\n return interpolate(fallbackMessage, values, currentLocale)\n }\n\n // Final fallback — if the id looks like an ICU message, interpolate it\n // (compile-time transforms like <Plural> emit inline ICU as t() arguments)\n if (messageId.includes('{')) {\n return interpolate(messageId, values, currentLocale)\n }\n return messageId\n }\n\n async function setLocale(newLocale: Locale): Promise<void> {\n if (!lazyLocaleLoading || !options.chunkLoader) {\n locale.value = newLocale\n return\n }\n\n const splitRuntime = getSplitRuntimeModule()\n\n if (loadedLocalesSet.has(newLocale)) {\n // Already loaded, instant switch\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n return\n }\n\n // Async load\n isLoading.value = true\n try {\n const messages = resolveChunkMessages(await options.chunkLoader(newLocale))\n catalogs[newLocale] = { ...catalogs[newLocale], ...messages }\n loadedLocalesSet.add(newLocale)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n } finally {\n isLoading.value = false\n }\n }\n\n function loadMessages(loc: Locale, messages: Messages): void {\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n }\n\n function preloadLocale(loc: string): void {\n if (!lazyLocaleLoading || loadedLocalesSet.has(loc) || !options.chunkLoader) return\n const splitRuntime = getSplitRuntimeModule()\n options.chunkLoader(loc).then(async (loaded) => {\n const messages = resolveChunkMessages(loaded)\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__preloadLocale) {\n await splitRuntime.__preloadLocale(loc)\n }\n }).catch(() => {\n // Silent failure for preload\n })\n }\n\n function getLocales(): Locale[] {\n return Object.keys(catalogs)\n }\n\n function d(value: Date | number, style?: string): string {\n const currentLocale = locale.value\n return formatDate(value, currentLocale, style, options.dateFormats)\n }\n\n function n(value: number, style?: string): string {\n const currentLocale = locale.value\n return formatNumber(value, currentLocale, style, options.numberFormats)\n }\n\n function format(message: string, values?: Record<string, unknown>): string {\n return resolveMessage(message, values, locale.value)\n }\n\n /**\n * Rich text helper for v-t with child elements.\n * Translates the message (which contains `<0>content</0>` placeholders),\n * then replaces each placeholder with the original HTML element.\n * Used via `v-html=\"$vtRich('msg', elements)\"` in compile-time transforms.\n * @internal\n */\n function vtRich(\n message: string | MessageDescriptor,\n elements: Array<{ tag: string; attrs: Record<string, string> }>,\n values?: Record<string, unknown>,\n ): string {\n const translated = values ? t(message, values) : t(message)\n // Escape the entire translated string first to neutralise any injected HTML\n const escaped = escapeHtml(translated)\n // Restore numbered placeholders (now escaped as <0>...</0>) back to real HTML\n return escaped.replace(/<(\\d+)>([\\s\\S]*?)<\\/\\1>/g, (_match, idxStr: string, content: string) => {\n const el = elements[Number(idxStr)]\n if (!el) return content\n const attrs = Object.entries(el.attrs)\n .map(([k, v]) => v ? `${escapeHtml(k)}=\"${escapeHtml(v)}\"` : escapeHtml(k))\n .join(' ')\n const tag = escapeHtml(el.tag)\n return `<${tag}${attrs ? ' ' + attrs : ''}>${content}</${tag}>`\n })\n }\n\n function te(key: string, loc?: string): boolean {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key) !== undefined\n }\n\n function tm(key: string, loc?: string): CompiledMessage | undefined {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key)\n }\n\n const context: FluentVueContext = {\n t,\n locale,\n setLocale,\n loadMessages,\n getLocales,\n d,\n n,\n format,\n isLoading,\n loadedLocales,\n preloadLocale,\n te,\n tm,\n }\n\n return {\n install(app: App) {\n app.provide(FLUENTI_KEY, context)\n const prefix = options.componentPrefix ?? ''\n app.component(`${prefix}Trans`, Trans)\n app.component(`${prefix}Plural`, Plural)\n app.component(`${prefix}Select`, Select)\n app.component(`${prefix}DateTime`, DateTime)\n app.component(`${prefix}NumberFormat`, NumberFormat)\n app.config.globalProperties['$t'] = t\n app.config.globalProperties['$d'] = d\n app.config.globalProperties['$n'] = n\n app.config.globalProperties['$vtRich'] = vtRich\n\n // Runtime v-t directive (fallback when compile-time transform is not used)\n app.directive('t', {\n mounted(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n // v-t.alt, v-t.placeholder, etc. — translate the attribute\n const original = el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n // v-t or v-t:id — translate text content\n const id = binding.arg ?? el.textContent ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n updated(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n const original = el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n const id = binding.arg ?? el.textContent ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n })\n },\n global: context,\n }\n}\n","import type { CompileTimeT } from '@fluenti/core'\n\nexport const t: CompileTimeT = ((..._args: unknown[]) => {\n throw new Error(\n \"[fluenti] `t` imported from '@fluenti/vue' is a compile-time API. \" +\n 'Use it only with the Fluenti build transform inside <script setup> or setup(). ' +\n 'For runtime lookups, use useI18n().t(...).',\n )\n}) as CompileTimeT\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/use-i18n.ts","../src/components/rich-text.ts","../src/components/Trans.ts","../src/components/Plural.ts","../src/components/Select.ts","../src/components/DateTime.ts","../src/components/NumberFormat.ts","../src/plugin.ts","../src/compile-time-t.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { FLUENTI_KEY, type FluentVueContext } from './plugin'\n\n/**\n * Composable that returns the Fluenti i18n context.\n *\n * Must be called inside a component whose ancestor app has installed the\n * `createFluentVue()` plugin.\n *\n * @throws If the plugin has not been installed\n */\nexport function useI18n(): FluentVueContext {\n const ctx = inject(FLUENTI_KEY)\n if (!ctx) {\n throw new Error('[fluenti] useI18n() requires createFluentVue plugin')\n }\n return ctx\n}\n","import { Comment, Text, h, isVNode, type VNode, type VNodeChild } from 'vue'\n\nexport function offsetIndices(message: string, offset: number): string {\n if (offset === 0) return message\n return message\n .replace(/<(\\d+)(\\/?>)/g, (_match, index: string, suffix: string) => `<${Number(index) + offset}${suffix}`)\n .replace(/<\\/(\\d+)>/g, (_match, index: string) => `</${Number(index) + offset}>`)\n}\n\nexport function extractMessage(children: VNodeChild | VNodeChild[] | undefined): {\n message: string\n components: VNode[]\n} {\n const components: VNode[] = []\n let message = ''\n\n function visit(node: VNodeChild | VNodeChild[] | undefined): void {\n if (node === null || node === undefined || typeof node === 'boolean') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n if (typeof node === 'string' || typeof node === 'number') {\n message += String(node)\n return\n }\n if (!isVNode(node) || node.type === Comment) return\n if (node.type === Text) {\n message += typeof node.children === 'string' ? node.children : ''\n return\n }\n\n const idx = components.length\n const inner = extractMessage(node.children as VNodeChild | VNodeChild[] | undefined)\n components.push(node)\n components.push(...inner.components)\n message += `<${idx}>${offsetIndices(inner.message, idx + 1)}</${idx}>`\n }\n\n visit(children)\n return { message, components }\n}\n\nexport function reconstruct(\n translated: string,\n components: VNode[],\n): VNodeChild {\n const tagRe = /<(\\d+)>([\\s\\S]*?)<\\/\\1>/g\n const result: VNodeChild[] = []\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n tagRe.lastIndex = 0\n match = tagRe.exec(translated)\n while (match !== null) {\n if (match.index > lastIndex) {\n result.push(translated.slice(lastIndex, match.index))\n }\n\n const idx = Number(match[1])\n const component = components[idx]\n const innerContent = reconstruct(match[2]!, components)\n if (component) {\n result.push(h(component.type as never, component.props ?? {}, Array.isArray(innerContent) ? innerContent : [innerContent]))\n } else {\n result.push(match[2]!)\n }\n\n lastIndex = tagRe.lastIndex\n match = tagRe.exec(translated)\n }\n\n if (lastIndex < translated.length) {\n result.push(translated.slice(lastIndex))\n }\n\n return result.length <= 1 ? (result[0] ?? '') : result\n}\n\nexport function serializeRichForms<T extends string>(\n keys: readonly T[],\n forms: Partial<Record<T, VNodeChild>> & Record<string, VNodeChild | undefined>,\n): {\n messages: Record<string, string>\n components: VNode[]\n} {\n const messages: Record<string, string> = {}\n const components: VNode[] = []\n\n for (const key of keys) {\n const value = forms[key]\n if (value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n for (const [key, value] of Object.entries(forms)) {\n if (keys.includes(key as T) || value === undefined) continue\n const extracted = extractMessage(value)\n messages[key] = offsetIndices(extracted.message, components.length)\n components.push(...extracted.components)\n }\n\n return { messages, components }\n}\n\nexport function buildICUSelectMessage(forms: Record<string, string>): string {\n return `{value, select, ${Object.entries(forms).map(([key, text]) => `${key} {${text}}`).join(' ')}}`\n}\n\nexport function normalizeSelectForms(forms: Record<string, string>): {\n forms: Record<string, string>\n valueMap: Record<string, string>\n} {\n const normalized: Record<string, string> = {}\n const valueMap: Record<string, string> = {}\n let index = 0\n\n for (const [key, text] of Object.entries(forms)) {\n if (key === 'other') {\n normalized['other'] = text\n continue\n }\n\n const safeKey = /^[A-Za-z0-9_]+$/.test(key) ? key : `case_${index++}`\n normalized[safeKey] = text\n valueMap[key] = safeKey\n }\n\n if (normalized['other'] === undefined) {\n normalized['other'] = ''\n }\n\n return { forms: normalized, valueMap }\n}\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\nimport { extractMessage, reconstruct } from './rich-text'\n\n/**\n * `<Trans>` component for rich text with Vue components.\n *\n * @example\n * ```vue\n * <Trans>\n * Visit our <a href=\"/docs\">documentation</a> to learn more.\n * </Trans>\n * ```\n *\n * @example\n * ```vue\n * <Trans>\n * Click <RouterLink to=\"/next\">here</RouterLink> to continue.\n * </Trans>\n * ```\n */\nconst transProps = {\n /** Override auto-generated hash ID */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type TransProps = Readonly<ExtractPropTypes<typeof transProps>>\n\nexport const Trans = defineComponent({\n name: 'Trans',\n props: transProps,\n setup(props, { slots }) {\n const { t } = useI18n()\n\n return () => {\n const defaultSlot = slots['default']?.()\n if (!defaultSlot) return null\n const { message, components } = extractMessage(defaultSlot)\n const translated = t({\n ...(props.id !== undefined ? { id: props.id } : {}),\n message,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n })\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n if (Array.isArray(result)) {\n return result.length === 1 ? result[0]! : h(props.tag, null, result)\n }\n return result\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { reconstruct, serializeRichForms } from './rich-text'\n\n/** Plural category names in a stable order for ICU message building. */\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n\ntype PluralCategory = (typeof PLURAL_CATEGORIES)[number]\n\n/**\n * Build an ICU plural message string from individual category props.\n *\n * Given `{ zero: \"No items\", one: \"# item\", other: \"# items\" }`,\n * produces `\"{count, plural, =0 {No items} one {# item} other {# items}}\"`.\n *\n * @internal\n */\nfunction buildICUPluralMessage(\n forms: Partial<Record<PluralCategory, string>> & { other: string },\n offset?: number,\n): string {\n const parts: string[] = []\n for (const cat of PLURAL_CATEGORIES) {\n const text = forms[cat]\n if (text !== undefined) {\n // Map the `zero` prop to ICU `=0` exact match. In ICU MessageFormat,\n // `zero` is a CLDR plural category that only activates in languages\n // with a grammatical zero form (e.g. Arabic). The `=0` exact match\n // works universally for the common \"show this when count is 0\" intent.\n const key = cat === 'zero' ? '=0' : cat\n parts.push(`${key} {${text}}`)\n }\n }\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{count, plural, ${offsetPrefix}${parts.join(' ')}}`\n}\n\n/**\n * `<Plural>` component — shorthand for ICU plural patterns.\n *\n * Plural form props (`zero`, `one`, `two`, `few`, `many`, `other`) are treated\n * as source-language messages. The component builds an ICU plural message,\n * looks it up via `t()` in the catalog, and interpolates the translated result.\n *\n * When no catalog translation exists, the component falls back to interpolating\n * the source-language ICU message directly via the `message` field of the\n * MessageDescriptor.\n *\n * Rich text is supported via named slots:\n * ```vue\n * <Plural :value=\"count\">\n * <template #zero>No <strong>items</strong></template>\n * <template #one><em>1</em> item</template>\n * <template #other><strong>{{ count }}</strong> items</template>\n * </Plural>\n * ```\n *\n * String props still work (backward compatible):\n * ```vue\n * <Plural :value=\"count\" zero=\"No items\" one=\"# item\" other=\"# items\" />\n * ```\n */\nconst pluralProps = {\n /** The numeric value to pluralise on */\n value: { type: Number, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Text for zero items (maps to `=0`) */\n zero: String,\n /** Text for singular (maps to `one`) */\n one: String,\n /** Text for dual (maps to `two`) */\n two: String,\n /** Text for few (maps to `few`) */\n few: String,\n /** Text for many (maps to `many`) */\n many: String,\n /** Text for the default/other category */\n other: { type: String, default: undefined },\n /** Offset from value before selecting form */\n offset: Number,\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type PluralProps = Readonly<ExtractPropTypes<typeof pluralProps>>\n\nexport const Plural = defineComponent({\n name: 'Plural',\n props: pluralProps,\n setup(props, { slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Partial<Record<PluralCategory, VNodeChild>> & Record<string, VNodeChild | undefined> = {\n zero: props.zero,\n one: props.one,\n two: props.two,\n few: props.few,\n many: props.many,\n other: props.other ?? '',\n }\n\n for (const cat of PLURAL_CATEGORIES) {\n const slot = slots[cat]\n if (slot) {\n forms[cat] = slot({ count: '#' })\n }\n }\n\n const { messages, components } = serializeRichForms(PLURAL_CATEGORIES, forms)\n const icuMessage = buildICUPluralMessage(\n {\n ...(messages['zero'] !== undefined && { zero: messages['zero'] }),\n ...(messages['one'] !== undefined && { one: messages['one'] }),\n ...(messages['two'] !== undefined && { two: messages['two'] }),\n ...(messages['few'] !== undefined && { few: messages['few'] }),\n ...(messages['many'] !== undefined && { many: messages['many'] }),\n other: messages['other'] ?? '',\n },\n props.offset,\n )\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { count: props.value },\n )\n\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType, SetupContext, VNodeChild } from 'vue'\nimport { hashMessage } from '@fluenti/core'\nimport { useI18n } from '../use-i18n'\nimport { buildICUSelectMessage, normalizeSelectForms, reconstruct, serializeRichForms } from './rich-text'\n\n/**\n * `<Select>` component — shorthand for ICU select patterns.\n *\n * Accepts a `value` string that selects among named options. Options can be\n * provided via the type-safe `options` prop (recommended), as direct attrs\n * (convenience), or as named slots (rich text).\n *\n * Falls back to `other` when no match is found.\n *\n * @example Type-safe usage (recommended):\n * ```vue\n * <Select\n * :value=\"gender\"\n * :options=\"{ male: 'He liked it', female: 'She liked it' }\"\n * other=\"They liked it\"\n * />\n * ```\n *\n * @example Rich text via named slots:\n * ```vue\n * <Select :value=\"gender\">\n * <template #male><strong>He</strong> liked this</template>\n * <template #female><strong>She</strong> liked this</template>\n * <template #other><em>They</em> liked this</template>\n * </Select>\n * ```\n */\nconst selectProps = {\n /** The value to select on (e.g. `\"male\"`, `\"female\"`) */\n value: { type: String, required: true },\n /** Override the auto-generated synthetic ICU message id */\n id: String,\n /** Message context used for identity and translator disambiguation */\n context: String,\n /** Translator-facing note preserved in extraction catalogs */\n comment: String,\n /** Fallback text when no option matches `value` */\n other: { type: String, default: undefined },\n /**\n * Named options map. Keys are match values, values are display strings.\n * Takes precedence over attrs when both are provided.\n *\n * @example `{ male: 'He', female: 'She' }`\n */\n options: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n /** Wrapper element tag name (default: `span`) */\n tag: { type: String, default: 'span' },\n} as const\n\nexport type SelectProps = Readonly<ExtractPropTypes<typeof selectProps>>\n\nexport const Select = defineComponent({\n name: 'Select',\n inheritAttrs: false,\n props: selectProps,\n setup(props, { attrs, slots }: SetupContext) {\n const { t } = useI18n()\n\n return () => {\n const forms: Record<string, VNodeChild | undefined> = {}\n\n if (props.options !== undefined) {\n for (const [key, value] of Object.entries(props.options)) {\n forms[key] = value\n }\n forms['other'] = props.other ?? ''\n } else {\n for (const [key, value] of Object.entries(attrs)) {\n if (typeof value === 'string') {\n forms[key] = value\n }\n }\n forms['other'] = props.other ?? ''\n }\n\n for (const [key, slot] of Object.entries(slots)) {\n if (key === 'default' || !slot) continue\n forms[key] = slot({ value: '{value}' })\n }\n\n const orderedKeys = [...Object.keys(forms).filter(key => key !== 'other'), 'other'] as const\n const { messages, components } = serializeRichForms(orderedKeys, forms)\n const normalized = normalizeSelectForms(\n Object.fromEntries(\n [...orderedKeys].map((key) => [key, messages[key] ?? '']),\n ),\n )\n const icuMessage = buildICUSelectMessage(normalized.forms)\n const translated = t(\n {\n id: props.id ?? (props.context === undefined ? icuMessage : hashMessage(icuMessage, props.context)),\n message: icuMessage,\n ...(props.context !== undefined ? { context: props.context } : {}),\n ...(props.comment !== undefined ? { comment: props.comment } : {}),\n },\n { value: normalized.valueMap[props.value] ?? 'other' },\n )\n const result = components.length > 0 ? reconstruct(translated, components) : translated\n return h(props.tag, undefined, result ?? undefined)\n }\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes, PropType } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<DateTime>` component for formatting dates according to locale.\n *\n * @example\n * ```vue\n * <DateTime :value=\"new Date()\" />\n * <DateTime :value=\"Date.now()\" style=\"short\" />\n * <DateTime :value=\"event.date\" style=\"long\" tag=\"time\" />\n * ```\n */\nconst dateTimeProps = {\n value: { type: [Date, Number] as PropType<Date | number>, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type DateTimeProps = Readonly<ExtractPropTypes<typeof dateTimeProps>>\n\nexport const DateTime = defineComponent({\n name: 'DateTime',\n props: dateTimeProps,\n setup(props) {\n const { d } = useI18n()\n return () => h(props.tag, d(props.value as Date | number, props.style))\n },\n})\n","import { defineComponent, h } from 'vue'\nimport type { ExtractPropTypes } from 'vue'\nimport { useI18n } from '../use-i18n'\n\n/**\n * `<NumberFormat>` component for formatting numbers according to locale.\n *\n * @example\n * ```vue\n * <NumberFormat :value=\"1234.56\" />\n * <NumberFormat :value=\"0.75\" style=\"percent\" />\n * <NumberFormat :value=\"99.99\" style=\"currency\" tag=\"strong\" />\n * ```\n */\nconst numberFormatProps = {\n value: { type: Number, required: true },\n style: { type: String, default: undefined },\n tag: { type: String, default: 'span' },\n} as const\n\nexport type NumberFormatProps = Readonly<ExtractPropTypes<typeof numberFormatProps>>\n\nexport const NumberFormat = defineComponent({\n name: 'NumberFormat',\n props: numberFormatProps,\n setup(props) {\n const { n } = useI18n()\n return () => h(props.tag, n(props.value, props.style))\n },\n})\n","import { type App, type InjectionKey, type Ref, ref, shallowReactive } from 'vue'\nimport type { AllMessages, Locale, Messages, CompiledMessage, MessageDescriptor } from '@fluenti/core'\nimport { interpolate, formatDate, formatNumber, buildICUMessage, resolveDescriptorId } from '@fluenti/core'\nimport { Trans } from './components/Trans'\nimport { Plural } from './components/Plural'\nimport { Select } from './components/Select'\nimport { DateTime } from './components/DateTime'\nimport { NumberFormat } from './components/NumberFormat'\n\n/** Escape HTML special characters to prevent XSS. @internal */\nfunction escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(/\"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Compiled message chunk loader for lazy locale loading */\nexport type ChunkLoader = (\n locale: string,\n) => Promise<Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> }>\n\ninterface SplitRuntimeModule {\n __switchLocale?: (locale: string) => Promise<void>\n __preloadLocale?: (locale: string) => Promise<void>\n}\n\nconst SPLIT_RUNTIME_KEY = Symbol.for('fluenti.runtime.vue')\n\nfunction getSplitRuntimeModule(): SplitRuntimeModule | null {\n const runtime = (globalThis as Record<PropertyKey, unknown>)[SPLIT_RUNTIME_KEY]\n return typeof runtime === 'object' && runtime !== null\n ? runtime as SplitRuntimeModule\n : null\n}\n\nfunction resolveChunkMessages(\n loaded: Record<string, CompiledMessage> | { default: Record<string, CompiledMessage> },\n): Record<string, CompiledMessage> {\n return typeof loaded === 'object' && loaded !== null && 'default' in loaded\n ? (loaded as { default: Record<string, CompiledMessage> }).default\n : loaded\n}\n\n/** Context object returned by `useI18n()` and available as `$t` etc. on globalProperties */\nexport interface FluentVueContext {\n /** Translate a message by id or MessageDescriptor, with optional interpolation values */\n t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n /** Tagged template form: t`Hello ${name}` */\n t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n /** Reactive ref for current locale */\n locale: Readonly<Ref<Locale>>\n /** Change the active locale (async when lazy locale loading is enabled) */\n setLocale(locale: Locale): Promise<void>\n /** Dynamically load messages for a locale */\n loadMessages(locale: Locale, messages: Messages): void\n /** Get all locales that have loaded messages */\n getLocales(): Locale[]\n /** Format a date value according to locale */\n d(value: Date | number, style?: string): string\n /** Format a number according to locale */\n n(value: number, style?: string): string\n /** Format an ICU message string directly (no catalog lookup) */\n format(message: string, values?: Record<string, unknown>): string\n /** Whether a locale chunk is currently being loaded */\n isLoading: Readonly<Ref<boolean>>\n /** Set of locales whose messages have been loaded */\n loadedLocales: Readonly<Ref<ReadonlySet<string>>>\n /** Preload a locale in the background without switching to it */\n preloadLocale(locale: string): void\n /** Check if a translation key exists in the catalog */\n te(key: string, locale?: string): boolean\n /** Get the raw compiled message without interpolation */\n tm(key: string, locale?: string): CompiledMessage | undefined\n}\n\n/** Injection key for providing/injecting fluenti context */\nexport const FLUENTI_KEY: InjectionKey<FluentVueContext> = Symbol('fluenti')\n\n/** Options for creating the FluentVue plugin */\nexport interface FluentVueOptions {\n locale: string\n fallbackLocale?: string\n messages: AllMessages\n missing?: (locale: string, id: string) => string | undefined\n dateFormats?: Record<string, Intl.DateTimeFormatOptions | 'relative'>\n numberFormats?: Record<string, Intl.NumberFormatOptions | ((locale: string) => Intl.NumberFormatOptions)>\n fallbackChain?: Record<string, string[]>\n /** Async chunk loader for lazy locale loading */\n chunkLoader?: ChunkLoader\n /** Enable lazy locale loading through chunkLoader */\n lazyLocaleLoading?: boolean\n /**\n * Prefix for globally registered components (Trans, Plural, Select).\n *\n * Set this to avoid naming conflicts with other libraries.\n *\n * @example\n * componentPrefix: 'I18n'\n * // Registers: I18nTrans, I18nPlural, I18nSelect\n *\n * @example\n * componentPrefix: 'Fluenti'\n * // Registers: FluentiTrans, FluentiPlural, FluentiSelect\n *\n * @default '' (no prefix — Trans, Plural, Select)\n */\n componentPrefix?: string\n}\n\n/** Return value of `createFluentVue()` */\nexport interface FluentVuePlugin {\n /** Vue plugin install method */\n install(app: App): void\n /** The global fluenti context (same as what useI18n returns) */\n global: FluentVueContext\n}\n\n/**\n * Resolve a compiled message to a string, applying values if needed.\n * @internal\n */\nfunction resolveMessage(\n compiled: CompiledMessage,\n values?: Record<string, unknown>,\n locale?: string,\n): string {\n if (typeof compiled === 'function') {\n return compiled(values)\n }\n // Use core interpolate for ICU message parsing (handles plural, select, etc.)\n return interpolate(compiled, values, locale)\n}\n\n/** Extract the attribute name from v-t modifiers (e.g., v-t.alt → 'alt') */\nfunction getModifierAttr(modifiers: Partial<Record<string, boolean>>): string | undefined {\n const keys = Object.keys(modifiers).filter((k) => k !== 'plural')\n return keys.length > 0 ? keys[0] : undefined\n}\n\n/**\n * Create a Fluenti Vue plugin (SSR-safe, per-request instance).\n *\n * Each invocation creates entirely fresh state — no module-level singletons —\n * so it is safe to call once per SSR request.\n */\nexport function createFluentVue(options: FluentVueOptions): FluentVuePlugin {\n const lazyLocaleLoading = options.lazyLocaleLoading\n ?? (options as FluentVueOptions & { splitting?: boolean }).splitting\n ?? false\n const locale = ref(options.locale)\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n const catalogs = shallowReactive<AllMessages>({ ...options.messages })\n const isLoading = ref(false)\n const loadedLocalesSet = new Set<string>([options.locale])\n const loadedLocales = ref<ReadonlySet<string>>(new Set(loadedLocalesSet))\n\n function lookup(\n loc: Locale,\n id: string,\n ): CompiledMessage | undefined {\n const msgs = catalogs[loc]\n if (!msgs) return undefined\n return msgs[id]\n }\n\n function t(strings: TemplateStringsArray, ...exprs: unknown[]): string\n function t(id: string | MessageDescriptor, values?: Record<string, unknown>): string\n function t(idOrStrings: string | MessageDescriptor | TemplateStringsArray, ...rest: unknown[]): string {\n // Tagged template form: t`Hello ${name}`\n if (Array.isArray(idOrStrings) && 'raw' in idOrStrings) {\n const strings = idOrStrings as TemplateStringsArray\n const icu = buildICUMessage(strings, rest)\n const values = Object.fromEntries(rest.map((v, i) => [String(i), v]))\n // Delegate to the function-call path with the ICU string as the id\n return t(icu, values)\n }\n\n // Function call form\n const id = idOrStrings as string | MessageDescriptor\n const values = rest[0] as Record<string, unknown> | undefined\n\n // Handle MessageDescriptor objects (from msg``)\n let messageId: string\n let fallbackMessage: string | undefined\n if (typeof id === 'object' && id !== null) {\n messageId = resolveDescriptorId(id) ?? ''\n fallbackMessage = id.message\n } else {\n messageId = id\n }\n\n // Read locale.value to register a Vue reactive dependency\n const currentLocale = locale.value\n\n // Build the chain of locales to try\n const chain: Locale[] = [currentLocale]\n\n if (options.fallbackLocale && !chain.includes(options.fallbackLocale)) {\n chain.push(options.fallbackLocale)\n }\n\n if (options.fallbackChain?.[currentLocale]) {\n for (const fallback of options.fallbackChain[currentLocale]) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n } else if (options.fallbackChain?.['*']) {\n for (const fallback of options.fallbackChain['*']) {\n if (!chain.includes(fallback)) {\n chain.push(fallback)\n }\n }\n }\n\n for (const loc of chain) {\n const compiled = lookup(loc, messageId)\n if (compiled !== undefined) {\n return resolveMessage(compiled, values, loc)\n }\n }\n\n // Try the missing handler\n if (options.missing) {\n const result = options.missing(currentLocale, messageId)\n if (result !== undefined) return result\n }\n\n // If we have a fallback message from a MessageDescriptor, interpolate it\n if (fallbackMessage) {\n return interpolate(fallbackMessage, values, currentLocale)\n }\n\n // Final fallback — if the id looks like an ICU message, interpolate it\n // (compile-time transforms like <Plural> emit inline ICU as t() arguments)\n if (messageId.includes('{')) {\n return interpolate(messageId, values, currentLocale)\n }\n return messageId\n }\n\n async function setLocale(newLocale: Locale): Promise<void> {\n if (!lazyLocaleLoading || !options.chunkLoader) {\n locale.value = newLocale\n return\n }\n\n const splitRuntime = getSplitRuntimeModule()\n\n if (loadedLocalesSet.has(newLocale)) {\n // Already loaded, instant switch\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n return\n }\n\n // Async load\n isLoading.value = true\n try {\n const messages = resolveChunkMessages(await options.chunkLoader(newLocale))\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[newLocale] = { ...catalogs[newLocale], ...messages }\n loadedLocalesSet.add(newLocale)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__switchLocale) {\n await splitRuntime.__switchLocale(newLocale)\n }\n locale.value = newLocale\n } finally {\n isLoading.value = false\n }\n }\n\n function loadMessages(loc: Locale, messages: Messages): void {\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n }\n\n function preloadLocale(loc: string): void {\n if (!lazyLocaleLoading || loadedLocalesSet.has(loc) || !options.chunkLoader) return\n const splitRuntime = getSplitRuntimeModule()\n options.chunkLoader(loc).then(async (loaded) => {\n const messages = resolveChunkMessages(loaded)\n // Intentional mutation: Vue's shallowReactive API requires in-place property assignment for reactivity\n catalogs[loc] = { ...catalogs[loc], ...messages }\n loadedLocalesSet.add(loc)\n loadedLocales.value = new Set(loadedLocalesSet)\n if (splitRuntime?.__preloadLocale) {\n await splitRuntime.__preloadLocale(loc)\n }\n }).catch((e: unknown) => {\n console.warn('[fluenti] preload failed:', loc, e)\n })\n }\n\n function getLocales(): Locale[] {\n return Object.keys(catalogs)\n }\n\n function d(value: Date | number, style?: string): string {\n const currentLocale = locale.value\n return formatDate(value, currentLocale, style, options.dateFormats)\n }\n\n function n(value: number, style?: string): string {\n const currentLocale = locale.value\n return formatNumber(value, currentLocale, style, options.numberFormats)\n }\n\n function format(message: string, values?: Record<string, unknown>): string {\n return resolveMessage(message, values, locale.value)\n }\n\n /**\n * Rich text helper for v-t with child elements.\n * Translates the message (which contains `<0>content</0>` placeholders),\n * then replaces each placeholder with the original HTML element.\n * Used via `v-html=\"$vtRich('msg', elements)\"` in compile-time transforms.\n * @internal\n */\n function vtRich(\n message: string | MessageDescriptor,\n elements: Array<{ tag: string; attrs: Record<string, string> }>,\n values?: Record<string, unknown>,\n ): string {\n const translated = values ? t(message, values) : t(message)\n // Escape the entire translated string first to neutralise any injected HTML\n const escaped = escapeHtml(translated)\n // Restore numbered placeholders (now escaped as <0>...</0>) back to real HTML\n return escaped.replace(/<(\\d+)>([\\s\\S]*?)<\\/\\1>/g, (_match, idxStr: string, content: string) => {\n const el = elements[Number(idxStr)]\n if (!el) return content\n const attrs = Object.entries(el.attrs)\n .map(([k, v]) => v ? `${escapeHtml(k)}=\"${escapeHtml(v)}\"` : escapeHtml(k))\n .join(' ')\n const tag = escapeHtml(el.tag)\n return `<${tag}${attrs ? ' ' + attrs : ''}>${content}</${tag}>`\n })\n }\n\n function te(key: string, loc?: string): boolean {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key) !== undefined\n }\n\n function tm(key: string, loc?: string): CompiledMessage | undefined {\n const targetLocale = loc ?? locale.value\n return lookup(targetLocale, key)\n }\n\n const context: FluentVueContext = {\n t,\n locale,\n setLocale,\n loadMessages,\n getLocales,\n d,\n n,\n format,\n isLoading,\n loadedLocales,\n preloadLocale,\n te,\n tm,\n }\n\n return {\n install(app: App) {\n app.provide(FLUENTI_KEY, context)\n const prefix = options.componentPrefix ?? ''\n app.component(`${prefix}Trans`, Trans)\n app.component(`${prefix}Plural`, Plural)\n app.component(`${prefix}Select`, Select)\n app.component(`${prefix}DateTime`, DateTime)\n app.component(`${prefix}NumberFormat`, NumberFormat)\n app.config.globalProperties['$t'] = t\n app.config.globalProperties['$d'] = d\n app.config.globalProperties['$n'] = n\n app.config.globalProperties['$vtRich'] = vtRich\n\n // Runtime v-t directive (fallback when compile-time transform is not used)\n const vtOriginalIds = new WeakMap<HTMLElement, string>()\n app.directive('t', {\n mounted(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n // v-t.alt, v-t.placeholder, etc. — translate the attribute\n const original = el.getAttribute(attrName) ?? ''\n vtOriginalIds.set(el, original)\n el.setAttribute(attrName, t(original))\n } else {\n // v-t or v-t:id — translate text content\n const id = binding.arg ?? el.textContent ?? ''\n vtOriginalIds.set(el, id.trim())\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n updated(el, binding) {\n const attrName = getModifierAttr(binding.modifiers)\n if (attrName) {\n const original = vtOriginalIds.get(el) ?? el.getAttribute(attrName) ?? ''\n el.setAttribute(attrName, t(original))\n } else {\n const id = binding.arg ?? vtOriginalIds.get(el) ?? ''\n el.textContent = t(id.trim(), binding.value != null ? { ...binding.value } : undefined)\n }\n },\n })\n },\n global: context,\n }\n}\n","import type { CompileTimeT } from '@fluenti/core'\n\nexport const t: CompileTimeT = ((..._args: unknown[]) => {\n throw new Error(\n \"[fluenti] `t` imported from '@fluenti/vue' is a compile-time API. \" +\n 'Use it only with the Fluenti build transform inside <script setup> or setup(). ' +\n 'For runtime lookups, use useI18n().t(...).',\n )\n}) as CompileTimeT\n"],"mappings":"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"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -54,6 +54,13 @@ export interface ServerI18n {
|
|
|
54
54
|
* For per-request isolation in Nuxt, use `useRequestEvent()` in your
|
|
55
55
|
* `resolveLocale` callback, or call `setLocale()` in a server plugin.
|
|
56
56
|
*
|
|
57
|
+
* **⚠️ SSR Concurrency Warning**: This function uses module-level state for locale
|
|
58
|
+
* and cached instance. In concurrent SSR environments (e.g. multiple simultaneous
|
|
59
|
+
* requests), this can cause cross-request locale leakage. For per-request isolation:
|
|
60
|
+
* - Use `useRequestEvent()` in Nuxt to scope locale per request
|
|
61
|
+
* - Or create a separate `createServerI18n()` per request context
|
|
62
|
+
* - Consider using AsyncLocalStorage for true per-request isolation (future)
|
|
63
|
+
*
|
|
57
64
|
* @example
|
|
58
65
|
* ```ts
|
|
59
66
|
* // server/i18n.ts
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EAEtB,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACxG,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAA;IAC3E,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9C,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,gCAAgC;IAChC,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,kCAAkC;IAClC,aAAa,CAAC,EAAE,mBAAmB,CAAA;IACnC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAEnC;;;OAGG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,sBAAsB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACpE;AAED
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EAEtB,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACxG,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAA;IAC3E,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9C,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,gCAAgC;IAChC,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,kCAAkC;IAClC,aAAa,CAAC,EAAE,mBAAmB,CAAA;IACnC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAEnC;;;OAGG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,sBAAsB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAoErE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluenti/vue",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vue 3 compile-time i18n — v-t directive, Trans/Plural/Select components, useI18n composable",
|
|
6
6
|
"homepage": "https://fluenti.dev",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"vue": "^3.5"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@fluenti/core": "0.1.
|
|
52
|
+
"@fluenti/core": "0.1.3"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"typescript": "^5.9",
|