@fluenti/react 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +244 -0
  3. package/dist/__tests__/DateTime.test.d.ts +2 -0
  4. package/dist/__tests__/DateTime.test.d.ts.map +1 -0
  5. package/dist/__tests__/Number.test.d.ts +2 -0
  6. package/dist/__tests__/Number.test.d.ts.map +1 -0
  7. package/dist/__tests__/Plural.test.d.ts +2 -0
  8. package/dist/__tests__/Plural.test.d.ts.map +1 -0
  9. package/dist/__tests__/Select.test.d.ts +2 -0
  10. package/dist/__tests__/Select.test.d.ts.map +1 -0
  11. package/dist/__tests__/Trans.test.d.ts +2 -0
  12. package/dist/__tests__/Trans.test.d.ts.map +1 -0
  13. package/dist/__tests__/locale-switch.test.d.ts +2 -0
  14. package/dist/__tests__/locale-switch.test.d.ts.map +1 -0
  15. package/dist/__tests__/plural-core.test.d.ts +2 -0
  16. package/dist/__tests__/plural-core.test.d.ts.map +1 -0
  17. package/dist/__tests__/provider.test.d.ts +2 -0
  18. package/dist/__tests__/provider.test.d.ts.map +1 -0
  19. package/dist/__tests__/server.test.d.ts +2 -0
  20. package/dist/__tests__/server.test.d.ts.map +1 -0
  21. package/dist/__tests__/trans-core.test.d.ts +2 -0
  22. package/dist/__tests__/trans-core.test.d.ts.map +1 -0
  23. package/dist/compile-time-t.d.ts +3 -0
  24. package/dist/compile-time-t.d.ts.map +1 -0
  25. package/dist/components/DateTime.d.ts +16 -0
  26. package/dist/components/DateTime.d.ts.map +1 -0
  27. package/dist/components/Number.d.ts +16 -0
  28. package/dist/components/Number.d.ts.map +1 -0
  29. package/dist/components/Plural.d.ts +35 -0
  30. package/dist/components/Plural.d.ts.map +1 -0
  31. package/dist/components/Select.d.ts +32 -0
  32. package/dist/components/Select.d.ts.map +1 -0
  33. package/dist/components/Trans.d.ts +29 -0
  34. package/dist/components/Trans.d.ts.map +1 -0
  35. package/dist/components/icu-rich.d.ts +22 -0
  36. package/dist/components/icu-rich.d.ts.map +1 -0
  37. package/dist/components/plural-core.d.ts +15 -0
  38. package/dist/components/plural-core.d.ts.map +1 -0
  39. package/dist/components/trans-core.d.ts +28 -0
  40. package/dist/components/trans-core.d.ts.map +1 -0
  41. package/dist/context.d.ts +3 -0
  42. package/dist/context.d.ts.map +1 -0
  43. package/dist/global-registry.d.ts +18 -0
  44. package/dist/global-registry.d.ts.map +1 -0
  45. package/dist/hooks/__useI18n.d.ts +12 -0
  46. package/dist/hooks/__useI18n.d.ts.map +1 -0
  47. package/dist/hooks/useI18n.d.ts +11 -0
  48. package/dist/hooks/useI18n.d.ts.map +1 -0
  49. package/dist/icu-rich-DBeWY1k6.js +108 -0
  50. package/dist/icu-rich-DBeWY1k6.js.map +1 -0
  51. package/dist/icu-rich-XY1SdM5K.cjs +2 -0
  52. package/dist/icu-rich-XY1SdM5K.cjs.map +1 -0
  53. package/dist/index.cjs +3 -0
  54. package/dist/index.cjs.map +1 -0
  55. package/dist/index.d.ts +17 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +200 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/msg.d.ts +2 -0
  60. package/dist/msg.d.ts.map +1 -0
  61. package/dist/provider.d.ts +3 -0
  62. package/dist/provider.d.ts.map +1 -0
  63. package/dist/server.cjs +2 -0
  64. package/dist/server.cjs.map +1 -0
  65. package/dist/server.d.ts +240 -0
  66. package/dist/server.d.ts.map +1 -0
  67. package/dist/server.js +122 -0
  68. package/dist/server.js.map +1 -0
  69. package/dist/types.d.ts +55 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/package.json +82 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fluenti Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # @fluenti/react
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@fluenti/react?color=4f46e5&label=npm)](https://www.npmjs.com/package/@fluenti/react)
4
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@fluenti/react?color=16a34a&label=size)](https://bundlephobia.com/package/@fluenti/react)
5
+ [![license](https://img.shields.io/npm/l/@fluenti/react?color=64748b)](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
6
+
7
+ **Compile-time i18n for React.** Zero runtime parsing. RSC-ready. React 19 compatible.
8
+
9
+ Fluenti compiles your translations at build time so your production bundle ships pre-resolved messages instead of an ICU parser. The result: smaller bundles, faster renders, and a DX that feels native to React.
10
+
11
+ ---
12
+
13
+ ## Features
14
+
15
+ - **Zero runtime parsing** -- ICU MessageFormat compiled away at build time
16
+ - **React Server Components** -- first-class RSC support via `@fluenti/react/server`
17
+ - **Streaming SSR & Suspense** -- works with `React.Suspense` and streamed responses out of the box
18
+ - **React 19 compatible** -- tested against React 19, works with 18+
19
+ - **Tagged template literals** -- write `t`\`Hello, {name}!\`` directly in JSX
20
+ - **Rich text components** -- `<Trans>`, `<Plural>`, `<Select>`, `<DateTime>`, `<NumberFormat>`
21
+ - **Lazy loading** -- load locale catalogs on demand with dynamic imports
22
+ - **Type-safe** -- full TypeScript support with strict types
23
+
24
+ ---
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Install
29
+
30
+ ```bash
31
+ pnpm add @fluenti/core @fluenti/react
32
+ pnpm add -D @fluenti/cli @fluenti/vite-plugin
33
+ ```
34
+
35
+ ### 2. Configure Vite
36
+
37
+ ```ts
38
+ // vite.config.ts
39
+ import react from '@vitejs/plugin-react'
40
+ import fluenti from '@fluenti/vite-plugin'
41
+
42
+ export default {
43
+ plugins: [
44
+ fluenti({ framework: 'react' }),
45
+ react(),
46
+ ],
47
+ }
48
+ ```
49
+
50
+ ### 3. Wrap your app with `I18nProvider`
51
+
52
+ ```tsx
53
+ import { I18nProvider } from '@fluenti/react'
54
+ import en from './locales/compiled/en'
55
+
56
+ function App() {
57
+ return (
58
+ <I18nProvider
59
+ locale="en"
60
+ fallbackLocale="en"
61
+ messages={{ en }}
62
+ loadMessages={(locale) => import(`./locales/compiled/${locale}.js`)}
63
+ >
64
+ <MyApp />
65
+ </I18nProvider>
66
+ )
67
+ }
68
+ ```
69
+
70
+ ### 4. Translate
71
+
72
+ ```tsx
73
+ import { t, useI18n, Trans, Plural, Select } from '@fluenti/react'
74
+
75
+ function Dashboard() {
76
+ const { d, n, locale, setLocale } = useI18n()
77
+ const name = 'Alice'
78
+
79
+ return (
80
+ <div>
81
+ {/* Compile-time tagged template */}
82
+ <h1>{t`Welcome back, ${name}!`}</h1>
83
+
84
+ {/* Rich text with embedded components */}
85
+ <Trans>Read the <a href="/docs">documentation</a></Trans>
86
+
87
+ {/* Locale-aware pluralization */}
88
+ <Plural value={count} one="# item in cart" other="# items in cart" />
89
+
90
+ {/* Gender / categorical selection */}
91
+ <Select value={role} admin="Full access" editor="Edit access" other="Read only" />
92
+
93
+ {/* Date & number formatting */}
94
+ <p>{d(new Date(), 'long')}</p>
95
+ <p>{n(9999.99, 'currency')}</p>
96
+
97
+ {/* Switch locale at runtime */}
98
+ <button onClick={() => setLocale('ja')}>日本語</button>
99
+ </div>
100
+ )
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Compile-Time Transform
107
+
108
+ Fluenti transforms your source code at build time. What you write:
109
+
110
+ ```tsx
111
+ <Trans>Read the <a href="/docs">documentation</a></Trans>
112
+ ```
113
+
114
+ What ships to production:
115
+
116
+ ```tsx
117
+ // Pre-resolved message, no parser needed at runtime
118
+ <>Read the <a href="/docs">ドキュメント</a></>
119
+ ```
120
+
121
+ The ICU parser is a dev dependency only -- it never reaches your users.
122
+
123
+ ## Direct-Import `t`
124
+
125
+ `import { t } from '@fluenti/react'` is Fluenti's primary compile-time API.
126
+
127
+ It supports:
128
+
129
+ - `` t`Hello ${name}` ``
130
+ - `t({ message: 'Hello {name}', context: 'hero' }, { name })`
131
+
132
+ It does not support ID lookup. For `t('message.id')`, locale switching, formatting helpers, or other imperative runtime APIs, use `useI18n()`.
133
+
134
+ ---
135
+
136
+ ## React Server Components (RSC)
137
+
138
+ For Next.js App Router and other RSC-capable frameworks, use `@fluenti/react/server`:
139
+
140
+ ```ts
141
+ // lib/i18n.server.ts
142
+ import { createServerI18n } from '@fluenti/react/server'
143
+
144
+ export const { setLocale, getI18n, Trans, Plural, DateTime, NumberFormat } =
145
+ createServerI18n({
146
+ loadMessages: (locale) => import(`../locales/compiled/${locale}.js`),
147
+ fallbackLocale: 'en',
148
+ resolveLocale: async () => {
149
+ const { cookies } = await import('next/headers')
150
+ return (await cookies()).get('locale')?.value ?? 'en'
151
+ },
152
+ })
153
+ ```
154
+
155
+ ```tsx
156
+ // app/layout.tsx -- set locale once per request
157
+ import { setLocale } from '@/lib/i18n.server'
158
+
159
+ export default async function Layout({ params, children }) {
160
+ const { locale } = await params
161
+ setLocale(locale)
162
+ return <html lang={locale}><body>{children}</body></html>
163
+ }
164
+ ```
165
+
166
+ ```tsx
167
+ // app/page.tsx -- use components directly, no prop drilling
168
+ import { Trans, Plural, DateTime, NumberFormat } from '@/lib/i18n.server'
169
+
170
+ export default async function Page() {
171
+ return (
172
+ <div>
173
+ <Trans>Read the <a href="/docs">documentation</a>.</Trans>
174
+ <Plural value={5} one="# item" other="# items" />
175
+ <DateTime value={new Date()} style="long" />
176
+ <NumberFormat value={1234.56} />
177
+ </div>
178
+ )
179
+ }
180
+ ```
181
+
182
+ Server components are async and use `React.cache()` for request-scoped state -- no Context needed. The API mirrors client components exactly.
183
+
184
+ ---
185
+
186
+ ## API Reference
187
+
188
+ ### Components
189
+
190
+ | Component | Description |
191
+ |-----------|-------------|
192
+ | `I18nProvider` | Provides i18n context to the component tree |
193
+ | `Trans` | Rich text with embedded component interpolation |
194
+ | `Plural` | Locale-aware pluralization via `Intl.PluralRules` |
195
+ | `Select` | Categorical value selection (gender, role, status) |
196
+ | `DateTime` | Date formatting via `Intl.DateTimeFormat` |
197
+ | `NumberFormat` | Number formatting via `Intl.NumberFormat` |
198
+
199
+ ### Hooks
200
+
201
+ | Hook | Returns |
202
+ |------|---------|
203
+ | `useI18n()` | `{ t, d, n, format, loadMessages, getLocales, i18n, locale, setLocale, ... }` |
204
+
205
+ `useI18n().t` remains the full runtime API for ID lookup, descriptor lookup, and imperative usage. Convenience methods `d()`, `n()`, `format()`, `loadMessages()`, `getLocales()` are also available directly. The `i18n` object is retained as an escape hatch.
206
+
207
+ ### Server API (`@fluenti/react/server`)
208
+
209
+ | Export | Description |
210
+ |--------|-------------|
211
+ | `createServerI18n(config)` | Create request-scoped i18n for RSC |
212
+ | `setLocale(locale)` | Set locale for the current request |
213
+ | `getI18n()` | Get the i18n instance (async) |
214
+ | `Trans`, `Plural`, `DateTime`, `NumberFormat` | Async server components |
215
+
216
+ ### Utilities
217
+
218
+ | Export | Entry point | Description |
219
+ |--------|-------------|-------------|
220
+ | `msg` | `@fluenti/react` | Tag for lazy message definitions outside the component tree |
221
+ | `detectLocale(options)` | `@fluenti/react/server` | SSR locale detection (cookie, query, path, headers) |
222
+ | `getSSRLocaleScript()` | `@fluenti/react/server` | Inline `<script>` for hydration without flash |
223
+ | `isRTL(locale)` | `@fluenti/react/server` | Check if a locale is right-to-left |
224
+
225
+ ---
226
+
227
+ ## Framework Compatibility
228
+
229
+ Works with any React-based framework:
230
+
231
+ - **React SPA** (Vite)
232
+ - **Next.js** (App Router + Pages Router)
233
+ - **React Router** / Remix
234
+ - **TanStack Start**
235
+
236
+ ---
237
+
238
+ ## Documentation
239
+
240
+ Full docs, guides, and examples at [fluenti.dev](https://fluenti.dev).
241
+
242
+ ## License
243
+
244
+ [MIT](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=DateTime.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateTime.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/DateTime.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Number.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Number.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/Number.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Plural.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plural.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/Plural.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Select.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/Select.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Trans.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Trans.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/Trans.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=locale-switch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-switch.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/locale-switch.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plural-core.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plural-core.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plural-core.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/provider.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/server.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=trans-core.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trans-core.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/trans-core.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { CompileTimeT } from '@fluenti/core';
2
+ export declare const t: CompileTimeT;
3
+ //# sourceMappingURL=compile-time-t.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-time-t.d.ts","sourceRoot":"","sources":["../src/compile-time-t.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,eAAO,MAAM,CAAC,EAAE,YAME,CAAA"}
@@ -0,0 +1,16 @@
1
+ export interface DateTimeProps {
2
+ /** Date value to format */
3
+ value: Date | number;
4
+ /** Named format style */
5
+ style?: string;
6
+ }
7
+ /**
8
+ * `<DateTime>` — formatting component using Intl APIs.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <DateTime value={new Date()} style="long" />
13
+ * ```
14
+ */
15
+ export declare function DateTime({ value, style }: DateTimeProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=DateTime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateTime.d.ts","sourceRoot":"","sources":["../../src/components/DateTime.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,KAAK,EAAE,IAAI,GAAG,MAAM,CAAA;IACpB,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,aAAa,2CAMvD"}
@@ -0,0 +1,16 @@
1
+ export interface NumberProps {
2
+ /** Number value to format */
3
+ value: number;
4
+ /** Named format style */
5
+ style?: string;
6
+ }
7
+ /**
8
+ * `<Number>` — number formatting component using Intl APIs.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <Number value={1234.56} style="currency" />
13
+ * ```
14
+ */
15
+ export declare function NumberFormat({ value, style }: NumberProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=Number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Number.d.ts","sourceRoot":"","sources":["../../src/components/Number.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,WAAW,2CAMzD"}
@@ -0,0 +1,35 @@
1
+ import { ReactNode } from 'react';
2
+ export interface PluralProps {
3
+ /** The count value */
4
+ value: number;
5
+ /** Override the auto-generated synthetic ICU message id */
6
+ id?: string;
7
+ /** Message context used for identity and translator disambiguation */
8
+ context?: string;
9
+ /** Translator-facing note preserved in extraction catalogs */
10
+ comment?: string;
11
+ /** Text for zero (if language supports) */
12
+ zero?: ReactNode;
13
+ /** Singular form. `#` replaced with value */
14
+ one?: ReactNode;
15
+ /** Dual form (Arabic, etc.) */
16
+ two?: ReactNode;
17
+ /** Few form (Slavic languages, etc.) */
18
+ few?: ReactNode;
19
+ /** Many form */
20
+ many?: ReactNode;
21
+ /** Default plural form */
22
+ other: ReactNode;
23
+ /** Offset from value before selecting form */
24
+ offset?: number;
25
+ }
26
+ /**
27
+ * `<Plural>` — ICU plural handling as a component.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <Plural value={count} zero="No messages" one="# message" other="# messages" />
32
+ * ```
33
+ */
34
+ export declare const Plural: import('react').NamedExoticComponent<PluralProps>;
35
+ //# sourceMappingURL=Plural.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plural.d.ts","sourceRoot":"","sources":["../../src/components/Plural.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMxD,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,+BAA+B;IAC/B,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,wCAAwC;IACxC,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,0BAA0B;IAC1B,KAAK,EAAE,SAAS,CAAA;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,mDA+CjB,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from 'react';
2
+ export interface SelectProps {
3
+ /** The selector value */
4
+ value: string;
5
+ /** Override the auto-generated synthetic ICU message id */
6
+ id?: string;
7
+ /** Message context used for identity and translator disambiguation */
8
+ context?: string;
9
+ /** Translator-facing note preserved in extraction catalogs */
10
+ comment?: string;
11
+ /** Default case */
12
+ other: ReactNode;
13
+ /** Type-safe named options. Takes precedence over direct case props. */
14
+ options?: Record<string, ReactNode>;
15
+ /** Named cases — any string key maps to a ReactNode */
16
+ [key: string]: ReactNode | Record<string, ReactNode> | undefined;
17
+ }
18
+ /**
19
+ * `<Select>` — ICU select for gender, role, or other categorical values.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <Select
24
+ * value={gender}
25
+ * male="He liked your post"
26
+ * female="She liked your post"
27
+ * other="They liked your post"
28
+ * />
29
+ * ```
30
+ */
31
+ export declare function Select(props: SelectProps): import("react/jsx-runtime").JSX.Element;
32
+ //# sourceMappingURL=Select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/components/Select.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAKlD,MAAM,WAAW,WAAW;IAC1B,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,KAAK,EAAE,SAAS,CAAA;IAChB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACnC,uDAAuD;IACvD,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAAA;CACjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,2CAyCxC"}
@@ -0,0 +1,29 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ export interface TransProps {
3
+ /** Source text with embedded components */
4
+ children: ReactNode;
5
+ /** Override auto-generated hash ID */
6
+ id?: string;
7
+ /** Message context used for identity and translator disambiguation */
8
+ context?: string;
9
+ /** Context comment for translators */
10
+ comment?: string;
11
+ /** Custom render wrapper */
12
+ render?: (translation: ReactNode) => ReactNode;
13
+ /** @internal Pre-computed message ID from build plugin */
14
+ __id?: string;
15
+ /** @internal Pre-computed ICU message from build plugin */
16
+ __message?: string;
17
+ /** @internal Pre-computed component list from build plugin */
18
+ __components?: ReactElement[];
19
+ }
20
+ /**
21
+ * `<Trans>` component for rich-text translations containing nested React elements.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <Trans>Read the <a href="/docs">documentation</a> for more info.</Trans>
26
+ * ```
27
+ */
28
+ export declare const Trans: import('react').NamedExoticComponent<TransProps>;
29
+ //# sourceMappingURL=Trans.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Trans.d.ts","sourceRoot":"","sources":["../../src/components/Trans.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAId,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,QAAQ,EAAE,SAAS,CAAA;IACnB,sCAAsC;IACtC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,KAAK,SAAS,CAAA;IAC9C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,YAAY,EAAE,CAAA;CAC9B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,kDAwChB,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { MessageDescriptor } from '@fluenti/core';
2
+ import { ReactElement, ReactNode } from 'react';
3
+ import { PluralCategory } from './plural-core';
4
+ export interface RichMessagePart {
5
+ message: string;
6
+ components: ReactElement[];
7
+ }
8
+ export declare function buildICUPluralMessage(forms: Partial<Record<PluralCategory, string>> & {
9
+ other: string;
10
+ }, offset?: number): string;
11
+ export declare function buildICUSelectMessage(forms: Record<string, string>): string;
12
+ export declare function normalizeSelectForms(forms: Record<string, string>): {
13
+ forms: Record<string, string>;
14
+ valueMap: Record<string, string>;
15
+ };
16
+ export declare function serializeRichNode(node: ReactNode): RichMessagePart;
17
+ export declare function serializeRichForms<T extends string>(keys: readonly T[], forms: Partial<Record<T, ReactNode>> & Record<string, ReactNode | undefined>): {
18
+ messages: Partial<Record<T, string>> & Record<string, string>;
19
+ components: ReactElement[];
20
+ };
21
+ export declare function renderRichTranslation(descriptor: MessageDescriptor, values: Record<string, unknown> | undefined, translate: (descriptor: MessageDescriptor, values?: Record<string, unknown>) => string, components: ReactElement[]): ReactNode;
22
+ //# sourceMappingURL=icu-rich.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icu-rich.d.ts","sourceRoot":"","sources":["../../src/components/icu-rich.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAEtE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,YAAY,EAAE,CAAA;CAC3B;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAClE,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CASR;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,MAAM,CAGR;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B;IACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CAqBA;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,CAMlE;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EACjD,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC,GAC3E;IACD,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7D,UAAU,EAAE,YAAY,EAAE,CAAA;CAC3B,CAoBA;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,iBAAiB,EAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,SAAS,EAAE,CAAC,UAAU,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,EACtF,UAAU,EAAE,YAAY,EAAE,GACzB,SAAS,CAGX"}
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ export declare const PLURAL_CATEGORIES: readonly ["zero", "one", "two", "few", "many", "other"];
3
+ export type PluralCategory = (typeof PLURAL_CATEGORIES)[number];
4
+ /**
5
+ * Resolve which plural category to use.
6
+ * Checks for exact =0 match first, then falls back to CLDR rules.
7
+ * @internal
8
+ */
9
+ export declare function resolveCategory(value: number, locale: string, available: Record<string, boolean>): PluralCategory;
10
+ /**
11
+ * Replace `#` with the formatted value in a ReactNode.
12
+ * @internal
13
+ */
14
+ export declare function replaceHash(node: ReactNode, formatted: string): ReactNode;
15
+ //# sourceMappingURL=plural-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plural-core.d.ts","sourceRoot":"","sources":["../../src/components/plural-core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,eAAO,MAAM,iBAAiB,yDAA0D,CAAA;AACxF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/D;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,cAAc,CAKhB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAKzE"}
@@ -0,0 +1,28 @@
1
+ import { ReactNode, ReactElement } from 'react';
2
+ import { hashMessage } from '@fluenti/core';
3
+ export { hashMessage };
4
+ /**
5
+ * Extract a message string and component list from React children.
6
+ *
7
+ * Converts:
8
+ * <Trans>Hello <b>{name}</b>, welcome!</Trans>
9
+ * Into:
10
+ * message: "Hello <0>{name}</0>, welcome!"
11
+ * components: [<b>{name}</b>]
12
+ *
13
+ * @internal
14
+ */
15
+ export declare function extractMessage(children: ReactNode): {
16
+ message: string;
17
+ components: ReactElement[];
18
+ };
19
+ export declare function offsetIndices(message: string, offset: number): string;
20
+ /**
21
+ * Reconstruct a translated message string back into React elements.
22
+ *
23
+ * Parses "<0>content</0>" tags and replaces them with cloned components.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare function reconstruct(translated: string, components: ReactElement[]): ReactNode;
28
+ //# sourceMappingURL=trans-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trans-core.d.ts","sourceRoot":"","sources":["../../src/components/trans-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,GAAG;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,YAAY,EAAE,CAAA;CAC3B,CAwBA;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,YAAY,EAAE,GACzB,SAAS,CAqCX"}
@@ -0,0 +1,3 @@
1
+ import { I18nContextValue } from './types';
2
+ export declare const I18nContext: import('react').Context<I18nContextValue | null>;
3
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,eAAO,MAAM,WAAW,kDAA+C,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { FluentInstanceExtended } from '@fluenti/core';
2
+ /**
3
+ * Global i18n instance registry.
4
+ *
5
+ * Used by `@fluenti/next` webpack loader and `@fluenti/vite-plugin` to access
6
+ * the i18n instance from module-level code via a Proxy. The instance is set by
7
+ * `<I18nProvider>` on mount.
8
+ */
9
+ declare global {
10
+ var __fluenti_i18n: FluentInstanceExtended | undefined;
11
+ }
12
+ /** Get the global i18n instance (set by `<I18nProvider>`). */
13
+ export declare function getGlobalI18n(): FluentInstanceExtended | undefined;
14
+ /** Set the global i18n instance. Called by `<I18nProvider>` on mount. */
15
+ export declare function setGlobalI18n(instance: FluentInstanceExtended): void;
16
+ /** Clear the global i18n instance. Primarily for testing. */
17
+ export declare function clearGlobalI18n(): void;
18
+ //# sourceMappingURL=global-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-registry.d.ts","sourceRoot":"","sources":["../src/global-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAE3D;;;;;;GAMG;AAEH,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,cAAc,EAAE,sBAAsB,GAAG,SAAS,CAAA;CACvD;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,IAAI,sBAAsB,GAAG,SAAS,CAElE;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAEpE;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,12 @@
1
+ import { FluentInstanceExtended } from '../types';
2
+ /**
3
+ * Internal hook used by the Vite plugin's compiled output.
4
+ * Returns the i18n instance for direct t() calls.
5
+ *
6
+ * **Not part of the public API.** Users never write this — the Vite plugin
7
+ * generates imports of this hook automatically.
8
+ *
9
+ * @internal
10
+ */
11
+ export declare function __useI18n(): FluentInstanceExtended;
12
+ //# sourceMappingURL=__useI18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"__useI18n.d.ts","sourceRoot":"","sources":["../../src/hooks/__useI18n.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAEtD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,IAAI,sBAAsB,CASlD"}