@i18n-micro/preact 1.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 +21 -0
- package/README.md +70 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +281 -0
- package/dist/index.mjs +499 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @i18n-micro/preact
|
|
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
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @i18n-micro/preact
|
|
9
|
+
# or
|
|
10
|
+
npm install @i18n-micro/preact
|
|
11
|
+
# or
|
|
12
|
+
yarn add @i18n-micro/preact
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { render } from 'preact'
|
|
19
|
+
import { createI18n, I18nProvider, useI18n } from '@i18n-micro/preact'
|
|
20
|
+
|
|
21
|
+
const i18n = createI18n({
|
|
22
|
+
locale: 'en',
|
|
23
|
+
fallbackLocale: 'en',
|
|
24
|
+
messages: {
|
|
25
|
+
en: {
|
|
26
|
+
greeting: 'Hello, {name}!',
|
|
27
|
+
apples: 'no apples | one apple | {count} apples',
|
|
28
|
+
},
|
|
29
|
+
fr: {
|
|
30
|
+
greeting: 'Bonjour, {name}!',
|
|
31
|
+
apples: 'pas de pommes | une pomme | {count} pommes',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
function App() {
|
|
37
|
+
return (
|
|
38
|
+
<I18nProvider i18n={i18n}>
|
|
39
|
+
<MyComponent />
|
|
40
|
+
</I18nProvider>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Usage in Components
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { useI18n } from '@i18n-micro/preact'
|
|
49
|
+
|
|
50
|
+
function MyComponent() {
|
|
51
|
+
const { t, tc, locale, setLocale } = useI18n()
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div>
|
|
55
|
+
<p>{t('greeting', { name: 'World' })}</p>
|
|
56
|
+
<p>{tc('apples', 5)}</p>
|
|
57
|
+
<button onClick={() => setLocale('fr')}>Switch to French</button>
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Resources
|
|
64
|
+
|
|
65
|
+
- **Repository**: [https://github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
|
|
66
|
+
- **Documentation**: [https://s00d.github.io/nuxt-i18n-micro/](https://s00d.github.io/nuxt-i18n-micro/)
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("@i18n-micro/core"),c=require("preact"),R=require("preact/hooks");class G extends H.BaseI18n{_locale;_fallbackLocale;_currentRoute="general";listeners=new Set;revision=0;cache;constructor(t){const n={generalLocaleCache:{},routeLocaleCache:{},dynamicTranslationsCaches:[],serverTranslationCache:{}};if(super({cache:n,plural:t.plural,missingWarn:t.missingWarn,missingHandler:t.missingHandler}),this.cache=n,this._locale=t.locale,this._fallbackLocale=t.fallbackLocale||t.locale,t.messages)for(const[e,r]of Object.entries(t.messages))this.helper.loadTranslations(e,r)}subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});getSnapshot=()=>`${this._locale}:${this._currentRoute}:${this.revision}`;notify(){this.revision++,this.listeners.forEach(t=>{t()})}get locale(){return this._locale}set locale(t){this._locale!==t&&(this._locale=t,this.notify())}get fallbackLocale(){return this._fallbackLocale}set fallbackLocale(t){this._fallbackLocale=t}get currentRoute(){return this._currentRoute}setRoute(t){this._currentRoute!==t&&(this._currentRoute=t,this.notify())}getLocale(){return this._locale}getFallbackLocale(){return this._fallbackLocale}getRoute(){return this._currentRoute}addTranslations(t,n,e=!0){super.loadTranslationsCore(t,n,e),this.notify()}addRouteTranslations(t,n,e,r=!0){super.loadRouteTranslationsCore(t,n,e,r),this.notify()}clearCache(){super.clearCache(),this.notify()}}function it(a){return new G(a)}const M=c.createContext(null),W=c.createContext(null),z=c.createContext(null),q=c.createContext(null),F=()=>{const a=R.useContext(M);if(!a)throw new Error("[i18n-micro] I18nContext not found. Make sure I18nProvider is used.");return a},V=()=>R.useContext(W),K=()=>R.useContext(z),$=()=>R.useContext(q);function ut({i18n:a,locales:t,defaultLocale:n,routingStrategy:e,children:r}){return c.h(M.Provider,{value:a},t?c.h(W.Provider,{value:t},n?c.h(z.Provider,{value:n},e?c.h(q.Provider,{value:e},r):r):r):r)}const N=a=>{const t=F(),n=$(),e=V(),r=K(),[,w]=R.useState(0);R.useEffect(()=>t.subscribe(()=>{w(d=>d+1)}),[t]);const m=a?.locales||e||[],g=a?.defaultLocale||r||t.locale,l=(o,d)=>n?.resolvePath?n.resolvePath(o,d||t.locale):o,p=o=>{if(t.locale=o,n){const d=n.getCurrentPath(),f=l(d,o);n.push(typeof f=="string"?{path:f}:{path:f.path||"/"})}};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:o=>{t.locale=o},setRoute:t.setRoute.bind(t),getRoute:t.getRoute.bind(t),getLocales:()=>m,defaultLocale:()=>g,getLocaleName:()=>m.find(d=>d.code===t.locale)?.displayName||null,switchLocale:p,localeRoute:l,localePath:(o,d)=>{const f=l(o,d);return typeof f=="string"?f:f.path||"/"},addTranslations:t.addTranslations.bind(t),addRouteTranslations:t.addRouteTranslations.bind(t),clearCache:t.clearCache.bind(t)}},dt=a=>{const{t,tc:n,tn:e,td:r,tdr:w,locale:m,getRoute:g}=N(),{keypath:l,params:p,tag:o="span",plural:d,defaultValue:f,html:P=!1,hideIfEmpty:x=!1,customPluralRule:_,number:i,date:y,relativeDate:k,...u}=a,I=g(),b=(L,h,v)=>c.h(L,h,v);if(i!==void 0){const L=Number(i),h=e(L),v=t(l,{number:h,...p||{}},void 0,I),T=typeof v=="string"?v:String(v);return P?b(o,{...u,dangerouslySetInnerHTML:{__html:T}},void 0):b(o,u,T)}if(y!==void 0){const L=r(y),h=t(l,{date:L,...p||{}},void 0,I),v=typeof h=="string"?h:String(h);return P?b(o,{...u,dangerouslySetInnerHTML:{__html:v}},void 0):b(o,u,v)}if(k!==void 0){const L=w(k),h=t(l,{relativeDate:L,...p||{}},void 0,I),v=typeof h=="string"?h:String(h);return P?b(o,{...u,dangerouslySetInnerHTML:{__html:v}},void 0):b(o,u,v)}if(d!==void 0){const L=Number.parseInt(d.toString());let h;return _?h=_(l,L,p||{},m,(T,O,B)=>{const j=t(T,O,B,I);return typeof j=="string"?j:String(j)})||"":h=n(l,{count:L,...p||{}},f),P?b(o,{...u,dangerouslySetInnerHTML:{__html:h}},void 0):b(o,u,h)}const E=t(l,p,f,I),A=typeof E=="string"?E:String(E);return x&&!A.trim()?f?c.h(c.Fragment,null,f):null:P?b(o,{...u,dangerouslySetInnerHTML:{__html:A}},void 0):b(o,u,A)},ft=a=>{const t=N(),n=$(),{to:e,activeStyle:r,localeRoute:w,children:m,...g}=a,l=w||t.localeRoute,p=()=>typeof e=="string"?/^(?:https?:\/\/|\/\/|[a-zA-Z0-9-]+\.[a-zA-Z]{2,})|tel:|mailto:/.test(e):!1,o=()=>{if(p()&&typeof e=="string")return/^https?:\/\//.test(e)?e:`https://${e}`},d=()=>{if(p())return typeof e=="string"?e:e?.path||"/";if(l){const y=l(e);return typeof y=="string"?y:y.path||"/"}if(!n?.resolvePath)return typeof e=="string"?e:e.path||"/";const i=n.resolvePath(e,t.locale);return typeof i=="string"?i:i.path||"/"},P=(()=>{if(p()||!n)return!1;const i=n.getCurrentPath(),y=d(),k=i.replace(/\/$/,""),u=y.replace(/\/$/,"");return!!(k===u||k.startsWith(u+"/"))})()?r||{}:{},x=d(),_=i=>{a.onClick&&a.onClick(i),!i.defaultPrevented&&!i.button&&!i.metaKey&&!i.ctrlKey&&n&&!p()&&(i.preventDefault(),n.push({path:x}))};if(p())return c.h("a",{...g,href:o(),style:P,target:"_blank",rel:"noopener noreferrer"},m);if(n?.linkComponent){const i=n.linkComponent;if(typeof i=="string")return c.h(i,{...g,href:x,style:P},m);const y=i,k={...g,href:x,style:P};return c.h(y,k,m)}return c.h("a",{...g,href:x,style:P,onClick:_},m)},pt=a=>{const{locales:t,currentLocale:n,getLocaleName:e,switchLocale:r,localeRoute:w,customLabels:m={},customWrapperStyle:g,customButtonStyle:l,customDropdownStyle:p,customItemStyle:o,customLinkStyle:d,customActiveLinkStyle:f,customIconStyle:P,...x}=a,_=N(),i=F(),y=$(),k=V(),[u,I]=R.useState(!1),b=R.useRef(null),E=t||k||_.getLocales()||[],L=typeof n=="function"?n():typeof n=="string"?n:_.locale,h=e?e():_.getLocaleName(),v=s=>{s&&(s.stopPropagation(),s.preventDefault()),I(!u)},T=s=>m[s.code]||s.displayName||s.code,O=()=>{const s=E.find(S=>S.code===L);return s?T(s):h||L},B=s=>{if(I(!1),r){r(s);return}if(i.locale=s,!y)return;const S=y.getCurrentPath(),D=a.localeRoute?(()=>{const C=a.localeRoute(S,s);return typeof C=="string"?C:C.path||"/"})():y?.resolvePath?(()=>{const C=y.resolvePath(S,s);return typeof C=="string"?C:C.path||"/"})():S;y.push({path:D})},j={position:"relative",display:"inline-block",verticalAlign:"middle"},Z={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"},J={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)"},Q={margin:"0",padding:"0"},X={display:"block",padding:"8px 12px",color:"#333",textDecoration:"none",transition:"background-color 0.3s ease",cursor:"pointer"},Y={fontWeight:"bold",color:"#007bff"},tt={marginLeft:"8px",display:"inline-block",transition:"transform 0.3s ease"},et={transform:"rotate(180deg)"};R.useEffect(()=>{if(!u)return;const s=S=>{if(!u)return;const D=S.target;if(!D||!b.current)return;const C=b.current.contains(D),lt=D.closest(".i18n-switcher-button")!==null;!C&&!lt&&I(!1)};return document.addEventListener("click",s),()=>{document.removeEventListener("click",s)}},[u]);const nt={...j,...g},rt={...Z,...l},ot={...J,...p},st={...Q,...o},at={...tt,...u?et:{},...P},ct=E.map(s=>{const S=s.code===L,D={...X,...S?Y:{},...d,...S?f:{},width:"100%",textAlign:"left",border:"none",background:"transparent"};return c.h("li",{key:s.code,style:st},c.h("button",{type:"button",className:`switcher-locale-${s.code}`,style:D,onClick:C=>{C.preventDefault(),C.stopPropagation(),B(s.code)}},T(s)))});return c.h("div",{ref:b,className:"i18n-switcher-wrapper",style:nt,...x},c.h("button",{type:"button",className:"i18n-switcher-button",style:rt,onClick:s=>{s.preventDefault(),s.stopPropagation(),v(s)},ariaHaspopup:"true",ariaExpanded:u},c.h("span",null,O()),c.h("span",{style:at},"▼")),u?c.h("ul",{className:"i18n-switcher-dropdown",style:ot},...ct):null)},ht=a=>{const{prefix:t,groupClass:n,children:e,...r}=a,{t:w,getRoute:m}=N(),g=(o,d)=>{const f=w(`${t}.${o}`,d,void 0,m());return typeof f=="string"?f:String(f)},l=["i18n-group",n].filter(Boolean).join(" "),p=typeof e=="function"?e({prefix:t,t:g}):e;return c.h("div",{...r,className:l},p)};function U(a,t){const n=a.map(r=>r.code),e=(r,w)=>{const g=(typeof r=="string"?r:r.path||"/").split("/").filter(Boolean);g.length>0&&n.includes(g[0])&&g.shift();const l="/"+g.join("/");return w===t?l:`/${w}${l==="/"?"":l}`};return{linkComponent:void 0,getCurrentPath:()=>typeof window<"u"?window.location.pathname:"/",push:r=>{typeof window<"u"&&(window.history.pushState({},"",r.path),window.dispatchEvent(new Event("popstate")))},replace:r=>{typeof window<"u"&&(window.history.replaceState({},"",r.path),window.dispatchEvent(new Event("popstate")))},resolvePath:(r,w)=>e(r,w),getRoute:()=>typeof window<"u"?{fullPath:window.location.pathname+window.location.search,query:Object.fromEntries(new URLSearchParams(window.location.search))}:{fullPath:"/",query:{}}}}const gt=U;Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>H.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>H.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>H.interpolate});exports.I18nContext=M;exports.I18nDefaultLocaleContext=z;exports.I18nGroup=ht;exports.I18nLink=ft;exports.I18nLocalesContext=W;exports.I18nProvider=ut;exports.I18nRouterContext=q;exports.I18nSwitcher=pt;exports.I18nT=dt;exports.PreactI18n=G;exports.createBrowserHistoryAdapter=U;exports.createI18n=it;exports.createPreactRouterAdapter=gt;exports.useI18n=N;exports.useI18nContext=F;exports.useI18nDefaultLocale=K;exports.useI18nLocales=V;exports.useI18nRouter=$;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/i18n.ts","../src/injection.ts","../src/context.tsx","../src/components/I18nT.tsx","../src/components/I18nLink.tsx","../src/components/I18nSwitcher.tsx","../src/components/I18nGroup.tsx","../src/router/adapter.tsx"],"sourcesContent":["import {\n BaseI18n,\n type TranslationCache,\n} from '@i18n-micro/core'\nimport type {\n Translations,\n PluralFunc,\n} from '@i18n-micro/types'\n\nexport interface PreactI18nOptions {\n locale: string\n fallbackLocale?: string\n messages?: Record<string, Translations>\n plural?: PluralFunc\n missingWarn?: boolean\n missingHandler?: (locale: string, key: string, routeName: string) => void\n}\n\n/**\n * Preact I18n Adapter\n *\n * Provides a Preact-compatible i18n instance that uses the shared core logic.\n * Implements Observer pattern for reactivity with useSyncExternalStore.\n * Works with Preact through preact/compat for React compatibility.\n */\nexport class PreactI18n extends BaseI18n {\n private _locale: string\n private _fallbackLocale: string\n private _currentRoute: string = 'general'\n private listeners = new Set<() => void>()\n private revision = 0\n\n // Cache для Core (plain objects, не реактивные)\n public readonly cache: TranslationCache\n\n constructor(options: PreactI18nOptions) {\n // Create cache first\n const cache: TranslationCache = {\n generalLocaleCache: {},\n routeLocaleCache: {},\n dynamicTranslationsCaches: [],\n serverTranslationCache: {},\n }\n\n // Call parent constructor with options\n super({\n cache,\n plural: options.plural,\n missingWarn: options.missingWarn,\n missingHandler: options.missingHandler,\n })\n\n // Assign cache to public readonly property\n this.cache = cache\n\n this._locale = options.locale\n this._fallbackLocale = options.fallbackLocale || options.locale\n\n // Загружаем начальные сообщения\n if (options.messages) {\n for (const [lang, msgs] of Object.entries(options.messages)) {\n this.helper.loadTranslations(lang, msgs)\n }\n }\n }\n\n // Для useSyncExternalStore\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = () => {\n // Возвращаем комбинированную строку локали и ревизии кэша\n // Это заставит компонент перерендериться при изменении\n return `${this._locale}:${this._currentRoute}:${this.revision}`\n }\n\n private notify() {\n this.revision++\n this.listeners.forEach((listener) => {\n listener()\n })\n }\n\n // Геттер/Сеттер для локали\n get locale(): string {\n return this._locale\n }\n\n set locale(val: string) {\n if (this._locale !== val) {\n this._locale = val\n this.notify()\n }\n }\n\n // Геттер/Сеттер для fallback локали\n get fallbackLocale(): string {\n return this._fallbackLocale\n }\n\n set fallbackLocale(val: string) {\n this._fallbackLocale = val\n }\n\n // Геттер/Сеттер для текущего роута\n get currentRoute(): string {\n return this._currentRoute\n }\n\n setRoute(routeName: string): void {\n if (this._currentRoute !== routeName) {\n this._currentRoute = routeName\n this.notify()\n }\n }\n\n // --- Implementation of abstract methods ---\n\n public getLocale(): string {\n return this._locale\n }\n\n public getFallbackLocale(): string {\n return this._fallbackLocale\n }\n\n public getRoute(): string {\n return this._currentRoute\n }\n\n // Translation management (uses protected methods from base class)\n public addTranslations(locale: string, translations: Translations, merge: boolean = true): void {\n super.loadTranslationsCore(locale, translations, merge)\n this.notify()\n }\n\n public addRouteTranslations(\n locale: string,\n routeName: string,\n translations: Translations,\n merge: boolean = true,\n ): void {\n super.loadRouteTranslationsCore(locale, routeName, translations, merge)\n this.notify()\n }\n\n public override clearCache(): void {\n super.clearCache()\n this.notify()\n }\n}\n\n/**\n * Create a new PreactI18n instance\n */\nexport function createI18n(options: PreactI18nOptions): PreactI18n {\n return new PreactI18n(options)\n}\n","import { createContext } from 'preact'\nimport { useContext } from 'preact/hooks'\nimport type { PreactI18n } from './i18n'\nimport type { Locale } from '@i18n-micro/types'\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 { h } from 'preact'\nimport { useEffect, useState } from 'preact/hooks'\nimport type { ComponentChildren } from 'preact'\nimport type { PreactI18n } from './i18n'\nimport type {\n Translations,\n Params,\n TranslationKey,\n CleanTranslation,\n Locale,\n} from '@i18n-micro/types'\nimport {\n I18nContext,\n I18nLocalesContext,\n I18nDefaultLocaleContext,\n I18nRouterContext,\n useI18nContext,\n useI18nLocales,\n useI18nDefaultLocale,\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\n ? h(\n I18nRouterContext.Provider,\n { value: routingStrategy },\n children,\n )\n : 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 { h, Fragment } from 'preact'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport type { TranslationKey, PluralFunc } from '@i18n-micro/types'\n\nexport interface I18nTProps extends Omit<JSX.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): JSX.Element | 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 = (\n elementTag: keyof JSX.IntrinsicElements,\n elementProps: JSX.HTMLAttributes<HTMLElement>,\n children?: string,\n ): JSX.Element => {\n return h(\n elementTag as unknown as keyof JSX.IntrinsicElements,\n elementProps as unknown as JSX.HTMLAttributes<HTMLElement>,\n children,\n ) as JSX.Element\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())\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 }\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 JSX.Element) : 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 { h } from 'preact'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport { useI18nRouter } from '../injection'\n\nexport interface I18nLinkProps extends JSX.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): JSX.Element => {\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: JSX.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 JSX.Element\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 JSX.Element\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?: JSX.Element | JSX.Element[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }) => JSX.Element\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?: JSX.Element | JSX.Element[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }\n return h(\n Component,\n componentProps,\n children,\n ) as JSX.Element\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 JSX.Element\n}\n","import { h } from 'preact'\nimport { useState, useEffect, useRef } from 'preact/hooks'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport { useI18nRouter, useI18nLocales, useI18nContext } from '../injection'\nimport type { Locale } from '@i18n-micro/types'\n\nexport interface I18nSwitcherProps extends JSX.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 customIconStyle?: Record<string, string | number>\n}\n\nexport const I18nSwitcher = (props: I18nSwitcherProps): JSX.Element => {\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 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 const locales = localesProp || injectedLocales || i18n.getLocales() || []\n\n // Get current locale value (handle both string and function)\n const getCurrentLocale = (): string => {\n if (typeof currentLocaleProp === 'function') {\n return currentLocaleProp()\n }\n if (typeof currentLocaleProp === 'string') {\n return currentLocaleProp\n }\n return i18n.locale\n }\n\n const currentLocale = getCurrentLocale()\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 }\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 = { ...buttonStyle, ...customButtonStyle }\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 ariaHaspopup: 'true',\n ariaExpanded: 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 JSX.Element\n}\n","import { h } from 'preact'\nimport type { JSX, ComponentChildren } from 'preact'\nimport { useI18n } from '../context'\nimport type { TranslationKey } from '@i18n-micro/types'\n\nexport interface I18nGroupProps extends Omit<JSX.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): JSX.Element => {\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'\n ? children({ prefix, t: translate })\n : children\n\n return h(\n 'div',\n { ...restProps, className },\n childrenContent,\n ) as JSX.Element\n}\n","import type { I18nRoutingStrategy } from './types'\nimport type { Locale } from '@i18n-micro/types'\n\n/**\n * Создает адаптер для работы с History API (универсальный для Pure Preact)\n * Работает с любым роутером, который использует History API (wouter, preact-router, и т.д.)\n */\nexport function createBrowserHistoryAdapter(\n locales: Locale[],\n defaultLocale: string,\n): 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 if (pathSegments.length > 0 && localeCodes.includes(pathSegments[0])) {\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"],"names":["PreactI18n","BaseI18n","options","cache","lang","msgs","listener","val","routeName","locale","translations","merge","createI18n","I18nContext","createContext","I18nLocalesContext","I18nDefaultLocaleContext","I18nRouterContext","useI18nContext","context","useContext","useI18nLocales","useI18nDefaultLocale","useI18nRouter","I18nProvider","i18n","locales","defaultLocale","routingStrategy","children","h","useI18n","router","injectedLocales","injectedDefaultLocale","forceUpdate","useState","useEffect","n","resolveLocalePath","to","localeCode","switchLocaleHelper","newLocale","currentPath","newPath","l","res","I18nT","props","tc","tn","td","tdr","getRoute","keypath","params","tag","plural","defaultValue","html","hideIfEmpty","customPluralRule","number","date","relativeDate","restProps","route","createElement","elementTag","elementProps","numberValue","formattedNumber","translation","content","formattedDate","formattedRelativeDate","count","k","p","dv","tResult","Fragment","I18nLink","activeStyle","localeRouteProp","localeRoute","isExternalLink","externalHref","targetPath","computedStyle","linkPath","normalizedCurrent","normalizedLink","toValue","handleClick","e","LinkComponent","Component","componentProps","I18nSwitcher","localesProp","currentLocaleProp","getLocaleNameProp","switchLocaleProp","_localeRouteProp","customLabels","customWrapperStyle","customButtonStyle","customDropdownStyle","customItemStyle","customLinkStyle","customActiveLinkStyle","customIconStyle","i18nInstance","dropdownOpen","setDropdownOpen","wrapperRef","useRef","currentLocale","currentLocaleName","toggleDropdown","event","localeLabel","localeItem","currentLocaleLabel","current","handleSwitchLocale","code","wrapperStyle","buttonStyle","dropdownStyle","itemStyle","linkStyle","activeLinkStyle","iconStyle","openIconStyle","handler","target","isClickInside","isButtonClick","mergedWrapperStyle","mergedButtonStyle","mergedDropdownStyle","mergedItemStyle","mergedIconStyle","dropdownItems","isActive","mergedLinkStyle","I18nGroup","prefix","groupClass","t","translate","key","result","className","childrenContent","createBrowserHistoryAdapter","localeCodes","loc","resolvePath","pathSegments","cleanPath","createPreactRouterAdapter"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { Attributes } from 'preact';
|
|
2
|
+
import { BaseI18n } from '@i18n-micro/core';
|
|
3
|
+
import { CleanTranslation } from '@i18n-micro/types';
|
|
4
|
+
import { ComponentChildren } from 'preact';
|
|
5
|
+
import { Context } from 'preact';
|
|
6
|
+
import { default as default_2 } from 'react';
|
|
7
|
+
import { defaultPlural } from '@i18n-micro/core';
|
|
8
|
+
import { FormatService } from '@i18n-micro/core';
|
|
9
|
+
import { Getter } from '@i18n-micro/types';
|
|
10
|
+
import { interpolate } from '@i18n-micro/core';
|
|
11
|
+
import { JSX as JSX_2 } from 'preact';
|
|
12
|
+
import { Locale } from '@i18n-micro/types';
|
|
13
|
+
import { LocaleCode } from '@i18n-micro/types';
|
|
14
|
+
import { ModuleOptions } from '@i18n-micro/types';
|
|
15
|
+
import { Params } from '@i18n-micro/types';
|
|
16
|
+
import { PluralFunc } from '@i18n-micro/types';
|
|
17
|
+
import { TranslationCache } from '@i18n-micro/core';
|
|
18
|
+
import { TranslationKey } from '@i18n-micro/types';
|
|
19
|
+
import { Translations } from '@i18n-micro/types';
|
|
20
|
+
import { VNode } from 'preact';
|
|
21
|
+
|
|
22
|
+
export { CleanTranslation }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Создает адаптер для работы с History API (универсальный для Pure Preact)
|
|
26
|
+
* Работает с любым роутером, который использует History API (wouter, preact-router, и т.д.)
|
|
27
|
+
*/
|
|
28
|
+
export declare function createBrowserHistoryAdapter(locales: Locale[], defaultLocale: string): I18nRoutingStrategy;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a new PreactI18n instance
|
|
32
|
+
*/
|
|
33
|
+
export declare function createI18n(options: PreactI18nOptions): PreactI18n;
|
|
34
|
+
|
|
35
|
+
export declare const createPreactRouterAdapter: typeof createBrowserHistoryAdapter;
|
|
36
|
+
|
|
37
|
+
export { defaultPlural }
|
|
38
|
+
|
|
39
|
+
export { FormatService }
|
|
40
|
+
|
|
41
|
+
export { Getter }
|
|
42
|
+
|
|
43
|
+
export declare const I18nContext: Context<PreactI18n | null>;
|
|
44
|
+
|
|
45
|
+
export declare const I18nDefaultLocaleContext: Context<string | null>;
|
|
46
|
+
|
|
47
|
+
export declare const I18nGroup: (props: I18nGroupProps) => JSX_2.Element;
|
|
48
|
+
|
|
49
|
+
export declare interface I18nGroupProps extends Omit<JSX_2.HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
50
|
+
prefix: string;
|
|
51
|
+
groupClass?: string;
|
|
52
|
+
children?: (props: {
|
|
53
|
+
prefix: string;
|
|
54
|
+
t: (key: string, params?: Record<string, string | number | boolean>) => string;
|
|
55
|
+
}) => ComponentChildren;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export declare const I18nLink: (props: I18nLinkProps) => JSX_2.Element;
|
|
59
|
+
|
|
60
|
+
export declare interface I18nLinkProps extends JSX_2.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
61
|
+
to: string | {
|
|
62
|
+
path?: string;
|
|
63
|
+
};
|
|
64
|
+
activeStyle?: Record<string, string | number>;
|
|
65
|
+
localeRoute?: (to: string | {
|
|
66
|
+
path?: string;
|
|
67
|
+
}, locale?: string) => string | {
|
|
68
|
+
path?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export declare const I18nLocalesContext: Context<Locale[] | null>;
|
|
73
|
+
|
|
74
|
+
export declare function I18nProvider({ i18n, locales, defaultLocale, routingStrategy, children }: I18nProviderProps): VNode<Attributes & {
|
|
75
|
+
value: PreactI18n | null;
|
|
76
|
+
children?: ComponentChildren;
|
|
77
|
+
}>;
|
|
78
|
+
|
|
79
|
+
export declare interface I18nProviderProps {
|
|
80
|
+
i18n: PreactI18n;
|
|
81
|
+
locales?: Locale[];
|
|
82
|
+
defaultLocale?: string;
|
|
83
|
+
routingStrategy?: I18nRoutingStrategy;
|
|
84
|
+
children?: ComponentChildren;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export declare const I18nRouterContext: Context<I18nRoutingStrategy | null>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Routing strategy interface for i18n
|
|
91
|
+
* Implement this interface to integrate with any router library
|
|
92
|
+
* Matches Vue/Solid package interface for consistency
|
|
93
|
+
*/
|
|
94
|
+
export declare interface I18nRoutingStrategy {
|
|
95
|
+
/**
|
|
96
|
+
* Returns current path (without locale prefix if needed, or full path)
|
|
97
|
+
* Used for determining active classes in links
|
|
98
|
+
*/
|
|
99
|
+
getCurrentPath: () => string;
|
|
100
|
+
/**
|
|
101
|
+
* Component to use for rendering links (e.g., RouterLink)
|
|
102
|
+
*/
|
|
103
|
+
linkComponent?: string | default_2.ComponentType<{
|
|
104
|
+
href: string;
|
|
105
|
+
children?: default_2.ReactNode;
|
|
106
|
+
style?: default_2.CSSProperties;
|
|
107
|
+
className?: string;
|
|
108
|
+
[key: string]: unknown;
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* Function to navigate to another route/locale
|
|
112
|
+
*/
|
|
113
|
+
push: (target: {
|
|
114
|
+
path: string;
|
|
115
|
+
}) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Function to replace current route
|
|
118
|
+
*/
|
|
119
|
+
replace: (target: {
|
|
120
|
+
path: string;
|
|
121
|
+
}) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Generate path for specific locale
|
|
124
|
+
*/
|
|
125
|
+
resolvePath?: (to: string | {
|
|
126
|
+
path?: string;
|
|
127
|
+
}, locale: string) => string | {
|
|
128
|
+
path?: string;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* (Optional) Get current route object for SEO/Meta tags
|
|
132
|
+
*/
|
|
133
|
+
getRoute?: () => {
|
|
134
|
+
fullPath: string;
|
|
135
|
+
query: Record<string, unknown>;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export declare const I18nSwitcher: (props: I18nSwitcherProps) => JSX_2.Element;
|
|
140
|
+
|
|
141
|
+
export declare interface I18nSwitcherProps extends JSX_2.HTMLAttributes<HTMLDivElement> {
|
|
142
|
+
locales?: Locale[];
|
|
143
|
+
currentLocale?: string | (() => string);
|
|
144
|
+
getLocaleName?: () => string | null;
|
|
145
|
+
switchLocale?: (locale: string) => void;
|
|
146
|
+
localeRoute?: (to: string | {
|
|
147
|
+
path?: string;
|
|
148
|
+
}, locale?: string) => string | {
|
|
149
|
+
path?: string;
|
|
150
|
+
};
|
|
151
|
+
customLabels?: Record<string, string>;
|
|
152
|
+
customWrapperStyle?: Record<string, string | number>;
|
|
153
|
+
customButtonStyle?: Record<string, string | number>;
|
|
154
|
+
customDropdownStyle?: Record<string, string | number>;
|
|
155
|
+
customItemStyle?: Record<string, string | number>;
|
|
156
|
+
customLinkStyle?: Record<string, string | number>;
|
|
157
|
+
customActiveLinkStyle?: Record<string, string | number>;
|
|
158
|
+
customIconStyle?: Record<string, string | number>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export declare const I18nT: (props: I18nTProps) => JSX_2.Element | null;
|
|
162
|
+
|
|
163
|
+
export declare interface I18nTProps extends Omit<JSX_2.HTMLAttributes<HTMLElement>, 'children'> {
|
|
164
|
+
keypath: TranslationKey;
|
|
165
|
+
params?: Record<string, string | number | boolean>;
|
|
166
|
+
tag?: keyof JSX_2.IntrinsicElements;
|
|
167
|
+
plural?: number | string;
|
|
168
|
+
defaultValue?: string;
|
|
169
|
+
html?: boolean;
|
|
170
|
+
hideIfEmpty?: boolean;
|
|
171
|
+
customPluralRule?: PluralFunc;
|
|
172
|
+
number?: number | string;
|
|
173
|
+
date?: Date | string | number;
|
|
174
|
+
relativeDate?: Date | string | number;
|
|
175
|
+
children?: never;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { interpolate }
|
|
179
|
+
|
|
180
|
+
export { Locale }
|
|
181
|
+
|
|
182
|
+
export { LocaleCode }
|
|
183
|
+
|
|
184
|
+
export { ModuleOptions }
|
|
185
|
+
|
|
186
|
+
export { Params }
|
|
187
|
+
|
|
188
|
+
export { PluralFunc }
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Preact I18n Adapter
|
|
192
|
+
*
|
|
193
|
+
* Provides a Preact-compatible i18n instance that uses the shared core logic.
|
|
194
|
+
* Implements Observer pattern for reactivity with useSyncExternalStore.
|
|
195
|
+
* Works with Preact through preact/compat for React compatibility.
|
|
196
|
+
*/
|
|
197
|
+
export declare class PreactI18n extends BaseI18n {
|
|
198
|
+
private _locale;
|
|
199
|
+
private _fallbackLocale;
|
|
200
|
+
private _currentRoute;
|
|
201
|
+
private listeners;
|
|
202
|
+
private revision;
|
|
203
|
+
readonly cache: TranslationCache;
|
|
204
|
+
constructor(options: PreactI18nOptions);
|
|
205
|
+
subscribe: (listener: () => void) => () => void;
|
|
206
|
+
getSnapshot: () => string;
|
|
207
|
+
private notify;
|
|
208
|
+
get locale(): string;
|
|
209
|
+
set locale(val: string);
|
|
210
|
+
get fallbackLocale(): string;
|
|
211
|
+
set fallbackLocale(val: string);
|
|
212
|
+
get currentRoute(): string;
|
|
213
|
+
setRoute(routeName: string): void;
|
|
214
|
+
getLocale(): string;
|
|
215
|
+
getFallbackLocale(): string;
|
|
216
|
+
getRoute(): string;
|
|
217
|
+
addTranslations(locale: string, translations: Translations, merge?: boolean): void;
|
|
218
|
+
addRouteTranslations(locale: string, routeName: string, translations: Translations, merge?: boolean): void;
|
|
219
|
+
clearCache(): void;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export declare interface PreactI18nOptions {
|
|
223
|
+
locale: string;
|
|
224
|
+
fallbackLocale?: string;
|
|
225
|
+
messages?: Record<string, Translations>;
|
|
226
|
+
plural?: PluralFunc;
|
|
227
|
+
missingWarn?: boolean;
|
|
228
|
+
missingHandler?: (locale: string, key: string, routeName: string) => void;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export { TranslationKey }
|
|
232
|
+
|
|
233
|
+
export { Translations }
|
|
234
|
+
|
|
235
|
+
export declare const useI18n: (options?: UseI18nOptions) => UseI18nReturn;
|
|
236
|
+
|
|
237
|
+
export declare const useI18nContext: () => PreactI18n;
|
|
238
|
+
|
|
239
|
+
export declare const useI18nDefaultLocale: () => string | null;
|
|
240
|
+
|
|
241
|
+
export declare const useI18nLocales: () => Locale[] | null;
|
|
242
|
+
|
|
243
|
+
export declare interface UseI18nOptions {
|
|
244
|
+
locales?: Locale[];
|
|
245
|
+
defaultLocale?: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export declare interface UseI18nReturn {
|
|
249
|
+
t: (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string) => CleanTranslation;
|
|
250
|
+
ts: (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string) => string;
|
|
251
|
+
tc: (key: TranslationKey, count: number | Params, defaultValue?: string) => string;
|
|
252
|
+
tn: (value: number, options?: Intl.NumberFormatOptions) => string;
|
|
253
|
+
td: (value: Date | number | string, options?: Intl.DateTimeFormatOptions) => string;
|
|
254
|
+
tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string;
|
|
255
|
+
has: (key: TranslationKey, routeName?: string) => boolean;
|
|
256
|
+
locale: string;
|
|
257
|
+
fallbackLocale: string;
|
|
258
|
+
currentRoute: string;
|
|
259
|
+
setLocale: (locale: string) => void;
|
|
260
|
+
setRoute: (routeName: string) => void;
|
|
261
|
+
getRoute: () => string;
|
|
262
|
+
getLocales: () => Locale[];
|
|
263
|
+
defaultLocale: () => string;
|
|
264
|
+
getLocaleName: () => string | null;
|
|
265
|
+
switchLocale?: (locale: string) => void;
|
|
266
|
+
localeRoute?: (to: string | {
|
|
267
|
+
path?: string;
|
|
268
|
+
}, locale?: string) => string | {
|
|
269
|
+
path?: string;
|
|
270
|
+
};
|
|
271
|
+
localePath?: (to: string | {
|
|
272
|
+
path?: string;
|
|
273
|
+
}, locale?: string) => string;
|
|
274
|
+
addTranslations: (locale: string, translations: Translations, merge?: boolean) => void;
|
|
275
|
+
addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void;
|
|
276
|
+
clearCache: () => void;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export declare const useI18nRouter: () => I18nRoutingStrategy | null;
|
|
280
|
+
|
|
281
|
+
export { }
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import { BaseI18n as lt } from "@i18n-micro/core";
|
|
2
|
+
import { FormatService as Rt, defaultPlural as xt, interpolate as It } from "@i18n-micro/core";
|
|
3
|
+
import { createContext as H, h, Fragment as it } from "preact";
|
|
4
|
+
import { useContext as $, useState as z, useEffect as M, useRef as ut } from "preact/hooks";
|
|
5
|
+
class dt extends lt {
|
|
6
|
+
_locale;
|
|
7
|
+
_fallbackLocale;
|
|
8
|
+
_currentRoute = "general";
|
|
9
|
+
listeners = /* @__PURE__ */ new Set();
|
|
10
|
+
revision = 0;
|
|
11
|
+
// Cache для Core (plain objects, не реактивные)
|
|
12
|
+
cache;
|
|
13
|
+
constructor(t) {
|
|
14
|
+
const n = {
|
|
15
|
+
generalLocaleCache: {},
|
|
16
|
+
routeLocaleCache: {},
|
|
17
|
+
dynamicTranslationsCaches: [],
|
|
18
|
+
serverTranslationCache: {}
|
|
19
|
+
};
|
|
20
|
+
if (super({
|
|
21
|
+
cache: n,
|
|
22
|
+
plural: t.plural,
|
|
23
|
+
missingWarn: t.missingWarn,
|
|
24
|
+
missingHandler: t.missingHandler
|
|
25
|
+
}), this.cache = n, this._locale = t.locale, this._fallbackLocale = t.fallbackLocale || t.locale, t.messages)
|
|
26
|
+
for (const [e, r] of Object.entries(t.messages))
|
|
27
|
+
this.helper.loadTranslations(e, r);
|
|
28
|
+
}
|
|
29
|
+
// Для useSyncExternalStore
|
|
30
|
+
subscribe = (t) => (this.listeners.add(t), () => {
|
|
31
|
+
this.listeners.delete(t);
|
|
32
|
+
});
|
|
33
|
+
getSnapshot = () => `${this._locale}:${this._currentRoute}:${this.revision}`;
|
|
34
|
+
notify() {
|
|
35
|
+
this.revision++, this.listeners.forEach((t) => {
|
|
36
|
+
t();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Геттер/Сеттер для локали
|
|
40
|
+
get locale() {
|
|
41
|
+
return this._locale;
|
|
42
|
+
}
|
|
43
|
+
set locale(t) {
|
|
44
|
+
this._locale !== t && (this._locale = t, this.notify());
|
|
45
|
+
}
|
|
46
|
+
// Геттер/Сеттер для fallback локали
|
|
47
|
+
get fallbackLocale() {
|
|
48
|
+
return this._fallbackLocale;
|
|
49
|
+
}
|
|
50
|
+
set fallbackLocale(t) {
|
|
51
|
+
this._fallbackLocale = t;
|
|
52
|
+
}
|
|
53
|
+
// Геттер/Сеттер для текущего роута
|
|
54
|
+
get currentRoute() {
|
|
55
|
+
return this._currentRoute;
|
|
56
|
+
}
|
|
57
|
+
setRoute(t) {
|
|
58
|
+
this._currentRoute !== t && (this._currentRoute = t, this.notify());
|
|
59
|
+
}
|
|
60
|
+
// --- Implementation of abstract methods ---
|
|
61
|
+
getLocale() {
|
|
62
|
+
return this._locale;
|
|
63
|
+
}
|
|
64
|
+
getFallbackLocale() {
|
|
65
|
+
return this._fallbackLocale;
|
|
66
|
+
}
|
|
67
|
+
getRoute() {
|
|
68
|
+
return this._currentRoute;
|
|
69
|
+
}
|
|
70
|
+
// Translation management (uses protected methods from base class)
|
|
71
|
+
addTranslations(t, n, e = !0) {
|
|
72
|
+
super.loadTranslationsCore(t, n, e), this.notify();
|
|
73
|
+
}
|
|
74
|
+
addRouteTranslations(t, n, e, r = !0) {
|
|
75
|
+
super.loadRouteTranslationsCore(t, n, e, r), this.notify();
|
|
76
|
+
}
|
|
77
|
+
clearCache() {
|
|
78
|
+
super.clearCache(), this.notify();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function yt(a) {
|
|
82
|
+
return new dt(a);
|
|
83
|
+
}
|
|
84
|
+
const O = H(null), F = H(null), V = H(null), q = H(null), K = () => {
|
|
85
|
+
const a = $(O);
|
|
86
|
+
if (!a)
|
|
87
|
+
throw new Error("[i18n-micro] I18nContext not found. Make sure I18nProvider is used.");
|
|
88
|
+
return a;
|
|
89
|
+
}, U = () => $(F), ft = () => $(V), W = () => $(q);
|
|
90
|
+
function bt({ i18n: a, locales: t, defaultLocale: n, routingStrategy: e, children: r }) {
|
|
91
|
+
return h(
|
|
92
|
+
O.Provider,
|
|
93
|
+
{ value: a },
|
|
94
|
+
t ? h(
|
|
95
|
+
F.Provider,
|
|
96
|
+
{ value: t },
|
|
97
|
+
n ? h(
|
|
98
|
+
V.Provider,
|
|
99
|
+
{ value: n },
|
|
100
|
+
e ? h(
|
|
101
|
+
q.Provider,
|
|
102
|
+
{ value: e },
|
|
103
|
+
r
|
|
104
|
+
) : r
|
|
105
|
+
) : r
|
|
106
|
+
) : r
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const j = (a) => {
|
|
110
|
+
const t = K(), n = W(), e = U(), r = ft(), [, w] = z(0);
|
|
111
|
+
M(() => t.subscribe(() => {
|
|
112
|
+
w((u) => u + 1);
|
|
113
|
+
}), [t]);
|
|
114
|
+
const y = a?.locales || e || [], g = a?.defaultLocale || r || t.locale, c = (o, u) => n?.resolvePath ? n.resolvePath(o, u || t.locale) : o, f = (o) => {
|
|
115
|
+
if (t.locale = o, n) {
|
|
116
|
+
const u = n.getCurrentPath(), d = c(u, o);
|
|
117
|
+
n.push(typeof d == "string" ? { path: d } : { path: d.path || "/" });
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
// Translation methods
|
|
122
|
+
t: t.t.bind(t),
|
|
123
|
+
ts: t.ts.bind(t),
|
|
124
|
+
tc: t.tc.bind(t),
|
|
125
|
+
tn: t.tn.bind(t),
|
|
126
|
+
td: t.td.bind(t),
|
|
127
|
+
tdr: t.tdr.bind(t),
|
|
128
|
+
has: t.has.bind(t),
|
|
129
|
+
// Locale management
|
|
130
|
+
get locale() {
|
|
131
|
+
return t.locale;
|
|
132
|
+
},
|
|
133
|
+
get fallbackLocale() {
|
|
134
|
+
return t.fallbackLocale;
|
|
135
|
+
},
|
|
136
|
+
get currentRoute() {
|
|
137
|
+
return t.currentRoute;
|
|
138
|
+
},
|
|
139
|
+
setLocale: (o) => {
|
|
140
|
+
t.locale = o;
|
|
141
|
+
},
|
|
142
|
+
// Route management
|
|
143
|
+
setRoute: t.setRoute.bind(t),
|
|
144
|
+
getRoute: t.getRoute.bind(t),
|
|
145
|
+
getLocales: () => y,
|
|
146
|
+
defaultLocale: () => g,
|
|
147
|
+
getLocaleName: () => y.find((u) => u.code === t.locale)?.displayName || null,
|
|
148
|
+
// Router methods (always available, but navigation handled by components)
|
|
149
|
+
switchLocale: f,
|
|
150
|
+
localeRoute: c,
|
|
151
|
+
localePath: (o, u) => {
|
|
152
|
+
const d = c(o, u);
|
|
153
|
+
return typeof d == "string" ? d : d.path || "/";
|
|
154
|
+
},
|
|
155
|
+
// Translation management
|
|
156
|
+
addTranslations: t.addTranslations.bind(t),
|
|
157
|
+
addRouteTranslations: t.addRouteTranslations.bind(t),
|
|
158
|
+
clearCache: t.clearCache.bind(t)
|
|
159
|
+
};
|
|
160
|
+
}, Lt = (a) => {
|
|
161
|
+
const { t, tc: n, tn: e, td: r, tdr: w, locale: y, getRoute: g } = j(), {
|
|
162
|
+
keypath: c,
|
|
163
|
+
params: f,
|
|
164
|
+
tag: o = "span",
|
|
165
|
+
plural: u,
|
|
166
|
+
defaultValue: d,
|
|
167
|
+
html: P = !1,
|
|
168
|
+
hideIfEmpty: x = !1,
|
|
169
|
+
customPluralRule: I,
|
|
170
|
+
number: l,
|
|
171
|
+
date: m,
|
|
172
|
+
relativeDate: C,
|
|
173
|
+
...i
|
|
174
|
+
} = a, R = g(), b = (L, p, v) => h(
|
|
175
|
+
L,
|
|
176
|
+
p,
|
|
177
|
+
v
|
|
178
|
+
);
|
|
179
|
+
if (l !== void 0) {
|
|
180
|
+
const L = Number(l), p = e(L), v = t(c, { number: p, ...f || {} }, void 0, R), _ = typeof v == "string" ? v : String(v);
|
|
181
|
+
return P ? b(o, { ...i, dangerouslySetInnerHTML: { __html: _ } }, void 0) : b(o, i, _);
|
|
182
|
+
}
|
|
183
|
+
if (m !== void 0) {
|
|
184
|
+
const L = r(m), p = t(c, { date: L, ...f || {} }, void 0, R), v = typeof p == "string" ? p : String(p);
|
|
185
|
+
return P ? b(o, { ...i, dangerouslySetInnerHTML: { __html: v } }, void 0) : b(o, i, v);
|
|
186
|
+
}
|
|
187
|
+
if (C !== void 0) {
|
|
188
|
+
const L = w(C), p = t(c, { relativeDate: L, ...f || {} }, void 0, R), v = typeof p == "string" ? p : String(p);
|
|
189
|
+
return P ? b(o, { ...i, dangerouslySetInnerHTML: { __html: v } }, void 0) : b(o, i, v);
|
|
190
|
+
}
|
|
191
|
+
if (u !== void 0) {
|
|
192
|
+
const L = Number.parseInt(u.toString());
|
|
193
|
+
let p;
|
|
194
|
+
return I ? p = I(
|
|
195
|
+
c,
|
|
196
|
+
L,
|
|
197
|
+
f || {},
|
|
198
|
+
y,
|
|
199
|
+
(_, A, B) => {
|
|
200
|
+
const E = t(_, A, B, R);
|
|
201
|
+
return typeof E == "string" ? E : String(E);
|
|
202
|
+
}
|
|
203
|
+
) || "" : p = n(c, { count: L, ...f || {} }, d), P ? b(o, { ...i, dangerouslySetInnerHTML: { __html: p } }, void 0) : b(o, i, p);
|
|
204
|
+
}
|
|
205
|
+
const D = t(c, f, d, R), N = typeof D == "string" ? D : String(D);
|
|
206
|
+
return x && !N.trim() ? d ? h(it, null, d) : null : P ? b(o, { ...i, dangerouslySetInnerHTML: { __html: N } }, void 0) : b(o, i, N);
|
|
207
|
+
}, vt = (a) => {
|
|
208
|
+
const t = j(), n = W(), { to: e, activeStyle: r, localeRoute: w, children: y, ...g } = a, c = w || t.localeRoute, f = () => typeof e == "string" ? /^(?:https?:\/\/|\/\/|[a-zA-Z0-9-]+\.[a-zA-Z]{2,})|tel:|mailto:/.test(e) : !1, o = () => {
|
|
209
|
+
if (f() && typeof e == "string")
|
|
210
|
+
return /^https?:\/\//.test(e) ? e : `https://${e}`;
|
|
211
|
+
}, u = () => {
|
|
212
|
+
if (f())
|
|
213
|
+
return typeof e == "string" ? e : e?.path || "/";
|
|
214
|
+
if (c) {
|
|
215
|
+
const m = c(e);
|
|
216
|
+
return typeof m == "string" ? m : m.path || "/";
|
|
217
|
+
}
|
|
218
|
+
if (!n?.resolvePath)
|
|
219
|
+
return typeof e == "string" ? e : e.path || "/";
|
|
220
|
+
const l = n.resolvePath(e, t.locale);
|
|
221
|
+
return typeof l == "string" ? l : l.path || "/";
|
|
222
|
+
}, P = (() => {
|
|
223
|
+
if (f() || !n)
|
|
224
|
+
return !1;
|
|
225
|
+
const l = n.getCurrentPath(), m = u(), C = l.replace(/\/$/, ""), i = m.replace(/\/$/, "");
|
|
226
|
+
return !!(C === i || C.startsWith(i + "/"));
|
|
227
|
+
})() ? r || {} : {}, x = u(), I = (l) => {
|
|
228
|
+
a.onClick && a.onClick(l), !l.defaultPrevented && !l.button && !l.metaKey && !l.ctrlKey && n && !f() && (l.preventDefault(), n.push({ path: x }));
|
|
229
|
+
};
|
|
230
|
+
if (f())
|
|
231
|
+
return h(
|
|
232
|
+
"a",
|
|
233
|
+
{
|
|
234
|
+
...g,
|
|
235
|
+
href: o(),
|
|
236
|
+
style: P,
|
|
237
|
+
target: "_blank",
|
|
238
|
+
rel: "noopener noreferrer"
|
|
239
|
+
},
|
|
240
|
+
y
|
|
241
|
+
);
|
|
242
|
+
if (n?.linkComponent) {
|
|
243
|
+
const l = n.linkComponent;
|
|
244
|
+
if (typeof l == "string")
|
|
245
|
+
return h(
|
|
246
|
+
l,
|
|
247
|
+
{
|
|
248
|
+
...g,
|
|
249
|
+
href: x,
|
|
250
|
+
style: P
|
|
251
|
+
},
|
|
252
|
+
y
|
|
253
|
+
);
|
|
254
|
+
const m = l, C = {
|
|
255
|
+
...g,
|
|
256
|
+
href: x,
|
|
257
|
+
style: P
|
|
258
|
+
};
|
|
259
|
+
return h(
|
|
260
|
+
m,
|
|
261
|
+
C,
|
|
262
|
+
y
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
return h(
|
|
266
|
+
"a",
|
|
267
|
+
{
|
|
268
|
+
...g,
|
|
269
|
+
href: x,
|
|
270
|
+
style: P,
|
|
271
|
+
onClick: I
|
|
272
|
+
},
|
|
273
|
+
y
|
|
274
|
+
);
|
|
275
|
+
}, wt = (a) => {
|
|
276
|
+
const {
|
|
277
|
+
locales: t,
|
|
278
|
+
currentLocale: n,
|
|
279
|
+
getLocaleName: e,
|
|
280
|
+
switchLocale: r,
|
|
281
|
+
localeRoute: w,
|
|
282
|
+
customLabels: y = {},
|
|
283
|
+
customWrapperStyle: g,
|
|
284
|
+
customButtonStyle: c,
|
|
285
|
+
customDropdownStyle: f,
|
|
286
|
+
customItemStyle: o,
|
|
287
|
+
customLinkStyle: u,
|
|
288
|
+
customActiveLinkStyle: d,
|
|
289
|
+
customIconStyle: P,
|
|
290
|
+
...x
|
|
291
|
+
} = a, I = j(), l = K(), m = W(), C = U(), [i, R] = z(!1), b = ut(null), D = t || C || I.getLocales() || [], L = typeof n == "function" ? n() : typeof n == "string" ? n : I.locale, p = e ? e() : I.getLocaleName(), v = (s) => {
|
|
292
|
+
s && (s.stopPropagation(), s.preventDefault()), R(!i);
|
|
293
|
+
}, _ = (s) => y[s.code] || s.displayName || s.code, A = () => {
|
|
294
|
+
const s = D.find((k) => k.code === L);
|
|
295
|
+
return s ? _(s) : p || L;
|
|
296
|
+
}, B = (s) => {
|
|
297
|
+
if (R(!1), r) {
|
|
298
|
+
r(s);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (l.locale = s, !m)
|
|
302
|
+
return;
|
|
303
|
+
const k = m.getCurrentPath(), T = a.localeRoute ? (() => {
|
|
304
|
+
const S = a.localeRoute(k, s);
|
|
305
|
+
return typeof S == "string" ? S : S.path || "/";
|
|
306
|
+
})() : m?.resolvePath ? (() => {
|
|
307
|
+
const S = m.resolvePath(k, s);
|
|
308
|
+
return typeof S == "string" ? S : S.path || "/";
|
|
309
|
+
})() : k;
|
|
310
|
+
m.push({ path: T });
|
|
311
|
+
}, E = {
|
|
312
|
+
position: "relative",
|
|
313
|
+
display: "inline-block",
|
|
314
|
+
verticalAlign: "middle"
|
|
315
|
+
}, Z = {
|
|
316
|
+
padding: "4px 12px",
|
|
317
|
+
fontSize: "16px",
|
|
318
|
+
cursor: "pointer",
|
|
319
|
+
backgroundColor: "#fff",
|
|
320
|
+
border: "1px solid #333",
|
|
321
|
+
transition: "background-color 0.3s ease",
|
|
322
|
+
display: "flex",
|
|
323
|
+
alignItems: "center",
|
|
324
|
+
justifyContent: "space-between"
|
|
325
|
+
}, G = {
|
|
326
|
+
position: "absolute",
|
|
327
|
+
top: "100%",
|
|
328
|
+
left: "0",
|
|
329
|
+
zIndex: 1e3,
|
|
330
|
+
backgroundColor: "#fff",
|
|
331
|
+
border: "1px solid #333",
|
|
332
|
+
listStyle: "none",
|
|
333
|
+
padding: "0",
|
|
334
|
+
margin: "4px 0 0 0",
|
|
335
|
+
minWidth: "150px",
|
|
336
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.15)"
|
|
337
|
+
}, J = {
|
|
338
|
+
margin: "0",
|
|
339
|
+
padding: "0"
|
|
340
|
+
}, Q = {
|
|
341
|
+
display: "block",
|
|
342
|
+
padding: "8px 12px",
|
|
343
|
+
color: "#333",
|
|
344
|
+
textDecoration: "none",
|
|
345
|
+
transition: "background-color 0.3s ease",
|
|
346
|
+
cursor: "pointer"
|
|
347
|
+
}, X = {
|
|
348
|
+
fontWeight: "bold",
|
|
349
|
+
color: "#007bff"
|
|
350
|
+
}, Y = {
|
|
351
|
+
marginLeft: "8px",
|
|
352
|
+
display: "inline-block",
|
|
353
|
+
transition: "transform 0.3s ease"
|
|
354
|
+
}, tt = {
|
|
355
|
+
transform: "rotate(180deg)"
|
|
356
|
+
};
|
|
357
|
+
M(() => {
|
|
358
|
+
if (!i) return;
|
|
359
|
+
const s = (k) => {
|
|
360
|
+
if (!i) return;
|
|
361
|
+
const T = k.target;
|
|
362
|
+
if (!T || !b.current) return;
|
|
363
|
+
const S = b.current.contains(T), ct = T.closest(".i18n-switcher-button") !== null;
|
|
364
|
+
!S && !ct && R(!1);
|
|
365
|
+
};
|
|
366
|
+
return document.addEventListener("click", s), () => {
|
|
367
|
+
document.removeEventListener("click", s);
|
|
368
|
+
};
|
|
369
|
+
}, [i]);
|
|
370
|
+
const et = { ...E, ...g }, nt = { ...Z, ...c }, rt = { ...G, ...f }, ot = { ...J, ...o }, st = {
|
|
371
|
+
...Y,
|
|
372
|
+
...i ? tt : {},
|
|
373
|
+
...P
|
|
374
|
+
}, at = D.map((s) => {
|
|
375
|
+
const k = s.code === L, T = {
|
|
376
|
+
...Q,
|
|
377
|
+
...k ? X : {},
|
|
378
|
+
...u,
|
|
379
|
+
...k ? d : {},
|
|
380
|
+
width: "100%",
|
|
381
|
+
textAlign: "left",
|
|
382
|
+
border: "none",
|
|
383
|
+
background: "transparent"
|
|
384
|
+
};
|
|
385
|
+
return h(
|
|
386
|
+
"li",
|
|
387
|
+
{
|
|
388
|
+
key: s.code,
|
|
389
|
+
style: ot
|
|
390
|
+
},
|
|
391
|
+
h(
|
|
392
|
+
"button",
|
|
393
|
+
{
|
|
394
|
+
type: "button",
|
|
395
|
+
className: `switcher-locale-${s.code}`,
|
|
396
|
+
style: T,
|
|
397
|
+
onClick: (S) => {
|
|
398
|
+
S.preventDefault(), S.stopPropagation(), B(s.code);
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
_(s)
|
|
402
|
+
)
|
|
403
|
+
);
|
|
404
|
+
});
|
|
405
|
+
return h(
|
|
406
|
+
"div",
|
|
407
|
+
{
|
|
408
|
+
ref: b,
|
|
409
|
+
className: "i18n-switcher-wrapper",
|
|
410
|
+
style: et,
|
|
411
|
+
...x
|
|
412
|
+
},
|
|
413
|
+
h(
|
|
414
|
+
"button",
|
|
415
|
+
{
|
|
416
|
+
type: "button",
|
|
417
|
+
className: "i18n-switcher-button",
|
|
418
|
+
style: nt,
|
|
419
|
+
onClick: (s) => {
|
|
420
|
+
s.preventDefault(), s.stopPropagation(), v(s);
|
|
421
|
+
},
|
|
422
|
+
ariaHaspopup: "true",
|
|
423
|
+
ariaExpanded: i
|
|
424
|
+
},
|
|
425
|
+
h("span", null, A()),
|
|
426
|
+
h("span", { style: st }, "▼")
|
|
427
|
+
),
|
|
428
|
+
i ? h(
|
|
429
|
+
"ul",
|
|
430
|
+
{
|
|
431
|
+
className: "i18n-switcher-dropdown",
|
|
432
|
+
style: rt
|
|
433
|
+
},
|
|
434
|
+
...at
|
|
435
|
+
) : null
|
|
436
|
+
);
|
|
437
|
+
}, Pt = (a) => {
|
|
438
|
+
const { prefix: t, groupClass: n, children: e, ...r } = a, { t: w, getRoute: y } = j(), g = (o, u) => {
|
|
439
|
+
const d = w(`${t}.${o}`, u, void 0, y());
|
|
440
|
+
return typeof d == "string" ? d : String(d);
|
|
441
|
+
}, c = ["i18n-group", n].filter(Boolean).join(" "), f = typeof e == "function" ? e({ prefix: t, t: g }) : e;
|
|
442
|
+
return h(
|
|
443
|
+
"div",
|
|
444
|
+
{ ...r, className: c },
|
|
445
|
+
f
|
|
446
|
+
);
|
|
447
|
+
};
|
|
448
|
+
function pt(a, t) {
|
|
449
|
+
const n = a.map((r) => r.code), e = (r, w) => {
|
|
450
|
+
const g = (typeof r == "string" ? r : r.path || "/").split("/").filter(Boolean);
|
|
451
|
+
g.length > 0 && n.includes(g[0]) && g.shift();
|
|
452
|
+
const c = "/" + g.join("/");
|
|
453
|
+
return w === t ? c : `/${w}${c === "/" ? "" : c}`;
|
|
454
|
+
};
|
|
455
|
+
return {
|
|
456
|
+
// Просто рендерим <a>, навигацию перехватит onClick в I18nLink
|
|
457
|
+
linkComponent: void 0,
|
|
458
|
+
getCurrentPath: () => typeof window < "u" ? window.location.pathname : "/",
|
|
459
|
+
push: (r) => {
|
|
460
|
+
typeof window < "u" && (window.history.pushState({}, "", r.path), window.dispatchEvent(new Event("popstate")));
|
|
461
|
+
},
|
|
462
|
+
replace: (r) => {
|
|
463
|
+
typeof window < "u" && (window.history.replaceState({}, "", r.path), window.dispatchEvent(new Event("popstate")));
|
|
464
|
+
},
|
|
465
|
+
resolvePath: (r, w) => e(r, w),
|
|
466
|
+
getRoute: () => typeof window < "u" ? {
|
|
467
|
+
fullPath: window.location.pathname + window.location.search,
|
|
468
|
+
query: Object.fromEntries(new URLSearchParams(window.location.search))
|
|
469
|
+
} : {
|
|
470
|
+
fullPath: "/",
|
|
471
|
+
query: {}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
const St = pt;
|
|
476
|
+
export {
|
|
477
|
+
Rt as FormatService,
|
|
478
|
+
O as I18nContext,
|
|
479
|
+
V as I18nDefaultLocaleContext,
|
|
480
|
+
Pt as I18nGroup,
|
|
481
|
+
vt as I18nLink,
|
|
482
|
+
F as I18nLocalesContext,
|
|
483
|
+
bt as I18nProvider,
|
|
484
|
+
q as I18nRouterContext,
|
|
485
|
+
wt as I18nSwitcher,
|
|
486
|
+
Lt as I18nT,
|
|
487
|
+
dt as PreactI18n,
|
|
488
|
+
pt as createBrowserHistoryAdapter,
|
|
489
|
+
yt as createI18n,
|
|
490
|
+
St as createPreactRouterAdapter,
|
|
491
|
+
xt as defaultPlural,
|
|
492
|
+
It as interpolate,
|
|
493
|
+
j as useI18n,
|
|
494
|
+
K as useI18nContext,
|
|
495
|
+
ft as useI18nDefaultLocale,
|
|
496
|
+
U as useI18nLocales,
|
|
497
|
+
W as useI18nRouter
|
|
498
|
+
};
|
|
499
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/i18n.ts","../src/injection.ts","../src/context.tsx","../src/components/I18nT.tsx","../src/components/I18nLink.tsx","../src/components/I18nSwitcher.tsx","../src/components/I18nGroup.tsx","../src/router/adapter.tsx"],"sourcesContent":["import {\n BaseI18n,\n type TranslationCache,\n} from '@i18n-micro/core'\nimport type {\n Translations,\n PluralFunc,\n} from '@i18n-micro/types'\n\nexport interface PreactI18nOptions {\n locale: string\n fallbackLocale?: string\n messages?: Record<string, Translations>\n plural?: PluralFunc\n missingWarn?: boolean\n missingHandler?: (locale: string, key: string, routeName: string) => void\n}\n\n/**\n * Preact I18n Adapter\n *\n * Provides a Preact-compatible i18n instance that uses the shared core logic.\n * Implements Observer pattern for reactivity with useSyncExternalStore.\n * Works with Preact through preact/compat for React compatibility.\n */\nexport class PreactI18n extends BaseI18n {\n private _locale: string\n private _fallbackLocale: string\n private _currentRoute: string = 'general'\n private listeners = new Set<() => void>()\n private revision = 0\n\n // Cache для Core (plain objects, не реактивные)\n public readonly cache: TranslationCache\n\n constructor(options: PreactI18nOptions) {\n // Create cache first\n const cache: TranslationCache = {\n generalLocaleCache: {},\n routeLocaleCache: {},\n dynamicTranslationsCaches: [],\n serverTranslationCache: {},\n }\n\n // Call parent constructor with options\n super({\n cache,\n plural: options.plural,\n missingWarn: options.missingWarn,\n missingHandler: options.missingHandler,\n })\n\n // Assign cache to public readonly property\n this.cache = cache\n\n this._locale = options.locale\n this._fallbackLocale = options.fallbackLocale || options.locale\n\n // Загружаем начальные сообщения\n if (options.messages) {\n for (const [lang, msgs] of Object.entries(options.messages)) {\n this.helper.loadTranslations(lang, msgs)\n }\n }\n }\n\n // Для useSyncExternalStore\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = () => {\n // Возвращаем комбинированную строку локали и ревизии кэша\n // Это заставит компонент перерендериться при изменении\n return `${this._locale}:${this._currentRoute}:${this.revision}`\n }\n\n private notify() {\n this.revision++\n this.listeners.forEach((listener) => {\n listener()\n })\n }\n\n // Геттер/Сеттер для локали\n get locale(): string {\n return this._locale\n }\n\n set locale(val: string) {\n if (this._locale !== val) {\n this._locale = val\n this.notify()\n }\n }\n\n // Геттер/Сеттер для fallback локали\n get fallbackLocale(): string {\n return this._fallbackLocale\n }\n\n set fallbackLocale(val: string) {\n this._fallbackLocale = val\n }\n\n // Геттер/Сеттер для текущего роута\n get currentRoute(): string {\n return this._currentRoute\n }\n\n setRoute(routeName: string): void {\n if (this._currentRoute !== routeName) {\n this._currentRoute = routeName\n this.notify()\n }\n }\n\n // --- Implementation of abstract methods ---\n\n public getLocale(): string {\n return this._locale\n }\n\n public getFallbackLocale(): string {\n return this._fallbackLocale\n }\n\n public getRoute(): string {\n return this._currentRoute\n }\n\n // Translation management (uses protected methods from base class)\n public addTranslations(locale: string, translations: Translations, merge: boolean = true): void {\n super.loadTranslationsCore(locale, translations, merge)\n this.notify()\n }\n\n public addRouteTranslations(\n locale: string,\n routeName: string,\n translations: Translations,\n merge: boolean = true,\n ): void {\n super.loadRouteTranslationsCore(locale, routeName, translations, merge)\n this.notify()\n }\n\n public override clearCache(): void {\n super.clearCache()\n this.notify()\n }\n}\n\n/**\n * Create a new PreactI18n instance\n */\nexport function createI18n(options: PreactI18nOptions): PreactI18n {\n return new PreactI18n(options)\n}\n","import { createContext } from 'preact'\nimport { useContext } from 'preact/hooks'\nimport type { PreactI18n } from './i18n'\nimport type { Locale } from '@i18n-micro/types'\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 { h } from 'preact'\nimport { useEffect, useState } from 'preact/hooks'\nimport type { ComponentChildren } from 'preact'\nimport type { PreactI18n } from './i18n'\nimport type {\n Translations,\n Params,\n TranslationKey,\n CleanTranslation,\n Locale,\n} from '@i18n-micro/types'\nimport {\n I18nContext,\n I18nLocalesContext,\n I18nDefaultLocaleContext,\n I18nRouterContext,\n useI18nContext,\n useI18nLocales,\n useI18nDefaultLocale,\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\n ? h(\n I18nRouterContext.Provider,\n { value: routingStrategy },\n children,\n )\n : 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 { h, Fragment } from 'preact'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport type { TranslationKey, PluralFunc } from '@i18n-micro/types'\n\nexport interface I18nTProps extends Omit<JSX.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): JSX.Element | 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 = (\n elementTag: keyof JSX.IntrinsicElements,\n elementProps: JSX.HTMLAttributes<HTMLElement>,\n children?: string,\n ): JSX.Element => {\n return h(\n elementTag as unknown as keyof JSX.IntrinsicElements,\n elementProps as unknown as JSX.HTMLAttributes<HTMLElement>,\n children,\n ) as JSX.Element\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())\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 }\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 JSX.Element) : 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 { h } from 'preact'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport { useI18nRouter } from '../injection'\n\nexport interface I18nLinkProps extends JSX.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): JSX.Element => {\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: JSX.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 JSX.Element\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 JSX.Element\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?: JSX.Element | JSX.Element[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }) => JSX.Element\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?: JSX.Element | JSX.Element[]\n style?: Record<string, string | number>\n className?: string\n [key: string]: unknown\n }\n return h(\n Component,\n componentProps,\n children,\n ) as JSX.Element\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 JSX.Element\n}\n","import { h } from 'preact'\nimport { useState, useEffect, useRef } from 'preact/hooks'\nimport type { JSX } from 'preact'\nimport { useI18n } from '../context'\nimport { useI18nRouter, useI18nLocales, useI18nContext } from '../injection'\nimport type { Locale } from '@i18n-micro/types'\n\nexport interface I18nSwitcherProps extends JSX.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 customIconStyle?: Record<string, string | number>\n}\n\nexport const I18nSwitcher = (props: I18nSwitcherProps): JSX.Element => {\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 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 const locales = localesProp || injectedLocales || i18n.getLocales() || []\n\n // Get current locale value (handle both string and function)\n const getCurrentLocale = (): string => {\n if (typeof currentLocaleProp === 'function') {\n return currentLocaleProp()\n }\n if (typeof currentLocaleProp === 'string') {\n return currentLocaleProp\n }\n return i18n.locale\n }\n\n const currentLocale = getCurrentLocale()\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 }\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 = { ...buttonStyle, ...customButtonStyle }\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 ariaHaspopup: 'true',\n ariaExpanded: 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 JSX.Element\n}\n","import { h } from 'preact'\nimport type { JSX, ComponentChildren } from 'preact'\nimport { useI18n } from '../context'\nimport type { TranslationKey } from '@i18n-micro/types'\n\nexport interface I18nGroupProps extends Omit<JSX.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): JSX.Element => {\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'\n ? children({ prefix, t: translate })\n : children\n\n return h(\n 'div',\n { ...restProps, className },\n childrenContent,\n ) as JSX.Element\n}\n","import type { I18nRoutingStrategy } from './types'\nimport type { Locale } from '@i18n-micro/types'\n\n/**\n * Создает адаптер для работы с History API (универсальный для Pure Preact)\n * Работает с любым роутером, который использует History API (wouter, preact-router, и т.д.)\n */\nexport function createBrowserHistoryAdapter(\n locales: Locale[],\n defaultLocale: string,\n): 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 if (pathSegments.length > 0 && localeCodes.includes(pathSegments[0])) {\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"],"names":["PreactI18n","BaseI18n","options","cache","lang","msgs","listener","val","routeName","locale","translations","merge","createI18n","I18nContext","createContext","I18nLocalesContext","I18nDefaultLocaleContext","I18nRouterContext","useI18nContext","context","useContext","useI18nLocales","useI18nDefaultLocale","useI18nRouter","I18nProvider","i18n","locales","defaultLocale","routingStrategy","children","useI18n","router","injectedLocales","injectedDefaultLocale","forceUpdate","useState","useEffect","n","resolveLocalePath","to","localeCode","switchLocaleHelper","newLocale","currentPath","newPath","l","res","I18nT","props","tc","tn","td","tdr","getRoute","keypath","params","tag","plural","defaultValue","html","hideIfEmpty","customPluralRule","number","date","relativeDate","restProps","route","createElement","elementTag","elementProps","numberValue","formattedNumber","translation","content","formattedDate","formattedRelativeDate","count","k","p","dv","tResult","Fragment","I18nLink","activeStyle","localeRouteProp","localeRoute","isExternalLink","externalHref","targetPath","computedStyle","linkPath","normalizedCurrent","normalizedLink","toValue","handleClick","e","LinkComponent","Component","componentProps","I18nSwitcher","localesProp","currentLocaleProp","getLocaleNameProp","switchLocaleProp","_localeRouteProp","customLabels","customWrapperStyle","customButtonStyle","customDropdownStyle","customItemStyle","customLinkStyle","customActiveLinkStyle","customIconStyle","i18nInstance","dropdownOpen","setDropdownOpen","wrapperRef","useRef","currentLocale","currentLocaleName","toggleDropdown","event","localeLabel","localeItem","currentLocaleLabel","current","handleSwitchLocale","code","wrapperStyle","buttonStyle","dropdownStyle","itemStyle","linkStyle","activeLinkStyle","iconStyle","openIconStyle","handler","target","isClickInside","isButtonClick","mergedWrapperStyle","mergedButtonStyle","mergedDropdownStyle","mergedItemStyle","mergedIconStyle","dropdownItems","isActive","mergedLinkStyle","I18nGroup","prefix","groupClass","t","translate","key","result","className","childrenContent","createBrowserHistoryAdapter","localeCodes","loc","resolvePath","pathSegments","cleanPath","createPreactRouterAdapter"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@i18n-micro/preact",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@i18n-micro/core": "1.0.28",
|
|
23
|
+
"@i18n-micro/types": "1.0.16"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"preact": "^10.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@babel/core": "^7.26.0",
|
|
30
|
+
"@babel/preset-env": "^7.26.0",
|
|
31
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
32
|
+
"@testing-library/preact": "^2.0.0",
|
|
33
|
+
"@types/jest": "^29.5.14",
|
|
34
|
+
"babel-jest": "^29.7.0",
|
|
35
|
+
"jest": "^29.7.0",
|
|
36
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
37
|
+
"preact": "^10.0.0",
|
|
38
|
+
"ts-jest": "^29.4.6",
|
|
39
|
+
"vite": "^7.2.7",
|
|
40
|
+
"vite-plugin-dts": "^4.5.4"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "vite build",
|
|
44
|
+
"dev": "cd playground && vite",
|
|
45
|
+
"test": "jest",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|