@genrwork/laravel-i18next 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.

Potentially problematic release.


This version of @genrwork/laravel-i18next might be problematic. Click here for more details.

Files changed (38) hide show
  1. package/README.md +367 -0
  2. package/client.d.ts +12 -0
  3. package/dist/index.cjs +12 -0
  4. package/dist/index.mjs +2 -0
  5. package/dist/react.cjs +40 -0
  6. package/dist/react.mjs +38 -0
  7. package/dist/shared/create-i18n-BSEwKsCX.mjs +641 -0
  8. package/dist/shared/create-i18n-WsDK4Z8L.cjs +647 -0
  9. package/dist/svelte.cjs +77 -0
  10. package/dist/svelte.mjs +74 -0
  11. package/dist/types/backend.d.ts +29 -0
  12. package/dist/types/contrib/get-plural-index.d.ts +15 -0
  13. package/dist/types/format.d.ts +43 -0
  14. package/dist/types/index.d.ts +7 -0
  15. package/dist/types/interfaces/locale-file.d.ts +8 -0
  16. package/dist/types/interfaces/options.d.ts +19 -0
  17. package/dist/types/interfaces/replacements.d.ts +6 -0
  18. package/dist/types/plugin/helper.d.ts +6 -0
  19. package/dist/types/plugin/locale.d.ts +11 -0
  20. package/dist/types/plugin/parser.d.ts +22 -0
  21. package/dist/types/plugin/sources.d.ts +53 -0
  22. package/dist/types/react/i18n-provider-props.d.ts +23 -0
  23. package/dist/types/react/index.d.ts +3 -0
  24. package/dist/types/react/provider.d.ts +10 -0
  25. package/dist/types/shared/create-i18n.d.ts +26 -0
  26. package/dist/types/svelte/index.d.ts +48 -0
  27. package/dist/types/utils/pluralization.d.ts +9 -0
  28. package/dist/types/utils/recognizer.d.ts +29 -0
  29. package/dist/types/utils/replacer.d.ts +9 -0
  30. package/dist/types/utils/resolver.d.ts +23 -0
  31. package/dist/types/utils/sources.d.ts +14 -0
  32. package/dist/types/vite.d.ts +25 -0
  33. package/dist/types/vue/index.d.ts +21 -0
  34. package/dist/vite.cjs +315 -0
  35. package/dist/vite.mjs +310 -0
  36. package/dist/vue.cjs +39 -0
  37. package/dist/vue.mjs +34 -0
  38. package/package.json +155 -0
