@intl-party/react 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.js ADDED
@@ -0,0 +1,1026 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AccessibleLocaleSelector: () => AccessibleLocaleSelector,
34
+ CompactLocaleSelector: () => CompactLocaleSelector,
35
+ ConditionalTrans: () => ConditionalTrans,
36
+ FlagLocaleSelector: () => FlagLocaleSelector,
37
+ I18nErrorBoundary: () => I18nErrorBoundary,
38
+ I18nProvider: () => I18nProvider,
39
+ LocaleSelector: () => LocaleSelector,
40
+ PluralTrans: () => PluralTrans,
41
+ RichTrans: () => RichTrans,
42
+ ScopedI18nProvider: () => ScopedI18nProvider,
43
+ Trans: () => Trans,
44
+ TypedI18nProvider: () => TypedI18nProvider,
45
+ VERSION: () => VERSION,
46
+ createI18nHook: () => createI18nHook,
47
+ createNamespaceHOC: () => createNamespaceHOC,
48
+ useBrowserLocale: () => useBrowserLocale,
49
+ useDirection: () => useDirection,
50
+ useFormatting: () => useFormatting,
51
+ useHasTranslation: () => useHasTranslation,
52
+ useI18nContext: () => useI18nContext,
53
+ useInterpolatedTranslation: () => useInterpolatedTranslation,
54
+ useLocale: () => useLocale,
55
+ useLocaleInfo: () => useLocaleInfo,
56
+ useLocalePreference: () => useLocalePreference,
57
+ useLocaleSwitch: () => useLocaleSwitch,
58
+ useMultipleNamespaces: () => useMultipleNamespaces,
59
+ useMultipleTranslations: () => useMultipleTranslations,
60
+ useNamespace: () => useNamespace,
61
+ useNamespaceInfo: () => useNamespaceInfo,
62
+ useNamespacePreloading: () => useNamespacePreloading,
63
+ useNamespaceSwitch: () => useNamespaceSwitch,
64
+ useOptionalTranslation: () => useOptionalTranslation,
65
+ usePluralization: () => usePluralization,
66
+ useScopedTranslations: () => useScopedTranslations,
67
+ useT: () => useT,
68
+ useTranslationValue: () => useTranslationValue,
69
+ useTranslationWithFallback: () => useTranslationWithFallback,
70
+ useTranslations: () => useTranslations,
71
+ useTypedI18nContext: () => useTypedI18nContext,
72
+ useTypedT: () => useTypedT,
73
+ useTypedTranslations: () => useTypedTranslations,
74
+ withI18n: () => withI18n
75
+ });
76
+ module.exports = __toCommonJS(index_exports);
77
+ var import_react7 = __toESM(require("react"));
78
+
79
+ // src/context/I18nContext.tsx
80
+ var import_react = require("react");
81
+ var import_core = require("@intl-party/core");
82
+ var import_jsx_runtime = require("react/jsx-runtime");
83
+ var I18nContext = (0, import_react.createContext)(null);
84
+ function I18nProvider({
85
+ children,
86
+ config,
87
+ i18n: externalI18n,
88
+ initialLocale,
89
+ initialNamespace,
90
+ loadingComponent,
91
+ fallbackComponent,
92
+ onLocaleChange,
93
+ onNamespaceChange,
94
+ onError
95
+ }) {
96
+ const i18nInstance = (0, import_react.useMemo)(() => {
97
+ if (externalI18n) {
98
+ return externalI18n;
99
+ }
100
+ if (!config) {
101
+ throw new Error(
102
+ "Either config or i18n instance must be provided to I18nProvider"
103
+ );
104
+ }
105
+ const instance = (0, import_core.createI18n)(config);
106
+ if (initialLocale && config.locales.includes(initialLocale)) {
107
+ instance.setLocale(initialLocale);
108
+ }
109
+ if (initialNamespace && config.namespaces.includes(initialNamespace)) {
110
+ instance.setNamespace(initialNamespace);
111
+ }
112
+ return instance;
113
+ }, [config, externalI18n, initialLocale, initialNamespace]);
114
+ const [locale, setLocaleState] = (0, import_react.useState)(i18nInstance.getLocale());
115
+ const [namespace, setNamespaceState] = (0, import_react.useState)(
116
+ i18nInstance.getNamespace()
117
+ );
118
+ const [isLoading, setIsLoading] = (0, import_react.useState)(false);
119
+ const [error, setError] = (0, import_react.useState)(null);
120
+ const handleLocaleChange = (newLocale) => {
121
+ try {
122
+ setIsLoading(true);
123
+ i18nInstance.setLocale(newLocale);
124
+ setLocaleState(newLocale);
125
+ onLocaleChange?.(newLocale);
126
+ } catch (err) {
127
+ const error2 = err instanceof Error ? err : new Error("Failed to change locale");
128
+ setError(error2);
129
+ onError?.(error2);
130
+ } finally {
131
+ setIsLoading(false);
132
+ }
133
+ };
134
+ const handleNamespaceChange = (newNamespace) => {
135
+ try {
136
+ i18nInstance.setNamespace(newNamespace);
137
+ setNamespaceState(newNamespace);
138
+ onNamespaceChange?.(newNamespace);
139
+ } catch (err) {
140
+ const error2 = err instanceof Error ? err : new Error("Failed to change namespace");
141
+ setError(error2);
142
+ onError?.(error2);
143
+ }
144
+ };
145
+ (0, import_react.useEffect)(() => {
146
+ const handleLocaleChangeEvent = ({
147
+ locale: newLocale
148
+ }) => {
149
+ setLocaleState(newLocale);
150
+ onLocaleChange?.(newLocale);
151
+ };
152
+ const handleNamespaceChangeEvent = ({
153
+ namespace: newNamespace
154
+ }) => {
155
+ setNamespaceState(newNamespace);
156
+ onNamespaceChange?.(newNamespace);
157
+ };
158
+ const handleTranslationsPreloading = () => setIsLoading(true);
159
+ const handleTranslationsPreloaded = () => setIsLoading(false);
160
+ i18nInstance.on("localeChange", handleLocaleChangeEvent);
161
+ i18nInstance.on("namespaceChange", handleNamespaceChangeEvent);
162
+ i18nInstance.on("translationsPreloading", handleTranslationsPreloading);
163
+ i18nInstance.on("translationsPreloaded", handleTranslationsPreloaded);
164
+ return () => {
165
+ i18nInstance.off("localeChange", handleLocaleChangeEvent);
166
+ i18nInstance.off("namespaceChange", handleNamespaceChangeEvent);
167
+ i18nInstance.off("translationsPreloading", handleTranslationsPreloading);
168
+ i18nInstance.off("translationsPreloaded", handleTranslationsPreloaded);
169
+ };
170
+ }, [i18nInstance, onLocaleChange, onNamespaceChange]);
171
+ const contextValue = (0, import_react.useMemo)(
172
+ () => ({
173
+ i18n: i18nInstance,
174
+ locale,
175
+ namespace,
176
+ t: i18nInstance.t,
177
+ setLocale: handleLocaleChange,
178
+ setNamespace: handleNamespaceChange,
179
+ isLoading
180
+ }),
181
+ [i18nInstance, locale, namespace, isLoading]
182
+ );
183
+ if (error && fallbackComponent) {
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallbackComponent });
185
+ }
186
+ if (error) {
187
+ throw error;
188
+ }
189
+ if (isLoading && loadingComponent) {
190
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingComponent });
191
+ }
192
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nContext.Provider, { value: contextValue, children });
193
+ }
194
+ function useI18nContext() {
195
+ const context = (0, import_react.useContext)(I18nContext);
196
+ if (!context) {
197
+ throw new Error("useI18nContext must be used within an I18nProvider");
198
+ }
199
+ return context;
200
+ }
201
+ var TypedI18nContext = (0, import_react.createContext)(null);
202
+ function TypedI18nProvider({
203
+ children,
204
+ ...props
205
+ }) {
206
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nProvider, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypedI18nContextWrapper, { children }) });
207
+ }
208
+ function TypedI18nContextWrapper({
209
+ children
210
+ }) {
211
+ const { i18n, locale, namespace, setLocale, setNamespace, isLoading } = useI18nContext();
212
+ const typedContextValue = (0, import_react.useMemo)(
213
+ () => ({
214
+ i18n,
215
+ locale,
216
+ namespace,
217
+ t: i18n.t,
218
+ setLocale,
219
+ setNamespace,
220
+ isLoading
221
+ }),
222
+ [i18n, locale, namespace, setLocale, setNamespace, isLoading]
223
+ );
224
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypedI18nContext.Provider, { value: typedContextValue, children });
225
+ }
226
+ function useTypedI18nContext() {
227
+ const context = (0, import_react.useContext)(
228
+ TypedI18nContext
229
+ );
230
+ if (!context) {
231
+ throw new Error(
232
+ "useTypedI18nContext must be used within a TypedI18nProvider"
233
+ );
234
+ }
235
+ return context;
236
+ }
237
+ function withI18n(Component) {
238
+ const WrappedComponent = (props) => {
239
+ const i18nContext = useI18nContext();
240
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, i18n: i18nContext });
241
+ };
242
+ WrappedComponent.displayName = `withI18n(${Component.displayName || Component.name})`;
243
+ return WrappedComponent;
244
+ }
245
+ function ScopedI18nProvider({
246
+ children,
247
+ namespace,
248
+ locale
249
+ }) {
250
+ const parentContext = useI18nContext();
251
+ const scopedContextValue = (0, import_react.useMemo)(
252
+ () => ({
253
+ ...parentContext,
254
+ namespace,
255
+ locale: locale || parentContext.locale,
256
+ t: parentContext.i18n.createScopedTranslator(namespace)
257
+ }),
258
+ [parentContext, namespace, locale]
259
+ );
260
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nContext.Provider, { value: scopedContextValue, children });
261
+ }
262
+
263
+ // src/hooks/useTranslations.ts
264
+ var import_react2 = require("react");
265
+ function useTranslations(namespace) {
266
+ const { i18n, namespace: currentNamespace } = useI18nContext();
267
+ const targetNamespace = namespace || currentNamespace;
268
+ return (0, import_react2.useCallback)(
269
+ (key, options) => {
270
+ return i18n.t(key, { ...options, namespace: targetNamespace });
271
+ },
272
+ [i18n, targetNamespace]
273
+ );
274
+ }
275
+ function useTypedTranslations(namespace) {
276
+ const { i18n, namespace: currentNamespace } = useTypedI18nContext();
277
+ const targetNamespace = namespace || currentNamespace;
278
+ return (0, import_react2.useCallback)(
279
+ (key, options) => {
280
+ return i18n.t(key, {
281
+ ...options,
282
+ namespace: targetNamespace
283
+ });
284
+ },
285
+ [i18n, targetNamespace]
286
+ );
287
+ }
288
+ var useT = useTranslations;
289
+ var useTypedT = useTypedTranslations;
290
+ function useScopedTranslations(namespace) {
291
+ const { i18n } = useI18nContext();
292
+ return (0, import_react2.useMemo)(() => {
293
+ return i18n.createScopedTranslator(namespace);
294
+ }, [i18n, namespace]);
295
+ }
296
+ function useMultipleTranslations(namespaces) {
297
+ const { i18n } = useI18nContext();
298
+ return (0, import_react2.useMemo)(() => {
299
+ const translators = {};
300
+ for (const namespace of namespaces) {
301
+ translators[namespace] = i18n.createScopedTranslator(namespace);
302
+ }
303
+ return translators;
304
+ }, [i18n, namespaces]);
305
+ }
306
+ function useOptionalTranslation(key, namespace, options) {
307
+ const { i18n, namespace: currentNamespace } = useI18nContext();
308
+ const targetNamespace = namespace || currentNamespace;
309
+ return (0, import_react2.useMemo)(() => {
310
+ if (i18n.hasTranslation(key, targetNamespace)) {
311
+ return i18n.t(key, { ...options, namespace: targetNamespace });
312
+ }
313
+ return void 0;
314
+ }, [i18n, key, targetNamespace, options]);
315
+ }
316
+ function useTranslationWithFallback(key, fallback, namespace, options) {
317
+ const { i18n, namespace: currentNamespace } = useI18nContext();
318
+ const targetNamespace = namespace || currentNamespace;
319
+ return (0, import_react2.useMemo)(() => {
320
+ return i18n.t(key, {
321
+ ...options,
322
+ namespace: targetNamespace,
323
+ fallback
324
+ });
325
+ }, [i18n, key, fallback, targetNamespace, options]);
326
+ }
327
+ function useHasTranslation() {
328
+ const { i18n, namespace: currentNamespace } = useI18nContext();
329
+ return (0, import_react2.useCallback)(
330
+ (key, namespace) => {
331
+ const targetNamespace = namespace || currentNamespace;
332
+ return i18n.hasTranslation(key, targetNamespace);
333
+ },
334
+ [i18n, currentNamespace]
335
+ );
336
+ }
337
+ function useTranslationValue() {
338
+ const { i18n, namespace: currentNamespace } = useI18nContext();
339
+ return (0, import_react2.useCallback)(
340
+ (key, namespace) => {
341
+ const targetNamespace = namespace || currentNamespace;
342
+ return i18n.getTranslation(key, targetNamespace);
343
+ },
344
+ [i18n, currentNamespace]
345
+ );
346
+ }
347
+ function useInterpolatedTranslation(key, variables, namespace) {
348
+ const t = useTranslations(namespace);
349
+ return (0, import_react2.useMemo)(() => {
350
+ return t(key, { interpolation: variables });
351
+ }, [t, key, variables]);
352
+ }
353
+ function usePluralization(key, count, namespace, additionalOptions) {
354
+ const t = useTranslations(namespace);
355
+ return (0, import_react2.useMemo)(() => {
356
+ return t(key, { ...additionalOptions, count });
357
+ }, [t, key, count, additionalOptions]);
358
+ }
359
+
360
+ // src/hooks/useLocale.ts
361
+ var import_react3 = require("react");
362
+ function useLocale() {
363
+ const { locale, setLocale } = useI18nContext();
364
+ return [locale, setLocale];
365
+ }
366
+ function useLocaleInfo() {
367
+ const { locale, i18n } = useI18nContext();
368
+ return (0, import_react3.useMemo)(() => {
369
+ const availableLocales = i18n.getAvailableLocales();
370
+ const fallbackChain = i18n.getFallbackChain(locale);
371
+ return {
372
+ current: locale,
373
+ available: availableLocales,
374
+ fallbackChain,
375
+ isRTL: isRTLLocale(locale),
376
+ direction: isRTLLocale(locale) ? "rtl" : "ltr"
377
+ };
378
+ }, [locale, i18n]);
379
+ }
380
+ function useLocaleSwitch() {
381
+ const { i18n, setLocale } = useI18nContext();
382
+ const switchLocale = (0, import_react3.useCallback)(
383
+ (locale) => {
384
+ const availableLocales = i18n.getAvailableLocales();
385
+ if (!availableLocales.includes(locale)) {
386
+ throw new Error(
387
+ `Locale "${locale}" is not available. Available locales: ${availableLocales.join(", ")}`
388
+ );
389
+ }
390
+ setLocale(locale);
391
+ },
392
+ [i18n, setLocale]
393
+ );
394
+ const isLocaleAvailable = (0, import_react3.useCallback)(
395
+ (locale) => {
396
+ return i18n.getAvailableLocales().includes(locale);
397
+ },
398
+ [i18n]
399
+ );
400
+ return {
401
+ switchLocale,
402
+ isLocaleAvailable,
403
+ availableLocales: i18n.getAvailableLocales()
404
+ };
405
+ }
406
+ function useBrowserLocale() {
407
+ const { i18n } = useI18nContext();
408
+ return (0, import_react3.useMemo)(() => {
409
+ if (typeof window === "undefined") return null;
410
+ const detected = i18n.detectLocale({
411
+ request: void 0,
412
+ url: window.location.href,
413
+ userAgent: navigator.userAgent
414
+ });
415
+ return {
416
+ detected,
417
+ browser: navigator.language,
418
+ supported: i18n.getAvailableLocales().includes(detected)
419
+ };
420
+ }, [i18n]);
421
+ }
422
+ function useLocalePreference() {
423
+ const { locale, setLocale, i18n } = useI18nContext();
424
+ const savePreference = (0, import_react3.useCallback)(
425
+ (newLocale) => {
426
+ if (typeof window !== "undefined") {
427
+ localStorage.setItem("intl-party-locale", newLocale);
428
+ }
429
+ setLocale(newLocale);
430
+ },
431
+ [setLocale]
432
+ );
433
+ const loadPreference = (0, import_react3.useCallback)(() => {
434
+ if (typeof window === "undefined") return null;
435
+ const saved = localStorage.getItem("intl-party-locale");
436
+ if (saved && i18n.getAvailableLocales().includes(saved)) {
437
+ return saved;
438
+ }
439
+ return null;
440
+ }, [i18n]);
441
+ const clearPreference = (0, import_react3.useCallback)(() => {
442
+ if (typeof window !== "undefined") {
443
+ localStorage.removeItem("intl-party-locale");
444
+ }
445
+ }, []);
446
+ return {
447
+ current: locale,
448
+ save: savePreference,
449
+ load: loadPreference,
450
+ clear: clearPreference
451
+ };
452
+ }
453
+ function isRTLLocale(locale) {
454
+ const rtlLocales = [
455
+ "ar",
456
+ "arc",
457
+ "ckb",
458
+ "dv",
459
+ "fa",
460
+ "ha",
461
+ "he",
462
+ "khw",
463
+ "ks",
464
+ "ku",
465
+ "ps",
466
+ "sd",
467
+ "ur",
468
+ "yi"
469
+ ];
470
+ const baseLocale = locale.split("-")[0];
471
+ return rtlLocales.includes(baseLocale);
472
+ }
473
+ function useDirection() {
474
+ const { locale } = useI18nContext();
475
+ return (0, import_react3.useMemo)(() => {
476
+ return isRTLLocale(locale) ? "rtl" : "ltr";
477
+ }, [locale]);
478
+ }
479
+ function useFormatting() {
480
+ const { i18n } = useI18nContext();
481
+ return (0, import_react3.useMemo)(
482
+ () => ({
483
+ formatDate: (date, options) => i18n.formatDate(date, options),
484
+ formatNumber: (number, options) => i18n.formatNumber(number, options),
485
+ formatCurrency: (amount, currency, options) => i18n.formatCurrency(amount, currency, options),
486
+ formatRelativeTime: (value, unit, options) => i18n.formatRelativeTime(value, unit, options)
487
+ }),
488
+ [i18n]
489
+ );
490
+ }
491
+
492
+ // src/hooks/useNamespace.ts
493
+ var import_react4 = require("react");
494
+ function useNamespace() {
495
+ const { namespace, setNamespace } = useI18nContext();
496
+ return [namespace, setNamespace];
497
+ }
498
+ function useNamespaceInfo() {
499
+ const { namespace, i18n } = useI18nContext();
500
+ return (0, import_react4.useMemo)(() => {
501
+ const availableNamespaces = i18n.getAvailableNamespaces();
502
+ return {
503
+ current: namespace,
504
+ available: availableNamespaces,
505
+ isAvailable: availableNamespaces.includes(namespace)
506
+ };
507
+ }, [namespace, i18n]);
508
+ }
509
+ function useNamespaceSwitch() {
510
+ const { i18n, setNamespace } = useI18nContext();
511
+ const switchNamespace = (0, import_react4.useCallback)(
512
+ (namespace) => {
513
+ const availableNamespaces = i18n.getAvailableNamespaces();
514
+ if (!availableNamespaces.includes(namespace)) {
515
+ throw new Error(
516
+ `Namespace "${namespace}" is not available. Available namespaces: ${availableNamespaces.join(", ")}`
517
+ );
518
+ }
519
+ setNamespace(namespace);
520
+ },
521
+ [i18n, setNamespace]
522
+ );
523
+ const isNamespaceAvailable = (0, import_react4.useCallback)(
524
+ (namespace) => {
525
+ return i18n.getAvailableNamespaces().includes(namespace);
526
+ },
527
+ [i18n]
528
+ );
529
+ return {
530
+ switchNamespace,
531
+ isNamespaceAvailable,
532
+ availableNamespaces: i18n.getAvailableNamespaces()
533
+ };
534
+ }
535
+ function useMultipleNamespaces(namespaces) {
536
+ const { i18n } = useI18nContext();
537
+ const translators = (0, import_react4.useMemo)(() => {
538
+ return namespaces.reduce(
539
+ (acc, ns) => {
540
+ acc[ns] = i18n.createScopedTranslator(ns);
541
+ return acc;
542
+ },
543
+ {}
544
+ );
545
+ }, [i18n, namespaces]);
546
+ const isAllAvailable = (0, import_react4.useMemo)(() => {
547
+ const available = i18n.getAvailableNamespaces();
548
+ return namespaces.every((ns) => available.includes(ns));
549
+ }, [i18n, namespaces]);
550
+ const getMissingNamespaces = (0, import_react4.useCallback)(() => {
551
+ const available = i18n.getAvailableNamespaces();
552
+ return namespaces.filter((ns) => !available.includes(ns));
553
+ }, [i18n, namespaces]);
554
+ return {
555
+ translators,
556
+ isAllAvailable,
557
+ getMissingNamespaces
558
+ };
559
+ }
560
+ function useNamespacePreloading() {
561
+ const { i18n, locale } = useI18nContext();
562
+ const preloadNamespace = (0, import_react4.useCallback)(
563
+ async (namespace) => {
564
+ await i18n.preloadTranslations(locale, namespace);
565
+ },
566
+ [i18n, locale]
567
+ );
568
+ const preloadNamespaces = (0, import_react4.useCallback)(
569
+ async (namespaces) => {
570
+ await i18n.preloadTranslations(locale, namespaces);
571
+ },
572
+ [i18n, locale]
573
+ );
574
+ return {
575
+ preloadNamespace,
576
+ preloadNamespaces
577
+ };
578
+ }
579
+
580
+ // src/components/Trans.tsx
581
+ var import_react5 = __toESM(require("react"));
582
+ var import_jsx_runtime2 = require("react/jsx-runtime");
583
+ function Trans({
584
+ i18nKey,
585
+ namespace,
586
+ values = {},
587
+ components = {},
588
+ count,
589
+ fallback,
590
+ children
591
+ }) {
592
+ const t = useTranslations(namespace);
593
+ const rendered = (0, import_react5.useMemo)(() => {
594
+ const options = {
595
+ interpolation: values,
596
+ count,
597
+ fallback
598
+ };
599
+ const translation = t(i18nKey, options);
600
+ if (Object.keys(components).length === 0) {
601
+ return translation;
602
+ }
603
+ return parseTranslationWithComponents(translation, components);
604
+ }, [t, i18nKey, values, components, count, fallback]);
605
+ if (typeof rendered === "string") {
606
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react5.Fragment, { children: rendered });
607
+ }
608
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react5.Fragment, { children: rendered });
609
+ }
610
+ function ConditionalTrans({
611
+ when = true,
612
+ fallbackComponent,
613
+ ...transProps
614
+ }) {
615
+ if (!when) {
616
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react5.Fragment, { children: fallbackComponent });
617
+ }
618
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Trans, { ...transProps });
619
+ }
620
+ function PluralTrans({
621
+ count,
622
+ zero,
623
+ one,
624
+ other,
625
+ i18nKey,
626
+ ...props
627
+ }) {
628
+ const selectedKey = (0, import_react5.useMemo)(() => {
629
+ if (count === 0 && zero) return zero;
630
+ if (count === 1 && one) return one;
631
+ if (other) return other;
632
+ return i18nKey;
633
+ }, [count, zero, one, other, i18nKey]);
634
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
635
+ Trans,
636
+ {
637
+ ...props,
638
+ i18nKey: selectedKey,
639
+ count,
640
+ values: { count, ...props.values }
641
+ }
642
+ );
643
+ }
644
+ function RichTrans({
645
+ allowedTags = ["strong", "em", "br", "span"],
646
+ sanitize = true,
647
+ ...transProps
648
+ }) {
649
+ const t = useTranslations(transProps.namespace);
650
+ const rendered = (0, import_react5.useMemo)(() => {
651
+ const translation = t(transProps.i18nKey, {
652
+ interpolation: transProps.values,
653
+ count: transProps.count,
654
+ fallback: transProps.fallback
655
+ });
656
+ if (sanitize) {
657
+ const sanitized = translation.replace(
658
+ /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
659
+ ""
660
+ );
661
+ return parseHTMLString(sanitized, allowedTags);
662
+ }
663
+ return parseHTMLString(translation, allowedTags);
664
+ }, [t, transProps, allowedTags, sanitize]);
665
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react5.Fragment, { children: rendered });
666
+ }
667
+ function parseTranslationWithComponents(text, components) {
668
+ const parts = [];
669
+ let currentIndex = 0;
670
+ const componentRegex = /<(\w+)>(.*?)<\/\1>/g;
671
+ let match;
672
+ while ((match = componentRegex.exec(text)) !== null) {
673
+ const [fullMatch, componentKey, content] = match;
674
+ const matchStart = match.index;
675
+ if (matchStart > currentIndex) {
676
+ parts.push(text.slice(currentIndex, matchStart));
677
+ }
678
+ if (components[componentKey]) {
679
+ if (import_react5.default.isValidElement(components[componentKey])) {
680
+ parts.push(
681
+ import_react5.default.cloneElement(
682
+ components[componentKey],
683
+ { key: parts.length },
684
+ content
685
+ )
686
+ );
687
+ } else {
688
+ parts.push(components[componentKey]);
689
+ }
690
+ } else {
691
+ parts.push(content);
692
+ }
693
+ currentIndex = matchStart + fullMatch.length;
694
+ }
695
+ if (currentIndex < text.length) {
696
+ parts.push(text.slice(currentIndex));
697
+ }
698
+ return parts.length > 0 ? parts : [text];
699
+ }
700
+ function parseHTMLString(html, allowedTags) {
701
+ if (!allowedTags.length) {
702
+ return html;
703
+ }
704
+ const tagRegex = new RegExp(
705
+ `<(/?)(${allowedTags.join("|")})(?:\\s[^>]*)?>`,
706
+ "gi"
707
+ );
708
+ const parts = html.split(tagRegex).filter(Boolean);
709
+ const elements = [];
710
+ let i = 0;
711
+ while (i < parts.length) {
712
+ const part = parts[i];
713
+ if (allowedTags.some((tag) => part.toLowerCase() === tag)) {
714
+ const tag = part.toLowerCase();
715
+ let content = "";
716
+ let depth = 1;
717
+ i++;
718
+ while (i < parts.length && depth > 0) {
719
+ const nextPart = parts[i];
720
+ if (nextPart === "/") {
721
+ i++;
722
+ if (i < parts.length && parts[i].toLowerCase() === tag) {
723
+ depth--;
724
+ i++;
725
+ }
726
+ } else if (allowedTags.some((t) => nextPart.toLowerCase() === t)) {
727
+ depth++;
728
+ content += `<${nextPart}>`;
729
+ i++;
730
+ } else {
731
+ content += nextPart;
732
+ i++;
733
+ }
734
+ }
735
+ elements.push(
736
+ import_react5.default.createElement(tag, { key: elements.length }, content)
737
+ );
738
+ } else {
739
+ elements.push(part);
740
+ i++;
741
+ }
742
+ }
743
+ return elements.length === 1 ? elements[0] : elements;
744
+ }
745
+
746
+ // src/components/LocaleSelector.tsx
747
+ var import_react6 = require("react");
748
+ var import_jsx_runtime3 = require("react/jsx-runtime");
749
+ function LocaleSelector({
750
+ className,
751
+ style,
752
+ placeholder = "Select language",
753
+ disabled = false,
754
+ showNativeNames = true,
755
+ filterLocales,
756
+ formatLocale,
757
+ onLocaleChange,
758
+ variant = "select"
759
+ }) {
760
+ const [currentLocale, setLocale] = useLocale();
761
+ const { available } = useLocaleInfo();
762
+ const filteredLocales = (0, import_react6.useMemo)(() => {
763
+ return filterLocales ? available.filter(filterLocales) : available;
764
+ }, [available, filterLocales]);
765
+ const handleLocaleChange = (locale) => {
766
+ setLocale(locale);
767
+ onLocaleChange?.(locale);
768
+ };
769
+ const formatLocaleDisplay = (locale) => {
770
+ if (formatLocale) {
771
+ return formatLocale(locale);
772
+ }
773
+ if (showNativeNames) {
774
+ try {
775
+ const intlLocale = new Intl.Locale(locale);
776
+ const displayNames = new Intl.DisplayNames([locale], {
777
+ type: "language"
778
+ });
779
+ return displayNames.of(intlLocale.language) || locale;
780
+ } catch {
781
+ return locale;
782
+ }
783
+ }
784
+ return locale;
785
+ };
786
+ if (variant === "select") {
787
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
788
+ "select",
789
+ {
790
+ className,
791
+ style,
792
+ value: currentLocale,
793
+ disabled,
794
+ onChange: (e) => handleLocaleChange(e.target.value),
795
+ children: [
796
+ placeholder && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", disabled: true, children: placeholder }),
797
+ filteredLocales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: locale, children: formatLocaleDisplay(locale) }, locale))
798
+ ]
799
+ }
800
+ );
801
+ }
802
+ if (variant === "buttons") {
803
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style, children: filteredLocales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
804
+ "button",
805
+ {
806
+ type: "button",
807
+ disabled,
808
+ onClick: () => handleLocaleChange(locale),
809
+ style: {
810
+ fontWeight: currentLocale === locale ? "bold" : "normal",
811
+ opacity: currentLocale === locale ? 1 : 0.7
812
+ },
813
+ children: formatLocaleDisplay(locale)
814
+ },
815
+ locale
816
+ )) });
817
+ }
818
+ return null;
819
+ }
820
+ function FlagLocaleSelector({
821
+ flagMap = {},
822
+ showFlags = true,
823
+ showLabels = true,
824
+ variant = "buttons",
825
+ ...props
826
+ }) {
827
+ const [currentLocale, setLocale] = useLocale();
828
+ const { available } = useLocaleInfo();
829
+ const defaultFlagMap = {
830
+ en: "\u{1F1FA}\u{1F1F8}",
831
+ es: "\u{1F1EA}\u{1F1F8}",
832
+ fr: "\u{1F1EB}\u{1F1F7}",
833
+ de: "\u{1F1E9}\u{1F1EA}",
834
+ it: "\u{1F1EE}\u{1F1F9}",
835
+ pt: "\u{1F1F5}\u{1F1F9}",
836
+ ru: "\u{1F1F7}\u{1F1FA}",
837
+ ja: "\u{1F1EF}\u{1F1F5}",
838
+ ko: "\u{1F1F0}\u{1F1F7}",
839
+ zh: "\u{1F1E8}\u{1F1F3}"
840
+ };
841
+ const combinedFlagMap = { ...defaultFlagMap, ...flagMap };
842
+ const formatLocaleWithFlag = (locale) => {
843
+ const parts = [];
844
+ if (showFlags && combinedFlagMap[locale]) {
845
+ parts.push(combinedFlagMap[locale]);
846
+ }
847
+ if (showLabels) {
848
+ if (props.formatLocale) {
849
+ parts.push(props.formatLocale(locale));
850
+ } else {
851
+ try {
852
+ const displayNames = new Intl.DisplayNames([locale], {
853
+ type: "language"
854
+ });
855
+ const intlLocale = new Intl.Locale(locale);
856
+ parts.push(displayNames.of(intlLocale.language) || locale);
857
+ } catch {
858
+ parts.push(locale);
859
+ }
860
+ }
861
+ }
862
+ return parts.join(" ");
863
+ };
864
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
865
+ LocaleSelector,
866
+ {
867
+ ...props,
868
+ variant,
869
+ formatLocale: formatLocaleWithFlag,
870
+ showNativeNames: false
871
+ }
872
+ );
873
+ }
874
+ function CompactLocaleSelector({
875
+ maxVisibleLocales = 3,
876
+ ...props
877
+ }) {
878
+ const { available } = useLocaleInfo();
879
+ if (available.length <= maxVisibleLocales) {
880
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocaleSelector, { ...props, variant: "buttons" });
881
+ }
882
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocaleSelector, { ...props, variant: "select" });
883
+ }
884
+ function AccessibleLocaleSelector({
885
+ ariaLabel = "Select language",
886
+ ariaDescribedBy,
887
+ ...props
888
+ }) {
889
+ const [currentLocale] = useLocale();
890
+ const enhancedProps = {
891
+ ...props,
892
+ style: {
893
+ ...props.style,
894
+ // Ensure minimum touch target size for accessibility
895
+ minHeight: "44px",
896
+ minWidth: "44px"
897
+ }
898
+ };
899
+ if (props.variant === "select") {
900
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
901
+ LocaleSelector,
902
+ {
903
+ ...enhancedProps,
904
+ className: `${props.className || ""} accessible-locale-selector`
905
+ }
906
+ );
907
+ }
908
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
909
+ "div",
910
+ {
911
+ role: "group",
912
+ "aria-label": ariaLabel,
913
+ "aria-describedby": ariaDescribedBy,
914
+ className: props.className,
915
+ style: props.style,
916
+ children: [
917
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LocaleSelector, { ...enhancedProps }),
918
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "sr-only", children: [
919
+ "Current language: ",
920
+ currentLocale
921
+ ] })
922
+ ]
923
+ }
924
+ );
925
+ }
926
+
927
+ // src/index.tsx
928
+ var import_jsx_runtime4 = require("react/jsx-runtime");
929
+ var VERSION = "0.1.0";
930
+ function createI18nHook() {
931
+ return {
932
+ useTranslations: useTypedTranslations,
933
+ useT: useTypedTranslations
934
+ };
935
+ }
936
+ function createNamespaceHOC(namespace) {
937
+ return function withNamespace(Component) {
938
+ return function NamespacedComponent(props) {
939
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ScopedI18nProvider, { namespace, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Component, { ...props }) });
940
+ };
941
+ };
942
+ }
943
+ var I18nErrorBoundary = class extends import_react7.default.Component {
944
+ constructor(props) {
945
+ super(props);
946
+ this.state = { hasError: false };
947
+ }
948
+ static getDerivedStateFromError(error) {
949
+ return { hasError: true, error };
950
+ }
951
+ componentDidCatch(error, errorInfo) {
952
+ this.props.onError?.(error, errorInfo);
953
+ }
954
+ render() {
955
+ if (this.state.hasError) {
956
+ const FallbackComponent = this.props.fallback;
957
+ if (FallbackComponent && this.state.error) {
958
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FallbackComponent, { error: this.state.error });
959
+ }
960
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
961
+ "div",
962
+ {
963
+ style: {
964
+ padding: "1rem",
965
+ border: "1px solid red",
966
+ borderRadius: "4px"
967
+ },
968
+ children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: "Translation Error" }),
970
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "Something went wrong with translations." }),
971
+ process.env.NODE_ENV === "development" && this.state.error && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { children: [
972
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("summary", { children: "Error details" }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { children: this.state.error.message })
974
+ ] })
975
+ ]
976
+ }
977
+ );
978
+ }
979
+ return this.props.children;
980
+ }
981
+ };
982
+ // Annotate the CommonJS export names for ESM import in node:
983
+ 0 && (module.exports = {
984
+ AccessibleLocaleSelector,
985
+ CompactLocaleSelector,
986
+ ConditionalTrans,
987
+ FlagLocaleSelector,
988
+ I18nErrorBoundary,
989
+ I18nProvider,
990
+ LocaleSelector,
991
+ PluralTrans,
992
+ RichTrans,
993
+ ScopedI18nProvider,
994
+ Trans,
995
+ TypedI18nProvider,
996
+ VERSION,
997
+ createI18nHook,
998
+ createNamespaceHOC,
999
+ useBrowserLocale,
1000
+ useDirection,
1001
+ useFormatting,
1002
+ useHasTranslation,
1003
+ useI18nContext,
1004
+ useInterpolatedTranslation,
1005
+ useLocale,
1006
+ useLocaleInfo,
1007
+ useLocalePreference,
1008
+ useLocaleSwitch,
1009
+ useMultipleNamespaces,
1010
+ useMultipleTranslations,
1011
+ useNamespace,
1012
+ useNamespaceInfo,
1013
+ useNamespacePreloading,
1014
+ useNamespaceSwitch,
1015
+ useOptionalTranslation,
1016
+ usePluralization,
1017
+ useScopedTranslations,
1018
+ useT,
1019
+ useTranslationValue,
1020
+ useTranslationWithFallback,
1021
+ useTranslations,
1022
+ useTypedI18nContext,
1023
+ useTypedT,
1024
+ useTypedTranslations,
1025
+ withI18n
1026
+ });