inline-i18n-multi-react 0.4.0 → 0.6.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/README.md CHANGED
@@ -60,14 +60,117 @@ function Nav() {
60
60
  }
61
61
  ```
62
62
 
63
+ ## Rich Text
64
+
65
+ Embed React components within translated strings using `<tag>` syntax.
66
+
67
+ ```tsx
68
+ import { RichText, useRichText } from 'inline-i18n-multi-react'
69
+
70
+ // Component approach
71
+ function Terms() {
72
+ return (
73
+ <RichText
74
+ translations={{
75
+ en: 'Read <link>terms</link> and <bold>agree</bold>',
76
+ ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요',
77
+ }}
78
+ components={{
79
+ link: (text) => <a href="/terms">{text}</a>,
80
+ bold: (text) => <strong>{text}</strong>,
81
+ }}
82
+ />
83
+ )
84
+ }
85
+
86
+ // Hook approach
87
+ function Legal() {
88
+ const richT = useRichText({
89
+ link: (text) => <a href="/terms">{text}</a>,
90
+ bold: (text) => <strong>{text}</strong>,
91
+ })
92
+
93
+ return <p>{richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })}</p>
94
+ }
95
+ ```
96
+
97
+ ## Lazy Loading with useLoadDictionaries
98
+
99
+ ```tsx
100
+ import { useLoadDictionaries, useT } from 'inline-i18n-multi-react'
101
+
102
+ function Dashboard() {
103
+ const { isLoading, error } = useLoadDictionaries('ko', 'dashboard')
104
+ const t = useT()
105
+
106
+ if (isLoading) return <Spinner />
107
+ if (error) return <p>Failed to load translations</p>
108
+
109
+ return <h1>{t('dashboard.title')}</h1>
110
+ }
111
+ ```
112
+
113
+ ## Automatic Locale Detection
114
+
115
+ ```tsx
116
+ import { LocaleProvider, useDetectedLocale } from 'inline-i18n-multi-react'
117
+
118
+ function App() {
119
+ return (
120
+ <LocaleProvider locale="en">
121
+ <AutoDetect />
122
+ </LocaleProvider>
123
+ )
124
+ }
125
+
126
+ function AutoDetect() {
127
+ useDetectedLocale({
128
+ supportedLocales: ['en', 'ko', 'ja'],
129
+ defaultLocale: 'en',
130
+ sources: ['cookie', 'navigator'],
131
+ })
132
+
133
+ return <Content />
134
+ }
135
+ ```
136
+
63
137
  ## API
64
138
 
65
- - `LocaleProvider` - Context provider for locale
66
- - `useLocale()` - Get/set current locale
67
- - `it(ko, en, vars?)` - Inline translation function
68
- - `T` - Translation component with language props
69
- - `useT()` - Hook returning key-based `t()` function
70
- - `loadDictionaries(dict)` - Load translation dictionaries
139
+ ### React-Specific
140
+
141
+ | Export | Description |
142
+ |---|---|
143
+ | `LocaleProvider` | Context provider for locale |
144
+ | `useLocale()` | Get/set current locale via context |
145
+ | `useT()` | Hook returning key-based `t()` function |
146
+ | `T` | Translation component with language props |
147
+ | `RichText` | Rich text translation component |
148
+ | `useRichText(components)` | Hook for rich text translations |
149
+ | `useLoadDictionaries(locale, namespace?)` | Lazy loading hook with loading/error state |
150
+ | `useDetectedLocale(options)` | Auto-detect and set locale on mount |
151
+
152
+ ### Re-exported from Core
153
+
154
+ **Inline translations:**
155
+ `it`, `it_ja`, `it_zh`, `it_es`, `it_fr`, `it_de`, `en_ja`, `en_zh`, `en_es`, `en_fr`, `en_de`, `ja_zh`, `ja_es`, `zh_es`
156
+
157
+ **Locale management:**
158
+ `getLocale`, `setLocale`
159
+
160
+ **Key-based translations:**
161
+ `t`, `loadDictionaries`, `loadDictionary`, `clearDictionaries`, `hasTranslation`, `getLoadedLocales`, `getDictionary`, `loadAsync`, `isLoaded`
162
+
163
+ **Configuration:**
164
+ `configure`, `getConfig`, `resetConfig`
165
+
166
+ **Rich text parsing:**
167
+ `parseRichText`
168
+
169
+ **Custom formatters:**
170
+ `registerFormatter`, `clearFormatters`
171
+
172
+ **Locale detection:**
173
+ `detectLocale`
71
174
 
72
175
  ## Documentation
73
176
 
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
- import { Locale, TranslationVars, Translations } from 'inline-i18n-multi';
4
- export { Dictionaries, Dictionary, Locale, PluralRules, TranslationVars, Translations, clearDictionaries, en_de, en_es, en_fr, en_ja, en_zh, getDictionary, getLoadedLocales, getLocale, hasTranslation, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadDictionaries, loadDictionary, setLocale, t, zh_es } from 'inline-i18n-multi';
2
+ import React, { ReactNode } from 'react';
3
+ import { Locale, TranslationVars, DetectLocaleOptions, Translations } from 'inline-i18n-multi';
4
+ export { CustomFormatter, DetectLocaleOptions, DetectSource, Dictionaries, Dictionary, Locale, PluralRules, RichTextSegment, TranslationVars, Translations, clearDictionaries, clearFormatters, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, setLocale, t, zh_es } from 'inline-i18n-multi';
5
5
 
6
6
  interface LocaleProviderProps {
7
7
  /**
@@ -33,6 +33,36 @@ declare function useLocale(): [Locale, (locale: Locale) => void];
33
33
  * t('items.count', { count: 5 })
34
34
  */
35
35
  declare function useT(): (key: string, vars?: TranslationVars) => string;
36
+ /**
37
+ * Hook for lazy loading dictionaries
38
+ * Automatically loads dictionaries when locale or namespace changes
39
+ *
40
+ * @example
41
+ * function Dashboard() {
42
+ * const { isLoading, error } = useLoadDictionaries('ko', 'dashboard')
43
+ * if (isLoading) return <Spinner />
44
+ * if (error) return <Error message={error.message} />
45
+ * return <Content />
46
+ * }
47
+ */
48
+ declare function useLoadDictionaries(locale: Locale, namespace?: string): {
49
+ isLoading: boolean;
50
+ error: Error | null;
51
+ };
52
+ /**
53
+ * Hook that auto-detects and sets locale on mount
54
+ *
55
+ * @example
56
+ * function App() {
57
+ * useDetectedLocale({
58
+ * supportedLocales: ['en', 'ko', 'ja'],
59
+ * defaultLocale: 'en',
60
+ * sources: ['cookie', 'navigator'],
61
+ * })
62
+ * return <Content />
63
+ * }
64
+ */
65
+ declare function useDetectedLocale(options: DetectLocaleOptions): void;
36
66
 
37
67
  interface TPropsShorthand {
38
68
  /**
@@ -62,4 +92,51 @@ type TProps = (TPropsShorthand | TPropsObject) & TranslationVars;
62
92
  */
63
93
  declare function T(props: TProps): react_jsx_runtime.JSX.Element;
64
94
 
65
- export { LocaleProvider, T, useLocale, useT };
95
+ type ComponentRenderer = (text: string) => ReactNode;
96
+ interface RichTextProps {
97
+ /**
98
+ * Translation map with locale keys
99
+ * Tags like <link>text</link> will be matched to component renderers
100
+ */
101
+ translations: Translations;
102
+ /**
103
+ * Component renderers for each tag name
104
+ * @example { link: (text) => <a href="/terms">{text}</a> }
105
+ */
106
+ components: Record<string, ComponentRenderer>;
107
+ /**
108
+ * Variables for interpolation (applied before rich text parsing)
109
+ */
110
+ vars?: TranslationVars;
111
+ }
112
+ /**
113
+ * Rich text translation component
114
+ * Supports embedding React components within translations
115
+ *
116
+ * @example
117
+ * <RichText
118
+ * translations={{
119
+ * en: 'Read <link>terms</link> and <bold>agree</bold>',
120
+ * ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요'
121
+ * }}
122
+ * components={{
123
+ * link: (text) => <a href="/terms">{text}</a>,
124
+ * bold: (text) => <strong>{text}</strong>
125
+ * }}
126
+ * />
127
+ */
128
+ declare function RichText({ translations, components, vars }: RichTextProps): React.JSX.Element;
129
+ /**
130
+ * Hook for rich text translations
131
+ * Returns a function that resolves translations with component interpolation
132
+ *
133
+ * @example
134
+ * const richT = useRichText({
135
+ * link: (text) => <a href="/terms">{text}</a>,
136
+ * bold: (text) => <strong>{text}</strong>,
137
+ * })
138
+ * return richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })
139
+ */
140
+ declare function useRichText(components: Record<string, ComponentRenderer>): (translations: Translations, vars?: TranslationVars) => ReactNode;
141
+
142
+ export { LocaleProvider, RichText, T, useDetectedLocale, useLoadDictionaries, useLocale, useRichText, useT };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
- import { Locale, TranslationVars, Translations } from 'inline-i18n-multi';
4
- export { Dictionaries, Dictionary, Locale, PluralRules, TranslationVars, Translations, clearDictionaries, en_de, en_es, en_fr, en_ja, en_zh, getDictionary, getLoadedLocales, getLocale, hasTranslation, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadDictionaries, loadDictionary, setLocale, t, zh_es } from 'inline-i18n-multi';
2
+ import React, { ReactNode } from 'react';
3
+ import { Locale, TranslationVars, DetectLocaleOptions, Translations } from 'inline-i18n-multi';
4
+ export { CustomFormatter, DetectLocaleOptions, DetectSource, Dictionaries, Dictionary, Locale, PluralRules, RichTextSegment, TranslationVars, Translations, clearDictionaries, clearFormatters, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, setLocale, t, zh_es } from 'inline-i18n-multi';
5
5
 
6
6
  interface LocaleProviderProps {
7
7
  /**
@@ -33,6 +33,36 @@ declare function useLocale(): [Locale, (locale: Locale) => void];
33
33
  * t('items.count', { count: 5 })
34
34
  */
35
35
  declare function useT(): (key: string, vars?: TranslationVars) => string;
36
+ /**
37
+ * Hook for lazy loading dictionaries
38
+ * Automatically loads dictionaries when locale or namespace changes
39
+ *
40
+ * @example
41
+ * function Dashboard() {
42
+ * const { isLoading, error } = useLoadDictionaries('ko', 'dashboard')
43
+ * if (isLoading) return <Spinner />
44
+ * if (error) return <Error message={error.message} />
45
+ * return <Content />
46
+ * }
47
+ */
48
+ declare function useLoadDictionaries(locale: Locale, namespace?: string): {
49
+ isLoading: boolean;
50
+ error: Error | null;
51
+ };
52
+ /**
53
+ * Hook that auto-detects and sets locale on mount
54
+ *
55
+ * @example
56
+ * function App() {
57
+ * useDetectedLocale({
58
+ * supportedLocales: ['en', 'ko', 'ja'],
59
+ * defaultLocale: 'en',
60
+ * sources: ['cookie', 'navigator'],
61
+ * })
62
+ * return <Content />
63
+ * }
64
+ */
65
+ declare function useDetectedLocale(options: DetectLocaleOptions): void;
36
66
 
37
67
  interface TPropsShorthand {
38
68
  /**
@@ -62,4 +92,51 @@ type TProps = (TPropsShorthand | TPropsObject) & TranslationVars;
62
92
  */
63
93
  declare function T(props: TProps): react_jsx_runtime.JSX.Element;
64
94
 
65
- export { LocaleProvider, T, useLocale, useT };
95
+ type ComponentRenderer = (text: string) => ReactNode;
96
+ interface RichTextProps {
97
+ /**
98
+ * Translation map with locale keys
99
+ * Tags like <link>text</link> will be matched to component renderers
100
+ */
101
+ translations: Translations;
102
+ /**
103
+ * Component renderers for each tag name
104
+ * @example { link: (text) => <a href="/terms">{text}</a> }
105
+ */
106
+ components: Record<string, ComponentRenderer>;
107
+ /**
108
+ * Variables for interpolation (applied before rich text parsing)
109
+ */
110
+ vars?: TranslationVars;
111
+ }
112
+ /**
113
+ * Rich text translation component
114
+ * Supports embedding React components within translations
115
+ *
116
+ * @example
117
+ * <RichText
118
+ * translations={{
119
+ * en: 'Read <link>terms</link> and <bold>agree</bold>',
120
+ * ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요'
121
+ * }}
122
+ * components={{
123
+ * link: (text) => <a href="/terms">{text}</a>,
124
+ * bold: (text) => <strong>{text}</strong>
125
+ * }}
126
+ * />
127
+ */
128
+ declare function RichText({ translations, components, vars }: RichTextProps): React.JSX.Element;
129
+ /**
130
+ * Hook for rich text translations
131
+ * Returns a function that resolves translations with component interpolation
132
+ *
133
+ * @example
134
+ * const richT = useRichText({
135
+ * link: (text) => <a href="/terms">{text}</a>,
136
+ * bold: (text) => <strong>{text}</strong>,
137
+ * })
138
+ * return richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })
139
+ */
140
+ declare function useRichText(components: Record<string, ComponentRenderer>): (translations: Translations, vars?: TranslationVars) => ReactNode;
141
+
142
+ export { LocaleProvider, RichText, T, useDetectedLocale, useLoadDictionaries, useLocale, useRichText, useT };
package/dist/index.js CHANGED
@@ -22,32 +22,45 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
24
  LocaleProvider: () => LocaleProvider,
25
+ RichText: () => RichText,
25
26
  T: () => T,
26
- clearDictionaries: () => import_inline_i18n_multi4.clearDictionaries,
27
- en_de: () => import_inline_i18n_multi4.en_de,
28
- en_es: () => import_inline_i18n_multi4.en_es,
29
- en_fr: () => import_inline_i18n_multi4.en_fr,
30
- en_ja: () => import_inline_i18n_multi4.en_ja,
31
- en_zh: () => import_inline_i18n_multi4.en_zh,
32
- getDictionary: () => import_inline_i18n_multi4.getDictionary,
33
- getLoadedLocales: () => import_inline_i18n_multi4.getLoadedLocales,
34
- getLocale: () => import_inline_i18n_multi4.getLocale,
35
- hasTranslation: () => import_inline_i18n_multi4.hasTranslation,
36
- it: () => import_inline_i18n_multi4.it,
37
- it_de: () => import_inline_i18n_multi4.it_de,
38
- it_es: () => import_inline_i18n_multi4.it_es,
39
- it_fr: () => import_inline_i18n_multi4.it_fr,
40
- it_ja: () => import_inline_i18n_multi4.it_ja,
41
- it_zh: () => import_inline_i18n_multi4.it_zh,
42
- ja_es: () => import_inline_i18n_multi4.ja_es,
43
- ja_zh: () => import_inline_i18n_multi4.ja_zh,
44
- loadDictionaries: () => import_inline_i18n_multi4.loadDictionaries,
45
- loadDictionary: () => import_inline_i18n_multi4.loadDictionary,
46
- setLocale: () => import_inline_i18n_multi4.setLocale,
47
- t: () => import_inline_i18n_multi4.t,
27
+ clearDictionaries: () => import_inline_i18n_multi5.clearDictionaries,
28
+ clearFormatters: () => import_inline_i18n_multi5.clearFormatters,
29
+ configure: () => import_inline_i18n_multi5.configure,
30
+ detectLocale: () => import_inline_i18n_multi5.detectLocale,
31
+ en_de: () => import_inline_i18n_multi5.en_de,
32
+ en_es: () => import_inline_i18n_multi5.en_es,
33
+ en_fr: () => import_inline_i18n_multi5.en_fr,
34
+ en_ja: () => import_inline_i18n_multi5.en_ja,
35
+ en_zh: () => import_inline_i18n_multi5.en_zh,
36
+ getConfig: () => import_inline_i18n_multi5.getConfig,
37
+ getDictionary: () => import_inline_i18n_multi5.getDictionary,
38
+ getLoadedLocales: () => import_inline_i18n_multi5.getLoadedLocales,
39
+ getLocale: () => import_inline_i18n_multi5.getLocale,
40
+ hasTranslation: () => import_inline_i18n_multi5.hasTranslation,
41
+ isLoaded: () => import_inline_i18n_multi5.isLoaded,
42
+ it: () => import_inline_i18n_multi5.it,
43
+ it_de: () => import_inline_i18n_multi5.it_de,
44
+ it_es: () => import_inline_i18n_multi5.it_es,
45
+ it_fr: () => import_inline_i18n_multi5.it_fr,
46
+ it_ja: () => import_inline_i18n_multi5.it_ja,
47
+ it_zh: () => import_inline_i18n_multi5.it_zh,
48
+ ja_es: () => import_inline_i18n_multi5.ja_es,
49
+ ja_zh: () => import_inline_i18n_multi5.ja_zh,
50
+ loadAsync: () => import_inline_i18n_multi5.loadAsync,
51
+ loadDictionaries: () => import_inline_i18n_multi5.loadDictionaries,
52
+ loadDictionary: () => import_inline_i18n_multi5.loadDictionary,
53
+ parseRichText: () => import_inline_i18n_multi5.parseRichText,
54
+ registerFormatter: () => import_inline_i18n_multi5.registerFormatter,
55
+ resetConfig: () => import_inline_i18n_multi5.resetConfig,
56
+ setLocale: () => import_inline_i18n_multi5.setLocale,
57
+ t: () => import_inline_i18n_multi5.t,
58
+ useDetectedLocale: () => useDetectedLocale,
59
+ useLoadDictionaries: () => useLoadDictionaries,
48
60
  useLocale: () => useLocale,
61
+ useRichText: () => useRichText,
49
62
  useT: () => useT,
50
- zh_es: () => import_inline_i18n_multi4.zh_es
63
+ zh_es: () => import_inline_i18n_multi5.zh_es
51
64
  });
52
65
  module.exports = __toCommonJS(index_exports);
53
66
 
@@ -83,7 +96,7 @@ function LocaleProvider({
83
96
  (0, import_react2.useEffect)(() => {
84
97
  (0, import_inline_i18n_multi.setLocale)(locale);
85
98
  }, [locale]);
86
- const setLocale2 = (0, import_react2.useCallback)(
99
+ const setLocale3 = (0, import_react2.useCallback)(
87
100
  (newLocale) => {
88
101
  setLocaleState(newLocale);
89
102
  (0, import_inline_i18n_multi.setLocale)(newLocale);
@@ -94,7 +107,7 @@ function LocaleProvider({
94
107
  },
95
108
  [cookieName, onLocaleChange]
96
109
  );
97
- const value = (0, import_react2.useMemo)(() => ({ locale, setLocale: setLocale2 }), [locale, setLocale2]);
110
+ const value = (0, import_react2.useMemo)(() => ({ locale, setLocale: setLocale3 }), [locale, setLocale3]);
98
111
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocaleContext.Provider, { value, children });
99
112
  }
100
113
 
@@ -102,8 +115,8 @@ function LocaleProvider({
102
115
  var import_react3 = require("react");
103
116
  var import_inline_i18n_multi2 = require("inline-i18n-multi");
104
117
  function useLocale() {
105
- const { locale, setLocale: setLocale2 } = useLocaleContext();
106
- return [locale, setLocale2];
118
+ const { locale, setLocale: setLocale3 } = useLocaleContext();
119
+ return [locale, setLocale3];
107
120
  }
108
121
  function useT() {
109
122
  const { locale } = useLocaleContext();
@@ -112,6 +125,32 @@ function useT() {
112
125
  [locale]
113
126
  );
114
127
  }
128
+ function useLoadDictionaries(locale, namespace) {
129
+ const [isLoading, setIsLoading] = (0, import_react3.useState)(() => !(0, import_inline_i18n_multi2.isLoaded)(locale, namespace));
130
+ const [error, setError] = (0, import_react3.useState)(null);
131
+ (0, import_react3.useEffect)(() => {
132
+ if ((0, import_inline_i18n_multi2.isLoaded)(locale, namespace)) {
133
+ setIsLoading(false);
134
+ setError(null);
135
+ return;
136
+ }
137
+ setIsLoading(true);
138
+ setError(null);
139
+ (0, import_inline_i18n_multi2.loadAsync)(locale, namespace).then(() => setIsLoading(false)).catch((err) => {
140
+ setError(err instanceof Error ? err : new Error(String(err)));
141
+ setIsLoading(false);
142
+ });
143
+ }, [locale, namespace]);
144
+ return { isLoading, error };
145
+ }
146
+ function useDetectedLocale(options) {
147
+ const { setLocale: setContextLocale } = useLocaleContext();
148
+ (0, import_react3.useEffect)(() => {
149
+ const detected = (0, import_inline_i18n_multi2.detectLocale)(options);
150
+ (0, import_inline_i18n_multi2.setLocale)(detected);
151
+ setContextLocale(detected);
152
+ }, []);
153
+ }
115
154
 
116
155
  // src/component.tsx
117
156
  var import_inline_i18n_multi3 = require("inline-i18n-multi");
@@ -127,22 +166,68 @@ function T(props) {
127
166
  throw new Error('T component requires either "translations" or both "ko" and "en" props');
128
167
  }
129
168
 
130
- // src/index.ts
169
+ // src/richtext.tsx
170
+ var import_react4 = require("react");
131
171
  var import_inline_i18n_multi4 = require("inline-i18n-multi");
172
+ var import_jsx_runtime3 = require("react/jsx-runtime");
173
+ function RichText({ translations, components, vars }) {
174
+ const componentNames = (0, import_react4.useMemo)(() => Object.keys(components), [components]);
175
+ const resolved = (0, import_inline_i18n_multi4.it)(translations, vars);
176
+ const segments = (0, import_inline_i18n_multi4.parseRichText)(resolved, componentNames);
177
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: segments.map((segment, index) => {
178
+ if (segment.type === "text") {
179
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: segment.content }, index);
180
+ }
181
+ const renderer = components[segment.componentName];
182
+ if (!renderer) {
183
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: segment.content }, index);
184
+ }
185
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: renderer(segment.content) }, index);
186
+ }) });
187
+ }
188
+ function useRichText(components) {
189
+ const componentNames = (0, import_react4.useMemo)(() => Object.keys(components), [components]);
190
+ return (0, import_react4.useCallback)(
191
+ (translations, vars) => {
192
+ const resolved = (0, import_inline_i18n_multi4.it)(translations, vars);
193
+ const segments = (0, import_inline_i18n_multi4.parseRichText)(resolved, componentNames);
194
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: segments.map((segment, index) => {
195
+ if (segment.type === "text") {
196
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: segment.content }, index);
197
+ }
198
+ const renderer = components[segment.componentName];
199
+ if (!renderer) {
200
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: segment.content }, index);
201
+ }
202
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Fragment, { children: renderer(segment.content) }, index);
203
+ }) });
204
+ },
205
+ [components, componentNames]
206
+ );
207
+ }
208
+
209
+ // src/index.ts
210
+ var import_inline_i18n_multi5 = require("inline-i18n-multi");
132
211
  // Annotate the CommonJS export names for ESM import in node:
133
212
  0 && (module.exports = {
134
213
  LocaleProvider,
214
+ RichText,
135
215
  T,
136
216
  clearDictionaries,
217
+ clearFormatters,
218
+ configure,
219
+ detectLocale,
137
220
  en_de,
138
221
  en_es,
139
222
  en_fr,
140
223
  en_ja,
141
224
  en_zh,
225
+ getConfig,
142
226
  getDictionary,
143
227
  getLoadedLocales,
144
228
  getLocale,
145
229
  hasTranslation,
230
+ isLoaded,
146
231
  it,
147
232
  it_de,
148
233
  it_es,
@@ -151,11 +236,18 @@ var import_inline_i18n_multi4 = require("inline-i18n-multi");
151
236
  it_zh,
152
237
  ja_es,
153
238
  ja_zh,
239
+ loadAsync,
154
240
  loadDictionaries,
155
241
  loadDictionary,
242
+ parseRichText,
243
+ registerFormatter,
244
+ resetConfig,
156
245
  setLocale,
157
246
  t,
247
+ useDetectedLocale,
248
+ useLoadDictionaries,
158
249
  useLocale,
250
+ useRichText,
159
251
  useT,
160
252
  zh_es
161
253
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/context.tsx","../src/hooks.ts","../src/component.tsx"],"sourcesContent":["export { LocaleProvider } from './provider'\nexport { useLocale, useT } from './hooks'\nexport { T } from './component'\n\n// re-export from core for convenience\nexport {\n // inline translations\n it,\n it_ja,\n it_zh,\n it_es,\n it_fr,\n it_de,\n en_ja,\n en_zh,\n en_es,\n en_fr,\n en_de,\n ja_zh,\n ja_es,\n zh_es,\n getLocale,\n setLocale,\n // key-based translations (i18n compatible)\n t,\n loadDictionaries,\n loadDictionary,\n clearDictionaries,\n hasTranslation,\n getLoadedLocales,\n getDictionary,\n // types\n type Locale,\n type Translations,\n type TranslationVars,\n type Dictionary,\n type Dictionaries,\n type PluralRules,\n} from 'inline-i18n-multi'\n","import { useState, useCallback, useMemo, useEffect, type ReactNode } from 'react'\nimport { setLocale as setCoreLocale, type Locale } from 'inline-i18n-multi'\nimport { LocaleContext } from './context'\n\ninterface LocaleProviderProps {\n /**\n * Initial locale value\n */\n locale: Locale\n /**\n * Cookie name for persisting locale (default: NEXT_LOCALE)\n * Set to false to disable cookie sync\n */\n cookieName?: string | false\n /**\n * Callback when locale changes\n */\n onLocaleChange?: (locale: Locale) => void\n children: ReactNode\n}\n\nfunction setCookie(name: string, value: string, days = 365): void {\n if (typeof document === 'undefined') return\n const expires = new Date(Date.now() + days * 864e5).toUTCString()\n document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`\n}\n\nexport function LocaleProvider({\n locale: initialLocale,\n cookieName = 'NEXT_LOCALE',\n onLocaleChange,\n children,\n}: LocaleProviderProps) {\n const [locale, setLocaleState] = useState<Locale>(initialLocale)\n\n // sync with core package on mount and locale change\n useEffect(() => {\n setCoreLocale(locale)\n }, [locale])\n\n const setLocale = useCallback(\n (newLocale: Locale) => {\n setLocaleState(newLocale)\n setCoreLocale(newLocale)\n\n // sync cookie for Next.js middleware\n if (cookieName) {\n setCookie(cookieName, newLocale)\n }\n\n // callback for custom handling\n onLocaleChange?.(newLocale)\n },\n [cookieName, onLocaleChange]\n )\n\n const value = useMemo(() => ({ locale, setLocale }), [locale, setLocale])\n\n return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>\n}\n","import { createContext, useContext } from 'react'\nimport type { Locale } from 'inline-i18n-multi'\n\ninterface LocaleContextValue {\n locale: Locale\n setLocale: (locale: Locale) => void\n}\n\nexport const LocaleContext = createContext<LocaleContextValue | null>(null)\n\nexport function useLocaleContext(): LocaleContextValue {\n const context = useContext(LocaleContext)\n\n if (!context) {\n throw new Error('useLocaleContext must be used within a LocaleProvider')\n }\n\n return context\n}\n","import { useCallback } from 'react'\nimport { useLocaleContext } from './context'\nimport { t as coreT } from 'inline-i18n-multi'\nimport type { Locale, TranslationVars } from 'inline-i18n-multi'\n\n/**\n * Get current locale and setter\n */\nexport function useLocale(): [Locale, (locale: Locale) => void] {\n const { locale, setLocale } = useLocaleContext()\n return [locale, setLocale]\n}\n\n/**\n * Get translation function bound to current locale\n * @example\n * const t = useT()\n * t('greeting.hello') // uses context locale\n * t('items.count', { count: 5 })\n */\nexport function useT(): (key: string, vars?: TranslationVars) => string {\n const { locale } = useLocaleContext()\n\n return useCallback(\n (key: string, vars?: TranslationVars) => coreT(key, vars, locale),\n [locale]\n )\n}\n","import { it, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ninterface TPropsShorthand {\n /**\n * Korean text\n */\n ko: string\n /**\n * English text\n */\n en: string\n translations?: never\n}\n\ninterface TPropsObject {\n ko?: never\n en?: never\n /**\n * Translation map with locale keys\n */\n translations: Translations\n}\n\ntype TProps = (TPropsShorthand | TPropsObject) & TranslationVars\n\n/**\n * Translation component for JSX\n * @example <T ko=\"안녕\" en=\"Hello\" />\n * @example <T translations={{ ko: '안녕', en: 'Hello', ja: 'こんにちは' }} />\n * @example <T ko=\"안녕 {name}\" en=\"Hello {name}\" name=\"철수\" />\n */\nexport function T(props: TProps) {\n const { ko, en, translations, ...vars } = props\n\n if (translations) {\n return <>{it(translations, vars)}</>\n }\n\n if (ko !== undefined && en !== undefined) {\n return <>{it(ko, en, vars)}</>\n }\n\n throw new Error('T component requires either \"translations\" or both \"ko\" and \"en\" props')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAA0E;AAC1E,+BAAwD;;;ACDxD,mBAA0C;AAQnC,IAAM,oBAAgB,4BAAyC,IAAI;AAEnE,SAAS,mBAAuC;AACrD,QAAM,cAAU,yBAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEA,SAAO;AACT;;;ADwCS;AArCT,SAAS,UAAU,MAAc,OAAe,OAAO,KAAW;AAChE,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,EAAE,YAAY;AAChE,WAAS,SAAS,GAAG,IAAI,IAAI,KAAK,aAAa,OAAO;AACxD;AAEO,SAAS,eAAe;AAAA,EAC7B,QAAQ;AAAA,EACR,aAAa;AAAA,EACb;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,CAAC,QAAQ,cAAc,QAAI,wBAAiB,aAAa;AAG/D,+BAAU,MAAM;AACd,iCAAAC,WAAc,MAAM;AAAA,EACtB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAMC,iBAAY;AAAA,IAChB,CAAC,cAAsB;AACrB,qBAAe,SAAS;AACxB,mCAAAD,WAAc,SAAS;AAGvB,UAAI,YAAY;AACd,kBAAU,YAAY,SAAS;AAAA,MACjC;AAGA,uBAAiB,SAAS;AAAA,IAC5B;AAAA,IACA,CAAC,YAAY,cAAc;AAAA,EAC7B;AAEA,QAAM,YAAQ,uBAAQ,OAAO,EAAE,QAAQ,WAAAC,WAAU,IAAI,CAAC,QAAQA,UAAS,CAAC;AAExE,SAAO,4CAAC,cAAc,UAAd,EAAuB,OAAe,UAAS;AACzD;;;AE3DA,IAAAC,gBAA4B;AAE5B,IAAAC,4BAA2B;AAMpB,SAAS,YAAgD;AAC9D,QAAM,EAAE,QAAQ,WAAAC,WAAU,IAAI,iBAAiB;AAC/C,SAAO,CAAC,QAAQA,UAAS;AAC3B;AASO,SAAS,OAAwD;AACtE,QAAM,EAAE,OAAO,IAAI,iBAAiB;AAEpC,aAAO;AAAA,IACL,CAAC,KAAa,aAA2B,0BAAAC,GAAM,KAAK,MAAM,MAAM;AAAA,IAChE,CAAC,MAAM;AAAA,EACT;AACF;;;AC3BA,IAAAC,4BAA4D;AAmCjD,IAAAC,sBAAA;AAJJ,SAAS,EAAE,OAAe;AAC/B,QAAM,EAAE,IAAI,IAAI,cAAc,GAAG,KAAK,IAAI;AAE1C,MAAI,cAAc;AAChB,WAAO,6EAAG,4CAAG,cAAc,IAAI,GAAE;AAAA,EACnC;AAEA,MAAI,OAAO,UAAa,OAAO,QAAW;AACxC,WAAO,6EAAG,4CAAG,IAAI,IAAI,IAAI,GAAE;AAAA,EAC7B;AAEA,QAAM,IAAI,MAAM,wEAAwE;AAC1F;;;AJtCA,IAAAC,4BAiCO;","names":["import_react","setCoreLocale","setLocale","import_react","import_inline_i18n_multi","setLocale","coreT","import_inline_i18n_multi","import_jsx_runtime","import_inline_i18n_multi"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/context.tsx","../src/hooks.ts","../src/component.tsx","../src/richtext.tsx"],"sourcesContent":["export { LocaleProvider } from './provider'\nexport { useLocale, useT, useLoadDictionaries, useDetectedLocale } from './hooks'\nexport { T } from './component'\nexport { RichText, useRichText } from './richtext'\n\n// re-export from core for convenience\nexport {\n // inline translations\n it,\n it_ja,\n it_zh,\n it_es,\n it_fr,\n it_de,\n en_ja,\n en_zh,\n en_es,\n en_fr,\n en_de,\n ja_zh,\n ja_es,\n zh_es,\n getLocale,\n setLocale,\n // key-based translations (i18n compatible)\n t,\n loadDictionaries,\n loadDictionary,\n clearDictionaries,\n hasTranslation,\n getLoadedLocales,\n getDictionary,\n loadAsync,\n isLoaded,\n // configuration\n configure,\n getConfig,\n resetConfig,\n // rich text parsing\n parseRichText,\n type RichTextSegment,\n // custom formatters (v0.6.0)\n registerFormatter,\n clearFormatters,\n type CustomFormatter,\n // locale detection (v0.6.0)\n detectLocale,\n type DetectLocaleOptions,\n type DetectSource,\n // types\n type Locale,\n type Translations,\n type TranslationVars,\n type Dictionary,\n type Dictionaries,\n type PluralRules,\n} from 'inline-i18n-multi'\n","import { useState, useCallback, useMemo, useEffect, type ReactNode } from 'react'\nimport { setLocale as setCoreLocale, type Locale } from 'inline-i18n-multi'\nimport { LocaleContext } from './context'\n\ninterface LocaleProviderProps {\n /**\n * Initial locale value\n */\n locale: Locale\n /**\n * Cookie name for persisting locale (default: NEXT_LOCALE)\n * Set to false to disable cookie sync\n */\n cookieName?: string | false\n /**\n * Callback when locale changes\n */\n onLocaleChange?: (locale: Locale) => void\n children: ReactNode\n}\n\nfunction setCookie(name: string, value: string, days = 365): void {\n if (typeof document === 'undefined') return\n const expires = new Date(Date.now() + days * 864e5).toUTCString()\n document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`\n}\n\nexport function LocaleProvider({\n locale: initialLocale,\n cookieName = 'NEXT_LOCALE',\n onLocaleChange,\n children,\n}: LocaleProviderProps) {\n const [locale, setLocaleState] = useState<Locale>(initialLocale)\n\n // sync with core package on mount and locale change\n useEffect(() => {\n setCoreLocale(locale)\n }, [locale])\n\n const setLocale = useCallback(\n (newLocale: Locale) => {\n setLocaleState(newLocale)\n setCoreLocale(newLocale)\n\n // sync cookie for Next.js middleware\n if (cookieName) {\n setCookie(cookieName, newLocale)\n }\n\n // callback for custom handling\n onLocaleChange?.(newLocale)\n },\n [cookieName, onLocaleChange]\n )\n\n const value = useMemo(() => ({ locale, setLocale }), [locale, setLocale])\n\n return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>\n}\n","import { createContext, useContext } from 'react'\nimport type { Locale } from 'inline-i18n-multi'\n\ninterface LocaleContextValue {\n locale: Locale\n setLocale: (locale: Locale) => void\n}\n\nexport const LocaleContext = createContext<LocaleContextValue | null>(null)\n\nexport function useLocaleContext(): LocaleContextValue {\n const context = useContext(LocaleContext)\n\n if (!context) {\n throw new Error('useLocaleContext must be used within a LocaleProvider')\n }\n\n return context\n}\n","import { useCallback, useState, useEffect } from 'react'\nimport { useLocaleContext } from './context'\nimport { t as coreT, loadAsync, isLoaded, detectLocale, setLocale } from 'inline-i18n-multi'\nimport type { Locale, TranslationVars, DetectLocaleOptions } from 'inline-i18n-multi'\n\n/**\n * Get current locale and setter\n */\nexport function useLocale(): [Locale, (locale: Locale) => void] {\n const { locale, setLocale } = useLocaleContext()\n return [locale, setLocale]\n}\n\n/**\n * Get translation function bound to current locale\n * @example\n * const t = useT()\n * t('greeting.hello') // uses context locale\n * t('items.count', { count: 5 })\n */\nexport function useT(): (key: string, vars?: TranslationVars) => string {\n const { locale } = useLocaleContext()\n\n return useCallback(\n (key: string, vars?: TranslationVars) => coreT(key, vars, locale),\n [locale]\n )\n}\n\n/**\n * Hook for lazy loading dictionaries\n * Automatically loads dictionaries when locale or namespace changes\n *\n * @example\n * function Dashboard() {\n * const { isLoading, error } = useLoadDictionaries('ko', 'dashboard')\n * if (isLoading) return <Spinner />\n * if (error) return <Error message={error.message} />\n * return <Content />\n * }\n */\nexport function useLoadDictionaries(\n locale: Locale,\n namespace?: string\n): { isLoading: boolean; error: Error | null } {\n const [isLoading, setIsLoading] = useState(() => !isLoaded(locale, namespace))\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n if (isLoaded(locale, namespace)) {\n setIsLoading(false)\n setError(null)\n return\n }\n\n setIsLoading(true)\n setError(null)\n\n loadAsync(locale, namespace)\n .then(() => setIsLoading(false))\n .catch((err) => {\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n })\n }, [locale, namespace])\n\n return { isLoading, error }\n}\n\n/**\n * Hook that auto-detects and sets locale on mount\n *\n * @example\n * function App() {\n * useDetectedLocale({\n * supportedLocales: ['en', 'ko', 'ja'],\n * defaultLocale: 'en',\n * sources: ['cookie', 'navigator'],\n * })\n * return <Content />\n * }\n */\nexport function useDetectedLocale(options: DetectLocaleOptions): void {\n const { setLocale: setContextLocale } = useLocaleContext()\n\n useEffect(() => {\n const detected = detectLocale(options)\n setLocale(detected)\n setContextLocale(detected)\n // Run once on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n","import { it, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ninterface TPropsShorthand {\n /**\n * Korean text\n */\n ko: string\n /**\n * English text\n */\n en: string\n translations?: never\n}\n\ninterface TPropsObject {\n ko?: never\n en?: never\n /**\n * Translation map with locale keys\n */\n translations: Translations\n}\n\ntype TProps = (TPropsShorthand | TPropsObject) & TranslationVars\n\n/**\n * Translation component for JSX\n * @example <T ko=\"안녕\" en=\"Hello\" />\n * @example <T translations={{ ko: '안녕', en: 'Hello', ja: 'こんにちは' }} />\n * @example <T ko=\"안녕 {name}\" en=\"Hello {name}\" name=\"철수\" />\n */\nexport function T(props: TProps) {\n const { ko, en, translations, ...vars } = props\n\n if (translations) {\n return <>{it(translations, vars)}</>\n }\n\n if (ko !== undefined && en !== undefined) {\n return <>{it(ko, en, vars)}</>\n }\n\n throw new Error('T component requires either \"translations\" or both \"ko\" and \"en\" props')\n}\n","import React, { type ReactNode, useMemo, useCallback, Fragment } from 'react'\nimport { it, parseRichText, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ntype ComponentRenderer = (text: string) => ReactNode\n\ninterface RichTextProps {\n /**\n * Translation map with locale keys\n * Tags like <link>text</link> will be matched to component renderers\n */\n translations: Translations\n /**\n * Component renderers for each tag name\n * @example { link: (text) => <a href=\"/terms\">{text}</a> }\n */\n components: Record<string, ComponentRenderer>\n /**\n * Variables for interpolation (applied before rich text parsing)\n */\n vars?: TranslationVars\n}\n\n/**\n * Rich text translation component\n * Supports embedding React components within translations\n *\n * @example\n * <RichText\n * translations={{\n * en: 'Read <link>terms</link> and <bold>agree</bold>',\n * ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요'\n * }}\n * components={{\n * link: (text) => <a href=\"/terms\">{text}</a>,\n * bold: (text) => <strong>{text}</strong>\n * }}\n * />\n */\nexport function RichText({ translations, components, vars }: RichTextProps): React.JSX.Element {\n const componentNames = useMemo(() => Object.keys(components), [components])\n\n // Resolve locale and interpolate variables ({curly} braces)\n // Rich text tags (<angle> brackets) don't conflict with variable interpolation\n const resolved = it(translations, vars)\n const segments = parseRichText(resolved, componentNames)\n\n return (\n <>\n {segments.map((segment, index) => {\n if (segment.type === 'text') {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n const renderer = components[segment.componentName!]\n if (!renderer) {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n return <Fragment key={index}>{renderer(segment.content)}</Fragment>\n })}\n </>\n )\n}\n\n/**\n * Hook for rich text translations\n * Returns a function that resolves translations with component interpolation\n *\n * @example\n * const richT = useRichText({\n * link: (text) => <a href=\"/terms\">{text}</a>,\n * bold: (text) => <strong>{text}</strong>,\n * })\n * return richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })\n */\nexport function useRichText(\n components: Record<string, ComponentRenderer>\n): (translations: Translations, vars?: TranslationVars) => ReactNode {\n const componentNames = useMemo(() => Object.keys(components), [components])\n\n return useCallback(\n (translations: Translations, vars?: TranslationVars): ReactNode => {\n const resolved = it(translations, vars)\n const segments = parseRichText(resolved, componentNames)\n\n return (\n <>\n {segments.map((segment, index) => {\n if (segment.type === 'text') {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n const renderer = components[segment.componentName!]\n if (!renderer) {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n return <Fragment key={index}>{renderer(segment.content)}</Fragment>\n })}\n </>\n )\n },\n [components, componentNames]\n )\n}\n"],"mappings":"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","names":["import_react","setCoreLocale","setLocale","import_react","import_inline_i18n_multi","setLocale","coreT","import_inline_i18n_multi","import_jsx_runtime","import_react","import_inline_i18n_multi","import_jsx_runtime","import_inline_i18n_multi"]}
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ function LocaleProvider({
32
32
  useEffect(() => {
33
33
  setCoreLocale(locale);
34
34
  }, [locale]);
35
- const setLocale2 = useCallback(
35
+ const setLocale3 = useCallback(
36
36
  (newLocale) => {
37
37
  setLocaleState(newLocale);
38
38
  setCoreLocale(newLocale);
@@ -43,16 +43,16 @@ function LocaleProvider({
43
43
  },
44
44
  [cookieName, onLocaleChange]
45
45
  );
46
- const value = useMemo(() => ({ locale, setLocale: setLocale2 }), [locale, setLocale2]);
46
+ const value = useMemo(() => ({ locale, setLocale: setLocale3 }), [locale, setLocale3]);
47
47
  return /* @__PURE__ */ jsx(LocaleContext.Provider, { value, children });
48
48
  }
49
49
 
50
50
  // src/hooks.ts
51
- import { useCallback as useCallback2 } from "react";
52
- import { t as coreT } from "inline-i18n-multi";
51
+ import { useCallback as useCallback2, useState as useState2, useEffect as useEffect2 } from "react";
52
+ import { t as coreT, loadAsync, isLoaded, detectLocale, setLocale } from "inline-i18n-multi";
53
53
  function useLocale() {
54
- const { locale, setLocale: setLocale2 } = useLocaleContext();
55
- return [locale, setLocale2];
54
+ const { locale, setLocale: setLocale3 } = useLocaleContext();
55
+ return [locale, setLocale3];
56
56
  }
57
57
  function useT() {
58
58
  const { locale } = useLocaleContext();
@@ -61,6 +61,32 @@ function useT() {
61
61
  [locale]
62
62
  );
63
63
  }
64
+ function useLoadDictionaries(locale, namespace) {
65
+ const [isLoading, setIsLoading] = useState2(() => !isLoaded(locale, namespace));
66
+ const [error, setError] = useState2(null);
67
+ useEffect2(() => {
68
+ if (isLoaded(locale, namespace)) {
69
+ setIsLoading(false);
70
+ setError(null);
71
+ return;
72
+ }
73
+ setIsLoading(true);
74
+ setError(null);
75
+ loadAsync(locale, namespace).then(() => setIsLoading(false)).catch((err) => {
76
+ setError(err instanceof Error ? err : new Error(String(err)));
77
+ setIsLoading(false);
78
+ });
79
+ }, [locale, namespace]);
80
+ return { isLoading, error };
81
+ }
82
+ function useDetectedLocale(options) {
83
+ const { setLocale: setContextLocale } = useLocaleContext();
84
+ useEffect2(() => {
85
+ const detected = detectLocale(options);
86
+ setLocale(detected);
87
+ setContextLocale(detected);
88
+ }, []);
89
+ }
64
90
 
65
91
  // src/component.tsx
66
92
  import { it } from "inline-i18n-multi";
@@ -76,9 +102,49 @@ function T(props) {
76
102
  throw new Error('T component requires either "translations" or both "ko" and "en" props');
77
103
  }
78
104
 
105
+ // src/richtext.tsx
106
+ import { useMemo as useMemo2, useCallback as useCallback3, Fragment as Fragment2 } from "react";
107
+ import { it as it2, parseRichText } from "inline-i18n-multi";
108
+ import { Fragment as Fragment3, jsx as jsx3 } from "react/jsx-runtime";
109
+ function RichText({ translations, components, vars }) {
110
+ const componentNames = useMemo2(() => Object.keys(components), [components]);
111
+ const resolved = it2(translations, vars);
112
+ const segments = parseRichText(resolved, componentNames);
113
+ return /* @__PURE__ */ jsx3(Fragment3, { children: segments.map((segment, index) => {
114
+ if (segment.type === "text") {
115
+ return /* @__PURE__ */ jsx3(Fragment2, { children: segment.content }, index);
116
+ }
117
+ const renderer = components[segment.componentName];
118
+ if (!renderer) {
119
+ return /* @__PURE__ */ jsx3(Fragment2, { children: segment.content }, index);
120
+ }
121
+ return /* @__PURE__ */ jsx3(Fragment2, { children: renderer(segment.content) }, index);
122
+ }) });
123
+ }
124
+ function useRichText(components) {
125
+ const componentNames = useMemo2(() => Object.keys(components), [components]);
126
+ return useCallback3(
127
+ (translations, vars) => {
128
+ const resolved = it2(translations, vars);
129
+ const segments = parseRichText(resolved, componentNames);
130
+ return /* @__PURE__ */ jsx3(Fragment3, { children: segments.map((segment, index) => {
131
+ if (segment.type === "text") {
132
+ return /* @__PURE__ */ jsx3(Fragment2, { children: segment.content }, index);
133
+ }
134
+ const renderer = components[segment.componentName];
135
+ if (!renderer) {
136
+ return /* @__PURE__ */ jsx3(Fragment2, { children: segment.content }, index);
137
+ }
138
+ return /* @__PURE__ */ jsx3(Fragment2, { children: renderer(segment.content) }, index);
139
+ }) });
140
+ },
141
+ [components, componentNames]
142
+ );
143
+ }
144
+
79
145
  // src/index.ts
80
146
  import {
81
- it as it2,
147
+ it as it3,
82
148
  it_ja,
83
149
  it_zh,
84
150
  it_es,
@@ -93,29 +159,44 @@ import {
93
159
  ja_es,
94
160
  zh_es,
95
161
  getLocale,
96
- setLocale,
162
+ setLocale as setLocale2,
97
163
  t,
98
164
  loadDictionaries,
99
165
  loadDictionary,
100
166
  clearDictionaries,
101
167
  hasTranslation,
102
168
  getLoadedLocales,
103
- getDictionary
169
+ getDictionary,
170
+ loadAsync as loadAsync2,
171
+ isLoaded as isLoaded2,
172
+ configure,
173
+ getConfig,
174
+ resetConfig,
175
+ parseRichText as parseRichText2,
176
+ registerFormatter,
177
+ clearFormatters,
178
+ detectLocale as detectLocale2
104
179
  } from "inline-i18n-multi";
105
180
  export {
106
181
  LocaleProvider,
182
+ RichText,
107
183
  T,
108
184
  clearDictionaries,
185
+ clearFormatters,
186
+ configure,
187
+ detectLocale2 as detectLocale,
109
188
  en_de,
110
189
  en_es,
111
190
  en_fr,
112
191
  en_ja,
113
192
  en_zh,
193
+ getConfig,
114
194
  getDictionary,
115
195
  getLoadedLocales,
116
196
  getLocale,
117
197
  hasTranslation,
118
- it2 as it,
198
+ isLoaded2 as isLoaded,
199
+ it3 as it,
119
200
  it_de,
120
201
  it_es,
121
202
  it_fr,
@@ -123,11 +204,18 @@ export {
123
204
  it_zh,
124
205
  ja_es,
125
206
  ja_zh,
207
+ loadAsync2 as loadAsync,
126
208
  loadDictionaries,
127
209
  loadDictionary,
128
- setLocale,
210
+ parseRichText2 as parseRichText,
211
+ registerFormatter,
212
+ resetConfig,
213
+ setLocale2 as setLocale,
129
214
  t,
215
+ useDetectedLocale,
216
+ useLoadDictionaries,
130
217
  useLocale,
218
+ useRichText,
131
219
  useT,
132
220
  zh_es
133
221
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/context.tsx","../src/hooks.ts","../src/component.tsx","../src/index.ts"],"sourcesContent":["import { useState, useCallback, useMemo, useEffect, type ReactNode } from 'react'\nimport { setLocale as setCoreLocale, type Locale } from 'inline-i18n-multi'\nimport { LocaleContext } from './context'\n\ninterface LocaleProviderProps {\n /**\n * Initial locale value\n */\n locale: Locale\n /**\n * Cookie name for persisting locale (default: NEXT_LOCALE)\n * Set to false to disable cookie sync\n */\n cookieName?: string | false\n /**\n * Callback when locale changes\n */\n onLocaleChange?: (locale: Locale) => void\n children: ReactNode\n}\n\nfunction setCookie(name: string, value: string, days = 365): void {\n if (typeof document === 'undefined') return\n const expires = new Date(Date.now() + days * 864e5).toUTCString()\n document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`\n}\n\nexport function LocaleProvider({\n locale: initialLocale,\n cookieName = 'NEXT_LOCALE',\n onLocaleChange,\n children,\n}: LocaleProviderProps) {\n const [locale, setLocaleState] = useState<Locale>(initialLocale)\n\n // sync with core package on mount and locale change\n useEffect(() => {\n setCoreLocale(locale)\n }, [locale])\n\n const setLocale = useCallback(\n (newLocale: Locale) => {\n setLocaleState(newLocale)\n setCoreLocale(newLocale)\n\n // sync cookie for Next.js middleware\n if (cookieName) {\n setCookie(cookieName, newLocale)\n }\n\n // callback for custom handling\n onLocaleChange?.(newLocale)\n },\n [cookieName, onLocaleChange]\n )\n\n const value = useMemo(() => ({ locale, setLocale }), [locale, setLocale])\n\n return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>\n}\n","import { createContext, useContext } from 'react'\nimport type { Locale } from 'inline-i18n-multi'\n\ninterface LocaleContextValue {\n locale: Locale\n setLocale: (locale: Locale) => void\n}\n\nexport const LocaleContext = createContext<LocaleContextValue | null>(null)\n\nexport function useLocaleContext(): LocaleContextValue {\n const context = useContext(LocaleContext)\n\n if (!context) {\n throw new Error('useLocaleContext must be used within a LocaleProvider')\n }\n\n return context\n}\n","import { useCallback } from 'react'\nimport { useLocaleContext } from './context'\nimport { t as coreT } from 'inline-i18n-multi'\nimport type { Locale, TranslationVars } from 'inline-i18n-multi'\n\n/**\n * Get current locale and setter\n */\nexport function useLocale(): [Locale, (locale: Locale) => void] {\n const { locale, setLocale } = useLocaleContext()\n return [locale, setLocale]\n}\n\n/**\n * Get translation function bound to current locale\n * @example\n * const t = useT()\n * t('greeting.hello') // uses context locale\n * t('items.count', { count: 5 })\n */\nexport function useT(): (key: string, vars?: TranslationVars) => string {\n const { locale } = useLocaleContext()\n\n return useCallback(\n (key: string, vars?: TranslationVars) => coreT(key, vars, locale),\n [locale]\n )\n}\n","import { it, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ninterface TPropsShorthand {\n /**\n * Korean text\n */\n ko: string\n /**\n * English text\n */\n en: string\n translations?: never\n}\n\ninterface TPropsObject {\n ko?: never\n en?: never\n /**\n * Translation map with locale keys\n */\n translations: Translations\n}\n\ntype TProps = (TPropsShorthand | TPropsObject) & TranslationVars\n\n/**\n * Translation component for JSX\n * @example <T ko=\"안녕\" en=\"Hello\" />\n * @example <T translations={{ ko: '안녕', en: 'Hello', ja: 'こんにちは' }} />\n * @example <T ko=\"안녕 {name}\" en=\"Hello {name}\" name=\"철수\" />\n */\nexport function T(props: TProps) {\n const { ko, en, translations, ...vars } = props\n\n if (translations) {\n return <>{it(translations, vars)}</>\n }\n\n if (ko !== undefined && en !== undefined) {\n return <>{it(ko, en, vars)}</>\n }\n\n throw new Error('T component requires either \"translations\" or both \"ko\" and \"en\" props')\n}\n","export { LocaleProvider } from './provider'\nexport { useLocale, useT } from './hooks'\nexport { T } from './component'\n\n// re-export from core for convenience\nexport {\n // inline translations\n it,\n it_ja,\n it_zh,\n it_es,\n it_fr,\n it_de,\n en_ja,\n en_zh,\n en_es,\n en_fr,\n en_de,\n ja_zh,\n ja_es,\n zh_es,\n getLocale,\n setLocale,\n // key-based translations (i18n compatible)\n t,\n loadDictionaries,\n loadDictionary,\n clearDictionaries,\n hasTranslation,\n getLoadedLocales,\n getDictionary,\n // types\n type Locale,\n type Translations,\n type TranslationVars,\n type Dictionary,\n type Dictionaries,\n type PluralRules,\n} from 'inline-i18n-multi'\n"],"mappings":";;;AAAA,SAAS,UAAU,aAAa,SAAS,iBAAiC;AAC1E,SAAS,aAAa,qBAAkC;;;ACDxD,SAAS,eAAe,kBAAkB;AAQnC,IAAM,gBAAgB,cAAyC,IAAI;AAEnE,SAAS,mBAAuC;AACrD,QAAM,UAAU,WAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEA,SAAO;AACT;;;ADwCS;AArCT,SAAS,UAAU,MAAc,OAAe,OAAO,KAAW;AAChE,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,EAAE,YAAY;AAChE,WAAS,SAAS,GAAG,IAAI,IAAI,KAAK,aAAa,OAAO;AACxD;AAEO,SAAS,eAAe;AAAA,EAC7B,QAAQ;AAAA,EACR,aAAa;AAAA,EACb;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,CAAC,QAAQ,cAAc,IAAI,SAAiB,aAAa;AAG/D,YAAU,MAAM;AACd,kBAAc,MAAM;AAAA,EACtB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAMA,aAAY;AAAA,IAChB,CAAC,cAAsB;AACrB,qBAAe,SAAS;AACxB,oBAAc,SAAS;AAGvB,UAAI,YAAY;AACd,kBAAU,YAAY,SAAS;AAAA,MACjC;AAGA,uBAAiB,SAAS;AAAA,IAC5B;AAAA,IACA,CAAC,YAAY,cAAc;AAAA,EAC7B;AAEA,QAAM,QAAQ,QAAQ,OAAO,EAAE,QAAQ,WAAAA,WAAU,IAAI,CAAC,QAAQA,UAAS,CAAC;AAExE,SAAO,oBAAC,cAAc,UAAd,EAAuB,OAAe,UAAS;AACzD;;;AE3DA,SAAS,eAAAC,oBAAmB;AAE5B,SAAS,KAAK,aAAa;AAMpB,SAAS,YAAgD;AAC9D,QAAM,EAAE,QAAQ,WAAAC,WAAU,IAAI,iBAAiB;AAC/C,SAAO,CAAC,QAAQA,UAAS;AAC3B;AASO,SAAS,OAAwD;AACtE,QAAM,EAAE,OAAO,IAAI,iBAAiB;AAEpC,SAAOC;AAAA,IACL,CAAC,KAAa,SAA2B,MAAM,KAAK,MAAM,MAAM;AAAA,IAChE,CAAC,MAAM;AAAA,EACT;AACF;;;AC3BA,SAAS,UAAmD;AAmCjD,0BAAAC,YAAA;AAJJ,SAAS,EAAE,OAAe;AAC/B,QAAM,EAAE,IAAI,IAAI,cAAc,GAAG,KAAK,IAAI;AAE1C,MAAI,cAAc;AAChB,WAAO,gBAAAA,KAAA,YAAG,aAAG,cAAc,IAAI,GAAE;AAAA,EACnC;AAEA,MAAI,OAAO,UAAa,OAAO,QAAW;AACxC,WAAO,gBAAAA,KAAA,YAAG,aAAG,IAAI,IAAI,IAAI,GAAE;AAAA,EAC7B;AAEA,QAAM,IAAI,MAAM,wEAAwE;AAC1F;;;ACtCA;AAAA,EAEE,MAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;","names":["setLocale","useCallback","setLocale","useCallback","jsx","it"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/context.tsx","../src/hooks.ts","../src/component.tsx","../src/richtext.tsx","../src/index.ts"],"sourcesContent":["import { useState, useCallback, useMemo, useEffect, type ReactNode } from 'react'\nimport { setLocale as setCoreLocale, type Locale } from 'inline-i18n-multi'\nimport { LocaleContext } from './context'\n\ninterface LocaleProviderProps {\n /**\n * Initial locale value\n */\n locale: Locale\n /**\n * Cookie name for persisting locale (default: NEXT_LOCALE)\n * Set to false to disable cookie sync\n */\n cookieName?: string | false\n /**\n * Callback when locale changes\n */\n onLocaleChange?: (locale: Locale) => void\n children: ReactNode\n}\n\nfunction setCookie(name: string, value: string, days = 365): void {\n if (typeof document === 'undefined') return\n const expires = new Date(Date.now() + days * 864e5).toUTCString()\n document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`\n}\n\nexport function LocaleProvider({\n locale: initialLocale,\n cookieName = 'NEXT_LOCALE',\n onLocaleChange,\n children,\n}: LocaleProviderProps) {\n const [locale, setLocaleState] = useState<Locale>(initialLocale)\n\n // sync with core package on mount and locale change\n useEffect(() => {\n setCoreLocale(locale)\n }, [locale])\n\n const setLocale = useCallback(\n (newLocale: Locale) => {\n setLocaleState(newLocale)\n setCoreLocale(newLocale)\n\n // sync cookie for Next.js middleware\n if (cookieName) {\n setCookie(cookieName, newLocale)\n }\n\n // callback for custom handling\n onLocaleChange?.(newLocale)\n },\n [cookieName, onLocaleChange]\n )\n\n const value = useMemo(() => ({ locale, setLocale }), [locale, setLocale])\n\n return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>\n}\n","import { createContext, useContext } from 'react'\nimport type { Locale } from 'inline-i18n-multi'\n\ninterface LocaleContextValue {\n locale: Locale\n setLocale: (locale: Locale) => void\n}\n\nexport const LocaleContext = createContext<LocaleContextValue | null>(null)\n\nexport function useLocaleContext(): LocaleContextValue {\n const context = useContext(LocaleContext)\n\n if (!context) {\n throw new Error('useLocaleContext must be used within a LocaleProvider')\n }\n\n return context\n}\n","import { useCallback, useState, useEffect } from 'react'\nimport { useLocaleContext } from './context'\nimport { t as coreT, loadAsync, isLoaded, detectLocale, setLocale } from 'inline-i18n-multi'\nimport type { Locale, TranslationVars, DetectLocaleOptions } from 'inline-i18n-multi'\n\n/**\n * Get current locale and setter\n */\nexport function useLocale(): [Locale, (locale: Locale) => void] {\n const { locale, setLocale } = useLocaleContext()\n return [locale, setLocale]\n}\n\n/**\n * Get translation function bound to current locale\n * @example\n * const t = useT()\n * t('greeting.hello') // uses context locale\n * t('items.count', { count: 5 })\n */\nexport function useT(): (key: string, vars?: TranslationVars) => string {\n const { locale } = useLocaleContext()\n\n return useCallback(\n (key: string, vars?: TranslationVars) => coreT(key, vars, locale),\n [locale]\n )\n}\n\n/**\n * Hook for lazy loading dictionaries\n * Automatically loads dictionaries when locale or namespace changes\n *\n * @example\n * function Dashboard() {\n * const { isLoading, error } = useLoadDictionaries('ko', 'dashboard')\n * if (isLoading) return <Spinner />\n * if (error) return <Error message={error.message} />\n * return <Content />\n * }\n */\nexport function useLoadDictionaries(\n locale: Locale,\n namespace?: string\n): { isLoading: boolean; error: Error | null } {\n const [isLoading, setIsLoading] = useState(() => !isLoaded(locale, namespace))\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n if (isLoaded(locale, namespace)) {\n setIsLoading(false)\n setError(null)\n return\n }\n\n setIsLoading(true)\n setError(null)\n\n loadAsync(locale, namespace)\n .then(() => setIsLoading(false))\n .catch((err) => {\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n })\n }, [locale, namespace])\n\n return { isLoading, error }\n}\n\n/**\n * Hook that auto-detects and sets locale on mount\n *\n * @example\n * function App() {\n * useDetectedLocale({\n * supportedLocales: ['en', 'ko', 'ja'],\n * defaultLocale: 'en',\n * sources: ['cookie', 'navigator'],\n * })\n * return <Content />\n * }\n */\nexport function useDetectedLocale(options: DetectLocaleOptions): void {\n const { setLocale: setContextLocale } = useLocaleContext()\n\n useEffect(() => {\n const detected = detectLocale(options)\n setLocale(detected)\n setContextLocale(detected)\n // Run once on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n","import { it, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ninterface TPropsShorthand {\n /**\n * Korean text\n */\n ko: string\n /**\n * English text\n */\n en: string\n translations?: never\n}\n\ninterface TPropsObject {\n ko?: never\n en?: never\n /**\n * Translation map with locale keys\n */\n translations: Translations\n}\n\ntype TProps = (TPropsShorthand | TPropsObject) & TranslationVars\n\n/**\n * Translation component for JSX\n * @example <T ko=\"안녕\" en=\"Hello\" />\n * @example <T translations={{ ko: '안녕', en: 'Hello', ja: 'こんにちは' }} />\n * @example <T ko=\"안녕 {name}\" en=\"Hello {name}\" name=\"철수\" />\n */\nexport function T(props: TProps) {\n const { ko, en, translations, ...vars } = props\n\n if (translations) {\n return <>{it(translations, vars)}</>\n }\n\n if (ko !== undefined && en !== undefined) {\n return <>{it(ko, en, vars)}</>\n }\n\n throw new Error('T component requires either \"translations\" or both \"ko\" and \"en\" props')\n}\n","import React, { type ReactNode, useMemo, useCallback, Fragment } from 'react'\nimport { it, parseRichText, type Translations, type TranslationVars } from 'inline-i18n-multi'\n\ntype ComponentRenderer = (text: string) => ReactNode\n\ninterface RichTextProps {\n /**\n * Translation map with locale keys\n * Tags like <link>text</link> will be matched to component renderers\n */\n translations: Translations\n /**\n * Component renderers for each tag name\n * @example { link: (text) => <a href=\"/terms\">{text}</a> }\n */\n components: Record<string, ComponentRenderer>\n /**\n * Variables for interpolation (applied before rich text parsing)\n */\n vars?: TranslationVars\n}\n\n/**\n * Rich text translation component\n * Supports embedding React components within translations\n *\n * @example\n * <RichText\n * translations={{\n * en: 'Read <link>terms</link> and <bold>agree</bold>',\n * ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요'\n * }}\n * components={{\n * link: (text) => <a href=\"/terms\">{text}</a>,\n * bold: (text) => <strong>{text}</strong>\n * }}\n * />\n */\nexport function RichText({ translations, components, vars }: RichTextProps): React.JSX.Element {\n const componentNames = useMemo(() => Object.keys(components), [components])\n\n // Resolve locale and interpolate variables ({curly} braces)\n // Rich text tags (<angle> brackets) don't conflict with variable interpolation\n const resolved = it(translations, vars)\n const segments = parseRichText(resolved, componentNames)\n\n return (\n <>\n {segments.map((segment, index) => {\n if (segment.type === 'text') {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n const renderer = components[segment.componentName!]\n if (!renderer) {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n return <Fragment key={index}>{renderer(segment.content)}</Fragment>\n })}\n </>\n )\n}\n\n/**\n * Hook for rich text translations\n * Returns a function that resolves translations with component interpolation\n *\n * @example\n * const richT = useRichText({\n * link: (text) => <a href=\"/terms\">{text}</a>,\n * bold: (text) => <strong>{text}</strong>,\n * })\n * return richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })\n */\nexport function useRichText(\n components: Record<string, ComponentRenderer>\n): (translations: Translations, vars?: TranslationVars) => ReactNode {\n const componentNames = useMemo(() => Object.keys(components), [components])\n\n return useCallback(\n (translations: Translations, vars?: TranslationVars): ReactNode => {\n const resolved = it(translations, vars)\n const segments = parseRichText(resolved, componentNames)\n\n return (\n <>\n {segments.map((segment, index) => {\n if (segment.type === 'text') {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n const renderer = components[segment.componentName!]\n if (!renderer) {\n return <Fragment key={index}>{segment.content}</Fragment>\n }\n return <Fragment key={index}>{renderer(segment.content)}</Fragment>\n })}\n </>\n )\n },\n [components, componentNames]\n )\n}\n","export { LocaleProvider } from './provider'\nexport { useLocale, useT, useLoadDictionaries, useDetectedLocale } from './hooks'\nexport { T } from './component'\nexport { RichText, useRichText } from './richtext'\n\n// re-export from core for convenience\nexport {\n // inline translations\n it,\n it_ja,\n it_zh,\n it_es,\n it_fr,\n it_de,\n en_ja,\n en_zh,\n en_es,\n en_fr,\n en_de,\n ja_zh,\n ja_es,\n zh_es,\n getLocale,\n setLocale,\n // key-based translations (i18n compatible)\n t,\n loadDictionaries,\n loadDictionary,\n clearDictionaries,\n hasTranslation,\n getLoadedLocales,\n getDictionary,\n loadAsync,\n isLoaded,\n // configuration\n configure,\n getConfig,\n resetConfig,\n // rich text parsing\n parseRichText,\n type RichTextSegment,\n // custom formatters (v0.6.0)\n registerFormatter,\n clearFormatters,\n type CustomFormatter,\n // locale detection (v0.6.0)\n detectLocale,\n type DetectLocaleOptions,\n type DetectSource,\n // types\n type Locale,\n type Translations,\n type TranslationVars,\n type Dictionary,\n type Dictionaries,\n type PluralRules,\n} from 'inline-i18n-multi'\n"],"mappings":"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","names":["setLocale","useCallback","useState","useEffect","setLocale","useCallback","useState","useEffect","jsx","useMemo","useCallback","Fragment","it","jsx","it","setLocale","loadAsync","isLoaded","parseRichText","detectLocale"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inline-i18n-multi-react",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "React integration for inline-i18n-multi",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -34,7 +34,7 @@
34
34
  "react": "^18.0.0 || ^19.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "inline-i18n-multi": "0.4.0"
37
+ "inline-i18n-multi": "0.6.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/react": "^19.0.2",