@i18n-micro/preact 1.2.16 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016
3
+ Copyright (c) 2024 s00d
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,71 +1,31 @@
1
1
  # @i18n-micro/preact
2
2
 
3
- Pure Preact plugin for internationalization using the same core logic as Nuxt I18n Micro. Provides reactive translations, route-specific support, and full TypeScript support. Works with any router (wouter, preact-router) or without a router.
4
-
5
- **Peer:** `preact@^10.27.2 || ^11.0.0-0`. Components use top-level `HTMLAttributes` / `TargetedMouseEvent` (shipped in Preact ≥10.27.2; Preact 11 removed those from the `JSX` namespace). `JSX.IntrinsicElements` remains. Monorepo installs pin Preact 10.x for tests; Preact 11 is ESM-only — prefer the ESM build of this package (or a bundler) over bare `require()` on older Node.
6
-
7
- ## Installation
3
+ Preact bindings for Nuxt I18n Micro: the same API as `@i18n-micro/react` (`createI18n`, `<I18nProvider>`, `useI18n()`, `useT`, `useLocaleSwitch`, four components), built from the same source on Preact itself, plus `createBrowserHistoryAdapter` in `@i18n-micro/preact/router` for any History API router (wouter, preact-router).
8
4
 
9
5
  ```bash
10
6
  pnpm add @i18n-micro/preact
11
- # or
12
- npm install @i18n-micro/preact
13
- # or
14
- yarn add @i18n-micro/preact
15
- ```
16
-
17
- ## Quick Start
18
-
19
- ```typescript
20
- import { render } from 'preact'
21
- import { createI18n, I18nProvider, useI18n } from '@i18n-micro/preact'
22
-
23
- const i18n = createI18n({
24
- locale: 'en',
25
- fallbackLocale: 'en',
26
- messages: {
27
- en: {
28
- greeting: 'Hello, {name}!',
29
- apples: 'no apples | one apple | {count} apples',
30
- },
31
- fr: {
32
- greeting: 'Bonjour, {name}!',
33
- apples: 'pas de pommes | une pomme | {count} pommes',
34
- },
35
- },
36
- })
37
-
38
- function App() {
39
- return (
40
- <I18nProvider i18n={i18n}>
41
- <MyComponent />
42
- </I18nProvider>
43
- )
44
- }
45
7
  ```
46
8
 
47
- ### Usage in Components
9
+ Peer: `preact` `^10.0.0 || ^11.0.0`. Tested on preact 10.29, and its types on 10.27.2 and 11. The published types need preact 10.27.2 or later with `skipLibCheck: false`; with `skipLibCheck: true`, the usual template setting, older versions compile too.
48
10
 
49
11
  ```tsx
50
- import { useI18n } from '@i18n-micro/preact'
51
-
52
- function MyComponent() {
53
- const { t, tc, locale, setLocale } = useI18n()
54
-
55
- return (
56
- <div>
57
- <p>{t('greeting', { name: 'World' })}</p>
58
- <p>{tc('apples', 5)}</p>
59
- <button onClick={() => setLocale('fr')}>Switch to French</button>
60
- </div>
61
- )
62
- }
12
+ import { render } from 'preact'
13
+ import { createI18n, I18nProvider } from '@i18n-micro/preact'
14
+ import { createBrowserHistoryAdapter } from '@i18n-micro/preact/router'
15
+ import { App } from './App'
16
+
17
+ const locales = [{ code: 'en' }, { code: 'de' }]
18
+ const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', messages: { en: { greeting: 'Hello, {name}!' } } })
19
+
20
+ render(
21
+ <I18nProvider i18n={i18n} locales={locales} defaultLocale="en" routingStrategy={createBrowserHistoryAdapter(locales, 'en')}>
22
+ <App />
23
+ </I18nProvider>,
24
+ document.getElementById('app')!,
25
+ )
63
26
  ```
64
27
 
