@fluenti/next 0.2.1 → 0.3.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/llms-full.txt ADDED
@@ -0,0 +1,122 @@
1
+ # @fluenti/next
2
+
3
+ > Next.js integration for Fluenti — `withFluenti()`, strict compile-time transforms, and generated server runtime helpers.
4
+
5
+ @fluenti/next integrates Fluenti into Next.js projects. Its job is to:
6
+
7
+ - wrap `next.config` with `withFluenti()`
8
+ - install the Fluenti loader
9
+ - generate the internal server runtime module consumed as `@fluenti/next`
10
+ - keep Next authoring aligned with the main React authoring surface
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add @fluenti/core @fluenti/react @fluenti/next
16
+ ```
17
+
18
+ ## Main public entry
19
+
20
+ ```ts
21
+ import { withFluenti } from '@fluenti/next'
22
+
23
+ export default withFluenti()({
24
+ reactStrictMode: true,
25
+ })
26
+ ```
27
+
28
+ ### `withFluenti(config?)`
29
+
30
+ Supports:
31
+
32
+ - `withFluenti(fluentiConfig?)(nextConfig)`
33
+ - `withFluenti(nextConfig)`
34
+
35
+ Public config fields:
36
+
37
+ - `locales`
38
+ - `defaultLocale`
39
+ - `compiledDir`
40
+ - `serverModule`
41
+ - `serverModuleOutDir`
42
+ - `resolveLocale`
43
+ - `dateFormats`
44
+ - `numberFormats`
45
+ - `fallbackChain`
46
+
47
+ ## Authoring model in Next
48
+
49
+ In a `withFluenti()` project, the recommended authoring surface is:
50
+
51
+ ```tsx
52
+ // ✅ Preferred: compile-time authoring surface
53
+ import { t, Trans, Plural, Select, DateTime, NumberFormat } from '@fluenti/react'
54
+ ```
55
+
56
+ This applies to both client and server authoring.
57
+
58
+ For runtime and integration concerns, use the generated module:
59
+
60
+ ```ts
61
+ import { I18nProvider, getI18n, setLocale } from '@fluenti/next'
62
+ ```
63
+
64
+ ### Important boundaries
65
+
66
+ - imported `t` is compile-time only — ✅ this is the preferred API
67
+ - client and server authoring should stay on `@fluenti/react`
68
+ - server runtime access should use `await getI18n()` — ⚠️ runtime fallback for dynamic keys
69
+ - direct-import server `t` requires an async server scope
70
+
71
+ ## What `withFluenti()` does
72
+
73
+ 1. resolves Fluenti config from `fluenti.config.ts` and explicit overrides
74
+ 2. generates a server module under the configured output directory
75
+ 3. aliases that generated module as `@fluenti/next`
76
+ 4. runs the loader on app code so official authoring APIs are transformed correctly
77
+
78
+ ## Generated runtime module
79
+
80
+ `@fluenti/next` is not a hand-authored package entry. It is a generated module created by `withFluenti()`.
81
+
82
+ It provides:
83
+
84
+ - `I18nProvider`
85
+ - `setLocale`
86
+ - `getI18n`
87
+ - compile-time `t` stub
88
+ - server-side `Trans`
89
+ - server-side `Plural`
90
+ - server-side `Select`
91
+ - server-side `DateTime`
92
+ - server-side `NumberFormat`
93
+
94
+ ### `I18nProvider`
95
+
96
+ Use in root layouts to initialize server and client runtime state.
97
+
98
+ ### `getI18n()`
99
+
100
+ Use in server components, route handlers, metadata functions, and server actions when you need the full runtime API.
101
+
102
+ ### `setLocale()`
103
+
104
+ Sets the request locale for the generated server runtime.
105
+
106
+ ## Public package subpaths
107
+
108
+ - `@fluenti/next` — config wrapper and types
109
+ - `@fluenti/next/server` — server-side helpers exported by the package itself
110
+ - `@fluenti/next/provider` — provider-related types/helpers
111
+ - `@fluenti/next/client` — client-side type declarations
112
+
113
+ `@fluenti/next` is created per project by `withFluenti()`.
114
+
115
+ ## Relationship to `@fluenti/react`
116
+
117
+ `@fluenti/next` builds on `@fluenti/react`.
118
+
119
+ - authoring surface: `@fluenti/react`
120
+ - Next-specific runtime integration: `@fluenti/next` + generated module
121
+
122
+ This keeps the main mental model aligned across React SPA, Vite, and Next.
@@ -0,0 +1,262 @@
1
+ # Migrating to @fluenti/next from next-intl / next-i18next
2
+
3
+ > Step-by-step guide to migrate a Next.js app from next-intl or next-i18next to Fluenti.
4
+
5
+ ## Overview
6
+
7
+ Fluenti is a **compile-time** i18n library — translations are compiled to optimized JS at build time. next-intl and next-i18next are runtime libraries. Fluenti's Next.js plugin provides webpack loader integration, React Server Component support, and zero-overhead compiled messages.
8
+
9
+ Key differences:
10
+ - Compile-time compilation vs runtime message parsing
11
+ - ICU MessageFormat (same as next-intl, different from next-i18next)
12
+ - Webpack loader for build-time `t` tag transforms
13
+ - PO or JSON catalogs managed by CLI
14
+ - RSC-native with server and client component support
15
+
16
+ ---
17
+
18
+ ## Migrating from next-intl
19
+
20
+ ### 1. Install Fluenti
21
+
22
+ ```bash
23
+ pnpm add @fluenti/core @fluenti/react @fluenti/next
24
+ pnpm add -D @fluenti/cli
25
+ ```
26
+
27
+ ### 2. Update Next.js config
28
+
29
+ Before (next-intl):
30
+ ```ts
31
+ // next.config.ts
32
+ import createNextIntlPlugin from 'next-intl/plugin'
33
+ const withNextIntl = createNextIntlPlugin()
34
+ export default withNextIntl({ /* next config */ })
35
+ ```
36
+
37
+ After (Fluenti):
38
+ ```ts
39
+ // next.config.ts
40
+ import { withFluenti } from '@fluenti/next'
41
+ export default withFluenti({ /* next config */ })
42
+ ```
43
+
44
+ ### 3. Replace provider
45
+
46
+ Before (next-intl):
47
+ ```tsx
48
+ // app/[locale]/layout.tsx
49
+ import { NextIntlClientProvider } from 'next-intl'
50
+ import { getMessages } from 'next-intl/server'
51
+
52
+ export default async function Layout({ children, params }) {
53
+ const messages = await getMessages()
54
+ return (
55
+ <NextIntlClientProvider messages={messages}>
56
+ {children}
57
+ </NextIntlClientProvider>
58
+ )
59
+ }
60
+ ```
61
+
62
+ After (Fluenti):
63
+ ```tsx
64
+ // app/[locale]/layout.tsx
65
+ import { I18nProvider } from '@fluenti/react'
66
+ import en from '@/locales/compiled/en'
67
+
68
+ export default function Layout({ children, params }) {
69
+ return (
70
+ <I18nProvider locale={params.locale} fallbackLocale="en" messages={{ en }}>
71
+ {children}
72
+ </I18nProvider>
73
+ )
74
+ }
75
+ ```
76
+
77
+ ### 4. Update usage in components
78
+
79
+ Before (next-intl):
80
+ ```tsx
81
+ import { useTranslations } from 'next-intl'
82
+ const t = useTranslations('namespace')
83
+ t('hello', { name: 'World' })
84
+ ```
85
+
86
+ After (Fluenti):
87
+ ```tsx
88
+ import { useI18n } from '@fluenti/react'
89
+ const { i18n } = useI18n()
90
+ i18n.t('hello', { name: 'World' })
91
+ ```
92
+
93
+ ### 5. Server components
94
+
95
+ Before (next-intl):
96
+ ```tsx
97
+ import { getTranslations } from 'next-intl/server'
98
+ const t = await getTranslations('namespace')
99
+ ```
100
+
101
+ After (Fluenti):
102
+ ```tsx
103
+ import { createServerI18n } from '@fluenti/react/server'
104
+ const i18n = createServerI18n({ locale: 'en', messages: { en } })
105
+ i18n.t('hello')
106
+ ```
107
+
108
+ ### API Mapping: next-intl → Fluenti
109
+
110
+ | next-intl | Fluenti |
111
+ |-----------|---------|
112
+ | `useTranslations()` | `useI18n()` |
113
+ | `t(key, values)` | `i18n.t(key, values)` |
114
+ | `t.rich(key, { bold: (text) => ... })` | `<Trans>` component |
115
+ | `useFormatter()` | `i18n.d()`, `i18n.n()` |
116
+ | `<NextIntlClientProvider>` | `<I18nProvider>` |
117
+ | `getTranslations()` (server) | `createServerI18n()` |
118
+ | `getMessages()` (server) | Import compiled messages directly |
119
+ | `createNextIntlPlugin()` | `withFluenti()` |
120
+ | Namespace-based `t('ns.key')` | Flat key `i18n.t('key')` |
121
+ | ICU MessageFormat | ICU MessageFormat (compatible) |
122
+
123
+ ---
124
+
125
+ ## Migrating from next-i18next
126
+
127
+ ### 1. Install Fluenti
128
+
129
+ ```bash
130
+ pnpm add @fluenti/core @fluenti/react @fluenti/next
131
+ pnpm add -D @fluenti/cli
132
+ ```
133
+
134
+ ### 2. Update Next.js config
135
+
136
+ Before (next-i18next):
137
+ ```ts
138
+ // next.config.js
139
+ const { i18n } = require('./next-i18next.config')
140
+ module.exports = { i18n }
141
+ ```
142
+
143
+ After (Fluenti):
144
+ ```ts
145
+ // next.config.ts
146
+ import { withFluenti } from '@fluenti/next'
147
+ export default withFluenti({})
148
+ ```
149
+
150
+ ### 3. Remove next-i18next.config.js
151
+
152
+ The old config file is no longer needed. Create a Fluenti config instead:
153
+
154
+ ```ts
155
+ // fluenti.config.ts
156
+ export default {
157
+ sourceLocale: 'en',
158
+ locales: ['en', 'ja'],
159
+ catalogDir: './locales',
160
+ format: 'po',
161
+ include: ['./src/**/*.{tsx,jsx,ts,js}', './app/**/*.{tsx,jsx,ts,js}'],
162
+ compileOutDir: './locales/compiled',
163
+ }
164
+ ```
165
+
166
+ ### 4. Replace serverSideTranslations
167
+
168
+ Before (next-i18next):
169
+ ```tsx
170
+ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
171
+
172
+ export async function getStaticProps({ locale }) {
173
+ return { props: { ...(await serverSideTranslations(locale, ['common'])) } }
174
+ }
175
+ ```
176
+
177
+ After (Fluenti — App Router):
178
+ ```tsx
179
+ // No getStaticProps needed — messages are compiled and imported directly
180
+ import { I18nProvider } from '@fluenti/react'
181
+ import en from '@/locales/compiled/en'
182
+ ```
183
+
184
+ ### 5. Update hook usage
185
+
186
+ Before (next-i18next):
187
+ ```tsx
188
+ import { useTranslation } from 'next-i18next'
189
+ const { t, i18n } = useTranslation('common')
190
+ t('hello', { name: 'World' })
191
+ ```
192
+
193
+ After (Fluenti):
194
+ ```tsx
195
+ import { useI18n } from '@fluenti/react'
196
+ const { i18n } = useI18n()
197
+ i18n.t('hello', { name: 'World' })
198
+ ```
199
+
200
+ ### 6. Convert message syntax
201
+
202
+ next-i18next interpolation → ICU:
203
+ ```
204
+ # next-i18next (i18next syntax)
205
+ "hello": "Hello, {{name}}!"
206
+ "items": "{{count}} item"
207
+ "items_plural": "{{count}} items"
208
+
209
+ # Fluenti (ICU MessageFormat)
210
+ "hello": "Hello, {name}!"
211
+ "items": "{count, plural, one {{count} item} other {{count} items}}"
212
+ ```
213
+
214
+ ### API Mapping: next-i18next → Fluenti
215
+
216
+ | next-i18next | Fluenti |
217
+ |--------------|---------|
218
+ | `useTranslation()` | `useI18n()` |
219
+ | `t(key, options)` | `i18n.t(key, values)` |
220
+ | `i18n.changeLanguage()` | `setLocale()` |
221
+ | `serverSideTranslations()` | Import compiled messages directly |
222
+ | `<Trans>` (react-i18next) | `<Trans>` (@fluenti/react) |
223
+ | `appWithTranslation()` HOC | `<I18nProvider>` |
224
+ | `next-i18next.config.js` | `fluenti.config.ts` |
225
+ | `{{var}}` interpolation | `{var}` interpolation |
226
+ | `_plural` suffix | ICU `{n, plural, ...}` |
227
+ | Namespaces | Flat message IDs |
228
+ | `/public/locales/` JSON files | PO/JSON catalogs in `./locales/` |
229
+
230
+ ---
231
+
232
+ ## Common Steps
233
+
234
+ ### Extract and compile catalogs
235
+
236
+ ```bash
237
+ npx fluenti extract # Extract messages from source
238
+ npx fluenti compile # Compile to JS modules
239
+ ```
240
+
241
+ ### Locale routing
242
+
243
+ For App Router, use `[locale]` dynamic segment in your route structure:
244
+
245
+ ```
246
+ app/
247
+ [locale]/
248
+ layout.tsx ← I18nProvider here
249
+ page.tsx
250
+ about/
251
+ page.tsx
252
+ ```
253
+
254
+ ## Key Behavioral Differences
255
+
256
+ 1. **Compile-time** — no runtime parser, messages are pre-compiled JS functions
257
+ 2. **No namespaces** — flat message IDs instead of namespace-based organization
258
+ 3. **No serverSideTranslations** — compiled messages imported directly, no serialization needed
259
+ 4. **ICU MessageFormat** — standard format for plurals, selects, formatting
260
+ 5. **PO file support** — compatible with Poedit, Crowdin, Weblate
261
+ 6. **Webpack loader** — transforms `t` tagged templates at build time
262
+ 7. **AI translation** — `npx fluenti translate --provider claude` for automated translation
package/llms.txt ADDED
@@ -0,0 +1,55 @@
1
+ # @fluenti/next
2
+
3
+ > Next.js integration for Fluenti — `withFluenti()`, strict compile-time transforms, and generated server runtime helpers.
4
+
5
+ `@fluenti/next` wires Fluenti into Next.js. In a `withFluenti()` project, the recommended authoring path is:
6
+
7
+ - client and server authoring: `import { t, Trans, Plural, Select, DateTime, NumberFormat } from '@fluenti/react'`
8
+ - Next runtime/integration: `I18nProvider`, `getI18n()`, and `setLocale()` from `@fluenti/next`
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @fluenti/core @fluenti/react @fluenti/next
14
+ ```
15
+
16
+ ## Main Exports
17
+
18
+ Main entry (`@fluenti/next`) — resolved at runtime to the generated server module:
19
+
20
+ - `withFluenti(config?)` — Next.js config wrapper (build-time only)
21
+ - `I18nProvider` — async server component for layouts
22
+ - `t` — compile-time authoring API
23
+ - `Trans`, `Plural`, `Select`, `DateTime`, `NumberFormat` — RSC components
24
+ - `getI18n()` — async server-side i18n instance access
25
+ - `setLocale(locale)` — set locale in the async local storage scope
26
+
27
+ Server entry (`@fluenti/next/server`):
28
+
29
+ - `withLocale(locale, fn)` — run a function with a specific locale in RSC context
30
+
31
+ Provider entry (`@fluenti/next/provider`):
32
+
33
+ - `I18nProvider` — client-side provider component
34
+ - `I18nProviderProps` — provider prop type
35
+
36
+ ## Important Boundaries
37
+
38
+ - `withFluenti()` installs the loader and generates `@fluenti/next`
39
+ - imported `t` remains compile-time only
40
+ - server-side direct-import `t` requires an async server scope
41
+ - `useI18n()` is not the server runtime escape hatch; use `await getI18n()` instead
42
+
43
+ ## Preferred Usage (compile-time first)
44
+
45
+ 1. t\`\` tagged template — t\`Hello {name}\` (primary compile-time API, works in client and server)
46
+ 2. `<Trans>` / `<Plural>` / `<Select>` — rich text with inline markup
47
+ 3. `msg` tagged template — outside components (route meta, stores)
48
+ 4. `getI18n().t()` / `useI18n().t()` — runtime fallback for dynamic keys only
49
+
50
+ ❌ AVOID: `t('some.key')` as the default — this is a legacy i18n pattern.
51
+
52
+ ## Docs
53
+
54
+ - Full docs: https://fluenti.dev
55
+ - Source: https://github.com/usefluenti/fluenti
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluenti/next",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Next.js plugin for Fluenti — withFluenti, I18nProvider, t`` transforms for App Router and Pages Router",
6
6
  "homepage": "https://fluenti.dev",
@@ -63,7 +63,8 @@
63
63
  }
64
64
  },
65
65
  "files": [
66
- "dist"
66
+ "dist",
67
+ "llms*.txt"
67
68
  ],
68
69
  "peerDependencies": {
69
70
  "next": ">=14.0.0",
@@ -71,11 +72,12 @@
71
72
  },
72
73
  "dependencies": {
73
74
  "jiti": "^2",
74
- "@fluenti/core": "0.2.1",
75
- "@fluenti/react": "0.2.1"
75
+ "picomatch": "^4",
76
+ "@fluenti/react": "0.3.0",
77
+ "@fluenti/core": "0.3.0"
76
78
  },
77
79
  "devDependencies": {
78
- "@types/node": "^22",
80
+ "@types/node": "^25",
79
81
  "@types/react": "^19.0.0",
80
82
  "@types/react-dom": "^19.0.0",
81
83
  "@vitest/coverage-v8": "^4",
@@ -1,3 +0,0 @@
1
- export { scopeTransform } from '@fluenti/core/internal';
2
- export type { ScopeTransformOptions, ScopeTransformResult, Replacement } from '@fluenti/core/internal';
3
- //# sourceMappingURL=scope-transform.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-transform.d.ts","sourceRoot":"","sources":["../src/scope-transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA"}
@@ -1,3 +0,0 @@
1
- export { transformTransComponents } from '@fluenti/core/internal';
2
- export type { TransTransformResult } from '@fluenti/core/internal';
3
- //# sourceMappingURL=trans-transform.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trans-transform.d.ts","sourceRoot":"","sources":["../src/trans-transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAA;AACjE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA"}