package/README.md ADDED
@@ -0,0 +1,367 @@
1
+ # laravel-i18next
2
+
3
+ Use your **Laravel** translation files with [i18next](https://www.i18next.com) in **React**, **Vue 3** or **Svelte** (4 or 5), translated exactly like [Laravel Localization](https://laravel.com/docs/localization) does.
4
+
5
+ Each Laravel language file becomes its own **i18next namespace**: `lang/{locale}.json` is the default namespace, and each `lang/{locale}/{namespace}.php` file (auth, validation, your own...) becomes a namespace of the same name — nested any number of levels deep, too (`lang/{locale}/{ns1}/{ns2}.php` → namespace `ns1/ns2`). Nothing is merged into one big bundle, so components only load and depend on the namespaces they actually use.
6
+
7
+ The Vite plugin can also read from **more than one directory**, in a fixed priority order — e.g. a hand-written frontend-only JSON catalog first, PHP translations second. A namespace present in several of these sources is merged per key, higher priority winning, so a project can move a namespace's strings out of PHP into hand-written JSON one string at a time without breaking the ones not yet moved. See [Sources and precedence](#sources-and-precedence).
8
+
9
+ Components use their framework's own i18next bindings: `useTranslation()` (React, Vue) or the store-based `useTranslation()` this package provides for Svelte. This package supplies:
10
+
11
+ - `LaravelBackend` and `LaravelFormat`, the i18next plugins doing the work: loading the namespaced language files (merging several sources per key when configured), and translating like Laravel (`:name` replacements, `trans_choice()` pluralization).
12
+ - A provider per framework — `LaravelReactI18nProvider` (`/react`), `laravelVueI18n` (`/vue`), `setLaravelI18nContext`/`useTranslation` (`/svelte`) — built on top of the two plugins above, SSR and hydration ready.
13
+ - A Vite plugin (`/vite`) turning PHP translations into JSON, and serving one or more sources of language files to the provider through a virtual module.
14
+
15
+ ## Requirements
16
+
17
+ - One of: React 18/19 + react-i18next >= 15, Vue 3.4+, Svelte 4 or 5
18
+ - i18next >= 24
19
+ - Vite >= 5 (optional; the framework bindings work with any bundler, only `/vite` needs Vite)
20
+
21
+ ## Installation
22
+
23
+ ```sh
24
+ npm install @genrwork/laravel-i18next i18next
25
+ # React
26
+ npm install react-i18next
27
+ # Vue
28
+ npm install i18next-vue
29
+ # Svelte: nothing else to install
30
+ ```
31
+
32
+ ## Setup
33
+
34
+ ### 1. Vite plugin
35
+
36
+ `vite.config.ts`:
37
+
38
+ ```ts
39
+ import i18n from '@genrwork/laravel-i18next/vite'; // <-- add this
40
+
41
+ export default defineConfig({
42
+ plugins: [
43
+ laravel({ input: ['resources/css/app.css', 'resources/js/app.ts'], refresh: true }),
44
+ react(), // or vue(), or svelte()
45
+ i18n(), // <-- add this
46
+ ],
47
+ });
48
+ ```
49
+
50
+ While Vite runs, the plugin converts every `.php` file found under a source directory (at any depth) into a sibling `.json` file (regenerated when the PHP file changes, deleted when the build ends). Keep them out of git:
51
+
52
+ ```
53
+ lang/*/*.json
54
+ Modules/*/lang/*/*.json
55
+ ```
56
+
57
+ The `sources` option is an ordered list of directories, **highest priority first**; each may hold hand-written `.json` files, `.php` files, or both (but not both for the same namespace — a hand-written file always wins where present, so don't shadow one with a same-named PHP file in the same directory). One `*` wildcard segment is allowed per entry, expanded against every matching directory that exists, e.g. `Modules/*/lang`. Defaults to `['lang']`, matching a single Laravel app with no other sources.
58
+
59
+ ```ts
60
+ i18n({
61
+ sources: [
62
+ 'resources/js/lang', // hand-written, frontend-only strings -- highest priority
63
+ 'Modules/*/lang', // this app's own modules' PHP translations
64
+ 'lang', // the app's own PHP translations
65
+ ],
66
+ });
67
+ ```
68
+
69
+ The plugin also serves the language files as `virtual:laravel-i18next/files`: an array, one entry per configured source in the same order, each eagerly loaded in server code (so SSR renders translated) and lazily loaded in client code, one chunk per namespace. Declare its type next to Vite's, e.g. in `resources/js/types/vite-env.d.ts`:
70
+
71
+ ```ts
72
+ /// <reference types="vite/client" />
73
+ /// <reference types="@genrwork/laravel-i18next/client" />
74
+ ```
75
+
76
+ Without the Vite plugin, build the same structure yourself: an array of `import.meta.glob('/lang/**/*.json')` calls (lazy) or `import.meta.glob('/lang/**/*.json', { eager: true })` calls (eager), one per source, in priority order — see [Namespaces](#namespaces) and [Sources and precedence](#sources-and-precedence). A single `import.meta.glob()` result (not wrapped in an array) is also accepted, as a one-source project.
77
+
78
+ ### 2. Share the locale
79
+
80
+ `app/Http/Middleware/HandleInertiaRequests.php` (or any equivalent for your setup):
81
+
82
+ ```php
83
+ public function share(Request $request): array
84
+ {
85
+ return [
86
+ ...parent::share($request),
87
+ 'locale' => app()->getLocale(),
88
+ // ...
89
+ ];
90
+ }
91
+ ```
92
+
93
+ ### 3. Framework setup
94
+
95
+ <details open><summary><strong>React</strong> (Inertia v3, <code>withApp</code>)</summary>
96
+
97
+ `resources/js/app.tsx`:
98
+
99
+ ```tsx
100
+ import { createInertiaApp } from '@inertiajs/react';
101
+ import { LaravelReactI18nProvider } from '@genrwork/laravel-i18next/react';
102
+ import files from 'virtual:laravel-i18next/files';
103
+
104
+ void createInertiaApp({
105
+ strictMode: true,
106
+ withApp(app, { page }) {
107
+ return (
108
+ <LaravelReactI18nProvider locale={page.props.locale as string} fallbackLocale="en" files={files}>
109
+ {app}
110
+ </LaravelReactI18nProvider>
111
+ );
112
+ },
113
+ });
114
+ ```
115
+
116
+ </details>
117
+
118
+ <details><summary><strong>React</strong> (Inertia v2, <code>setup</code>)</summary>
119
+
120
+ `resources/js/app.tsx`:
121
+
122
+ ```tsx
123
+ import { createInertiaApp } from '@inertiajs/react';
124
+ import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
125
+ import { hydrateRoot } from 'react-dom/client';
126
+ import { LaravelReactI18nProvider } from '@genrwork/laravel-i18next/react';
127
+ import files from 'virtual:laravel-i18next/files';
128
+
129
+ createInertiaApp({
130
+ resolve: (name) => resolvePageComponent(`./pages/${name}.tsx`, import.meta.glob('./pages/**/*.tsx')),
131
+ setup({ el, App, props }) {
132
+ // Without SSR: createRoot(el).render(...)
133
+ hydrateRoot(
134
+ el,
135
+ <LaravelReactI18nProvider locale={props.initialPage.props.locale as string} fallbackLocale="en" files={files}>
136
+ <App {...props} />
137
+ </LaravelReactI18nProvider>
138
+ );
139
+ },
140
+ });
141
+ ```
142
+
143
+ With SSR, `resources/js/ssr.tsx` follows the same shape with `render: ReactDOMServer.renderToString` and `createServer()`, as in [Laravel's own SSR guide](https://inertiajs.com/server-side-rendering).
144
+
145
+ </details>
146
+
147
+ <details><summary><strong>Vue 3</strong></summary>
148
+
149
+ `resources/js/app.ts`:
150
+
151
+ ```ts
152
+ import { createInertiaApp } from '@inertiajs/vue3';
153
+ import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
154
+ import { createApp, h } from 'vue';
155
+ import { laravelVueI18n } from '@genrwork/laravel-i18next/vue';
156
+ import files from 'virtual:laravel-i18next/files';
157
+
158
+ createInertiaApp({
159
+ resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob('./pages/**/*.vue')),
160
+ setup({ el, App, props, plugin }) {
161
+ createApp({ render: () => h(App, props) })
162
+ .use(plugin)
163
+ .use(laravelVueI18n({ locale: props.initialPage.props.locale as string, fallbackLocale: 'en', files }))
164
+ .mount(el);
165
+ },
166
+ });
167
+ ```
168
+
169
+ For SSR, use `createSSRApp` instead of `createApp` in `resources/js/ssr.ts`, as in [Inertia's own Vue 3 SSR guide](https://inertiajs.com/server-side-rendering) — everything else stays the same.
170
+
171
+ In components: `import { useTranslation } from '@genrwork/laravel-i18next/vue'` (re-exported from `i18next-vue`), or the global `$t` / `$i18next`.
172
+
173
+ </details>
174
+
175
+ <details><summary><strong>Svelte</strong> (4 or 5)</summary>
176
+
177
+ `resources/js/app.ts` (with [`@inertiajs/svelte`](https://inertiajs.com)):
178
+
179
+ ```ts
180
+ import { createInertiaApp } from '@inertiajs/svelte';
181
+ import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
182
+ import files from 'virtual:laravel-i18next/files';
183
+ import App from './App.svelte';
184
+
185
+ createInertiaApp({
186
+ resolve: (name) => resolvePageComponent(`./pages/${name}.svelte`, import.meta.glob('./pages/**/*.svelte')),
187
+ setup({ el, App: Page, props }) {
188
+ new App({ target: el, props: { Page, props, files } });
189
+ },
190
+ });
191
+ ```
192
+
193
+ `App.svelte` (top of the component tree — the locale prop is whatever Inertia passes through `props`):
194
+
195
+ ```svelte
196
+ <script lang="ts">
197
+ import { setLaravelI18nContext } from '@genrwork/laravel-i18next/svelte';
198
+
199
+ export let Page;
200
+ export let props;
201
+ export let files;
202
+
203
+ setLaravelI18nContext({ locale: props.locale, fallbackLocale: 'en', files });
204
+ </script>
205
+
206
+ <svelte:component this={Page} {...props} />
207
+ ```
208
+
209
+ In any child component:
210
+
211
+ ```svelte
212
+ <script lang="ts">
213
+ import { useTranslation } from '@genrwork/laravel-i18next/svelte';
214
+
215
+ const { t } = useTranslation('auth');
216
+ </script>
217
+
218
+ <p>{$t('failed')}</p>
219
+ ```
220
+
221
+ </details>
222
+
223
+ ### Following locale changes
224
+
225
+ The framework setup above only runs once, when the page loads. When Laravel shares another locale after a visit (e.g. the user switched language), change the language from a layout component. React:
226
+
227
+ ```tsx
228
+ import { usePage } from '@inertiajs/react';
229
+ import { useEffect } from 'react';
230
+ import { useTranslation } from 'react-i18next';
231
+
232
+ export default function AppLayout({ children }: { children: React.ReactNode }) {
233
+ const { locale } = usePage<{ locale: string }>().props;
234
+ const { i18n } = useTranslation();
235
+
236
+ useEffect(() => {
237
+ if (i18n.language !== locale) i18n.changeLanguage(locale);
238
+ }, [i18n, locale]);
239
+
240
+ return children;
241
+ }
242
+ ```
243
+
244
+ Vue and Svelte follow the same idea: watch the shared `locale` prop and call `i18next.changeLanguage(locale)` (Vue: `const { i18next } = useTranslation()`; Svelte: the `i18next` instance returned by `setLaravelI18nContext()`/`useTranslation()`).
245
+
246
+ ## Sources and precedence
247
+
248
+ With more than one `sources` entry, the same `(locale, namespace)` pair can come from several places at once. They are merged **per key**, highest-priority source winning, rather than one source replacing another wholesale:
249
+
250
+ ```
251
+ resources/js/lang/es/settings.json { "Save": "Guardar" }
252
+ lang/es/settings.php ['Save' => 'Guardar (antiguo)', 'profile_updated' => 'Perfil actualizado.']
253
+
254
+ → namespace "settings", locale "es":
255
+ Save -> "Guardar" (from the higher-priority source)
256
+ profile_updated -> "Perfil actualizado." (only in the lower-priority source, resolves from there)
257
+ ```
258
+
259
+ This is what lets a namespace migrate from PHP to hand-written JSON one string at a time: move a key, and every key not yet moved keeps resolving from PHP.
260
+
261
+ The merge is a **shallow** merge over already-flattened, dotted keys (`sub_level1.text`, not `{ sub_level1: { text: ... } }`) — since a PHP file is flattened before it ever becomes JSON, this shallow merge is exactly the deep merge Laravel itself performs over the original nested arrays; no separate deep-merge step is needed.
262
+
263
+ Two things worth knowing:
264
+
265
+ - **Ties within one source resolve by path order** (alphabetical, as `import.meta.glob()` returns them) — if a wildcard source matches two directories that both produce the very same `(locale, namespace)` pair (e.g. two modules that happen to define an identically-named namespace), the alphabetically-first path wins, silently. Prefixing a module's own namespaces with its name avoids this in practice.
266
+ - **A namespace segment that itself looks like a locale code is misread as the locale** — see the note on `classify()` in `src/utils/recognizer.ts`. No namespace in a typical app looks like a locale code, so this is a documented edge case, not something the library tries to solve.
267
+
268
+ ## Namespaces
269
+
270
+ Every Laravel language file is its own namespace:
271
+
272
+ ```
273
+ lang/
274
+ en.json → default namespace ("translation")
275
+ en/
276
+ auth.php → "auth" namespace
277
+ validation.php → "validation" namespace
278
+ teams/
279
+ roles.php → "teams/roles" namespace (nested any number of levels)
280
+ it/
281
+ auth.php → "auth" namespace
282
+ ```
283
+
284
+ `import.meta.glob('/lang/**/*.json')` (or the `virtual:laravel-i18next/files` module) must be **recursive** so it picks up all of these. A component requests a namespace the same way it would for any i18next app:
285
+
286
+ ```tsx
287
+ const { t } = useTranslation('auth'); // React
288
+ const { t } = useTranslation('auth'); // Vue (i18next-vue)
289
+ const { t } = useTranslation('auth'); // Svelte
290
+ ```
291
+
292
+ Namespaces are not merged with each other: `t('failed')` inside the `auth` namespace only sees `auth.php`'s keys — even with several `sources`, a namespace only ever merges with the SAME namespace from another source (see [Sources and precedence](#sources-and-precedence)), never with a different one. Request several namespaces at once (`useTranslation(['translation', 'auth'])` in React/Vue) to use more than one from the same component — list the default namespace **first** if you call `t()` without an explicit `ns`, since react-i18next/i18next-vue resolve unscoped calls against the first namespace in that list. Passing `{ ns: 'auth' }` per call works regardless of order, and is what the Svelte binding always does (its `useTranslation()` is scoped to one namespace per call).
293
+
294
+ ## Provider / plugin options
295
+
296
+ `files`, `locale` and `fallbackLocale` are the same across React, Vue and Svelte:
297
+
298
+ - `files` _(required)_: `virtual:laravel-i18next/files` (an array, one entry per configured source), or your own single `import.meta.glob('/lang/**/*.json')` (lazy) / `import.meta.glob('/lang/**/*.json', { eager: true })` (eager) — a bare map behaves exactly like a one-source array.
299
+ - `locale` _(optional)_: defaults to the `<html lang="">` attribute, or `en`.
300
+ - `fallbackLocale` _(optional)_: used when a translation is missing, or when a namespace has no file for `locale`. Defaults to the `<html lang="">` attribute, or `en`.
301
+
302
+ Every provider/plugin instance creates its own i18next instance, so concurrent SSR requests never share a language. Eagerness is all-or-nothing **across every non-empty source**: with every source eager, every known namespace is preloaded and translated on the first render, synchronously — this is what the Vite plugin always emits for SSR, and what a hand-rolled config should match to keep SSR synchronous. With any source lazy, a namespace is fetched the first time a component requests it (merging still waits for every source's candidate to resolve) — in React, requesting components suspend meanwhile (wrap them in `<Suspense>`, which the provider already does around its children); in Vue and Svelte, use the `ready` value (`i18next-vue` re-renders once loaded; the Svelte `useTranslation()` returns a `ready` store) to show a loading state instead. The `<html lang="">` attribute is set immediately and kept in sync with the language.
303
+
304
+ ## Usage
305
+
306
+ ### Translating
307
+
308
+ `lang/pt.json` (default namespace):
309
+
310
+ ```json
311
+ {
312
+ "Welcome!": "Bem-vindo!",
313
+ "Welcome, :name!": "Bem-vindo, :name!"
314
+ }
315
+ ```
316
+
317
+ ```tsx
318
+ const { t } = useTranslation();
319
+
320
+ t('Welcome!'); // Bem-vindo!
321
+ t('Welcome, :name!', { name: 'Francisco' }); // Bem-vindo, Francisco!
322
+ t('Welcome, :NAME!', { name: 'Francisco' }); // Bem-vindo, FRANCISCO!
323
+ t('Some untranslated'); // Some untranslated
324
+ ```
325
+
326
+ `lang/pt/auth.php` → `auth` namespace:
327
+
328
+ ```tsx
329
+ const { t } = useTranslation('auth');
330
+
331
+ t('failed'); // PHP translation from lang/pt/auth.php's 'failed' key
332
+ ```
333
+
334
+ A missing (or empty) translation is looked up in the fallback language, then the key itself is returned.
335
+
336
+ i18next `{{name}}` interpolation and `$t()` nesting are not applied. Replacements named like an i18next option (`lng`, `ns`, `context`, `defaultValue`...) must be given in `replace`: `t('Hello :lng', { replace: { lng: 'PHP' } })`.
337
+
338
+ ### Pluralization
339
+
340
+ Pass the number as `count`:
341
+
342
+ `lang/pt/fruits.php`:
343
+
344
+ ```php
345
+ <?php
346
+ return [
347
+ 'apple_count' => ':count apple|:count apples',
348
+ 'none_some_many' => '{0} There are none|[1,19] There are some|[20,*] There are many',
349
+ ];
350
+ ```
351
+
352
+ ```tsx
353
+ const { t } = useTranslation('fruits');
354
+
355
+ t('apple_count', { count: 1 }); // 1 apple
356
+ t('none_some_many', { count: 19 }); // There are some
357
+ ```
358
+
359
+ Segments without an explicit range are picked with the plural rules of the language the message actually resolved in — the current language, or the fallback language when the message itself came from there, like Laravel does. This is deliberately not just "does the namespace have a file for the current language": with several `sources`, a namespace can end up with SOME content for a language (enough to make `hasResourceBundle()` true) while the specific message being pluralized still came from the fallback — pluralization follows the message, not the namespace. `_one` / `_other` suffixed keys are not used.
360
+
361
+ ## Credits
362
+
363
+ - The translation behavior (replacements, pluralization) mirrors Laravel's own [`__()`](https://laravel.com/docs/localization) and `trans_choice()`.
364
+
365
+ ## License
366
+
367
+ MIT &copy; GenrWork
package/client.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ declare module 'virtual:laravel-i18next/files' {
2
+ import type { LocaleFiles } from '@genrwork/laravel-i18next';
3
+
4
+ /**
5
+ * Laravel language files, one entry per configured `sources` (see the
6
+ * `/vite` plugin's options), highest priority first. Each entry is loaded
7
+ * eagerly on the server (SSR) and lazily on the client.
8
+ */
9
+ const files: LocaleFiles[];
10
+
11
+ export default files;
12
+ }
package/dist/index.cjs ADDED
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var createI18n = require('./shared/create-i18n-WsDK4Z8L.cjs');
4
+ require('i18next');
5
+
6
+
7
+
8
+ exports.LaravelBackend = createI18n.LaravelBackend;
9
+ exports.LaravelFormat = createI18n.LaravelFormat;
10
+ exports.createI18n = createI18n.createI18n;
11
+ exports.documentLocale = createI18n.documentLocale;
12
+ exports.syncDocumentLang = createI18n.syncDocumentLang;
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export { L as LaravelBackend, a as LaravelFormat, c as createI18n, d as documentLocale, s as syncDocumentLang } from './shared/create-i18n-BSEwKsCX.mjs';
2
+ import 'i18next';
package/dist/react.cjs ADDED
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var reactI18next = require('react-i18next');
6
+ var createI18n = require('./shared/create-i18n-WsDK4Z8L.cjs');
7
+ require('i18next');
8
+
9
+ /**
10
+ * Provides an i18next instance translating Laravel language files to react-i18next.
11
+ *
12
+ * Every provider owns its instance, so concurrent SSR requests do not share a language.
13
+ * With eager files, every namespace is preloaded and translated on the first render.
14
+ * While a lazy namespace loads, the children suspend, which keeps server-rendered
15
+ * HTML in place until it can be hydrated.
16
+ */ function LaravelReactI18nProvider({ children, files, locale, fallbackLocale }) {
17
+ const [i18n] = react.useState(()=>createI18n.createI18n({
18
+ files,
19
+ locale,
20
+ fallbackLocale
21
+ }));
22
+ react.useEffect(()=>{
23
+ if (locale && locale !== i18n.language) i18n.changeLanguage(locale);
24
+ }, [
25
+ i18n,
26
+ locale
27
+ ]);
28
+ react.useEffect(()=>createI18n.syncDocumentLang(i18n), [
29
+ i18n
30
+ ]);
31
+ return jsxRuntime.jsx(reactI18next.I18nextProvider, {
32
+ i18n: i18n,
33
+ children: jsxRuntime.jsx(react.Suspense, {
34
+ fallback: null,
35
+ children: children
36
+ })
37
+ });
38
+ }
39
+
40
+ exports.LaravelReactI18nProvider = LaravelReactI18nProvider;
package/dist/react.mjs ADDED
@@ -0,0 +1,38 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect, Suspense } from 'react';
3
+ import { I18nextProvider } from 'react-i18next';
4
+ import { c as createI18n, s as syncDocumentLang } from './shared/create-i18n-BSEwKsCX.mjs';
5
+ import 'i18next';
6
+
7
+ /**
8
+ * Provides an i18next instance translating Laravel language files to react-i18next.
9
+ *
10
+ * Every provider owns its instance, so concurrent SSR requests do not share a language.
11
+ * With eager files, every namespace is preloaded and translated on the first render.
12
+ * While a lazy namespace loads, the children suspend, which keeps server-rendered
13
+ * HTML in place until it can be hydrated.
14
+ */ function LaravelReactI18nProvider({ children, files, locale, fallbackLocale }) {
15
+ const [i18n] = useState(()=>createI18n({
16
+ files,
17
+ locale,
18
+ fallbackLocale
19
+ }));
20
+ useEffect(()=>{
21
+ if (locale && locale !== i18n.language) i18n.changeLanguage(locale);
22
+ }, [
23
+ i18n,
24
+ locale
25
+ ]);
26
+ useEffect(()=>syncDocumentLang(i18n), [
27
+ i18n
28
+ ]);
29
+ return jsx(I18nextProvider, {
30
+ i18n: i18n,
31
+ children: jsx(Suspense, {
32
+ fallback: null,
33
+ children: children
34
+ })
35
+ });
36
+ }
37
+
38
+ export { LaravelReactI18nProvider };