@i18n-micro/solid 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/dist/index.mjs ADDED
@@ -0,0 +1,575 @@
1
+ import { createSignal as I, createContext as E, useContext as j, createMemo as S, splitProps as V, onMount as de, onCleanup as he, createEffect as fe } from "solid-js";
2
+ import { createStore as pe } from "solid-js/store";
3
+ import { BaseI18n as ge } from "@i18n-micro/core";
4
+ import { FormatService as He, defaultPlural as Fe, interpolate as Ze } from "@i18n-micro/core";
5
+ import { createComponent as C, memo as v, Dynamic as W, mergeProps as P, template as R, spread as T, insert as x, delegateEvents as me, use as ye, setAttribute as K, effect as H, style as A, className as ve } from "solid-js/web";
6
+ import { A as Le } from "@solidjs/router";
7
+ class be extends ge {
8
+ // Реактивные примитивы Solid
9
+ _locale;
10
+ _setLocale;
11
+ _fallbackLocale;
12
+ _currentRoute;
13
+ _setRoute;
14
+ // Store для кэша.
15
+ // Мы используем createStore для глубокой реактивности, чтобы при подгрузке
16
+ // частичных переводов (mergeTranslation) интерфейс обновлялся.
17
+ cacheStore;
18
+ setCacheStore;
19
+ // Слушатели для DevTools (аналог subscribe в React версии)
20
+ listeners = /* @__PURE__ */ new Set();
21
+ constructor(e) {
22
+ const [t, o] = I(e.locale), [r] = I(e.fallbackLocale || e.locale), [d, f] = I("general"), [l, a] = pe({
23
+ general: {},
24
+ route: {}
25
+ }), s = {
26
+ // Solid Store Proxy is compatible with reading objects
27
+ generalLocaleCache: { value: l.general },
28
+ routeLocaleCache: { value: l.route },
29
+ dynamicTranslationsCaches: { value: [] },
30
+ serverTranslationCache: { value: {} }
31
+ };
32
+ if (super({
33
+ cache: s,
34
+ plural: e.plural,
35
+ missingWarn: e.missingWarn,
36
+ missingHandler: e.missingHandler
37
+ }), this._locale = t, this._setLocale = o, this._fallbackLocale = r, this._currentRoute = d, this._setRoute = f, this.cacheStore = l, this.setCacheStore = a, e.messages)
38
+ for (const [c, p] of Object.entries(e.messages))
39
+ this.addTranslations(c, p);
40
+ }
41
+ // --- Abstract Implementation ---
42
+ getLocale() {
43
+ return this._locale();
44
+ }
45
+ getFallbackLocale() {
46
+ return this._fallbackLocale();
47
+ }
48
+ getRoute() {
49
+ return this._currentRoute();
50
+ }
51
+ // --- Setters ---
52
+ set locale(e) {
53
+ this._setLocale(e), this.notifyListeners();
54
+ }
55
+ get locale() {
56
+ return this._locale();
57
+ }
58
+ // Публичный accessor для реактивности
59
+ get localeAccessor() {
60
+ return this._locale;
61
+ }
62
+ get fallbackLocale() {
63
+ return this._fallbackLocale();
64
+ }
65
+ get currentRoute() {
66
+ return this._currentRoute();
67
+ }
68
+ // Публичный accessor для реактивности
69
+ get routeAccessor() {
70
+ return this._currentRoute;
71
+ }
72
+ setRoute(e) {
73
+ this._setRoute(e), this.notifyListeners();
74
+ }
75
+ // --- Overrides for Reactivity ---
76
+ addTranslations(e, t, o = !0) {
77
+ o ? this.setCacheStore("general", e, (r) => ({
78
+ ...r || {},
79
+ ...t
80
+ })) : this.setCacheStore("general", e, t), this.notifyListeners();
81
+ }
82
+ addRouteTranslations(e, t, o, r = !0) {
83
+ const d = `${e}:${t}`;
84
+ r ? this.setCacheStore("route", d, (f) => ({
85
+ ...f || {},
86
+ ...o
87
+ })) : this.setCacheStore("route", d, o), this.notifyListeners();
88
+ }
89
+ clearCache() {
90
+ this.setCacheStore("general", {}), this.setCacheStore("route", {}), super.clearCache(), this.notifyListeners();
91
+ }
92
+ subscribe(e) {
93
+ return this.listeners.add(e), () => this.listeners.delete(e);
94
+ }
95
+ notifyListeners() {
96
+ this.listeners.forEach((e) => {
97
+ e();
98
+ });
99
+ }
100
+ }
101
+ function Ne(n) {
102
+ return new be(n);
103
+ }
104
+ const Q = E(), U = E(), X = E(), Y = E(), D = () => {
105
+ const n = j(Q);
106
+ if (!n)
107
+ throw new Error("[i18n-micro] I18nContext not found. Make sure I18nProvider is used.");
108
+ return n;
109
+ }, ee = () => {
110
+ const n = j(U);
111
+ if (!n)
112
+ throw new Error("[i18n-micro] I18nLocalesContext not found. Make sure I18nLocalesContext is provided.");
113
+ return n;
114
+ }, Se = () => {
115
+ const n = j(X);
116
+ if (!n)
117
+ throw new Error("[i18n-micro] I18nDefaultLocaleContext not found. Make sure I18nDefaultLocaleContext is provided.");
118
+ return n;
119
+ }, F = () => j(Y), Te = (n) => {
120
+ const e = n.children;
121
+ return (
122
+ // @ts-expect-error - Provider components type conflict with Vue JSX
123
+ C(Q.Provider, {
124
+ get value() {
125
+ return n.i18n;
126
+ },
127
+ get children() {
128
+ return [v(() => v(() => !!n.locales)() && // @ts-expect-error - Provider components type conflict with Vue JSX
129
+ C(U.Provider, {
130
+ get value() {
131
+ return n.locales;
132
+ },
133
+ get children() {
134
+ return [v(() => v(() => !!n.defaultLocale)() && // @ts-expect-error - Provider components type conflict with Vue JSX
135
+ C(X.Provider, {
136
+ get value() {
137
+ return n.defaultLocale;
138
+ },
139
+ get children() {
140
+ return [v(() => v(() => !!n.routingStrategy)() && // @ts-expect-error - Provider components type conflict with Vue JSX
141
+ C(Y.Provider, {
142
+ get value() {
143
+ return n.routingStrategy;
144
+ },
145
+ children: e
146
+ })), v(() => !n.routingStrategy && e)];
147
+ }
148
+ })), v(() => !n.defaultLocale && e)];
149
+ }
150
+ })), v(() => !n.locales && e)];
151
+ }
152
+ })
153
+ );
154
+ };
155
+ function Ee(n) {
156
+ const e = D(), t = F(), o = ee(), r = Se(), d = n?.locales || o, f = n?.defaultLocale || r, l = (a, s) => t?.resolvePath ? t.resolvePath(a, s || e.getLocale()) : a;
157
+ return {
158
+ // Direct access to instance
159
+ instance: e,
160
+ // Locale (reactive) - используем accessor для отслеживания изменений
161
+ locale: S(() => e.localeAccessor()),
162
+ // Locale helpers
163
+ getLocales: () => d,
164
+ defaultLocale: () => f,
165
+ getLocaleName: () => d.find((s) => s.code === e.localeAccessor())?.displayName || null,
166
+ // Routing helpers
167
+ localeRoute: l,
168
+ localePath: (a, s) => {
169
+ const c = l(a, s);
170
+ return typeof c == "string" ? c : c.path || "/";
171
+ },
172
+ switchLocale: (a) => {
173
+ if (e.locale = a, t) {
174
+ const s = t.getCurrentPath(), c = l(s, a);
175
+ t.push(typeof c == "string" ? { path: c } : { path: c.path || "/" });
176
+ }
177
+ },
178
+ // Translation methods (delegate to instance)
179
+ t: e.t.bind(e),
180
+ ts: e.ts.bind(e),
181
+ tc: e.tc.bind(e),
182
+ tn: e.tn.bind(e),
183
+ td: e.td.bind(e),
184
+ tdr: e.tdr.bind(e),
185
+ has: e.has.bind(e),
186
+ // Route management
187
+ setRoute: e.setRoute.bind(e),
188
+ getRoute: e.getRoute.bind(e),
189
+ getLocale: () => e.getLocale(),
190
+ // Translation management
191
+ addTranslations: e.addTranslations.bind(e),
192
+ addRouteTranslations: e.addRouteTranslations.bind(e),
193
+ clearCache: e.clearCache.bind(e)
194
+ };
195
+ }
196
+ const je = (n) => {
197
+ const e = D(), [t, o] = V(n, ["keypath", "params", "tag", "plural", "defaultValue", "html", "hideIfEmpty", "customPluralRule", "number", "date", "relativeDate"]), r = S(() => {
198
+ const f = e.localeAccessor(), l = e.routeAccessor();
199
+ if (t.number !== void 0) {
200
+ const s = Number(t.number), c = e.tn(s), p = e.t(t.keypath, {
201
+ number: c,
202
+ ...t.params || {}
203
+ }, void 0, l);
204
+ return typeof p == "string" ? p : String(p);
205
+ }
206
+ if (t.date !== void 0) {
207
+ const s = e.td(t.date), c = e.t(t.keypath, {
208
+ date: s,
209
+ ...t.params || {}
210
+ }, void 0, l);
211
+ return typeof c == "string" ? c : String(c);
212
+ }
213
+ if (t.relativeDate !== void 0) {
214
+ const s = e.tdr(t.relativeDate), c = e.t(t.keypath, {
215
+ relativeDate: s,
216
+ ...t.params || {}
217
+ }, void 0, l);
218
+ return typeof c == "string" ? c : String(c);
219
+ }
220
+ if (t.plural !== void 0) {
221
+ const s = Number.parseInt(t.plural.toString());
222
+ return t.customPluralRule ? t.customPluralRule(t.keypath, s, t.params || {}, f, (p, i, g) => e.t(p, i, g, l)) || "" : e.tc(t.keypath, {
223
+ count: s,
224
+ ...t.params || {}
225
+ }, t.defaultValue);
226
+ }
227
+ const a = (e.t(t.keypath, t.params, t.defaultValue, l) ?? "").toString();
228
+ return t.hideIfEmpty && !a.trim() ? t.defaultValue || "" : a;
229
+ });
230
+ if (t.html)
231
+ return (
232
+ // @ts-expect-error - Dynamic component type conflict with Vue JSX
233
+ C(W, P({
234
+ get component() {
235
+ return t.tag || "span";
236
+ }
237
+ }, o, {
238
+ get innerHTML() {
239
+ return r();
240
+ }
241
+ }))
242
+ );
243
+ const d = r();
244
+ return t.hideIfEmpty && !d.trim() ? t.defaultValue ? C(W, P({
245
+ get component() {
246
+ return t.tag || "span";
247
+ }
248
+ }, o, {
249
+ get children() {
250
+ return t.defaultValue;
251
+ }
252
+ })) : null : (
253
+ // @ts-expect-error - Dynamic component type conflict with Vue JSX
254
+ C(W, P({
255
+ get component() {
256
+ return t.tag || "span";
257
+ }
258
+ }, o, {
259
+ children: d
260
+ }))
261
+ );
262
+ };
263
+ var Ce = /* @__PURE__ */ R('<a target=_blank rel="noopener noreferrer">'), Pe = /* @__PURE__ */ R("<a>");
264
+ const Ve = (n) => {
265
+ const e = F(), t = D(), [o, r] = V(n, ["to", "localeRoute", "activeStyle", "style", "children"]), f = e?.getCurrentPathAccessor, l = S(() => {
266
+ const i = t.localeAccessor();
267
+ let g;
268
+ if (o.localeRoute) {
269
+ const y = o.localeRoute(o.to, i);
270
+ g = typeof y == "string" ? y : y?.path || "/";
271
+ } else if (e?.resolvePath) {
272
+ const y = e.resolvePath(o.to, i);
273
+ g = typeof y == "string" ? y : y?.path || "/";
274
+ } else typeof o.to == "string" ? g = o.to : g = o.to?.path || "/";
275
+ return g;
276
+ }), a = S(() => typeof o.to == "string" ? /^(?:https?:\/\/|\/\/|[a-zA-Z0-9-]+\.[a-zA-Z]{2,})|tel:|mailto:/.test(o.to) : !1), s = S(() => {
277
+ if (a())
278
+ return !1;
279
+ const i = f ? f() : e ? e.getCurrentPath() : typeof window < "u" ? window.location.pathname : "/", g = l(), y = i === "/" ? "/" : i.replace(/\/$/, ""), B = g === "/" ? "/" : g.replace(/\/$/, "");
280
+ return y === B;
281
+ }), c = S(() => {
282
+ const i = o.style || {}, y = s() ? o.activeStyle || {} : {};
283
+ return {
284
+ ...typeof i == "object" ? i : {},
285
+ ...typeof y == "object" ? y : {}
286
+ };
287
+ }), p = e?.linkComponent;
288
+ return a() ? (
289
+ // @ts-expect-error - Type conflict with Vue JSX
290
+ (() => {
291
+ var i = Ce();
292
+ return T(i, P({
293
+ get href() {
294
+ return v(() => typeof o.to == "string")() ? o.to : "";
295
+ },
296
+ get style() {
297
+ return c();
298
+ }
299
+ }, r), !1, !0), x(i, () => o.children), i;
300
+ })()
301
+ ) : p ? (
302
+ // @ts-expect-error - Type conflict with router component types
303
+ C(p, P({
304
+ get href() {
305
+ return l();
306
+ },
307
+ get style() {
308
+ return c();
309
+ }
310
+ }, r, {
311
+ get children() {
312
+ return o.children;
313
+ }
314
+ }))
315
+ ) : (
316
+ // @ts-expect-error - Type conflict with Vue JSX
317
+ (() => {
318
+ var i = Pe();
319
+ return T(i, P({
320
+ get href() {
321
+ return l();
322
+ },
323
+ get style() {
324
+ return c();
325
+ }
326
+ }, r, {
327
+ onClick: (g) => {
328
+ e && !a() && (g.preventDefault(), e.push({
329
+ path: l()
330
+ }));
331
+ }
332
+ }), !1, !0), x(i, () => o.children), i;
333
+ })()
334
+ );
335
+ };
336
+ var ke = /* @__PURE__ */ R("<div class=i18n-switcher-wrapper><button type=button class=i18n-switcher-button aria-haspopup=true><span></span><span>▼"), xe = /* @__PURE__ */ R("<ul class=i18n-switcher-dropdown>"), Re = /* @__PURE__ */ R("<li><a>");
337
+ const Be = (n) => {
338
+ const e = D(), t = F(), o = ee(), [r, d] = V(n, ["locales", "currentLocale", "getLocaleName", "switchLocale", "localeRoute", "customLabels", "customWrapperStyle", "customButtonStyle", "customDropdownStyle", "customItemStyle", "customLinkStyle", "customActiveLinkStyle", "customDisabledLinkStyle", "customIconStyle"]), [f, l] = I(!1);
339
+ let a;
340
+ const s = S(() => r.locales || o || []), c = S(() => r.currentLocale !== void 0 ? typeof r.currentLocale == "function" ? r.currentLocale() : r.currentLocale : e.localeAccessor()), p = S(() => r.getLocaleName ? r.getLocaleName() || null : s().find((m) => m.code === e.localeAccessor())?.displayName || null), i = (u) => {
341
+ u && (u.stopPropagation(), u.preventDefault()), l(!f());
342
+ }, g = (u) => r.customLabels?.[u.code] || u.displayName || u.code, y = S(() => {
343
+ const u = s().find((m) => m.code === c());
344
+ return u ? g(u) : p() || c();
345
+ }), B = async (u) => {
346
+ if (l(!1), r.switchLocale) {
347
+ r.switchLocale(u);
348
+ return;
349
+ }
350
+ if (e.locale = u, !t)
351
+ return;
352
+ const m = t, k = m.getCurrentPathAccessor ? m.getCurrentPathAccessor() : t.getCurrentPath(), w = r.localeRoute ? (() => {
353
+ const h = r.localeRoute(k, u);
354
+ return typeof h == "string" ? h : h.path || "/";
355
+ })() : t?.resolvePath ? (() => {
356
+ const h = t.resolvePath(k, u);
357
+ return typeof h == "string" ? h : h.path || "/";
358
+ })() : k;
359
+ t.push({
360
+ path: w
361
+ });
362
+ }, te = {
363
+ position: "relative",
364
+ display: "inline-block",
365
+ "vertical-align": "middle"
366
+ }, re = {
367
+ padding: "4px 12px",
368
+ "font-size": "16px",
369
+ cursor: "pointer",
370
+ "background-color": "#fff",
371
+ border: "1px solid #333",
372
+ transition: "background-color 0.3s ease",
373
+ display: "flex",
374
+ "align-items": "center",
375
+ "justify-content": "space-between"
376
+ }, ne = {
377
+ position: "absolute",
378
+ top: "100%",
379
+ left: "0",
380
+ "z-index": 1e3,
381
+ "background-color": "#fff",
382
+ border: "1px solid #333",
383
+ "list-style": "none",
384
+ padding: "0",
385
+ margin: "4px 0 0 0",
386
+ "min-width": "150px",
387
+ "box-shadow": "0 2px 8px rgba(0,0,0,0.15)"
388
+ }, oe = {
389
+ margin: "0",
390
+ padding: "0"
391
+ }, ae = {
392
+ display: "block",
393
+ padding: "8px 12px",
394
+ color: "#333",
395
+ "text-decoration": "none",
396
+ transition: "background-color 0.3s ease",
397
+ cursor: "pointer"
398
+ }, se = {
399
+ "font-weight": "bold",
400
+ color: "#007bff"
401
+ }, ce = {
402
+ "margin-left": "8px",
403
+ display: "inline-block",
404
+ transition: "transform 0.3s ease"
405
+ }, le = {
406
+ transform: "rotate(180deg)"
407
+ }, Z = (u) => {
408
+ if (!f()) return;
409
+ const m = u.target;
410
+ if (!m || !a) return;
411
+ const k = a.contains(m), w = m.closest(".i18n-switcher-button") !== null;
412
+ !k && !w && l(!1);
413
+ };
414
+ return de(() => {
415
+ document.addEventListener("click", Z);
416
+ }), he(() => {
417
+ document.removeEventListener("click", Z);
418
+ }), (() => {
419
+ var u = ke(), m = u.firstChild, k = m.firstChild, w = k.nextSibling;
420
+ return ye((h) => {
421
+ a = h;
422
+ }, u), T(u, P({
423
+ get style() {
424
+ return {
425
+ ...te,
426
+ ...r.customWrapperStyle
427
+ };
428
+ }
429
+ }, d), !1, !0), m.$$click = (h) => {
430
+ h.preventDefault(), h.stopPropagation(), i(h);
431
+ }, x(k, y), x(u, (() => {
432
+ var h = v(() => !!f());
433
+ return () => h() && (() => {
434
+ var _ = xe();
435
+ return x(_, () => s().map((L) => {
436
+ const N = L.code === c(), q = t, M = q?.getCurrentPathAccessor ? q.getCurrentPathAccessor() : t?.getCurrentPath() || (typeof window < "u" ? window.location.pathname : "/"), z = r.localeRoute ? r.localeRoute(M, L.code) : t?.resolvePath ? t.resolvePath(M, L.code) : M, G = typeof z == "string" ? z : z?.path || "#";
437
+ return (() => {
438
+ var O = Re(), $ = O.firstChild;
439
+ return $.$$click = (b) => {
440
+ b.preventDefault(), b.stopPropagation(), B(L.code);
441
+ }, K($, "href", typeof G == "string" ? G : "#"), x($, () => g(L)), H((b) => {
442
+ var ie = {
443
+ ...oe,
444
+ ...r.customItemStyle
445
+ }, J = `switcher-locale-${L.code}`, ue = {
446
+ ...ae,
447
+ ...N ? se : {},
448
+ ...r.customLinkStyle,
449
+ ...N ? r.customActiveLinkStyle : {}
450
+ };
451
+ return b.e = A(O, ie, b.e), J !== b.t && ve($, b.t = J), b.a = A($, ue, b.a), b;
452
+ }, {
453
+ e: void 0,
454
+ t: void 0,
455
+ a: void 0
456
+ }), O;
457
+ })();
458
+ })), H((L) => A(_, {
459
+ ...ne,
460
+ ...r.customDropdownStyle
461
+ }, L)), _;
462
+ })();
463
+ })(), null), H((h) => {
464
+ var _ = {
465
+ ...re,
466
+ ...r.customButtonStyle
467
+ }, L = f(), N = {
468
+ ...ce,
469
+ ...f() ? le : {},
470
+ ...r.customIconStyle
471
+ };
472
+ return h.e = A(m, _, h.e), L !== h.t && K(m, "aria-expanded", h.t = L), h.a = A(w, N, h.a), h;
473
+ }, {
474
+ e: void 0,
475
+ t: void 0,
476
+ a: void 0
477
+ }), u;
478
+ })();
479
+ };
480
+ me(["click"]);
481
+ var we = /* @__PURE__ */ R("<div>");
482
+ const Me = (n) => {
483
+ const e = D(), [t, o] = V(n, ["prefix", "groupClass"]), r = (d, f) => {
484
+ const l = e.t(`${t.prefix}.${d}`, f, void 0, e.getRoute());
485
+ return typeof l == "string" ? l : String(l);
486
+ };
487
+ return (
488
+ // @ts-expect-error - Type conflict with Vue JSX in monorepo
489
+ (() => {
490
+ var d = we();
491
+ return T(d, P({
492
+ get class() {
493
+ return ["i18n-group", t.groupClass].filter(Boolean).join(" ");
494
+ }
495
+ }, o), !1, !0), x(d, (() => {
496
+ var f = v(() => typeof n.children == "function");
497
+ return () => f() ? n.children({
498
+ prefix: t.prefix,
499
+ t: r
500
+ }) : n.children;
501
+ })()), d;
502
+ })()
503
+ );
504
+ };
505
+ function ze(n, e, t, o) {
506
+ const r = n.map((a) => a.code), [d, f] = I(o.pathname);
507
+ fe(() => {
508
+ f(o.pathname);
509
+ });
510
+ const l = (a, s) => {
511
+ const p = (typeof a == "string" ? a : a.path || "/").split("/").filter(Boolean);
512
+ p.length > 0 && r.includes(p[0]) && p.shift();
513
+ const i = "/" + p.join("/");
514
+ return s === e ? i : `/${s}${i === "/" ? "" : i}`;
515
+ };
516
+ return {
517
+ getCurrentPath: () => d(),
518
+ // Returns current value for compatibility
519
+ getCurrentPathAccessor: d,
520
+ // Returns accessor for reactivity
521
+ push: (a) => {
522
+ t(a.path);
523
+ },
524
+ replace: (a) => {
525
+ t(a.path, {
526
+ replace: !0
527
+ });
528
+ },
529
+ resolvePath: (a, s) => l(a, s),
530
+ getRoute: () => ({
531
+ fullPath: d(),
532
+ query: {}
533
+ }),
534
+ // Use A component from @solidjs/router
535
+ linkComponent: ((a) => {
536
+ const {
537
+ href: s,
538
+ children: c,
539
+ class: p,
540
+ style: i,
541
+ ...g
542
+ } = a;
543
+ return C(Le, P({
544
+ href: s,
545
+ class: p,
546
+ style: i
547
+ }, g, {
548
+ children: c
549
+ }));
550
+ })
551
+ };
552
+ }
553
+ export {
554
+ He as FormatService,
555
+ Q as I18nContext,
556
+ X as I18nDefaultLocaleContext,
557
+ Me as I18nGroup,
558
+ Ve as I18nLink,
559
+ U as I18nLocalesContext,
560
+ Te as I18nProvider,
561
+ Y as I18nRouterContext,
562
+ Be as I18nSwitcher,
563
+ je as I18nT,
564
+ be as SolidI18n,
565
+ Ne as createI18n,
566
+ ze as createSolidRouterAdapter,
567
+ Fe as defaultPlural,
568
+ Ze as interpolate,
569
+ Ee as useI18n,
570
+ D as useI18nContext,
571
+ Se as useI18nDefaultLocale,
572
+ ee as useI18nLocales,
573
+ F as useI18nRouter
574
+ };
575
+ //# sourceMappingURL=index.mjs.map