@i18n-micro/astro 1.2.0 → 1.2.1

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 CHANGED
@@ -87,18 +87,13 @@ function v() {
87
87
  return j;
88
88
  }
89
89
  function U(n) {
90
- const {
91
- locale: e,
92
- fallbackLocale: s,
93
- translationDir: o,
94
- routingStrategy: i
95
- } = n;
90
+ const { locale: e, fallbackLocale: s, translationDir: o, routingStrategy: i } = n;
96
91
  return j = i || null, {
97
92
  name: "@i18n-micro/astro",
98
93
  hooks: {
99
94
  // 1. Настройка Vite (Виртуальный модуль) происходит здесь
100
95
  "astro:config:setup": (c) => {
101
- const { updateConfig: f } = c, t = "virtual:i18n-micro/config", l = "\0" + t, r = {
96
+ const { updateConfig: f } = c, t = "virtual:i18n-micro/config", l = `\0${t}`, r = {
102
97
  defaultLocale: e,
103
98
  fallbackLocale: s || e,
104
99
  locales: n.locales || [],
@@ -157,7 +152,39 @@ function U(n) {
157
152
  function E(n) {
158
153
  return new S(n);
159
154
  }
160
- function J(n) {
155
+ function M(n) {
156
+ const { translationDir: e, rootDir: s = process.cwd(), disablePageLocales: o = !1 } = n, i = O(s, e);
157
+ if (!R(i))
158
+ return console.warn(`[i18n] Translation directory not found: ${i}`), { general: {}, routes: {} };
159
+ const c = {}, f = {}, t = (l, r = "") => {
160
+ if (!R(l)) return;
161
+ const a = _(l);
162
+ for (const u of a) {
163
+ const h = q(l, u);
164
+ if (C(h).isDirectory())
165
+ u === "pages" && !o ? t(h, "") : r || o ? t(h, r) : t(h, u);
166
+ else if (u.endsWith(".json")) {
167
+ const m = u.replace(".json", "");
168
+ try {
169
+ const g = N(h, "utf-8"), p = JSON.parse(g);
170
+ r && !o ? (f[r] || (f[r] = {}), f[r][m] = p) : c[m] = p;
171
+ } catch (g) {
172
+ console.error(`[i18n] Failed to load translation file: ${h}`, g);
173
+ }
174
+ }
175
+ }
176
+ };
177
+ return t(i), { general: c, routes: f };
178
+ }
179
+ function J(n, e) {
180
+ const { general: s, routes: o } = M(e);
181
+ for (const [i, c] of Object.entries(s))
182
+ n.addTranslations(i, c, !1);
183
+ for (const [i, c] of Object.entries(o))
184
+ for (const [f, t] of Object.entries(c))
185
+ n.addRouteTranslations(f, i, t, !1);
186
+ }
187
+ function V(n) {
161
188
  const {
162
189
  i18n: e,
163
190
  // Это глобальный синглтон с кэшем
@@ -190,7 +217,7 @@ function J(n) {
190
217
  return L.setRoute(b), r.locals.i18n = L, r.locals.locale = P, r.locals.defaultLocale = s, r.locals.locales = i || o.map((y) => ({ code: y })), r.locals.currentUrl = u, r.locals.routingStrategy = d, a();
191
218
  };
192
219
  }
193
- function M(n) {
220
+ function W(n) {
194
221
  const e = [], s = n.split(",");
195
222
  for (const o of s) {
196
223
  const [i, c = "1.0"] = o.trim().split(";q=");
@@ -201,7 +228,7 @@ function M(n) {
201
228
  }
202
229
  return e;
203
230
  }
204
- function V(n, e, s, o, i, c = "i18n-locale") {
231
+ function K(n, e, s, o, i, c = "i18n-locale") {
205
232
  const f = v();
206
233
  let t = o;
207
234
  if (f?.getLocaleFromPath)
@@ -218,7 +245,7 @@ function V(n, e, s, o, i, c = "i18n-locale") {
218
245
  try {
219
246
  const l = s.get("accept-language");
220
247
  if (l) {
221
- const r = M(l);
248
+ const r = W(l);
222
249
  for (const a of r)
223
250
  if (i.includes(a)) {
224
251
  t = a;
@@ -229,6 +256,89 @@ function V(n, e, s, o, i, c = "i18n-locale") {
229
256
  }
230
257
  return t;
231
258
  }
259
+ function Q(n, e, s) {
260
+ const o = n.map((a) => a.code), i = (a, u = []) => {
261
+ const h = a.replace(/^\//, "").replace(/\/$/, "");
262
+ if (!h)
263
+ return "index";
264
+ const d = h.split("/").filter(Boolean), m = d[0];
265
+ return m && u.includes(m) && d.shift(), d.length === 0 ? "index" : d.join("-");
266
+ }, c = (a, u = "en", h = []) => {
267
+ const m = a.split("/").filter(Boolean)[0];
268
+ return m && h.includes(m) ? m : u;
269
+ }, f = (a, u, h = [], d) => {
270
+ const m = a.split("/").filter(Boolean), g = m[0];
271
+ return g && h.includes(g) && m.shift(), (u !== d || d === void 0) && m.unshift(u), `/${m.join("/")}`;
272
+ }, t = (a, u, h = [], d) => {
273
+ const g = (a.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), p = g[0];
274
+ return p && h.includes(p) && g.shift(), (u !== d || d === void 0) && g.unshift(u), `/${g.join("/")}`;
275
+ };
276
+ return {
277
+ getCurrentPath: () => s ? s().pathname : typeof window < "u" ? window.location.pathname : "/",
278
+ getRouteName: i,
279
+ getLocaleFromPath: c,
280
+ switchLocalePath: f,
281
+ localizePath: t,
282
+ removeLocaleFromPath: (a, u = []) => {
283
+ const h = a.split("/").filter(Boolean), d = h[0];
284
+ return d && u.includes(d) && h.shift(), `/${h.join("/")}`;
285
+ },
286
+ resolvePath: (a, u) => {
287
+ const h = typeof a == "string" ? a : a.path || "/";
288
+ return t(h, u, o, e);
289
+ },
290
+ getRoute: () => {
291
+ if (s) {
292
+ const a = s();
293
+ return {
294
+ fullPath: a.pathname + a.search,
295
+ query: Object.fromEntries(a.searchParams)
296
+ };
297
+ }
298
+ if (typeof window < "u") {
299
+ const a = new URL(window.location.href);
300
+ return {
301
+ fullPath: a.pathname + a.search,
302
+ query: Object.fromEntries(a.searchParams)
303
+ };
304
+ }
305
+ return {
306
+ fullPath: "/",
307
+ query: {}
308
+ };
309
+ },
310
+ // Optional: client-side navigation for islands
311
+ push: (a) => {
312
+ typeof window < "u" && (window.location.href = a.path);
313
+ },
314
+ replace: (a) => {
315
+ typeof window < "u" && window.location.replace(a.path);
316
+ }
317
+ };
318
+ }
319
+ function X(n, e = []) {
320
+ const s = n.replace(/^\//, "").replace(/\/$/, "");
321
+ if (!s)
322
+ return "index";
323
+ const o = s.split("/").filter(Boolean), i = o[0];
324
+ return i && e.includes(i) && o.shift(), o.length === 0 ? "index" : o.join("-");
325
+ }
326
+ function Y(n, e = "en", s = []) {
327
+ const i = n.split("/").filter(Boolean)[0];
328
+ return i && s.includes(i) ? i : e;
329
+ }
330
+ function Z(n, e, s = [], o) {
331
+ const i = n.split("/").filter(Boolean), c = i[0];
332
+ return c && s.includes(c) && i.shift(), (e !== o || o === void 0) && i.unshift(e), `/${i.join("/")}`;
333
+ }
334
+ function x(n, e, s = [], o) {
335
+ const c = (n.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), f = c[0];
336
+ return f && s.includes(f) && c.shift(), (e !== o || o === void 0) && c.unshift(e), `/${c.join("/")}`;
337
+ }
338
+ function ee(n, e = []) {
339
+ const s = n.split("/").filter(Boolean), o = s[0];
340
+ return o && e.includes(o) && s.shift(), `/${s.join("/")}`;
341
+ }
232
342
  function k(n) {
233
343
  const e = n.locals.i18n;
234
344
  if (!e)
@@ -247,7 +357,7 @@ function $(n) {
247
357
  function D(n) {
248
358
  return n.locals.routingStrategy || null;
249
359
  }
250
- function K(n) {
360
+ function te(n) {
251
361
  const e = k(n), s = T(n), o = w(n), i = $(n), c = i.map((t) => t.code), f = D(n);
252
362
  return {
253
363
  // Current locale
@@ -318,12 +428,8 @@ function K(n) {
318
428
  }
319
429
  };
320
430
  }
321
- function Q(n, e = {}) {
322
- const {
323
- baseUrl: s = "/",
324
- addDirAttribute: o = !0,
325
- addSeoAttributes: i = !0
326
- } = e, c = T(n), f = w(n), t = $(n), l = t.find((g) => g.code === c);
431
+ function ne(n, e = {}) {
432
+ const { baseUrl: s = "/", addDirAttribute: o = !0, addSeoAttributes: i = !0 } = e, c = T(n), f = w(n), t = $(n), l = t.find((g) => g.code === c);
327
433
  if (!l)
328
434
  return { htmlAttrs: {}, link: [], meta: [] };
329
435
  const r = l.iso || c, a = l.dir || "auto", u = {
@@ -376,7 +482,7 @@ function Q(n, e = {}) {
376
482
  });
377
483
  return u;
378
484
  }
379
- function W(n, e, s) {
485
+ function A(n, e, s) {
380
486
  const o = e.split(".");
381
487
  let i = n;
382
488
  for (let f = 0; f < o.length - 1; f++) {
@@ -386,13 +492,13 @@ function W(n, e, s) {
386
492
  const c = o[o.length - 1];
387
493
  c !== void 0 && (i[c] = s);
388
494
  }
389
- function X(n, e) {
495
+ function oe(n, e) {
390
496
  const s = k(n), o = T(n), i = w(n), c = s.getRoute(), f = {};
391
497
  if (e && e.length > 0) {
392
498
  const t = {};
393
499
  for (const l of e) {
394
500
  const r = s.t(l, void 0, void 0, c);
395
- r != null && r !== l && W(t, l, r);
501
+ r != null && r !== l && A(t, l, r);
396
502
  }
397
503
  Object.keys(t).length > 0 && (f[c] = t);
398
504
  } else {
@@ -406,143 +512,28 @@ function X(n, e) {
406
512
  translations: f
407
513
  };
408
514
  }
409
- function Y(n, e, s) {
410
- const o = n.map((a) => a.code), i = (a, u = []) => {
411
- const h = a.replace(/^\//, "").replace(/\/$/, "");
412
- if (!h)
413
- return "index";
414
- const d = h.split("/").filter(Boolean), m = d[0];
415
- return m && u.includes(m) && d.shift(), d.length === 0 ? "index" : d.join("-");
416
- }, c = (a, u = "en", h = []) => {
417
- const m = a.split("/").filter(Boolean)[0];
418
- return m && h.includes(m) ? m : u;
419
- }, f = (a, u, h = [], d) => {
420
- const m = a.split("/").filter(Boolean), g = m[0];
421
- return g && h.includes(g) && m.shift(), (u !== d || d === void 0) && m.unshift(u), `/${m.join("/")}`;
422
- }, t = (a, u, h = [], d) => {
423
- const g = (a.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), p = g[0];
424
- return p && h.includes(p) && g.shift(), (u !== d || d === void 0) && g.unshift(u), `/${g.join("/")}`;
425
- };
426
- return {
427
- getCurrentPath: () => s ? s().pathname : typeof window < "u" ? window.location.pathname : "/",
428
- getRouteName: i,
429
- getLocaleFromPath: c,
430
- switchLocalePath: f,
431
- localizePath: t,
432
- removeLocaleFromPath: (a, u = []) => {
433
- const h = a.split("/").filter(Boolean), d = h[0];
434
- return d && u.includes(d) && h.shift(), `/${h.join("/")}`;
435
- },
436
- resolvePath: (a, u) => {
437
- const h = typeof a == "string" ? a : a.path || "/";
438
- return t(h, u, o, e);
439
- },
440
- getRoute: () => {
441
- if (s) {
442
- const a = s();
443
- return {
444
- fullPath: a.pathname + a.search,
445
- query: Object.fromEntries(a.searchParams)
446
- };
447
- }
448
- if (typeof window < "u") {
449
- const a = new URL(window.location.href);
450
- return {
451
- fullPath: a.pathname + a.search,
452
- query: Object.fromEntries(a.searchParams)
453
- };
454
- }
455
- return {
456
- fullPath: "/",
457
- query: {}
458
- };
459
- },
460
- // Optional: client-side navigation for islands
461
- push: (a) => {
462
- typeof window < "u" && (window.location.href = a.path);
463
- },
464
- replace: (a) => {
465
- typeof window < "u" && window.location.replace(a.path);
466
- }
467
- };
468
- }
469
- function Z(n, e = []) {
470
- const s = n.replace(/^\//, "").replace(/\/$/, "");
471
- if (!s)
472
- return "index";
473
- const o = s.split("/").filter(Boolean), i = o[0];
474
- return i && e.includes(i) && o.shift(), o.length === 0 ? "index" : o.join("-");
475
- }
476
- function x(n, e = "en", s = []) {
477
- const i = n.split("/").filter(Boolean)[0];
478
- return i && s.includes(i) ? i : e;
479
- }
480
- function ee(n, e, s = [], o) {
481
- const i = n.split("/").filter(Boolean), c = i[0];
482
- return c && s.includes(c) && i.shift(), (e !== o || o === void 0) && i.unshift(e), `/${i.join("/")}`;
483
- }
484
- function te(n, e, s = [], o) {
485
- const c = (n.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), f = c[0];
486
- return f && s.includes(f) && c.shift(), (e !== o || o === void 0) && c.unshift(e), `/${c.join("/")}`;
487
- }
488
- function ne(n, e = []) {
489
- const s = n.split("/").filter(Boolean), o = s[0];
490
- return o && e.includes(o) && s.shift(), `/${s.join("/")}`;
491
- }
492
- function A(n) {
493
- const { translationDir: e, rootDir: s = process.cwd(), disablePageLocales: o = !1 } = n, i = O(s, e);
494
- if (!R(i))
495
- return console.warn(`[i18n] Translation directory not found: ${i}`), { general: {}, routes: {} };
496
- const c = {}, f = {}, t = (l, r = "") => {
497
- if (!R(l)) return;
498
- const a = _(l);
499
- for (const u of a) {
500
- const h = q(l, u);
501
- if (C(h).isDirectory())
502
- u === "pages" && !o ? t(h, "") : r || o ? t(h, r) : t(h, u);
503
- else if (u.endsWith(".json")) {
504
- const m = u.replace(".json", "");
505
- try {
506
- const g = N(h, "utf-8"), p = JSON.parse(g);
507
- r && !o ? (f[r] || (f[r] = {}), f[r][m] = p) : c[m] = p;
508
- } catch (g) {
509
- console.error(`[i18n] Failed to load translation file: ${h}`, g);
510
- }
511
- }
512
- }
513
- };
514
- return t(i), { general: c, routes: f };
515
- }
516
- function oe(n, e) {
517
- const { general: s, routes: o } = A(e);
518
- for (const [i, c] of Object.entries(s))
519
- n.addTranslations(i, c, !1);
520
- for (const [i, c] of Object.entries(o))
521
- for (const [f, t] of Object.entries(c))
522
- n.addRouteTranslations(f, i, t, !1);
523
- }
524
515
  export {
525
516
  S as AstroI18n,
526
517
  le as FormatService,
527
- Y as createAstroRouterAdapter,
518
+ Q as createAstroRouterAdapter,
528
519
  E as createI18n,
529
- J as createI18nMiddleware,
520
+ V as createI18nMiddleware,
530
521
  re as defaultPlural,
531
- V as detectLocale,
522
+ K as detectLocale,
532
523
  w as getDefaultLocale,
533
524
  k as getI18n,
534
- X as getI18nProps,
525
+ oe as getI18nProps,
535
526
  T as getLocale,
536
- x as getLocaleFromPath,
527
+ Y as getLocaleFromPath,
537
528
  $ as getLocales,
538
- Z as getRouteName,
529
+ X as getRouteName,
539
530
  U as i18nIntegration,
540
531
  ie as interpolate,
541
- A as loadTranslationsFromDir,
542
- oe as loadTranslationsIntoI18n,
543
- te as localizePath,
544
- ne as removeLocaleFromPath,
545
- ee as switchLocalePath,
546
- K as useI18n,
547
- Q as useLocaleHead
532
+ M as loadTranslationsFromDir,
533
+ J as loadTranslationsIntoI18n,
534
+ x as localizePath,
535
+ ee as removeLocaleFromPath,
536
+ Z as switchLocalePath,
537
+ te as useI18n,
538
+ ne as useLocaleHead
548
539
  };
@@ -1,6 +1,6 @@
1
+ import { Locale, ModuleOptions, PluralFunc } from '@i18n-micro/types';
1
2
  import { AstroIntegration } from 'astro';
2
3
  import { AstroI18n, AstroI18nOptions } from './composer';
3
- import { Locale, ModuleOptions, PluralFunc } from '@i18n-micro/types';
4
4
  import { I18nRoutingStrategy } from './router/types';
5
5
  export interface I18nIntegrationOptions extends Omit<ModuleOptions, 'plural'> {
6
6
  locale: string;
@@ -1,6 +1,6 @@
1
- import { AstroI18n } from './composer';
2
- import { MiddlewareHandler } from 'astro';
3
1
  import { Locale } from '@i18n-micro/types';
2
+ import { MiddlewareHandler } from 'astro';
3
+ import { AstroI18n } from './composer';
4
4
  import { I18nRoutingStrategy } from './router/types';
5
5
  export interface I18nMiddlewareOptions {
6
6
  i18n: AstroI18n;
@@ -1,5 +1,5 @@
1
- import { I18nRoutingStrategy } from './types';
2
1
  import { Locale } from '@i18n-micro/types';
2
+ import { I18nRoutingStrategy } from './types';
3
3
  /**
4
4
  * Factory for Astro router adapter
5
5
  * Implements routing utilities for Astro file-based routing
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { AstroI18n } from './composer';
2
- import { Params, Locale, CleanTranslation, TranslationKey, Translations } from '@i18n-micro/types';
1
+ import { CleanTranslation, Locale, Params, TranslationKey, Translations } from '@i18n-micro/types';
3
2
  import { AstroGlobal } from 'astro';
3
+ import { AstroI18n } from './composer';
4
4
  /**
5
5
  * Get i18n instance from Astro context
6
6
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-micro/astro",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -51,9 +51,9 @@
51
51
  "access": "public"
52
52
  },
53
53
  "dependencies": {
54
- "@i18n-micro/core": "1.1.0",
55
- "@i18n-micro/node": "1.1.0",
56
- "@i18n-micro/types": "1.1.0"
54
+ "@i18n-micro/core": "1.1.2",
55
+ "@i18n-micro/types": "1.1.1",
56
+ "@i18n-micro/node": "1.1.1"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "astro": "^5.16.5",
@@ -1,5 +1,5 @@
1
- import type { Translations, Params } from '@i18n-micro/types'
2
1
  import { interpolate } from '@i18n-micro/core'
2
+ import type { Params, Translations } from '@i18n-micro/types'
3
3
 
4
4
  /**
5
5
  * Состояние i18n для клиентских островов
@@ -23,15 +23,13 @@ function findTranslation<T = unknown>(translations: Translations | null, key: st
23
23
  // Прямой доступ к ключу
24
24
  if (translations[key]) {
25
25
  value = translations[key]
26
- }
27
- else {
26
+ } else {
28
27
  // Поиск по вложенным ключам (например, "nested.message")
29
28
  const parts = key.toString().split('.')
30
29
  for (const part of parts) {
31
30
  if (value && typeof value === 'object' && value !== null && part in value) {
32
31
  value = (value as Translations)[part]
33
- }
34
- else {
32
+ } else {
35
33
  return null
36
34
  }
37
35
  }
@@ -76,7 +74,7 @@ export function translate(
76
74
 
77
75
  // 3. Если не найдено, используем defaultValue или key
78
76
  if (!value) {
79
- value = defaultValue === undefined ? key : (defaultValue || key)
77
+ value = defaultValue === undefined ? key : defaultValue || key
80
78
  }
81
79
 
82
80
  // 4. Интерполяция параметров (только для строк)
@@ -92,11 +90,7 @@ export function translate(
92
90
  /**
93
91
  * Проверяет наличие перевода в состоянии
94
92
  */
95
- export function hasTranslation(
96
- state: I18nState,
97
- key: string,
98
- routeName?: string,
99
- ): boolean {
93
+ export function hasTranslation(state: I18nState, key: string, routeName?: string): boolean {
100
94
  const route = routeName || state.currentRoute
101
95
  const routeTranslations = state.translations[route]
102
96
  const generalTranslations = state.translations.general
@@ -1,15 +1,13 @@
1
1
  // Core utilities (чистые функции)
2
- export { translate, hasTranslation } from './core'
3
- export type { I18nState } from './core'
4
-
5
- // Vue adapter
6
- export { provideI18n, useAstroI18n as useAstroI18nVue } from './vue'
7
-
8
- // React adapter
9
- export { I18nProvider, useAstroI18n as useAstroI18nReact } from './react'
10
2
 
3
+ export type { I18nState } from './core'
4
+ export { hasTranslation, translate } from './core'
11
5
  // Preact adapter
12
6
  export { I18nProvider as I18nProviderPreact, useAstroI18n as useAstroI18nPreact } from './preact'
13
7
 
8
+ // React adapter
9
+ export { I18nProvider, useAstroI18n as useAstroI18nReact } from './react'
14
10
  // Svelte adapter
15
11
  export { createI18nStore, useAstroI18n as useAstroI18nSvelte } from './svelte'
12
+ // Vue adapter
13
+ export { provideI18n, useAstroI18n as useAstroI18nVue } from './vue'
@@ -1,11 +1,12 @@
1
1
  // Preact может использовать React Context API, так как Preact совместим с React
2
+
3
+ import { defaultPlural, FormatService } from '@i18n-micro/core'
4
+ import type { CleanTranslation, Params, TranslationKey } from '@i18n-micro/types'
2
5
  import type { ComponentChildren } from 'preact'
3
6
  import { createContext, createElement } from 'preact'
4
- import { useContext, useState, useMemo } from 'preact/hooks'
7
+ import { useContext, useMemo, useState } from 'preact/hooks'
5
8
  import type { I18nClientProps } from '../utils'
6
- import { translate, hasTranslation, type I18nState } from './core'
7
- import { defaultPlural, FormatService } from '@i18n-micro/core'
8
- import type { Params, TranslationKey, CleanTranslation } from '@i18n-micro/types'
9
+ import { hasTranslation, type I18nState, translate } from './core'
9
10
 
10
11
  const formatter = new FormatService()
11
12
 
@@ -14,7 +15,7 @@ const I18nContext = createContext<I18nState | null>(null)
14
15
  /**
15
16
  * Провайдер для i18n в Preact островах
16
17
  */
17
- export const I18nProvider = ({ children, value }: { children: ComponentChildren, value: I18nClientProps }) => {
18
+ export const I18nProvider = ({ children, value }: { children: ComponentChildren; value: I18nClientProps }) => {
18
19
  const [state] = useState<I18nState>(() => ({
19
20
  locale: value.locale,
20
21
  fallbackLocale: value.fallbackLocale,
@@ -34,62 +35,74 @@ export function useAstroI18n() {
34
35
  throw new Error('useAstroI18n must be used within an I18nProvider')
35
36
  }
36
37
 
37
- const t = useMemo(() => (
38
- key: TranslationKey,
39
- params?: Params,
40
- defaultValue?: string | null,
41
- routeName?: string,
42
- ): CleanTranslation => {
43
- return translate(state, key as string, params, defaultValue, routeName)
44
- }, [state])
45
-
46
- const ts = useMemo(() => (
47
- key: TranslationKey,
48
- params?: Params,
49
- defaultValue?: string,
50
- routeName?: string,
51
- ): string => {
52
- const value = t(key, params, defaultValue, routeName)
53
- return value?.toString() ?? defaultValue ?? (key as string)
54
- }, [t])
55
-
56
- const tc = useMemo(() => (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
57
- const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
58
-
59
- if (countValue === undefined) {
60
- return defaultValue ?? (key as string)
61
- }
62
-
63
- const getter = (k: TranslationKey, p?: Params, dv?: string) => {
64
- return t(k, p, dv)
65
- }
66
-
67
- const result = defaultPlural(
68
- key,
69
- Number.parseInt(countValue.toString(), 10),
70
- params,
71
- state.locale,
72
- getter,
73
- )
74
-
75
- return result ?? defaultValue ?? (key as string)
76
- }, [t, state])
77
-
78
- const tn = useMemo(() => (value: number, options?: Intl.NumberFormatOptions): string => {
79
- return formatter.formatNumber(value, state.locale, options)
80
- }, [state.locale])
81
-
82
- const td = useMemo(() => (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
83
- return formatter.formatDate(value, state.locale, options)
84
- }, [state.locale])
85
-
86
- const tdr = useMemo(() => (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
87
- return formatter.formatRelativeTime(value, state.locale, options)
88
- }, [state.locale])
89
-
90
- const has = useMemo(() => (key: TranslationKey, routeName?: string): boolean => {
91
- return hasTranslation(state, key as string, routeName)
92
- }, [state])
38
+ const t = useMemo(
39
+ () =>
40
+ (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string): CleanTranslation => {
41
+ return translate(state, key as string, params, defaultValue, routeName)
42
+ },
43
+ [state],
44
+ )
45
+
46
+ const ts = useMemo(
47
+ () =>
48
+ (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string => {
49
+ const value = t(key, params, defaultValue, routeName)
50
+ return value?.toString() ?? defaultValue ?? (key as string)
51
+ },
52
+ [t],
53
+ )
54
+
55
+ const tc = useMemo(
56
+ () =>
57
+ (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
58
+ const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
59
+
60
+ if (countValue === undefined) {
61
+ return defaultValue ?? (key as string)
62
+ }
63
+
64
+ const getter = (k: TranslationKey, p?: Params, dv?: string) => {
65
+ return t(k, p, dv)
66
+ }
67
+
68
+ const result = defaultPlural(key, Number.parseInt(countValue.toString(), 10), params, state.locale, getter)
69
+
70
+ return result ?? defaultValue ?? (key as string)
71
+ },
72
+ [t, state],
73
+ )
74
+
75
+ const tn = useMemo(
76
+ () =>
77
+ (value: number, options?: Intl.NumberFormatOptions): string => {
78
+ return formatter.formatNumber(value, state.locale, options)
79
+ },
80
+ [state.locale],
81
+ )
82
+
83
+ const td = useMemo(
84
+ () =>
85
+ (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
86
+ return formatter.formatDate(value, state.locale, options)
87
+ },
88
+ [state.locale],
89
+ )
90
+
91
+ const tdr = useMemo(
92
+ () =>
93
+ (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
94
+ return formatter.formatRelativeTime(value, state.locale, options)
95
+ },
96
+ [state.locale],
97
+ )
98
+
99
+ const has = useMemo(
100
+ () =>
101
+ (key: TranslationKey, routeName?: string): boolean => {
102
+ return hasTranslation(state, key as string, routeName)
103
+ },
104
+ [state],
105
+ )
93
106
 
94
107
  return {
95
108
  // Translation methods