65
- ## Resources
66
-
67
- - **Repository**: [https://github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
68
- - **Documentation**: [https://s00d.github.io/nuxt-i18n-micro/](https://s00d.github.io/nuxt-i18n-micro/)
28
+ Docs: [https://s00d.github.io/nuxt-i18n-micro/integrations/react-package#preact](https://s00d.github.io/nuxt-i18n-micro/integrations/react-package#preact) · Repository: [github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
69
29
 
70
30
  ## License
71
31
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@i18n-micro/core"),t=require("preact"),n=require("preact/hooks"),r=require("@i18n-micro/runtime");var i=(0,t.createContext)(null),a=(0,t.createContext)(null),o=(0,t.createContext)(null),s=(0,t.createContext)(null),c=()=>{let e=(0,n.useContext)(i);if(!e)throw Error(`[i18n-micro] I18nContext not found. Make sure I18nProvider is used.`);return e},l=()=>(0,n.useContext)(a),u=()=>(0,n.useContext)(o),d=()=>(0,n.useContext)(s);function f({i18n:e,locales:n,defaultLocale:r,routingStrategy:c,children:l}){return(0,t.h)(i.Provider,{value:e},n?(0,t.h)(a.Provider,{value:n},r?(0,t.h)(o.Provider,{value:r},c?(0,t.h)(s.Provider,{value:c},l):l):l):l)}var p=e=>{let t=c(),r=d(),i=l(),a=u(),[,o]=(0,n.useState)(0);(0,n.useEffect)(()=>t.subscribe(()=>{o(e=>e+1)}),[t]);let s=e?.locales||i||[],f=e?.defaultLocale||a||t.locale,p=(e,n)=>r?.resolvePath?r.resolvePath(e,n||t.locale):e;return{t:t.t.bind(t),ts:t.ts.bind(t),tc:t.tc.bind(t),tn:t.tn.bind(t),td:t.td.bind(t),tdr:t.tdr.bind(t),has:t.has.bind(t),get locale(){return t.locale},get fallbackLocale(){return t.fallbackLocale},get currentRoute(){return t.currentRoute},setLocale:e=>{t.locale=e},setRoute:t.setRoute.bind(t),getRoute:t.getRoute.bind(t),getLocales:()=>s,defaultLocale:()=>f,getLocaleName:()=>s.find(e=>e.code===t.locale)?.displayName||null,switchLocale:e=>{if(t.locale=e,r){let t=r.getCurrentPath(),n=p(t,e);r.push(typeof n==`string`?{path:n}:{path:n.path||`/`})}},localeRoute:p,localePath:(e,t)=>{let n=p(e,t);return typeof n==`string`?n:n.path||`/`},addTranslations:t.addTranslations.bind(t),addRouteTranslations:t.addRouteTranslations.bind(t),clearCache:t.clearCache.bind(t)}},m=e=>{let{prefix:n,groupClass:r,children:i,...a}=e,{t:o,getRoute:s}=p(),c=(e,t)=>{let r=o(`${n}.${e}`,t,void 0,s());return typeof r==`string`?r:String(r)},l=[`i18n-group`,r].filter(Boolean).join(` `),u=typeof i==`function`?i({prefix:n,t:c}):i;return(0,t.h)(`div`,{...a,className:l},u)},h=e=>{let n=p(),r=d(),{to:i,activeStyle:a,localeRoute:o,children:s,...c}=e,l=o||n.localeRoute,u=()=>typeof i==`string`&&/^(?:https?:\/\/|\/\/|[a-zA-Z0-9-]+\.[a-zA-Z]{2,})|tel:|mailto:/.test(i),f=()=>{if(u()&&typeof i==`string`)return/^https?:\/\//.test(i)?i:`https://${i}`},m=()=>{if(u())return typeof i==`string`?i:i?.path||`/`;if(l){let e=l(i);return typeof e==`string`?e:e.path||`/`}if(!r?.resolvePath)return typeof i==`string`?i:i.path||`/`;let e=r.resolvePath(i,n.locale);return typeof e==`string`?e:e.path||`/`},h=(()=>{if(u()||!r)return!1;let e=r.getCurrentPath(),t=m(),n=e.replace(/\/$/,``),i=t.replace(/\/$/,``);return!!(n===i||n.startsWith(`${i}/`))})()&&a||{},g=m(),_=t=>{e.onClick&&e.onClick(t),!t.defaultPrevented&&!t.button&&!t.metaKey&&!t.ctrlKey&&r&&!u()&&(t.preventDefault(),r.push({path:g}))};if(u())return(0,t.h)(`a`,{...c,href:f(),style:h,target:`_blank`,rel:`noopener noreferrer`},s);if(r?.linkComponent){let e=r.linkComponent;if(typeof e==`string`)return(0,t.h)(e,{...c,href:g,style:h},s);let n=e,i={...c,href:g,style:h};return(0,t.h)(n,i,s)}return(0,t.h)(`a`,{...c,href:g,style:h,onClick:_},s)};function g(e,t){return typeof e==`function`?e():typeof e==`string`?e:t}var _=e=>{let{locales:r,currentLocale:i,getLocaleName:a,switchLocale:o,localeRoute:s,customLabels:u={},customWrapperStyle:f,customButtonStyle:m,customDropdownStyle:h,customItemStyle:_,customLinkStyle:v,customActiveLinkStyle:y,customDisabledLinkStyle:b={},customIconStyle:x,...S}=e,C=p(),w=c(),T=d(),E=l(),[D,O]=(0,n.useState)(!1),k=(0,n.useRef)(null),A=r||E||C.getLocales()||[],j=A.filter(e=>!e.disabled),M=g(i,C.locale),N=A.some(e=>e.code===M&&e.disabled),P=a?a():C.getLocaleName(),F=e=>{e&&(e.stopPropagation(),e.preventDefault()),O(!D)},I=e=>u[e.code]||e.displayName||e.code,L=()=>{let e=j.find(e=>e.code===M);return e?I(e):P||M},R=t=>{if(O(!1),o){o(t);return}if(w.locale=t,!T)return;let n=T.getCurrentPath(),r=e.localeRoute?(()=>{let r=e.localeRoute(n,t);return typeof r==`string`?r:r.path||`/`})():T?.resolvePath?(()=>{let e=T.resolvePath(n,t);return typeof e==`string`?e:e.path||`/`})():n;T.push({path:r})},z={position:`relative`,display:`inline-block`,verticalAlign:`middle`},B={padding:`4px 12px`,fontSize:`16px`,cursor:`pointer`,backgroundColor:`#fff`,border:`1px solid #333`,transition:`background-color 0.3s ease`,display:`flex`,alignItems:`center`,justifyContent:`space-between`},V={position:`absolute`,top:`100%`,left:`0`,zIndex:1e3,backgroundColor:`#fff`,border:`1px solid #333`,listStyle:`none`,padding:`0`,margin:`4px 0 0 0`,minWidth:`150px`,boxShadow:`0 2px 8px rgba(0,0,0,0.15)`},H={margin:`0`,padding:`0`},U={display:`block`,padding:`8px 12px`,color:`#333`,textDecoration:`none`,transition:`background-color 0.3s ease`,cursor:`pointer`},W={fontWeight:`bold`,color:`#007bff`,cursor:`not-allowed`},G={marginLeft:`8px`,display:`inline-block`,transition:`transform 0.3s ease`},K={transform:`rotate(180deg)`};(0,n.useEffect)(()=>{if(!D)return;let e=e=>{if(!D)return;let t=e.target;if(!t||!k.current)return;let n=k.current.contains(t),r=t.closest(`.i18n-switcher-button`)!==null;!n&&!r&&O(!1)};return document.addEventListener(`click`,e),()=>{document.removeEventListener(`click`,e)}},[D]);let q={...z,...f},J={...B,...m,...N?b:{}},Y={...V,...h},X={...H,..._},Z={...G,...D?K:{},...x},Q=j.map(e=>{let n=e.code===M,r={...U,...n?W:{},...v,...n?y:{},width:`100%`,textAlign:`left`,border:`none`,background:`transparent`};return(0,t.h)(`li`,{key:e.code,style:X},(0,t.h)(`button`,{type:`button`,className:`switcher-locale-${e.code}`,style:r,onClick:t=>{t.preventDefault(),t.stopPropagation(),R(e.code)}},I(e)))});return(0,t.h)(`div`,{ref:k,className:`i18n-switcher-wrapper`,style:q,...S},(0,t.h)(`button`,{type:`button`,className:`i18n-switcher-button`,style:J,onClick:e=>{e.preventDefault(),e.stopPropagation(),F(e)},"aria-haspopup":`true`,"aria-expanded":D},(0,t.h)(`span`,null,L()),(0,t.h)(`span`,{style:Z},`▼`)),D?(0,t.h)(`ul`,{className:`i18n-switcher-dropdown`,style:Y},...Q):null)},v=e=>{let{t:n,tc:r,tn:i,td:a,tdr:o,locale:s,getRoute:c}=p(),{keypath:l,params:u,tag:d=`span`,plural:f,defaultValue:m,html:h=!1,hideIfEmpty:g=!1,customPluralRule:_,number:v,date:y,relativeDate:b,...x}=e,S=c(),C=(e,n,r)=>(0,t.h)(e,n,r);if(v!==void 0){let e=n(l,{number:i(Number(v)),...u||{}},void 0,S),t=typeof e==`string`?e:String(e);return h?C(d,{...x,dangerouslySetInnerHTML:{__html:t}},void 0):C(d,x,t)}if(y!==void 0){let e=n(l,{date:a(y),...u||{}},void 0,S),t=typeof e==`string`?e:String(e);return h?C(d,{...x,dangerouslySetInnerHTML:{__html:t}},void 0):C(d,x,t)}if(b!==void 0){let e=n(l,{relativeDate:o(b),...u||{}},void 0,S),t=typeof e==`string`?e:String(e);return h?C(d,{...x,dangerouslySetInnerHTML:{__html:t}},void 0):C(d,x,t)}if(f!==void 0){let e=Number.parseInt(f.toString(),10),t;return t=_?_(l,e,u||{},s,(e,t,r)=>{let i=n(e,t,r,S);return typeof i==`string`?i:String(i)})||``:r(l,{count:e,...u||{}},m),h?C(d,{...x,dangerouslySetInnerHTML:{__html:t}},void 0):C(d,x,t)}let w=n(l,u,m,S),T=typeof w==`string`?w:String(w);return g&&!T.trim()?m?(0,t.h)(t.Fragment,null,m):null:h?C(d,{...x,dangerouslySetInnerHTML:{__html:T}},void 0):C(d,x,T)},y=class extends r.I18n{};function b(e){return new y(e)}function x(e,t){let n=e.map(e=>e.code),r=(e,r)=>{let i=(typeof e==`string`?e:e.path||`/`).split(`/`).filter(Boolean),a=i[0];a!==void 0&&n.includes(a)&&i.shift();let o=`/${i.join(`/`)}`;return r===t?o:`/${r}${o===`/`?``:o}`};return{linkComponent:void 0,getCurrentPath:()=>typeof window<`u`?window.location.pathname:`/`,push:e=>{typeof window<`u`&&(window.history.pushState({},``,e.path),window.dispatchEvent(new Event(`popstate`)))},replace:e=>{typeof window<`u`&&(window.history.replaceState({},``,e.path),window.dispatchEvent(new Event(`popstate`)))},resolvePath:(e,t)=>r(e,t),getRoute:()=>typeof window<`u`?{fullPath:window.location.pathname+window.location.search,query:Object.fromEntries(new URLSearchParams(window.location.search))}:{fullPath:`/`,query:{}}}}var S=x;Object.defineProperty(exports,"FormatService",{enumerable:!0,get:function(){return e.FormatService}}),exports.I18nContext=i,exports.I18nDefaultLocaleContext=o,exports.I18nGroup=m,exports.I18nLink=h,exports.I18nLocalesContext=a,exports.I18nProvider=f,exports.I18nRouterContext=s,exports.I18nSwitcher=_,exports.I18nT=v,exports.PreactI18n=y,exports.createBrowserHistoryAdapter=x,exports.createI18n=b,exports.createPreactRouterAdapter=S,Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:function(){return e.defaultPlural}}),Object.defineProperty(exports,"interpolate",{enumerable:!0,get:function(){return e.interpolate}}),exports.useI18n=p,exports.useI18nContext=c,exports.useI18nDefaultLocale=u,exports.useI18nLocales=l,exports.useI18nRouter=d;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@i18n-micro/runtime"),t=require("@i18n-micro/core"),n=require("preact"),r=require("preact/hooks"),i=require("@i18n-micro/core/render");var a={h:n.h,Fragment:n.Fragment,markup:e=>({dangerouslySetInnerHTML:{__html:e}}),dated:{}};function o(e,t){let n=t(),[,i]=(0,r.useState)(0),a=(0,r.useRef)({read:t,value:n});return a.current={read:t,value:n},(0,r.useLayoutEffect)(()=>{let t=()=>{a.current.read()!==a.current.value&&i(e=>e+1)};return t(),e(t)},[e]),n}var s=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,c=([e,t])=>e===`cssText`?String(t):e[0]===`-`?`${e}:${t}`:`${e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}:${typeof t==`number`&&!s.test(e)?`${t}px`:t}`,l=e=>typeof e==`string`?e:Object.entries(e).filter(([,e])=>e!=null).map(c).join(`;`);function u(...e){let t=e.filter(e=>e!=null);return t.some(e=>typeof e==`string`)?t.map(l).filter(Boolean).join(`;`):Object.assign({},...t)}var d=(0,n.createContext)(null),f=(0,n.createContext)(null),p=()=>{let e=(0,r.useContext)(d);if(!e)throw Error(`[i18n-micro] I18nContext not found. Make sure I18nProvider is used.`);return e},m=()=>(0,r.useContext)(f)?.locales??null,h=()=>(0,r.useContext)(f)?.defaultLocale??null,g=()=>(0,r.useContext)(f)?.router??null;function _(t){if(!t.locale)throw Error("[i18n-micro] I18nProvider needs an `i18n` instance, an outer provider, or a `locale`.");return(0,e.createI18n)(t)}function v({i18n:e,locales:i,defaultLocale:a,routingStrategy:o,children:s,...c}){let l=(0,r.useContext)(d),u=(0,r.useContext)(f),p=e??l,m=(0,r.useMemo)(()=>p??_(c),[p,c.locale]),h=(0,r.useRef)(null),g=(0,r.useRef)(null);i&&g.current!==m&&m.addLocaleIso((0,t.localeIsoMap)(i),!1),(0,r.useEffect)(()=>{g.current=m,i&&m.addLocaleIso((0,t.localeIsoMap)(i))},[m,i]);let v=(0,r.useMemo)(()=>({locales:i??u?.locales??null,defaultLocale:a??u?.defaultLocale??null,router:o??u?.router??null,api:null,methods:h}),[i,a,o,u]);return(0,n.h)(d.Provider,{value:m},(0,n.h)(f.Provider,{value:v},s))}var y=e=>typeof e==`string`?e:e.path||`/`,b=e=>({addTranslations:e.addTranslations.bind(e),addRouteTranslations:e.addRouteTranslations.bind(e),clearCache:e.clearCache.bind(e)});function x(e,t,n){let r=n?.current;if(r&&r.i18n===e&&r.snapshot===t)return r;let i={...r?.i18n===e?r:b(e),i18n:e,snapshot:t,t:e.t.bind(e),ts:e.ts.bind(e),tc:e.tc.bind(e),tn:e.tn.bind(e),td:e.td.bind(e),tdr:e.tdr.bind(e),has:e.has.bind(e)};return n&&(n.current=i),i}function S(e,{locales:t,defaultLocale:n,router:r},i){let a=t??[],o=(t,n)=>r?.resolvePath?r.resolvePath(t,n||e.locale):t,{t:s,ts:c,tc:l,tn:u,td:d,tdr:f,has:p,addTranslations:m,addRouteTranslations:h,clearCache:g}=i;return{t:s,ts:c,tc:l,tn:u,td:d,tdr:f,has:p,get locale(){return e.locale},get fallbackLocale(){return e.fallbackLocale},get currentRoute(){return e.currentRoute},setLocale:t=>{e.locale=t},setRoute:e.setRoute.bind(e),getRoute:e.getRoute.bind(e),getLocales:()=>a,defaultLocale:()=>n??e.fallbackLocale,getLocaleName:()=>a.find(t=>t.code===e.locale)?.displayName||null,switchLocale:t=>{e.locale=t,r&&r.push({path:y(o(r.getCurrentPath(),t))})},localeRoute:o,localePath:(e,t)=>y(o(e,t)),addTranslations:m,addRouteTranslations:h,clearCache:g}}var C=e=>{let t=p(),n=(0,r.useContext)(f),i=o(t.subscribe,t.getSnapshot),a=e?.locales??n?.locales??null,s=e?.defaultLocale??n?.defaultLocale??null,c=n?.router??null,l=n&&!e?.locales&&!e?.defaultLocale?n:null,u=(0,r.useMemo)(()=>l?null:S(t,{locales:a,defaultLocale:s,router:c},x(t,i,n?.methods)),[l,t,i,a,s,c]);return u||!l?u:(l.api?.snapshot!==i&&(l.api={snapshot:i,value:S(t,l,x(t,i,l.methods))}),l.api.value)};function w(e,t,n,r){let i=p();return o(i.subscribe,()=>i.ts(e,t,n,r))}function T(e){let{switchLocale:t}=C(),[n,i]=(0,r.useState)(!1),a=(0,r.useRef)(0),o=(0,r.useRef)(t);return o.current=t,[async t=>{let n=++a.current;i(!0);try{await e(t),n===a.current&&o.current(t)}finally{n===a.current&&i(!1)}},n]}var E=e=>{let{prefix:t,groupClass:r,children:i,className:a,class:o,...s}=e,{ts:c}=C(),l=(e,n)=>c(`${t}.${e}`,n);return(0,n.h)(`div`,{...s,className:[`i18n-group`,r,a,o].filter(Boolean).join(` `)},typeof i==`function`?i({prefix:t,t:l}):i)},D=e=>{let r=C(),i=g(),{to:a,activeStyle:o,localeRoute:s=r.localeRoute,style:c,onClick:l,children:d,...f}=e,p=(0,t.externalLinkHref)(a);if(p!==void 0)return(0,n.h)(`a`,{target:`_blank`,rel:`noopener noreferrer`,...f,onClick:l,style:c,href:p},d);let m=y(s(a)),h=o&&i&&(0,t.isActiveLink)(i.getCurrentPath(),m,[r.locale,r.defaultLocale(),r.fallbackLocale,...r.getLocales().map(e=>e.code)]),_={...f,href:m,style:h?u(c,o):c};if(i?.linkComponent)return(0,n.h)(i.linkComponent,{..._,onClick:l},d);let v=e=>{l?.(e),i&&(0,t.isPlainClick)(e)&&(e.preventDefault(),i.push({path:m}))};return(0,n.h)(`a`,{..._,onClick:v},d)},O=e=>{let{locales:a,currentLocale:o,getLocaleName:s,switchLocale:c,localeRoute:l,customLabels:d,customWrapperStyle:f,customButtonStyle:p,customDropdownStyle:h,customItemStyle:_,customLinkStyle:v,customActiveLinkStyle:b,customDisabledLinkStyle:x,customIconStyle:S,className:w,class:T,style:E,...D}=e,O=C(),k=g(),A=m(),[j,M]=(0,r.useState)(!1),N=(0,r.useRef)(null),P=a??A??O.getLocales(),F=typeof o==`function`?o():o??O.locale,I=P.find(e=>e.code===F);(0,r.useEffect)(()=>{if(!j)return;let e=e=>{N.current?.contains(e.target)||M(!1)},t=e=>{e.key===`Escape`&&M(!1)};return document.addEventListener(`click`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`click`,e),document.removeEventListener(`keydown`,t)}},[j]);let L=e=>d&&(0,t.ownValue)(d,e.code)||e.displayName||e.code,R=e=>{let t=k?.getCurrentPath()??(typeof window>`u`?`/`:window.location.pathname+window.location.search+window.location.hash);return l?y(l(t,e)):k?y(k.resolvePath?k.resolvePath(t,e):t):`#`},z=(e,n)=>{if((0,t.isPlainClick)(e)){if((c||k||!l)&&e.preventDefault(),M(!1),c)return c(n);if(!l)return O.switchLocale(n);O.setLocale(n),k?.push({path:R(n)})}},B=e=>{let t=e.code===F,r=e.iso||e.code;return(0,n.h)(`li`,{key:e.code,style:{...i.SWITCHER_STYLES.item,..._}},(0,n.h)(`a`,{className:`switcher-locale-${e.code}`,href:R(e.code),hrefLang:r,lang:r,dir:e.dir,"aria-current":t?`page`:void 0,style:{...i.SWITCHER_STYLES.link,...t?i.SWITCHER_STYLES.activeLink:null,...v,...t?b:null},onClick:t=>z(t,e.code)},L(e)))};return(0,n.h)(`div`,{...D,ref:N,className:[`i18n-switcher-wrapper`,w,T].filter(Boolean).join(` `),style:u(i.SWITCHER_STYLES.wrapper,f,E)},(0,n.h)(`button`,{type:`button`,className:`i18n-switcher-button language-switcher`,style:{...i.SWITCHER_STYLES.button,...p,...I?.disabled?x:null},"aria-expanded":j,onClick:()=>M(!j)},(0,n.h)(`span`,null,s?.()||L(I??{code:F})),` `,(0,n.h)(`span`,{style:{...i.SWITCHER_STYLES.icon,...j?i.SWITCHER_STYLES.openIcon:null,...S}},`▾`)),j?(0,n.h)(`ul`,{className:`i18n-switcher-dropdown`,style:{...i.SWITCHER_STYLES.dropdown,...h}},P.filter(e=>!e.disabled).map(B)):null)},k={},A=e=>e==null||typeof e==`boolean`,j=({render:e})=>e();function M({h:e},t,n){if(!t&&A(n))return k;let r=Object.create(null);for(let n of Object.keys(t??{})){let i=t[n];i!==void 0&&(r[n]=typeof i==`function`?()=>e(j,{render:i}):()=>i)}return A(n)||(r.default=typeof n==`function`?n:()=>n),r}function N(e,t,n){let{keypath:r,params:a,tag:o,plural:s,defaultValue:c,html:l,hideIfEmpty:u,customPluralRule:d,number:f,date:p,relativeDate:m,components:h,children:g,..._}=n;return(0,i.renderI18nT)(e,t,n,M(e,h,g),_)}var P=e=>{let t=p();return o(t.subscribe,t.getSnapshot),N(a,t,e)};Object.defineProperty(exports,"FormatService",{enumerable:!0,get:function(){return t.FormatService}}),exports.I18nConfigContext=f,exports.I18nContext=d,exports.I18nGroup=E,exports.I18nLink=D,exports.I18nProvider=v,exports.I18nSwitcher=O,exports.I18nT=P,Object.defineProperty(exports,"PreactI18n",{enumerable:!0,get:function(){return e.I18n}}),Object.defineProperty(exports,"createI18n",{enumerable:!0,get:function(){return e.createI18n}}),Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:function(){return t.defaultPlural}}),Object.defineProperty(exports,"interpolate",{enumerable:!0,get:function(){return t.interpolate}}),exports.useI18n=C,exports.useI18nContext=p,exports.useI18nDefaultLocale=h,exports.useI18nLocales=m,exports.useI18nRouter=g,exports.useLocaleSwitch=T,exports.useT=w;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["createContext","useContext","h","useState","h","toObj","h","useState","useRef","h","h","Fragment","RuntimeI18n","_i18n_micro_core","preact","preact_hooks","_i18n_micro_runtime","I18nContext","I18nLocalesContext","I18nDefaultLocaleContext","I18nRouterContext","useI18nContext","context","useI18nLocales","useI18nDefaultLocale","useI18nRouter","I18nProvider","i18n","locales","defaultLocale","routingStrategy","children","useI18n","router","injectedLocales","injectedDefaultLocale","forceUpdate","n","options","resolveLocalePath","to","localeCode","locale","l","newLocale","currentPath","newPath","res","I18nGroup","restProps","props","translate","result","t","prefix","key","params","getRoute","className","groupClass","childrenContent","I18nLink","localeRouteProp","localeRoute","isExternalLink","externalHref","targetPath","computedStyle","linkPath","normalizedCurrent","normalizedLink","activeStyle","toValue","handleClick","e","LinkComponent","Component","componentProps","resolveCurrentLocale","prop","fallback","I18nSwitcher","localesProp","currentLocaleProp","getLocaleNameProp","switchLocaleProp","_localeRouteProp","i18nInstance","dropdownOpen","setDropdownOpen","wrapperRef","allLocales","currentLocale","currentLocaleDisabled","currentLocaleName","toggleDropdown","event","localeLabel","customLabels","localeItem","currentLocaleLabel","current","handleSwitchLocale","code","wrapperStyle","buttonStyle","dropdownStyle","itemStyle","linkStyle","activeLinkStyle","iconStyle","openIconStyle","handler","target","isClickInside","isButtonClick","mergedWrapperStyle","customWrapperStyle","mergedButtonStyle","customButtonStyle","customDisabledLinkStyle","mergedDropdownStyle","customDropdownStyle","mergedItemStyle","customItemStyle","mergedIconStyle","customIconStyle","dropdownItems","isActive","mergedLinkStyle","customLinkStyle","customActiveLinkStyle","I18nT","route","createElement","elementTag","elementProps","number","translation","keypath","tn","content","html","tag","date","td","relativeDate","tdr","plural","count","customPluralRule","tResult","k","p","dv","tc","defaultValue","hideIfEmpty","PreactI18n","createI18n","createBrowserHistoryAdapter","localeCodes","loc","resolvePath","pathSegments","first","cleanPath","createPreactRouterAdapter"],"sources":["../src/injection.ts","../src/context.tsx","../src/components/I18nGroup.tsx","../src/components/I18nLink.tsx","../src/components/I18nSwitcher.tsx","../src/components/I18nT.tsx","../src/i18n.ts","../src/router/adapter.tsx"],"sourcesContent":["import type { Locale } from '@i18n-micro/types'\nimport { createContext } from 'preact'\nimport { useContext } from 'preact/hooks'\nimport type { PreactI18n } from './i18n'\nimport type { I18nRoutingStrategy } from './router/types'\n\n// Context keys (analogous to Vue's InjectionKey)\nexport const I18nContext = createContext<PreactI18n | null>(null)\nexport const I18nLocalesContext = createContext<Locale[] | null>(null)\nexport const I18nDefaultLocaleContext = createContext<string | null>(null)\nexport const I18nRouterContext = createContext<I18nRoutingStrategy | null>(null)\n\n// Helper hooks (analogous to Vue's inject)\nexport const useI18nContext = () => {\n const context = useContext(I18nContext)\n if (!context) {\n throw new Error('[i18n-micro] I18nContext not found. Make sure I18nProvider is used.')\n }\n return context\n}\n\nexport const useI18nLocales = () => {\n return useContext(I18nLocalesContext)\n}\n\nexport const useI18nDefaultLocale = () => {\n return useContext(I18nDefaultLocaleContext)\n}\n\nexport const useI18nRouter = () => {\n return useContext(I18nRouterContext)\n}\n","import type { CleanTranslation, Locale, Params, TranslationKey, Translations } from '@i18n-micro/types'\nimport type { ComponentChildren } from 'preact'\nimport { h } from 'preact'\nimport { useEffect, useState } from 'preact/hooks'\nimport type { PreactI18n } from './i18n'\nimport {\n I18nContext,\n I18nDefaultLocaleContext,\n I18nLocalesContext,\n I18nRouterContext,\n useI18nContext,\n useI18nDefaultLocale,\n useI18nLocales,\n useI18nRouter,\n} from './injection'\nimport type { I18nRoutingStrategy } from './router/types'\n\nexport interface I18nProviderProps {\n i18n: PreactI18n\n locales?: Locale[]\n defaultLocale?: string\n routingStrategy?: I18nRoutingStrategy\n children?: ComponentChildren\n}\n\nexport function I18nProvider({ i18n, locales, defaultLocale, routingStrategy, children }: I18nProviderProps) {\n return h(\n I18nContext.Provider,\n { value: i18n },\n locales\n ? h(\n I18nLocalesContext.Provider,\n { value: locales },\n defaultLocale\n ? h(\n I18nDefaultLocaleContext.Provider,\n { value: defaultLocale },\n routingStrategy ? h(I18nRouterContext.Provider, { value: routingStrategy }, children) : children,\n )\n : children,\n )\n : children,\n )\n}\n\nexport interface UseI18nOptions {\n locales?: Locale[]\n defaultLocale?: string\n}\n\nexport interface UseI18nReturn {\n // Translation methods\n t: (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string) => CleanTranslation\n ts: (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string) => string\n tc: (key: TranslationKey, count: number | Params, defaultValue?: string) => string\n tn: (value: number, options?: Intl.NumberFormatOptions) => string\n td: (value: Date | number | string, options?: Intl.DateTimeFormatOptions) => string\n tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string\n has: (key: TranslationKey, routeName?: string) => boolean\n\n // Locale management\n locale: string\n fallbackLocale: string\n currentRoute: string\n setLocale: (locale: string) => void\n\n // Route management\n setRoute: (routeName: string) => void\n getRoute: () => string\n getLocales: () => Locale[]\n defaultLocale: () => string\n getLocaleName: () => string | null\n\n // Router methods (if router is available)\n switchLocale?: (locale: string) => void\n localeRoute?: (to: string | { path?: string }, locale?: string) => string | { path?: string }\n localePath?: (to: string | { path?: string }, locale?: string) => string\n\n // Translation management\n addTranslations: (locale: string, translations: Translations, merge?: boolean) => void\n addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void\n clearCache: () => void\n}\n\nexport const useI18n = (options?: UseI18nOptions): UseI18nReturn => {\n const i18n = useI18nContext()\n const router = useI18nRouter()\n const injectedLocales = useI18nLocales()\n const injectedDefaultLocale = useI18nDefaultLocale()\n\n // --- Замена useSyncExternalStore для Pure Preact ---\n // Подписываемся на изменения в i18n и форсируем ре-рендер\n const [, forceUpdate] = useState(0)\n\n useEffect(() => {\n // subscribe возвращает функцию отписки\n const unsubscribe = i18n.subscribe(() => {\n forceUpdate((n) => n + 1)\n })\n return unsubscribe\n }, [i18n])\n // ---------------------------------------------------\n\n const locales = options?.locales || injectedLocales || []\n const defaultLocale = options?.defaultLocale || injectedDefaultLocale || i18n.locale\n\n const resolveLocalePath = (to: string | { path?: string }, localeCode?: string): string | { path?: string } => {\n if (!router?.resolvePath) {\n return to\n }\n return router.resolvePath(to, localeCode || i18n.locale)\n }\n\n const switchLocaleHelper = (newLocale: string): void => {\n i18n.locale = newLocale\n if (router) {\n const currentPath = router.getCurrentPath()\n const newPath = resolveLocalePath(currentPath, newLocale)\n router.push(typeof newPath === 'string' ? { path: newPath } : { path: newPath.path || '/' })\n }\n }\n\n return {\n // Translation methods\n t: i18n.t.bind(i18n),\n ts: i18n.ts.bind(i18n),\n tc: i18n.tc.bind(i18n),\n tn: i18n.tn.bind(i18n),\n td: i18n.td.bind(i18n),\n tdr: i18n.tdr.bind(i18n),\n has: i18n.has.bind(i18n),\n\n // Locale management\n get locale() {\n return i18n.locale\n },\n get fallbackLocale() {\n return i18n.fallbackLocale\n },\n get currentRoute() {\n return i18n.currentRoute\n },\n setLocale: (locale: string) => {\n i18n.locale = locale\n },\n\n // Route management\n setRoute: i18n.setRoute.bind(i18n),\n getRoute: i18n.getRoute.bind(i18n),\n getLocales: () => locales,\n defaultLocale: () => defaultLocale,\n getLocaleName: () => {\n const current = locales.find((l) => l.code === i18n.locale)\n return current?.displayName || null\n },\n\n // Router methods (always available, but navigation handled by components)\n switchLocale: switchLocaleHelper,\n localeRoute: resolveLocalePath,\n localePath: (to: string | { path?: string }, locale?: string) => {\n const res = resolveLocalePath(to, locale)\n return typeof res === 'string' ? res : res.path || '/'\n },\n\n // Translation management\n addTranslations: i18n.addTranslations.bind(i18n),\n addRouteTranslations: i18n.addRouteTranslations.bind(i18n),\n clearCache: i18n.clearCache.bind(i18n),\n }\n}\n\n// Export context for advanced usage\nexport { I18nContext } from './injection'\n","import type { TranslationKey } from '@i18n-micro/types'\nimport type { ComponentChildren, HTMLAttributes, VNode } from 'preact'\nimport { h } from 'preact'\nimport { useI18n } from '../context'\n\nexport interface I18nGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n prefix: string\n groupClass?: string\n children?: (props: { prefix: string; t: (key: string, params?: Record<string, string | number | boolean>) => string }) => ComponentChildren\n}\n\nexport const I18nGroup = (props: I18nGroupProps): VNode => {\n const { prefix, groupClass, children, ...restProps } = props\n const { t, getRoute } = useI18n()\n\n const translate = (key: string, params?: Record<string, string | number | boolean>): string => {\n const result = t(`${prefix}.${key}` as TranslationKey, params, undefined, getRoute())\n return typeof result === 'string' ? result : String(result)\n }\n\n const className = ['i18n-group', groupClass].filter(Boolean).join(' ')\n\n const childrenContent: ComponentChildren = typeof children === 'function' ? children({ prefix, t: translate }) : children\n\n return h('div', { ...restProps, className }, childrenContent) as VNode\n}\n","import type { AnchorHTMLAttributes, TargetedMouseEvent, VNode } from 'preact'\nimport { h } from 'preact'\nimport { useI18n } from '../context'\nimport { useI18nRouter } from '../injection'\n\nexport interface I18nLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n to: string | { path?: string }\n activeStyle?: Record<string, string | number>\n localeRoute?: (to: string | { path?: string }, locale?: string) => string | { path?: string }\n}\n\nexport const I18nLink = (props: I18nLinkProps): VNode => {\n const i18n = useI18n()\n const router = useI18nRouter()\n const { to, activeStyle, localeRoute: localeRouteProp, children, ...restProps } = props\n\n // Use prop if provided, otherwise fallback to useI18n\n const localeRoute = localeRouteProp || i18n.localeRoute\n\n const isExternalLink = (): boolean => {\n if (typeof to === 'string') {\n return /^(?:https?:\\/\\/|\\/\\/|[a-zA-Z0-9-]+\\.[a-zA-Z]{2,})|tel:|mailto:/.test(to)\n }\n return false\n }\n\n const externalHref = (): string | undefined => {\n if (isExternalLink() && typeof to === 'string') {\n if (!/^https?:\\/\\//.test(to)) {\n return `https://${to}`\n }\n return to\n }\n return undefined\n }\n\n const targetPath = (): string => {\n if (isExternalLink()) {\n if (typeof to === 'string') {\n return to\n }\n const toObj = to as { path?: string }\n return toObj?.path || '/'\n }\n\n if (localeRoute) {\n const res = localeRoute(to)\n return typeof res === 'string' ? res : res.path || '/'\n }\n\n if (!router?.resolvePath) {\n return typeof to === 'string' ? to : to.path || '/'\n }\n\n const res = router.resolvePath(to, i18n.locale)\n return typeof res === 'string' ? res : res.path || '/'\n }\n\n const isActive = (): boolean => {\n if (isExternalLink() || !router) {\n return false\n }\n\n const currentPath = router.getCurrentPath()\n const linkPath = targetPath()\n\n // Normalize paths (remove trailing slashes)\n const normalizedCurrent = currentPath.replace(/\\/$/, '')\n const normalizedLink = linkPath.replace(/\\/$/, '')\n\n // Exact match (ignoring query params and hash)\n if (normalizedCurrent === normalizedLink) {\n return true\n }\n\n // Partial match: check if current path starts with link path\n // This allows parent routes to be marked as active\n if (normalizedCurrent.startsWith(`${normalizedLink}/`)) {\n return true\n }\n\n return false\n }\n\n const computedStyle: Record<string, string | number> = isActive() ? activeStyle || {} : {}\n const toValue = targetPath()\n\n const handleClick = (e: TargetedMouseEvent<HTMLAnchorElement>) => {\n if (props.onClick) {\n props.onClick(e)\n }\n\n // Если это не внешний линк и нет модификаторов (ctrl/meta)\n if (!e.defaultPrevented && !e.button && !e.metaKey && !e.ctrlKey && router && !isExternalLink()) {\n e.preventDefault()\n router.push({ path: toValue })\n }\n }\n\n if (isExternalLink()) {\n return h(\n 'a',\n {\n ...restProps,\n href: externalHref(),\n style: computedStyle,\n target: '_blank',\n rel: 'noopener noreferrer',\n },\n children,\n ) as VNode\n }\n\n // Use router linkComponent if available\n if (router?.linkComponent) {\n const LinkComponent = router.linkComponent\n if (typeof LinkComponent === 'string') {\n return h(\n LinkComponent,\n {\n ...restProps,\n href: toValue,\n style: computedStyle,\n },\n children,\n ) as VNode\n }\n // Type assertion needed because React.ComponentType from I18nRoutingStrategy\n // is compatible with Preact components at runtime\n const Component = LinkComponent as unknown as (props: {\n href: string\n children?: VNode | VNode[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }) => VNode\n // Extract only the props that are compatible with the component type\n const componentProps = {\n ...restProps,\n href: toValue,\n style: computedStyle,\n } as {\n href: string\n children?: VNode | VNode[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }\n return h(Component, componentProps, children) as VNode\n }\n\n // Fallback to anchor with onClick handler\n return h(\n 'a',\n {\n ...restProps,\n href: toValue,\n style: computedStyle,\n onClick: handleClick,\n },\n children,\n ) as VNode\n}\n","import type { Locale } from '@i18n-micro/types'\nimport type { HTMLAttributes, VNode } from 'preact'\nimport { h } from 'preact'\nimport { useEffect, useRef, useState } from 'preact/hooks'\nimport { useI18n } from '../context'\nimport { useI18nContext, useI18nLocales, useI18nRouter } from '../injection'\n\nfunction resolveCurrentLocale(prop: string | (() => string) | undefined, fallback: string): string {\n if (typeof prop === 'function') return prop()\n if (typeof prop === 'string') return prop\n return fallback\n}\n\nexport interface I18nSwitcherProps extends HTMLAttributes<HTMLDivElement> {\n locales?: Locale[]\n currentLocale?: string | (() => string)\n getLocaleName?: () => string | null\n switchLocale?: (locale: string) => void\n localeRoute?: (to: string | { path?: string }, locale?: string) => string | { path?: string }\n customLabels?: Record<string, string>\n customWrapperStyle?: Record<string, string | number>\n customButtonStyle?: Record<string, string | number>\n customDropdownStyle?: Record<string, string | number>\n customItemStyle?: Record<string, string | number>\n customLinkStyle?: Record<string, string | number>\n customActiveLinkStyle?: Record<string, string | number>\n /**\n * Inline style applied to the main switcher button when the current locale is\n * marked as `disabled: true` in locale config.\n *\n * Disabled locales are omitted from dropdown items.\n */\n customDisabledLinkStyle?: Record<string, string | number>\n customIconStyle?: Record<string, string | number>\n}\n\nexport const I18nSwitcher = (props: I18nSwitcherProps): VNode => {\n const {\n locales: localesProp,\n currentLocale: currentLocaleProp,\n getLocaleName: getLocaleNameProp,\n switchLocale: switchLocaleProp,\n localeRoute: _localeRouteProp,\n customLabels = {},\n customWrapperStyle,\n customButtonStyle,\n customDropdownStyle,\n customItemStyle,\n customLinkStyle,\n customActiveLinkStyle,\n customDisabledLinkStyle = {},\n customIconStyle,\n ...restProps\n } = props\n\n const i18n = useI18n()\n const i18nInstance = useI18nContext()\n const router = useI18nRouter()\n const injectedLocales = useI18nLocales()\n const [dropdownOpen, setDropdownOpen] = useState(false)\n const wrapperRef = useRef<HTMLDivElement>(null)\n\n // Use props if provided, otherwise fallback to injected or useI18n.\n // Exclude `disabled: true` locales from the UI switcher (keep them available via getLocales for SEO).\n const allLocales = localesProp || injectedLocales || i18n.getLocales() || []\n const locales = allLocales.filter((locale) => !locale.disabled)\n\n // Get current locale value (handle both string and function)\n const currentLocale = resolveCurrentLocale(currentLocaleProp, i18n.locale)\n const currentLocaleDisabled = allLocales.some((l) => l.code === currentLocale && l.disabled)\n const currentLocaleName = getLocaleNameProp ? getLocaleNameProp() : i18n.getLocaleName()\n\n const toggleDropdown = (event?: Event) => {\n if (event) {\n event.stopPropagation()\n event.preventDefault()\n }\n setDropdownOpen(!dropdownOpen)\n }\n\n const localeLabel = (localeItem: Locale): string => {\n const current = customLabels[localeItem.code] || localeItem.displayName\n return current || localeItem.code\n }\n\n const currentLocaleLabel = (): string => {\n const current = locales.find((l) => l.code === currentLocale)\n return current ? localeLabel(current) : currentLocaleName || currentLocale\n }\n\n const handleSwitchLocale = (code: string) => {\n setDropdownOpen(false)\n if (switchLocaleProp) {\n switchLocaleProp(code)\n return\n }\n\n i18nInstance.locale = code\n\n if (!router) {\n return\n }\n\n const currentPath = router.getCurrentPath()\n const newPath = props.localeRoute\n ? (() => {\n const res = props.localeRoute(currentPath, code)\n return typeof res === 'string' ? res : res.path || '/'\n })()\n : router?.resolvePath\n ? (() => {\n const res = router.resolvePath(currentPath, code)\n return typeof res === 'string' ? res : res.path || '/'\n })()\n : currentPath\n\n router.push({ path: newPath })\n }\n\n // Default Styles\n const wrapperStyle: Record<string, string | number> = {\n position: 'relative',\n display: 'inline-block',\n verticalAlign: 'middle',\n }\n\n const buttonStyle: Record<string, string | number> = {\n padding: '4px 12px',\n fontSize: '16px',\n cursor: 'pointer',\n backgroundColor: '#fff',\n border: '1px solid #333',\n transition: 'background-color 0.3s ease',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }\n\n const dropdownStyle: Record<string, string | number> = {\n position: 'absolute',\n top: '100%',\n left: '0',\n zIndex: 1000,\n backgroundColor: '#fff',\n border: '1px solid #333',\n listStyle: 'none',\n padding: '0',\n margin: '4px 0 0 0',\n minWidth: '150px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n }\n\n const itemStyle: Record<string, string | number> = {\n margin: '0',\n padding: '0',\n }\n\n const linkStyle: Record<string, string | number> = {\n display: 'block',\n padding: '8px 12px',\n color: '#333',\n textDecoration: 'none',\n transition: 'background-color 0.3s ease',\n cursor: 'pointer',\n }\n\n const activeLinkStyle: Record<string, string | number> = {\n fontWeight: 'bold',\n color: '#007bff',\n cursor: 'not-allowed',\n }\n\n const iconStyle: Record<string, string | number> = {\n marginLeft: '8px',\n display: 'inline-block',\n transition: 'transform 0.3s ease',\n }\n\n const openIconStyle: Record<string, string | number> = {\n transform: 'rotate(180deg)',\n }\n\n useEffect(() => {\n if (!dropdownOpen) return\n const handler = (event: MouseEvent) => {\n if (!dropdownOpen) return\n\n const target = event.target as HTMLElement\n if (!target || !wrapperRef.current) return\n\n const isClickInside = wrapperRef.current.contains(target)\n const isButtonClick = target.closest('.i18n-switcher-button') !== null\n\n if (!isClickInside && !isButtonClick) {\n setDropdownOpen(false)\n }\n }\n document.addEventListener('click', handler)\n return () => {\n document.removeEventListener('click', handler)\n }\n }, [dropdownOpen])\n\n const mergedWrapperStyle = { ...wrapperStyle, ...customWrapperStyle }\n const mergedButtonStyle = {\n ...buttonStyle,\n ...customButtonStyle,\n ...(currentLocaleDisabled ? customDisabledLinkStyle : {}),\n }\n const mergedDropdownStyle = { ...dropdownStyle, ...customDropdownStyle }\n const mergedItemStyle = { ...itemStyle, ...customItemStyle }\n const mergedIconStyle = {\n ...iconStyle,\n ...(dropdownOpen ? openIconStyle : {}),\n ...customIconStyle,\n }\n\n const dropdownItems = locales.map((localeItem) => {\n const isActive = localeItem.code === currentLocale\n const mergedLinkStyle = {\n ...linkStyle,\n ...(isActive ? activeLinkStyle : {}),\n ...customLinkStyle,\n ...(isActive ? customActiveLinkStyle : {}),\n width: '100%',\n textAlign: 'left',\n border: 'none',\n background: 'transparent',\n }\n\n return h(\n 'li',\n {\n key: localeItem.code,\n style: mergedItemStyle,\n },\n h(\n 'button',\n {\n type: 'button',\n className: `switcher-locale-${localeItem.code}`,\n style: mergedLinkStyle,\n onClick: (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n handleSwitchLocale(localeItem.code)\n },\n },\n localeLabel(localeItem),\n ),\n )\n })\n\n return h(\n 'div',\n {\n ref: wrapperRef,\n className: 'i18n-switcher-wrapper',\n style: mergedWrapperStyle,\n ...restProps,\n },\n h(\n 'button',\n {\n type: 'button',\n className: 'i18n-switcher-button',\n style: mergedButtonStyle,\n onClick: (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n toggleDropdown(e)\n },\n 'aria-haspopup': 'true',\n 'aria-expanded': dropdownOpen,\n },\n h('span', null, currentLocaleLabel()),\n h('span', { style: mergedIconStyle }, '▼'),\n ),\n dropdownOpen\n ? h(\n 'ul',\n {\n className: 'i18n-switcher-dropdown',\n style: mergedDropdownStyle,\n },\n ...dropdownItems,\n )\n : null,\n ) as VNode\n}\n","import type { PluralFunc, TranslationKey } from '@i18n-micro/types'\nimport type { HTMLAttributes, JSX, VNode } from 'preact'\nimport { Fragment, h } from 'preact'\nimport { useI18n } from '../context'\n\nexport interface I18nTProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {\n keypath: TranslationKey\n params?: Record<string, string | number | boolean>\n tag?: keyof JSX.IntrinsicElements\n plural?: number | string\n defaultValue?: string\n html?: boolean\n hideIfEmpty?: boolean\n customPluralRule?: PluralFunc\n number?: number | string\n date?: Date | string | number\n relativeDate?: Date | string | number\n children?: never // I18nT doesn't support children - translation is rendered as content\n}\n\nexport const I18nT = (props: I18nTProps): VNode | null => {\n const { t, tc, tn, td, tdr, locale, getRoute } = useI18n()\n const {\n keypath,\n params,\n tag = 'span',\n plural,\n defaultValue,\n html = false,\n hideIfEmpty = false,\n customPluralRule,\n number,\n date,\n relativeDate,\n ...restProps\n } = props\n\n const route = getRoute()\n\n // Helper function to create element with proper typing\n const createElement = (elementTag: keyof JSX.IntrinsicElements, elementProps: HTMLAttributes<HTMLElement>, children?: string): VNode => {\n return h(elementTag as unknown as keyof JSX.IntrinsicElements, elementProps as unknown as HTMLAttributes<HTMLElement>, children) as VNode\n }\n\n // Handle number formatting\n if (number !== undefined) {\n const numberValue = Number(number)\n const formattedNumber = tn(numberValue)\n const translation = t(keypath, { number: formattedNumber, ...(params || {}) }, undefined, route)\n const content = typeof translation === 'string' ? translation : String(translation)\n if (html) {\n return createElement(tag, { ...restProps, dangerouslySetInnerHTML: { __html: content } }, undefined)\n }\n return createElement(tag, restProps, content)\n }\n\n // Handle date formatting\n if (date !== undefined) {\n const formattedDate = td(date)\n const translation = t(keypath, { date: formattedDate, ...(params || {}) }, undefined, route)\n const content = typeof translation === 'string' ? translation : String(translation)\n if (html) {\n return createElement(tag, { ...restProps, dangerouslySetInnerHTML: { __html: content } }, undefined)\n }\n return createElement(tag, restProps, content)\n }\n\n // Handle relative date formatting\n if (relativeDate !== undefined) {\n const formattedRelativeDate = tdr(relativeDate)\n const translation = t(keypath, { relativeDate: formattedRelativeDate, ...(params || {}) }, undefined, route)\n const content = typeof translation === 'string' ? translation : String(translation)\n if (html) {\n return createElement(tag, { ...restProps, dangerouslySetInnerHTML: { __html: content } }, undefined)\n }\n return createElement(tag, restProps, content)\n }\n\n // Handle pluralization\n if (plural !== undefined) {\n const count = Number.parseInt(plural.toString(), 10)\n let translation: string\n if (customPluralRule) {\n const result = customPluralRule(\n keypath,\n count,\n params || {},\n locale,\n (k: TranslationKey, p?: Record<string, string | number | boolean>, dv?: string) => {\n const tResult = t(k, p, dv, route)\n return typeof tResult === 'string' ? tResult : String(tResult)\n },\n )\n translation = result || ''\n } else {\n translation = tc(keypath, { count, ...(params || {}) }, defaultValue)\n }\n if (html) {\n return createElement(tag, { ...restProps, dangerouslySetInnerHTML: { __html: translation } }, undefined)\n }\n return createElement(tag, restProps, translation)\n }\n\n // Regular translation\n const translation = t(keypath, params, defaultValue, route)\n const content = typeof translation === 'string' ? translation : String(translation)\n\n if (hideIfEmpty && !content.trim()) {\n return defaultValue ? (h(Fragment, null, defaultValue) as VNode) : null\n }\n\n if (html) {\n return createElement(tag, { ...restProps, dangerouslySetInnerHTML: { __html: content } }, undefined)\n }\n\n return createElement(tag, restProps, content)\n}\n","import { I18n as RuntimeI18n, type I18nOptions as RuntimeI18nOptions } from '@i18n-micro/runtime'\n\nexport interface PreactI18nOptions extends RuntimeI18nOptions {}\n\n/**\n * Preact-facing i18n instance. Same surface as `@i18n-micro/runtime`, kept as a\n * named subclass so `instanceof PreactI18n` and context typing stay stable.\n */\nexport class PreactI18n extends RuntimeI18n {}\n\nexport function createI18n(options: PreactI18nOptions): PreactI18n {\n return new PreactI18n(options)\n}\n","import type { Locale } from '@i18n-micro/types'\nimport type { I18nRoutingStrategy } from './types'\n\n/**\n * Создает адаптер для работы с History API (универсальный для Pure Preact)\n * Работает с любым роутером, который использует History API (wouter, preact-router, и т.д.)\n */\nexport function createBrowserHistoryAdapter(locales: Locale[], defaultLocale: string): I18nRoutingStrategy {\n const localeCodes = locales.map((loc) => loc.code)\n\n /**\n * Path resolution logic (add prefix or not)\n */\n const resolvePath = (to: string | { path?: string }, locale: string): string | { path?: string } => {\n const path = typeof to === 'string' ? to : to.path || '/'\n const pathSegments = path.split('/').filter(Boolean)\n\n // If path already starts with a locale, remove it\n const first = pathSegments[0]\n if (first !== undefined && localeCodes.includes(first)) {\n pathSegments.shift()\n }\n\n const cleanPath = `/${pathSegments.join('/')}`\n\n // If default locale - return clean path\n if (locale === defaultLocale) {\n return cleanPath\n }\n\n // Otherwise add prefix\n return `/${locale}${cleanPath === '/' ? '' : cleanPath}`\n }\n\n return {\n // Просто рендерим <a>, навигацию перехватит onClick в I18nLink\n linkComponent: undefined,\n\n getCurrentPath: () => {\n if (typeof window !== 'undefined') {\n return window.location.pathname\n }\n return '/'\n },\n\n push: (target) => {\n if (typeof window !== 'undefined') {\n window.history.pushState({}, '', target.path)\n // Вызываем событие, чтобы роутеры (wouter/preact-router) узнали об изменении\n window.dispatchEvent(new Event('popstate'))\n }\n },\n\n replace: (target) => {\n if (typeof window !== 'undefined') {\n window.history.replaceState({}, '', target.path)\n window.dispatchEvent(new Event('popstate'))\n }\n },\n\n resolvePath: (to, locale) => resolvePath(to, locale),\n\n getRoute: () => {\n if (typeof window !== 'undefined') {\n return {\n fullPath: window.location.pathname + window.location.search,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n }\n }\n return {\n fullPath: '/',\n query: {},\n }\n },\n }\n}\n\n// Export for backward compatibility (old name)\nexport const createPreactRouterAdapter = createBrowserHistoryAdapter\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["useState","useRef","createContext","useContext","createI18n","useContext","useMemo","useRef","localeIsoMap","h","useState","h","externalLinkHref","h","isActiveLink","isPlainClick","useState","useRef","ownValue","isPlainClick","h","STYLES","renderI18nT","_i18n_micro_runtime","_i18n_micro_core","preact","preact_hooks","_i18n_micro_core_render","API","html","useStore","value","read","update","latest","check","n","subscribe","IS_NON_DIMENSIONAL","declaration","name","letter","cssText","style","mergeStyles","styles","present","I18nContext","I18nConfigContext","useI18nContext","context","useI18nLocales","useI18nDefaultLocale","useI18nRouter","buildInstance","options","I18nProvider","outerInstance","outer","inherited","i18n","instance","methods","committed","locales","config","defaultLocale","routingStrategy","children","routePath","target","bindWriters","translationMethods","known","cache","snapshot","createApi","list","localeRoute","router","to","code","locale","l","useI18n","shared","own","useT","key","params","defaultValue","routeName","useLocaleSwitch","pending","setPending","current","switchLocale","call","load","I18nGroup","userClass","restProps","props","translate","ts","prefix","groupClass","className","I18nLink","externalHref","href","active","activeStyle","linkProps","handleClick","onClick","event","I18nSwitcher","localesProp","currentLocaleProp","injectedLocales","open","setOpen","wrapper","allLocales","currentItem","onKeydown","label","customLabels","path","select","renderItem","language","customItemStyle","customLinkStyle","customActiveLinkStyle","customWrapperStyle","customButtonStyle","customDisabledLinkStyle","getLocaleName","customIconStyle","customDropdownStyle","NO_SLOTS","isUnset","Slot","render","toSlots","components","slots","h","renderText","attrs","api","I18nT"],"sources":["../src/host.ts","../../react/src/injection.ts","../../react/src/context.tsx","../../react/src/components/I18nGroup.tsx","../../react/src/components/I18nLink.tsx","../../react/src/components/I18nSwitcher.tsx","../../react/src/components/render-text.ts","../../react/src/components/I18nT.tsx"],"sourcesContent":["/**\n * `#host` of the source shared with `@i18n-micro/react`: the same names over Preact itself, not\n * `preact/compat`, whose `useSyncExternalStore` alone costs more than the rest of this package.\n */\nimport type { RenderApi } from '@i18n-micro/core/render'\nimport type { AnchorHTMLAttributes, ComponentChildren, ComponentType, CSSProperties, HTMLAttributes, JSX, TargetedMouseEvent, VNode } from 'preact'\nimport { createContext, Fragment, h } from 'preact'\nimport { useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'preact/hooks'\n\nexport { createContext, Fragment, h, useContext, useEffect, useMemo, useRef, useState }\n\nexport const API: RenderApi = {\n h,\n Fragment,\n markup: (html) => ({ dangerouslySetInnerHTML: { __html: html } }),\n // Preact does not check text on hydration, and would print this as an attribute\n dated: {},\n}\n\n/**\n * A store read. Subscribing in a layout effect leaves a gap after render, where a child's effect or\n * a resolved load can change the store: the first check closes it.\n */\nexport function useStore<T>(subscribe: (listener: () => void) => () => void, read: () => T): T {\n const value = read()\n const [, update] = useState(0)\n const latest = useRef({ read, value })\n latest.current = { read, value }\n useLayoutEffect(() => {\n const check = () => {\n if (latest.current.read() !== latest.current.value) update((n) => n + 1)\n }\n check()\n return subscribe(check)\n }, [subscribe])\n return value\n}\n\n/** Preact's own rule for a number without a unit. */\nconst IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i\n\n/** What Preact's `setStyle` does for one entry: `cssText` is raw CSS, `--name` is a custom property and takes no unit. */\nconst declaration = ([name, value]: [string, unknown]): string => {\n if (name === 'cssText') return String(value)\n if (name[0] === '-') return `${name}:${value}`\n return `${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}:${typeof value === 'number' && !IS_NON_DIMENSIONAL.test(name) ? `${value}px` : value}`\n}\n\nconst cssText = (style: CSSProperties | string): string =>\n typeof style === 'string'\n ? style\n : Object.entries(style)\n .filter(([, value]) => value !== null && value !== undefined)\n .map(declaration)\n .join(';')\n\n/** Later wins. Preact's `style` takes an object or a CSS string; a string among them makes the result one too. */\nexport function mergeStyles(...styles: (CSSProperties | string | null | undefined)[]): CSSProperties | string {\n const present = styles.filter((style) => style !== null && style !== undefined)\n if (present.some((style) => typeof style === 'string')) return present.map(cssText).filter(Boolean).join(';')\n return Object.assign({}, ...present)\n}\n\nexport type HostNode = ComponentChildren\nexport type HostElement = VNode<any> | null\nexport type HostStyle = CSSProperties\nexport type HostTag = keyof JSX.IntrinsicElements\nexport type HostAttrs<E extends EventTarget> = HTMLAttributes<E>\nexport type HostAnchorAttrs<E extends EventTarget> = AnchorHTMLAttributes<E>\nexport type HostMouseEvent<E extends Element> = TargetedMouseEvent<E>\nexport type HostComponent<P> = ComponentType<P>\n","import type { I18n } from '@i18n-micro/runtime'\nimport type { Locale } from '@i18n-micro/types'\nimport { createContext, type HostComponent, type HostNode, type HostStyle, useContext } from '#host'\nimport type { TranslationMethods, UseI18nReturn } from './context'\n\n/** Where a link or a switch goes. */\nexport type RouteTarget = string | { path?: string }\n\n/**\n * Routing strategy interface for i18n\n * Implement this interface to integrate with any router library\n * Matches Vue/Solid package interface for consistency\n */\nexport interface I18nRoutingStrategy {\n /**\n * Returns the current path with its query and hash, so a locale switch keeps them.\n * Links compare it by page: query and hash do not count.\n */\n getCurrentPath: () => string\n\n /**\n * Component to use for rendering links (e.g., RouterLink)\n */\n linkComponent?:\n | string\n | HostComponent<{\n href: string\n children?: HostNode\n style?: HostStyle\n className?: string\n [key: string]: unknown\n }>\n\n /**\n * Function to navigate to another route/locale\n */\n push: (target: { path: string }) => void\n\n /**\n * Function to replace current route\n */\n replace: (target: { path: string }) => void\n\n /**\n * Generate path for specific locale\n */\n resolvePath?: (to: RouteTarget, locale: string) => RouteTarget\n\n /**\n * (Optional) Get current route object for SEO/Meta tags\n */\n getRoute?: () => {\n fullPath: string\n query: Record<string, unknown>\n }\n}\n\n/** What a provider adds to its instance. It changes with its props, an adapter built in render on every render. */\nexport interface I18nConfig {\n locales: Locale[] | null\n defaultLocale: string | null\n router: I18nRoutingStrategy | null\n /** The `useI18n()` object of the current snapshot, shared by every consumer of this provider. */\n api: { snapshot: string; value: UseI18nReturn } | null\n /** Translation methods by snapshot: they outlive the config, so `t` does not change with an adapter. */\n methods: { current: TranslationMethods | null }\n}\n\n/**\n * The instance alone, stable while the app runs: `useT` and `<I18nT>` read only this, so a new\n * adapter object does not render them.\n */\nexport const I18nContext = createContext<I18n | null>(null)\nexport const I18nConfigContext = createContext<I18nConfig | null>(null)\n\nexport const useI18nContext = (): I18n => {\n const context = useContext(I18nContext)\n if (!context) {\n throw new Error('[i18n-micro] I18nContext not found. Make sure I18nProvider is used.')\n }\n return context\n}\n\nexport const useI18nLocales = (): Locale[] | null => useContext(I18nConfigContext)?.locales ?? null\nexport const useI18nDefaultLocale = (): string | null => useContext(I18nConfigContext)?.defaultLocale ?? null\nexport const useI18nRouter = (): I18nRoutingStrategy | null => useContext(I18nConfigContext)?.router ?? null\n","import { localeIsoMap } from '@i18n-micro/core'\nimport { createI18n, type I18n, type I18nOptions } from '@i18n-micro/runtime'\nimport type { CleanTranslation, Locale, Params, TranslationKey, Translations } from '@i18n-micro/types'\nimport { h, type HostElement, type HostNode, useContext, useEffect, useMemo, useRef, useState, useStore } from '#host'\nimport { type I18nConfig, I18nConfigContext, I18nContext, type I18nRoutingStrategy, type RouteTarget, useI18nContext } from './injection'\n\nexport interface I18nProviderProps extends Partial<I18nOptions> {\n /** An instance you created. Without it, the outer provider's; without that, one built from the options next to it: plain data, so a server component can pass them. */\n i18n?: I18n\n locales?: Locale[]\n defaultLocale?: string\n routingStrategy?: I18nRoutingStrategy\n children?: HostNode\n}\n\nfunction buildInstance(options: Partial<I18nOptions>): I18n {\n if (!options.locale) throw new Error('[i18n-micro] I18nProvider needs an `i18n` instance, an outer provider, or a `locale`.')\n return createI18n(options as I18nOptions)\n}\n\nexport function I18nProvider({ i18n, locales, defaultLocale, routingStrategy, children, ...options }: I18nProviderProps): HostElement {\n const outerInstance = useContext(I18nContext)\n const outer = useContext(I18nConfigContext)\n const inherited = i18n ?? outerInstance\n // A new `locale` prop comes with its own messages. Keyed by it alone: an inline `messages` object must not reset the instance.\n const instance = useMemo(() => inherited ?? buildInstance(options), [inherited, options.locale])\n const methods = useRef<TranslationMethods | null>(null)\n // The first render writes the tags: a server has no commit, and hydration must render the same\n // plurals. Later changes wait for the commit, so a render React discards leaves nothing behind.\n // ponytail: the first write is silent, so a provider mounted late over a live instance does not wake what is already on screen; that text follows on the next store change.\n const committed = useRef<I18n | null>(null)\n if (locales && committed.current !== instance) instance.addLocaleIso(localeIsoMap(locales), false)\n useEffect(() => {\n committed.current = instance\n if (locales) instance.addLocaleIso(localeIsoMap(locales))\n }, [instance, locales])\n const config = useMemo<I18nConfig>(\n () => ({\n // an omitted prop leaves the outer provider's value in place\n locales: locales ?? outer?.locales ?? null,\n defaultLocale: defaultLocale ?? outer?.defaultLocale ?? null,\n router: routingStrategy ?? outer?.router ?? null,\n api: null,\n methods,\n }),\n [locales, defaultLocale, routingStrategy, outer],\n )\n return h(I18nContext.Provider, { value: instance }, h(I18nConfigContext.Provider, { value: config }, children))\n}\n\nexport interface UseI18nOptions {\n locales?: Locale[]\n defaultLocale?: string\n}\n\nexport interface UseI18nReturn {\n // Translation methods\n t: (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string) => CleanTranslation\n ts: (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string) => string\n tc: (key: TranslationKey, count: number | Params, defaultValue?: string) => string\n tn: (value: number, options?: Intl.NumberFormatOptions) => string\n td: (value: Date | number | string, options?: Intl.DateTimeFormatOptions) => string\n tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string\n has: (key: TranslationKey, routeName?: string) => boolean\n\n // Locale management\n locale: string\n fallbackLocale: string\n currentRoute: string\n setLocale: (locale: string) => void\n\n // Route management\n setRoute: (routeName: string) => void\n getRoute: () => string\n getLocales: () => Locale[]\n defaultLocale: () => string\n getLocaleName: () => string | null\n\n // Router methods; without a router they answer the input and only switch the locale\n switchLocale: (locale: string) => void\n localeRoute: (to: RouteTarget, locale?: string) => RouteTarget\n localePath: (to: RouteTarget, locale?: string) => string\n\n // Translation management\n addTranslations: (locale: string, translations: Translations, merge?: boolean) => void\n addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void\n clearCache: () => void\n}\n\nexport const routePath = (target: RouteTarget): string => (typeof target === 'string' ? target : target.path || '/')\n\ntype Writers = Pick<UseI18nReturn, 'addTranslations' | 'addRouteTranslations' | 'clearCache'>\n\nexport type TranslationMethods = Pick<UseI18nReturn, 't' | 'ts' | 'tc' | 'tn' | 'td' | 'tdr' | 'has'> & Writers & { i18n: I18n; snapshot: string }\n\nconst bindWriters = (i18n: I18n): Writers => ({\n addTranslations: i18n.addTranslations.bind(i18n),\n addRouteTranslations: i18n.addRouteTranslations.bind(i18n),\n clearCache: i18n.clearCache.bind(i18n),\n})\n\n/**\n * The readers are bound per snapshot: their identity changes when the text can, so `memo` and effect deps stay right.\n * The writers are bound once per instance: every write makes a snapshot, so an effect on one would write for ever.\n * ponytail: without a provider there is no cache and they change with the snapshot; a bare `I18nContext` is the ceiling.\n */\nfunction translationMethods(i18n: I18n, snapshot: string, cache: I18nConfig['methods'] | undefined): TranslationMethods {\n const known = cache?.current\n if (known && known.i18n === i18n && known.snapshot === snapshot) return known\n const methods = {\n ...(known?.i18n === i18n ? known : bindWriters(i18n)),\n i18n,\n snapshot,\n t: i18n.t.bind(i18n),\n ts: i18n.ts.bind(i18n),\n tc: i18n.tc.bind(i18n),\n tn: i18n.tn.bind(i18n),\n td: i18n.td.bind(i18n),\n tdr: i18n.tdr.bind(i18n),\n has: i18n.has.bind(i18n),\n }\n if (cache) cache.current = methods\n return methods\n}\n\nfunction createApi(\n i18n: I18n,\n { locales, defaultLocale, router }: Pick<I18nConfig, 'locales' | 'defaultLocale' | 'router'>,\n methods: TranslationMethods,\n): UseI18nReturn {\n const list = locales ?? []\n const localeRoute = (to: RouteTarget, code?: string): RouteTarget => (router?.resolvePath ? router.resolvePath(to, code || i18n.locale) : to)\n const { t, ts, tc, tn, td, tdr, has, addTranslations, addRouteTranslations, clearCache } = methods\n return {\n t,\n ts,\n tc,\n tn,\n td,\n tdr,\n has,\n\n get locale() {\n return i18n.locale\n },\n get fallbackLocale() {\n return i18n.fallbackLocale\n },\n get currentRoute() {\n return i18n.currentRoute\n },\n setLocale: (locale) => {\n i18n.locale = locale\n },\n\n setRoute: i18n.setRoute.bind(i18n),\n getRoute: i18n.getRoute.bind(i18n),\n getLocales: () => list,\n defaultLocale: () => defaultLocale ?? i18n.fallbackLocale,\n getLocaleName: () => list.find((l) => l.code === i18n.locale)?.displayName || null,\n\n switchLocale: (locale) => {\n i18n.locale = locale\n if (router) router.push({ path: routePath(localeRoute(router.getCurrentPath(), locale)) })\n },\n localeRoute,\n localePath: (to, locale) => routePath(localeRoute(to, locale)),\n\n addTranslations,\n addRouteTranslations,\n clearCache,\n }\n}\n\nexport const useI18n = (options?: UseI18nOptions): UseI18nReturn => {\n const i18n = useI18nContext()\n const config = useContext(I18nConfigContext)\n const snapshot = useStore(i18n.subscribe, i18n.getSnapshot)\n const locales = options?.locales ?? config?.locales ?? null\n const defaultLocale = options?.defaultLocale ?? config?.defaultLocale ?? null\n const router = config?.router ?? null\n // one object for all consumers, unless this hook overrides the provider or stands under a bare `I18nContext`\n const shared = config && !options?.locales && !options?.defaultLocale ? config : null\n const own = useMemo(\n () => (shared ? null : createApi(i18n, { locales, defaultLocale, router }, translationMethods(i18n, snapshot, config?.methods))),\n [shared, i18n, snapshot, locales, defaultLocale, router],\n )\n if (own || !shared) return own!\n if (shared.api?.snapshot !== snapshot) shared.api = { snapshot, value: createApi(i18n, shared, translationMethods(i18n, snapshot, shared.methods)) }\n return shared.api.value\n}\n\n/**\n * One translation as a value: the component renders only when this string changes, not on every\n * locale or message write, nor when a provider gets a new adapter object.\n */\nexport function useT(key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string {\n const i18n = useI18nContext()\n return useStore(i18n.subscribe, () => i18n.ts(key, params, defaultValue, routeName))\n}\n\n/**\n * `setLocale` that loads first. A store write is synchronous for React, even inside\n * `startTransition`, so a reader that suspends on a missing dictionary would show its fallback:\n * this keeps the old UI until the messages are in. The last call wins; a failed `load` rejects\n * and leaves the locale as it was.\n */\nexport function useLocaleSwitch(load: (locale: string) => unknown): [(locale: string) => Promise<void>, boolean] {\n const { switchLocale } = useI18n()\n const [pending, setPending] = useState(false)\n const latest = useRef(0)\n // the router may have moved during the load: switch with the adapter of the last render\n const current = useRef(switchLocale)\n current.current = switchLocale\n const run = async (locale: string): Promise<void> => {\n const call = ++latest.current\n setPending(true)\n try {\n await load(locale)\n if (call === latest.current) current.current(locale)\n } finally {\n if (call === latest.current) setPending(false)\n }\n }\n return [run, pending]\n}\n","import type { TranslationKey } from '@i18n-micro/types'\nimport { h, type HostAttrs, type HostElement, type HostNode } from '#host'\nimport { useI18n } from '../context'\n\nexport interface I18nGroupProps extends Omit<HostAttrs<HTMLDivElement>, 'children'> {\n prefix: string\n groupClass?: string\n children?: HostNode | ((props: { prefix: string; t: (key: string, params?: Record<string, string | number | boolean>) => string }) => HostNode)\n}\n\nexport const I18nGroup = (props: I18nGroupProps): HostElement => {\n const { prefix, groupClass, children, className, class: userClass, ...restProps } = props as I18nGroupProps & { class?: string }\n const { ts } = useI18n()\n\n const translate = (key: string, params?: Record<string, string | number | boolean>): string => ts(`${prefix}.${key}` as TranslationKey, params)\n\n return h(\n 'div',\n { ...restProps, className: ['i18n-group', groupClass, className, userClass].filter(Boolean).join(' ') },\n typeof children === 'function' ? children({ prefix, t: translate }) : children,\n )\n}\n","import { externalLinkHref, isActiveLink, isPlainClick } from '@i18n-micro/core'\nimport { h, type HostAnchorAttrs, type HostElement, type HostMouseEvent, type HostNode, type HostStyle, mergeStyles } from '#host'\nimport { routePath, useI18n } from '../context'\nimport { type RouteTarget, useI18nRouter } from '../injection'\n\n// a type, not an interface: Preact 11's anchor attributes are a union alias\nexport type I18nLinkProps = HostAnchorAttrs<HTMLAnchorElement> & {\n to: RouteTarget\n activeStyle?: HostStyle\n localeRoute?: (to: RouteTarget, locale?: string) => RouteTarget\n children?: HostNode\n}\n\nexport const I18nLink = (props: I18nLinkProps): HostElement => {\n const i18n = useI18n()\n const router = useI18nRouter()\n const { to, activeStyle, localeRoute = i18n.localeRoute, style, onClick, children, ...restProps } = props\n\n const externalHref = externalLinkHref(to)\n if (externalHref !== undefined) {\n return h('a', { target: '_blank', rel: 'noopener noreferrer', ...restProps, onClick, style, href: externalHref }, children)\n }\n\n const href = routePath(localeRoute(to))\n // The current, default and fallback locale count too, so a provider without `locales` still knows its own root.\n const codes = () => [i18n.locale, i18n.defaultLocale(), i18n.fallbackLocale, ...i18n.getLocales().map((l) => l.code)]\n const active = activeStyle && router && isActiveLink(router.getCurrentPath(), href, codes())\n const linkProps = { ...restProps, href, style: active ? mergeStyles(style as HostStyle, activeStyle) : style }\n\n if (router?.linkComponent) return h(router.linkComponent as never, { ...linkProps, onClick }, children)\n\n const handleClick = (event: HostMouseEvent<HTMLAnchorElement>) => {\n onClick?.(event as never)\n if (!router || !isPlainClick(event as unknown as MouseEvent)) return\n event.preventDefault()\n router.push({ path: href })\n }\n return h('a', { ...linkProps, onClick: handleClick }, children)\n}\n","import { isPlainClick, ownValue } from '@i18n-micro/core'\nimport { SWITCHER_STYLES as STYLES } from '@i18n-micro/core/render'\nimport type { Locale } from '@i18n-micro/types'\nimport { h, type HostAttrs, type HostElement, type HostMouseEvent, type HostStyle, mergeStyles, useEffect, useRef, useState } from '#host'\nimport { routePath, useI18n } from '../context'\nimport { type RouteTarget, useI18nLocales, useI18nRouter } from '../injection'\n\nexport interface I18nSwitcherProps extends HostAttrs<HTMLDivElement> {\n locales?: Locale[]\n currentLocale?: string | (() => string)\n getLocaleName?: () => string | null\n switchLocale?: (locale: string) => void\n localeRoute?: (to: RouteTarget, locale?: string) => RouteTarget\n customLabels?: Record<string, string>\n customWrapperStyle?: HostStyle\n customButtonStyle?: HostStyle\n customDropdownStyle?: HostStyle\n customItemStyle?: HostStyle\n customLinkStyle?: HostStyle\n customActiveLinkStyle?: HostStyle\n /**\n * Inline style applied to the main switcher button when the current locale is\n * marked as `disabled: true` in the locale config.\n *\n * Disabled locales are omitted from the dropdown items, but still shown as the\n * active button label.\n */\n customDisabledLinkStyle?: HostStyle\n customIconStyle?: HostStyle\n}\n\nexport const I18nSwitcher = (props: I18nSwitcherProps): HostElement => {\n const {\n locales: localesProp,\n currentLocale: currentLocaleProp,\n getLocaleName,\n switchLocale,\n localeRoute,\n customLabels,\n customWrapperStyle,\n customButtonStyle,\n customDropdownStyle,\n customItemStyle,\n customLinkStyle,\n customActiveLinkStyle,\n customDisabledLinkStyle,\n customIconStyle,\n className,\n class: userClass,\n style,\n ...restProps\n } = props as I18nSwitcherProps & { class?: string }\n\n const i18n = useI18n()\n const router = useI18nRouter()\n const injectedLocales = useI18nLocales()\n const [open, setOpen] = useState(false)\n const wrapper = useRef<HTMLDivElement>(null)\n\n // `disabled` locales stay out of the list, but one that is current still labels the button.\n const allLocales = localesProp ?? injectedLocales ?? i18n.getLocales()\n const current = typeof currentLocaleProp === 'function' ? currentLocaleProp() : (currentLocaleProp ?? i18n.locale)\n const currentItem = allLocales.find((l) => l.code === current)\n\n useEffect(() => {\n if (!open) return\n const onClick = (event: MouseEvent) => {\n if (!wrapper.current?.contains(event.target as Node)) setOpen(false)\n }\n const onKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('click', onClick)\n document.addEventListener('keydown', onKeydown)\n return () => {\n document.removeEventListener('click', onClick)\n document.removeEventListener('keydown', onKeydown)\n }\n }, [open])\n\n const label = (locale: Locale): string => (customLabels && (ownValue(customLabels, locale.code) as string)) || locale.displayName || locale.code\n const href = (code: string): string => {\n const path =\n router?.getCurrentPath() ?? (typeof window === 'undefined' ? '/' : window.location.pathname + window.location.search + window.location.hash)\n if (localeRoute) return routePath(localeRoute(path, code))\n if (!router) return '#'\n return routePath(router.resolvePath ? router.resolvePath(path, code) : path)\n }\n\n const select = (event: HostMouseEvent<HTMLAnchorElement>, code: string) => {\n if (!isPlainClick(event as unknown as MouseEvent)) return\n // a custom `localeRoute` with nothing to navigate: `href` is a real page, the browser's to follow\n if (switchLocale || router || !localeRoute) event.preventDefault()\n setOpen(false)\n if (switchLocale) return switchLocale(code)\n if (!localeRoute) return i18n.switchLocale(code)\n i18n.setLocale(code)\n router?.push({ path: href(code) })\n }\n\n const renderItem = (locale: Locale) => {\n const active = locale.code === current\n const language = locale.iso || locale.code\n return h(\n 'li',\n { key: locale.code, style: { ...STYLES.item, ...customItemStyle } },\n h(\n 'a',\n {\n className: `switcher-locale-${locale.code}`,\n href: href(locale.code),\n hrefLang: language,\n lang: language,\n dir: locale.dir,\n 'aria-current': active ? 'page' : undefined,\n style: { ...STYLES.link, ...(active ? STYLES.activeLink : null), ...customLinkStyle, ...(active ? customActiveLinkStyle : null) },\n onClick: (event: HostMouseEvent<HTMLAnchorElement>) => select(event, locale.code),\n },\n label(locale),\n ),\n )\n }\n\n return h(\n 'div',\n {\n ...restProps,\n ref: wrapper,\n className: ['i18n-switcher-wrapper', className, userClass].filter(Boolean).join(' '),\n style: mergeStyles(STYLES.wrapper as HostStyle, customWrapperStyle, style as HostStyle),\n },\n h(\n 'button',\n {\n type: 'button',\n className: 'i18n-switcher-button language-switcher',\n style: { ...STYLES.button, ...customButtonStyle, ...(currentItem?.disabled ? customDisabledLinkStyle : null) },\n 'aria-expanded': open,\n onClick: () => setOpen(!open),\n },\n h('span', null, getLocaleName?.() || label(currentItem ?? { code: current })),\n ' ',\n h('span', { style: { ...STYLES.icon, ...(open ? STYLES.openIcon : null), ...customIconStyle } }, '▾'),\n ),\n open\n ? h(\n 'ul',\n { className: 'i18n-switcher-dropdown', style: { ...STYLES.dropdown, ...customDropdownStyle } },\n allLocales.filter((l) => !l.disabled).map(renderItem),\n )\n : null,\n )\n}\n","import { renderI18nT, type I18nTRenderProps, type RenderApi, type RenderSlot, type RenderSlots, type TextHost } from '@i18n-micro/core/render'\nimport type { HostAttrs, HostElement, HostNode, HostTag } from '#host'\n\n/** What fills a `{name}` placeholder: a node, or a function returning one (it may use hooks). */\nexport type I18nTComponent = HostNode | (() => HostNode)\n\nexport interface I18nTProps extends Omit<HostAttrs<HTMLElement>, 'children' | 'defaultValue'>, Omit<I18nTRenderProps, 'tag'> {\n tag?: HostTag\n /** Elements for `{name}` placeholders. Beats a param of the same name. */\n components?: Record<string, I18nTComponent>\n /** Replaces the text. As a function it gets the translation, like Vue's default slot. */\n children?: HostNode | ((props: { translation: string }) => HostNode)\n}\n\nconst NO_SLOTS: RenderSlots = {}\n\n/** What JSX itself draws as nothing, `{cond && <b />}` among them: no children, not empty ones. */\nconst isUnset = (children: I18nTProps['children']): boolean => children === undefined || children === null || typeof children === 'boolean'\n\n/** A stable type around a slot function: called directly it would run its hooks in `<I18nT>`, in any order. */\nconst Slot = ({ render }: { render: () => HostNode }) => render()\n\nfunction toSlots({ h }: RenderApi, components: I18nTProps['components'], children: I18nTProps['children']): RenderSlots {\n if (!components && isUnset(children)) return NO_SLOTS\n const slots: Record<string, RenderSlot> = Object.create(null)\n for (const name of Object.keys(components ?? {})) {\n const value = components![name]\n if (value !== undefined) slots[name] = typeof value === 'function' ? () => h(Slot, { render: value }) : () => value\n }\n if (!isUnset(children)) slots.default = typeof children === 'function' ? (children as RenderSlot) : () => children\n return slots\n}\n\n/** Props to element: no hooks, so it serves both the client component and the server one. */\nexport function renderText(api: RenderApi, i18n: TextHost, props: I18nTProps): HostElement {\n const {\n keypath,\n params,\n tag,\n plural,\n defaultValue,\n html,\n hideIfEmpty,\n customPluralRule,\n number,\n date,\n relativeDate,\n components,\n children,\n ...attrs\n } = props\n return renderI18nT(api, i18n, props, toSlots(api, components, children), attrs) as HostElement\n}\n","import { API, type HostElement, useStore } from '#host'\nimport { useI18nContext } from '../injection'\nimport { type I18nTProps, renderText } from './render-text'\n\nexport type { I18nTComponent, I18nTProps } from './render-text'\n\nexport const I18nT = (props: I18nTProps): HostElement => {\n const i18n = useI18nContext()\n useStore(i18n.subscribe, i18n.getSnapshot)\n return renderText(API, i18n, props)\n}\n"],"mappings":"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"}