UNPKG

@gulibs/react-vintl

Version:

Type-safe i18n library for React with Vite plugin and automatic type inference

1 lines 11.2 kB
const e=require(`./logger-qt2bO9d_.cjs`);let t=require(`react`);t=e.__toESM(t);let n=require(`react/jsx-runtime`);n=e.__toESM(n);function r(e,t){return t.split(`.`).reduce((e,t)=>{if(typeof e==`object`&&e&&t in e)return e[t]},e)}function i(t,n={}){return t.replace(/\{\{([^}]+)\}\}/g,(t,r)=>{try{return a(r.trim(),n)}catch(n){return e.logger.warn(`Failed to process interpolation "${t}":`,n),t}})}function a(e,t){let n=e.split(`,`).map(e=>e.trim()),r=n[0];if(!r)throw Error(`Missing parameter key`);let i=o(t,r);if(i===void 0)throw Error(`Parameter "${r}" not found`);if(n.length===1)return String(i);let a=n[1],p=n.slice(2);switch(a){case`plural`:return s(i,p);case`select`:return c(i,p);case`number`:return l(i,p);case`date`:return u(i,p);case`currency`:return d(i,p);default:return f(i,a,p)}}function o(e,t){return t.split(`.`).reduce((e,t)=>{if(typeof e==`object`&&e&&t in e)return e[t]},e)}function s(e,t){let n=Number(e);if(isNaN(n))return String(e);let r={};for(let e of t){let[t,n]=e.split(`=`,2).map(e=>e.trim());t&&n&&(r[t]=n)}let i=`other`;return n===1&&`one`in r?i=`one`:n===0&&`zero`in r?i=`zero`:n>1&&`few`in r?i=`few`:n>1&&`many`in r&&(i=`many`),(r[i]||r.other||String(e)).replace(/#/g,String(n))}function c(e,t){let n=String(e),r={};for(let e of t){let[t,n]=e.split(`=`,2).map(e=>e.trim());t&&n&&(r[t]=n)}return r[n]||r.other||n}function l(e,t){let n=Number(e);if(isNaN(n))return String(e);let r={};for(let e of t){let[t,n]=e.split(`=`,2).map(e=>e.trim());if(t&&n){let e=Number(n);isNaN(e)||(r[t]=e)}}try{return new Intl.NumberFormat(void 0,r).format(n)}catch{return String(n)}}function u(e,t){let n;if(e instanceof Date)n=e;else if(typeof e==`string`||typeof e==`number`)n=new Date(e);else return String(e);if(isNaN(n.getTime()))return String(e);let r={};for(let e of t){let[t,n]=e.split(`=`,2).map(e=>e.trim());t&&n&&(r[t]=n)}try{return new Intl.DateTimeFormat(void 0,r).format(n)}catch{return n.toLocaleDateString()}}function d(e,t){let n=Number(e);if(isNaN(n))return String(e);let r={style:`currency`};for(let e of t){let[t,n]=e.split(`=`,2).map(e=>e.trim());if(t&&n)if(t===`currency`)r.currency=n;else{let e=Number(n);isNaN(e)||(r[t]=e)}}try{return new Intl.NumberFormat(void 0,r).format(n)}catch{return String(n)}}function f(e,t,n){switch(t){case`uppercase`:return String(e).toUpperCase();case`lowercase`:return String(e).toLowerCase();case`capitalize`:return String(e).charAt(0).toUpperCase()+String(e).slice(1).toLowerCase();default:return String(e)}}function p(t){if(!t||typeof t!=`object`)return!1;try{return JSON.stringify(t),!0}catch{return e.logger.warn(`Invalid params object: contains circular reference`),!1}}function m(t,n){return(a,o)=>{let s=t[n];if(!s)return e.logger.warn(`Locale "${n}" not found in resources`),a;let c=r(s,a);if(typeof c!=`string`)return e.logger.warn(`Translation key "${a}" not found or not a string in locale "${n}"`),a;if(o&&!p(o))return e.logger.warn(`Invalid params for key "${a}":`,o),c;try{return o?i(c,o):c}catch(t){return e.logger.error(`Failed to process translation for key "${a}":`,t),c}}}function h(t){if(!t||typeof t!=`object`)return e.logger.error(`Resources must be an object`),!1;let n=Object.keys(t);if(n.length===0)return e.logger.error(`Resources must contain at least one locale`),!1;let r=n[0],i=v(t[r]);for(let r of n.slice(1)){let n=v(t[r]),a=i.filter(e=>!n.includes(e)),o=n.filter(e=>!i.includes(e));a.length>0&&e.logger.warn(`Locale "${r}" is missing keys: ${a.join(`, `)}`),o.length>0&&e.logger.warn(`Locale "${r}" has extra keys: ${o.join(`, `)}`)}return!0}function g(e,t){if(typeof e!=`object`||!e||Array.isArray(e))return t;if(typeof t!=`object`||!t||Array.isArray(t))return e;let n={...e};for(let r in t)if(Object.prototype.hasOwnProperty.call(t,r)){let i=t[r],a=e[r];typeof i==`object`&&i&&!Array.isArray(i)&&typeof a==`object`&&a&&!Array.isArray(a)?n[r]=g(a,i):i!==void 0&&(n[r]=i)}return n}function _(t,n,r){let i={};for(let e in t)Object.prototype.hasOwnProperty.call(t,e)&&(i[e]={...t[e]});for(let t in n){if(!Object.prototype.hasOwnProperty.call(n,t)||r?.locale&&t!==r.locale)continue;let a=n[t];if(!a||typeof a!=`object`)continue;i[t]?i[t]={...i[t]}:i[t]={};let o=i[t];if(r?.namespace){o[r.namespace]||(o[r.namespace]={});let e;e=r.namespace in a&&typeof a[r.namespace]==`object`&&a[r.namespace]!==null&&!Array.isArray(a[r.namespace])?a[r.namespace]:a;let t=g(o[r.namespace],e);o[r.namespace]=t}else{for(let n in e.logger.debug(`[mergeResources] Root level merge:`,{locale:t,overlayKeys:Object.keys(a),baseKeys:Object.keys(o)}),a){if(!Object.prototype.hasOwnProperty.call(a,n))continue;o[n]||(o[n]={});let t=g(o[n],a[n]);o[n]=t,e.logger.debug(`[mergeResources] Merged namespace:`,n,{mergedKeys:Object.keys(t)})}e.logger.debug(`[mergeResources] After root level merge, baseLocale keys:`,Object.keys(o))}}return i}function v(e,t=``){let n=[];if(typeof e!=`object`||!e||Array.isArray(e))return n;for(let r in e)if(Object.prototype.hasOwnProperty.call(e,r)){let i=t?`${t}.${r}`:r,a=e[r];typeof a==`object`&&a&&!Array.isArray(a)?n.push(...v(a,i)):n.push(i)}return n}var y=(0,t.createContext)(null),b=`@gulibs/react-vintl:locale`;function x({resources:r,defaultLocale:i,supportedLocales:a,children:o}){if(!h(r)){let e=r&&typeof r==`object`&&Object.keys(r).length===0?`Invalid i18n resources: resources object is empty. Please configure the @gulibs/react-vintl plugin in your vite.config.ts to generate locale resources from your translation files.`:`Invalid i18n resources`;throw Error(e)}let s=a||Object.keys(r),c=i||s[0];if(!s.includes(c))throw Error(`Default locale "${c}" is not in supported locales: ${s.join(`, `)}`);let[l,u]=(0,t.useState)(()=>{if(typeof window>`u`)return c;try{let e=localStorage.getItem(b);if(e&&s.includes(e))return e}catch(t){e.logger.warn(`Failed to read locale from localStorage:`,t)}return c}),[d,f]=(0,t.useState)(r),p=t=>{if(!s.includes(t)){e.logger.warn(`Locale "${t}" is not in supported locales: ${s.join(`, `)}`);return}if(u(t),typeof window<`u`)try{localStorage.setItem(b,t)}catch(t){e.logger.warn(`Failed to save locale to localStorage:`,t)}};(0,t.useEffect)(()=>{if(typeof window>`u`)return;let e=e=>{if(e.key===b&&e.newValue){let t=e.newValue;s.includes(t)&&t!==l&&u(t)}};return window.addEventListener(`storage`,e),()=>{window.removeEventListener(`storage`,e)}},[s,l]);let g=(0,t.useCallback)((e,t)=>{f(n=>t?.merge===!1?e:_(n,e,{namespace:t?.namespace,locale:t?.locale}))},[]),v=(0,t.useMemo)(()=>m(d,l),[d,l]),x=(0,t.useMemo)(()=>({locale:l,supportedLocales:s,t:v,setLocale:p,resources:d,updateResources:g}),[l,s,v,d,g]);return(0,n.jsx)(y.Provider,{value:x,children:o})}function S(){let e=(0,t.useContext)(y);if(!e)throw Error(`useI18nContext must be used within an I18nProvider`);return e}function C(e){let t=S();return e?(n,r)=>{let i=`${e}.${n}`;return t.t(i,r)}:t.t}function w(){let e=S();return{locale:e.locale,supportedLocales:e.supportedLocales,setLocale:e.setLocale,resources:e.resources}}function T(e,n){let r=C(),i=(0,t.useCallback)(t=>r(e,t||n),[r,e,n]);return{translation:(0,t.useCallback)(()=>r(e,n),[r,e,n])(),t:i}}function E(){let{locale:e,supportedLocales:n,setLocale:r}=w(),i=(0,t.useCallback)(e=>n.includes(e),[n]);return{locale:e,supportedLocales:n,setLocale:r,isSupportedLocale:i}}var D=new Map,O=300*1e3,k=new Map;async function A(e){let t=await fetch(e);if(!t.ok)throw Error(`Failed to load translations from ${e}: ${t.statusText}`);return await t.json()}async function j(e){return await e()}async function M(e){return await e}async function N(e){return typeof e==`string`?await A(e):typeof e==`function`?await j(e):await M(e)}function P(e,t){return typeof e==`string`?`${e}:${t||`default`}`:`${String(e)}:${t||`default`}`}function F(n,r={}){let{locale:i,namespace:a,merge:o=!0,cache:s=!0,onSuccess:c,onError:l,retry:u=0,retryDelay:d=1e3}=r,f=S(),[p,m]=(0,t.useState)(!1),[h,g]=(0,t.useState)(null),[_,v]=(0,t.useState)(null),y=(0,t.useRef)(0),b=(0,t.useRef)(n),x=(0,t.useRef)(f.updateResources),C=(0,t.useRef)(f.locale);(0,t.useEffect)(()=>{x.current=f.updateResources,C.current=f.locale},[f.updateResources,f.locale]);let w=(0,t.useRef)(new Set);(0,t.useEffect)(()=>{b.current=n},[n]);let T=(0,t.useMemo)(()=>{let e=i||C.current;return[typeof n==`string`?n:String(n),e,a||``,String(o)].join(`|`)},[n,i,a,o]),E=(0,t.useCallback)(async()=>{let t=i||C.current,n=P(b.current,t),r=a===void 0?`${n}:root`:`${n}:ns:${a}`;if(w.current.has(T)){if(e.logger.debug(`[useLoadRemoteTranslations] Resource already loaded, skipping:`,{resourceKey:T,namespace:a===void 0?`(root level)`:a}),s){let e=D.get(r);if(e){v(e.data),g(null),m(!1);return}}return}if(s){let n=D.get(r);if(n&&Date.now()-n.timestamp<O){e.logger.debug(`[useLoadRemoteTranslations] Using cached data:`,{resourceKey:T,namespace:a===void 0?`(root level)`:a,namespaceType:typeof a}),v(n.data),g(null),m(!1),w.current.add(T),o&&(e.logger.debug(`[useLoadRemoteTranslations] Merging cached resources:`,{namespace:a===void 0?`(root level)`:a,locale:t}),x.current(n.data,{namespace:a,locale:t})),c&&c(n.data);return}}let f=k.get(r);if(f){e.logger.debug(`[useLoadRemoteTranslations] Pending request found, waiting:`,{cacheKey:r,resourceKey:T,namespace:a===void 0?`(root level)`:a});try{let n=await f;v(n),g(null),m(!1),w.current.add(T),o&&(e.logger.debug(`[useLoadRemoteTranslations] Merging pending resources:`,{namespace:a===void 0?`(root level)`:a,locale:t}),x.current(n,{namespace:a,locale:t})),c&&c(n);return}catch(t){e.logger.debug(`[useLoadRemoteTranslations] Pending request failed, continuing:`,t)}}m(!0),g(null),e.logger.debug(`[useLoadRemoteTranslations] Starting load:`,{resourceKey:T,namespace:a===void 0?`(root level)`:a,namespaceType:typeof a,locale:t});let p=async n=>{try{let n=await N(b.current);return s&&D.set(r,{data:n,timestamp:Date.now()}),o?(e.logger.debug(`[useLoadRemoteTranslations] Merging resources:`,{hasResources:!!n,namespace:a===void 0?`(root level)`:a,namespaceType:typeof a,locale:t,resourceKeys:n[t]?Object.keys(n[t]):[],resourceStructure:n[t]}),x.current(n,{namespace:a,locale:t})):e.logger.debug(`[useLoadRemoteTranslations] Merge disabled, skipping resource merge`),w.current.add(T),v(n),g(null),m(!1),c&&c(n),n}catch(t){let r=t instanceof Error?t:Error(String(t));if(n<u)return y.current=n+1,e.logger.warn(`Translation load failed, retrying (${y.current}/${u})...`),await new Promise(e=>setTimeout(e,d)),await p(n+1);throw g(r),m(!1),l?l(r):e.logger.error(`Failed to load remote translations:`,r),r}},h=p(0).finally(()=>{k.delete(r)});k.set(r,h);try{await h}catch{}},[i,a,o,s,c,l,u,d,T]);(0,t.useEffect)(()=>{e.logger.debug(`[useLoadRemoteTranslations] useEffect triggered:`,{resourceKey:T,namespace:a===void 0?`(root level)`:a,namespaceType:typeof a}),y.current=0,E()},[E,T,a]);let A=(0,t.useCallback)(()=>{y.current=0,w.current.delete(T),E()},[E,T]);return{loading:p,error:h,data:_,retry:A}}exports.I18nProvider=x,exports.Logger=e.Logger,exports.createTranslationFunction=m,exports.deepMerge=g,exports.getNestedValue=r,exports.logger=e.logger,exports.mergeResources=_,exports.replaceParams=i,exports.useI18n=w,exports.useI18nContext=S,exports.useLoadRemoteTranslations=F,exports.useLocale=E,exports.useTranslation=C,exports.useTranslationKey=T,exports.validateResources=h;