@fluenti/vue-i18n-compat 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.
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,237 @@
1
+ # @fluenti/vue-i18n-compat
2
+
3
+ [![npm](https://img.shields.io/npm/v/@fluenti/vue-i18n-compat?color=4f46e5&label=npm)](https://www.npmjs.com/package/@fluenti/vue-i18n-compat)
4
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@fluenti/vue-i18n-compat?color=22c55e&label=size)](https://bundlephobia.com/package/@fluenti/vue-i18n-compat)
5
+ [![license](https://img.shields.io/npm/l/@fluenti/vue-i18n-compat?color=gray)](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
6
+
7
+ **Drop-in migration from vue-i18n to Fluenti.** Keep your existing `$t()` calls, swap one plugin, and adopt compile-time i18n at your own pace.
8
+
9
+ ---
10
+
11
+ ## Why?
12
+
13
+ Rewriting every translation call in a large Vue app is impractical. This package lets you:
14
+
15
+ - **Keep existing code working** -- `$t()`, `$tc()`, `$te()`, and the Composition API all behave the same way they always have.
16
+ - **Add Fluenti incrementally** -- new features use ICU MessageFormat and compile-time transforms; legacy messages stay in vue-i18n format until you are ready to move them.
17
+ - **Share locale state** -- switching language in one library automatically updates the other, so users never see mixed-language UI.
18
+ - **Remove it when you are done** -- once every message is migrated, swap `@fluenti/vue-i18n-compat` for `@fluenti/vue` and delete vue-i18n.
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Install
23
+
24
+ ```bash
25
+ pnpm add @fluenti/vue-i18n-compat @fluenti/core @fluenti/vue
26
+ # vue ^3.5 and vue-i18n ^9 || ^10 are peer dependencies
27
+ ```
28
+
29
+ ### 2. Swap the Plugin
30
+
31
+ **Before** (vue-i18n only):
32
+
33
+ ```ts
34
+ import { createApp } from 'vue'
35
+ import { createI18n } from 'vue-i18n'
36
+
37
+ const i18n = createI18n({
38
+ legacy: false,
39
+ locale: 'en',
40
+ messages: {
41
+ en: { greeting: 'Hello!', farewell: 'Goodbye, {name}!' },
42
+ ja: { greeting: 'こんにちは!', farewell: 'さようなら、{name}!' },
43
+ },
44
+ })
45
+
46
+ const app = createApp(App)
47
+ app.use(i18n)
48
+ app.mount('#app')
49
+ ```
50
+
51
+ **After** (bridge installed, existing code unchanged):
52
+
53
+ ```ts
54
+ import { createApp } from 'vue'
55
+ import { createI18n } from 'vue-i18n'
56
+ import { createFluentVue } from '@fluenti/vue'
57
+ import { createFluentBridge } from '@fluenti/vue-i18n-compat'
58
+
59
+ // Your existing vue-i18n setup -- nothing changes here
60
+ const i18n = createI18n({
61
+ legacy: false,
62
+ locale: 'en',
63
+ messages: {
64
+ en: { greeting: 'Hello!', farewell: 'Goodbye, {name}!' },
65
+ ja: { greeting: 'こんにちは!', farewell: 'さようなら、{name}!' },
66
+ },
67
+ })
68
+
69
+ // Fluenti setup (empty for now -- you will add messages here over time)
70
+ const fluenti = createFluentVue({
71
+ locale: 'en',
72
+ fallbackLocale: 'en',
73
+ messages: { en: {}, ja: {} },
74
+ })
75
+
76
+ // Bridge: one plugin to rule them both
77
+ const bridge = createFluentBridge({ vueI18n: i18n, fluenti })
78
+
79
+ const app = createApp(App)
80
+ app.use(bridge) // replaces app.use(i18n)
81
+ app.mount('#app')
82
+ ```
83
+
84
+ ### 3. Existing Code Works
85
+
86
+ Every `$t('greeting')` in your templates and every `useI18n()` in your `<script setup>` blocks keeps working. No changes required.
87
+
88
+ ```vue
89
+ <template>
90
+ <!-- These calls hit vue-i18n, just like before -->
91
+ <h1>{{ $t('greeting') }}</h1>
92
+ <p>{{ $t('farewell', { name: 'Alice' }) }}</p>
93
+ </template>
94
+ ```
95
+
96
+ ### 4. Gradually Migrate
97
+
98
+ Move messages one at a time. When a key exists in both libraries, the bridge resolves it from Fluenti first (configurable).
99
+
100
+ ```ts
101
+ // Before: vue-i18n format
102
+ { greeting: 'Hello!' }
103
+
104
+ // After: ICU MessageFormat in Fluenti
105
+ { greeting: 'Hello!' } // simple strings are identical
106
+
107
+ // Before: vue-i18n plural (pipe syntax)
108
+ { items: 'no items | one item | {count} items' }
109
+
110
+ // After: ICU plural in Fluenti
111
+ { items: '{count, plural, =0 {no items} one {one item} other {# items}}' }
112
+ ```
113
+
114
+ Once a key is in Fluenti, delete it from the vue-i18n messages object. When every key has been moved, replace the bridge with `@fluenti/vue` directly:
115
+
116
+ ```diff
117
+ - import { createFluentBridge } from '@fluenti/vue-i18n-compat'
118
+ + import { createFluentVue } from '@fluenti/vue'
119
+
120
+ - app.use(bridge)
121
+ + app.use(fluenti)
122
+ ```
123
+
124
+ ## Usage
125
+
126
+ ### Composition API
127
+
128
+ ```vue
129
+ <script setup>
130
+ import { useI18n } from '@fluenti/vue-i18n-compat'
131
+
132
+ const { t, tc, te, locale, setLocale, availableLocales } = useI18n()
133
+ </script>
134
+
135
+ <template>
136
+ <h1>{{ t('greeting') }}</h1> <!-- vue-i18n key -->
137
+ <p>{{ t('welcome') }}</p> <!-- Fluenti key -->
138
+ <p v-if="te('greeting')">Exists!</p> <!-- checks both libraries -->
139
+ <p>{{ tc('items', count) }}</p> <!-- pipe-separated or ICU plurals -->
140
+
141
+ <button @click="setLocale('ja')">日本語</button>
142
+ </template>
143
+ ```
144
+
145
+ ### Options API
146
+
147
+ `$t`, `$te`, and `$tc` are overridden globally -- existing templates work without changes.
148
+
149
+ ```vue
150
+ <template>
151
+ <p>{{ $t('greeting') }}</p>
152
+ <p>{{ $tc('items', 3) }}</p>
153
+ <p v-if="$te('farewell')">{{ $t('farewell', { name: 'Bob' }) }}</p>
154
+ </template>
155
+ ```
156
+
157
+ ## How It Works
158
+
159
+ ```
160
+ ┌────────────┐ locale sync ┌─────────┐
161
+ │ vue-i18n │◄───────────────►│ Fluenti │
162
+ └─────┬──────┘ └────┬────┘
163
+ │ ┌──────────────┐ │
164
+ └─────►│ Bridge │◄──────┘
165
+ │ t / tc / te │
166
+ └──────────────┘
167
+ ```
168
+
169
+ The bridge installs both libraries as a single Vue plugin. Locale state is synced bidirectionally -- switching language in one library automatically updates the other. Translation lookups fall through: if the primary library does not have a key, the bridge checks the other.
170
+
171
+ ## API Reference
172
+
173
+ ### `createFluentBridge(options)`
174
+
175
+ Creates the bridge plugin. Call `app.use(bridge)` instead of `app.use(i18n)`.
176
+
177
+ | Option | Type | Default | Description |
178
+ |--------|------|---------|-------------|
179
+ | `vueI18n` | `VueI18nInstance` | **required** | vue-i18n instance from `createI18n()` |
180
+ | `fluenti` | `FluentVuePlugin` | **required** | Fluenti plugin from `createFluentVue()` |
181
+ | `priority` | `'fluenti-first' \| 'vue-i18n-first'` | `'fluenti-first'` | Which library to check first for translations |
182
+
183
+ ### `useI18n()`
184
+
185
+ Returns the `BridgeContext`. Must be called inside a component where the bridge plugin is installed.
186
+
187
+ ### `BridgeContext`
188
+
189
+ | Property / Method | Type | Description |
190
+ |-------------------|------|-------------|
191
+ | `t(key, values?)` | `string` | Translate -- checks both libraries per priority |
192
+ | `tc(key, count, values?)` | `string` | Pluralized translation (pipe syntax or ICU) |
193
+ | `te(key, locale?)` | `boolean` | Check if key exists in either library |
194
+ | `tm(key)` | `unknown` | Get the raw message object |
195
+ | `d(value, style?)` | `string` | Format a date |
196
+ | `n(value, style?)` | `string` | Format a number |
197
+ | `format(message, values?)` | `string` | Format an ICU message string directly |
198
+ | `locale` | `Ref<string>` | Reactive locale (synced across both libraries) |
199
+ | `setLocale(locale)` | `Promise<void>` | Change locale (syncs to both libraries) |
200
+ | `availableLocales` | `ComputedRef<string[]>` | Merged locales from both libraries |
201
+ | `isLoading` | `Ref<boolean>` | Whether Fluenti is loading a locale chunk |
202
+ | `fluenti` | `FluentVueContext` | Access the underlying Fluenti context |
203
+ | `vueI18n` | `VueI18nGlobal` | Access the underlying vue-i18n global composer |
204
+
205
+ ## Compatibility Matrix
206
+
207
+ | vue-i18n feature | Supported | Notes |
208
+ |------------------|-----------|-------|
209
+ | `$t()` / `t()` | Yes | Bridged with fallthrough to both libraries |
210
+ | `$tc()` / `tc()` | Yes | Pipe-separated plurals via vue-i18n; ICU plurals via Fluenti |
211
+ | `$te()` / `te()` | Yes | Returns `true` if key exists in either library |
212
+ | `$tm()` / `tm()` | Yes | Returns raw message from priority library |
213
+ | `$d()` / `d()` | Yes | Delegates to Fluenti's date formatter |
214
+ | `$n()` / `n()` | Yes | Delegates to Fluenti's number formatter |
215
+ | `useI18n()` | Yes | Returns unified `BridgeContext` |
216
+ | Composition API mode | Yes | Requires `legacy: false` in vue-i18n |
217
+ | Legacy API mode | No | Use `legacy: false` -- the bridge requires the Composition API |
218
+ | Component interpolation (`<i18n-t>`) | No | Use Fluenti's `<Trans>` component instead |
219
+ | Custom directives (`v-t`) | No | Fluenti uses `v-t` as a compile-time node transform |
220
+ | Per-component `i18n` blocks | No | Use Fluenti's file-based catalogs or `defineMessages()` |
221
+
222
+ ## Migration Checklist
223
+
224
+ 1. Install the bridge alongside your existing vue-i18n setup
225
+ 2. Verify your app works without any other changes
226
+ 3. Write new features using Fluenti messages (ICU MessageFormat)
227
+ 4. Move existing messages from vue-i18n format to ICU format, one file at a time
228
+ 5. Remove empty vue-i18n locale objects as they become unnecessary
229
+ 6. When all messages are migrated, replace the bridge with `@fluenti/vue` and uninstall vue-i18n
230
+
231
+ ## Documentation
232
+
233
+ Full documentation at [fluenti.dev](https://fluenti.dev).
234
+
235
+ ## License
236
+
237
+ [MIT](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
@@ -0,0 +1,22 @@
1
+ import { InjectionKey } from 'vue';
2
+ import { BridgeOptions, BridgeContext, BridgePlugin } from './types';
3
+ /** Injection key for the bridge context */
4
+ export declare const BRIDGE_KEY: InjectionKey<BridgeContext>;
5
+ /**
6
+ * Create a bridge plugin that connects vue-i18n and fluenti.
7
+ *
8
+ * Both libraries are installed, locale is synced bidirectionally,
9
+ * and translation lookups fall through from one library to the other.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const bridge = createFluentBridge({
14
+ * vueI18n: i18n,
15
+ * fluenti: fluent,
16
+ * priority: 'fluenti-first',
17
+ * })
18
+ * app.use(bridge)
19
+ * ```
20
+ */
21
+ export declare function createFluentBridge(options: BridgeOptions): BridgePlugin;
22
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAmB,MAAM,KAAK,CAAA;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEzE,2CAA2C;AAC3C,eAAO,MAAM,UAAU,EAAE,YAAY,CAAC,aAAa,CAA4B,CAAA;AAE/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CA0HvE"}
@@ -0,0 +1,15 @@
1
+ import { BridgeContext } from './types';
2
+ /**
3
+ * Unified composable that provides access to the bridge context.
4
+ *
5
+ * Returns a `BridgeContext` with translation methods that check both
6
+ * vue-i18n and fluenti catalogs, locale management that syncs across
7
+ * both libraries, and direct access to each underlying instance.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const { t, tc, te, locale, setLocale, fluenti, vueI18n } = useI18n()
12
+ * ```
13
+ */
14
+ export declare function useI18n(): BridgeContext;
15
+ //# sourceMappingURL=composable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composable.d.ts","sourceRoot":"","sources":["../src/composable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,IAAI,aAAa,CASvC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`);var t=Symbol(`fluenti-bridge`);function n(n){let{vueI18n:r,fluenti:i,priority:a=`fluenti-first`}=n,o=i.global,s=r.global,c=!1;function l(e,t){if(!c){c=!0;try{e===`fluenti`?s.locale.value!==t&&(s.locale.value=t):o.locale.value!==t&&o.setLocale(t)}finally{c=!1}}}function u(e,t){let n=typeof e==`string`?e:e.id;return a===`fluenti-first`?o.te(n)?o.t(e,t):s.t(n,t??{}):s.te(n)?s.t(n,t??{}):o.t(e,t)}function d(e,t,n){return a===`fluenti-first`&&o.te(e)?o.t(e,{count:t,...n}):s.tc?s.tc(e,t,n??{}):s.t(e,{count:t,...n})}function f(e,t){return o.te(e,t)||s.te(e,t)}function p(e){if(a===`fluenti-first`){let t=o.tm(e);if(t!==void 0)return t}return s.tm(e)}let m=(0,e.computed)(()=>[...new Set([...o.getLocales(),...s.availableLocales])].sort()),h={t:u,tc:d,te:f,tm:p,d:o.d,n:o.n,format:o.format,locale:o.locale,setLocale:async e=>{await o.setLocale(e),l(`fluenti`,e)},availableLocales:m,isLoading:o.isLoading,fluenti:o,vueI18n:s};return{install(n){n.use(r),n.use(i),(0,e.watch)(o.locale,e=>{l(`fluenti`,e)}),(0,e.watch)(s.locale,e=>{l(`vue-i18n`,e)}),n.config.globalProperties.$t=u,n.config.globalProperties.$te=f,n.config.globalProperties.$tc=d,n.provide(t,h)},global:h}}function r(){let n=(0,e.inject)(t);if(!n)throw Error(`[@fluenti/vue-i18n-compat] useI18n() requires the bridge plugin to be installed. Call app.use(bridge) where bridge = createFluentBridge({ vueI18n, fluenti }).`);return n}exports.BRIDGE_KEY=t,exports.createFluentBridge=n,exports.useI18n=r;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/bridge.ts","../src/composable.ts"],"sourcesContent":["import { type App, type InjectionKey, computed, watch } from 'vue'\nimport type { BridgeOptions, BridgeContext, BridgePlugin } from './types'\n\n/** Injection key for the bridge context */\nexport const BRIDGE_KEY: InjectionKey<BridgeContext> = Symbol('fluenti-bridge')\n\n/**\n * Create a bridge plugin that connects vue-i18n and fluenti.\n *\n * Both libraries are installed, locale is synced bidirectionally,\n * and translation lookups fall through from one library to the other.\n *\n * @example\n * ```ts\n * const bridge = createFluentBridge({\n * vueI18n: i18n,\n * fluenti: fluent,\n * priority: 'fluenti-first',\n * })\n * app.use(bridge)\n * ```\n */\nexport function createFluentBridge(options: BridgeOptions): BridgePlugin {\n const { vueI18n, fluenti, priority = 'fluenti-first' } = options\n const fluentCtx = fluenti.global\n const vueI18nGlobal = vueI18n.global\n\n // --- Locale sync (bidirectional, with guard to prevent loops) ---\n let syncing = false\n\n function syncLocale(source: 'fluenti' | 'vue-i18n', newLocale: string) {\n if (syncing) return\n syncing = true\n try {\n if (source === 'fluenti') {\n if (vueI18nGlobal.locale.value !== newLocale) {\n vueI18nGlobal.locale.value = newLocale\n }\n } else {\n if (fluentCtx.locale.value !== newLocale) {\n fluentCtx.setLocale(newLocale)\n }\n }\n } finally {\n syncing = false\n }\n }\n\n // --- Bridged translation functions ---\n\n function bridgedT(key: string | { id: string; message?: string }, values?: Record<string, unknown>): string {\n const stringKey = typeof key === 'string' ? key : key.id\n\n if (priority === 'fluenti-first') {\n if (fluentCtx.te(stringKey)) {\n return fluentCtx.t(key, values)\n }\n return vueI18nGlobal.t(stringKey, values ?? {})\n } else {\n if (vueI18nGlobal.te(stringKey)) {\n return vueI18nGlobal.t(stringKey, values ?? {})\n }\n return fluentCtx.t(key, values)\n }\n }\n\n function bridgedTc(key: string, count: number, values?: Record<string, unknown>): string {\n // If fluenti has the key, use ICU plural resolution via t()\n if (priority === 'fluenti-first' && fluentCtx.te(key)) {\n return fluentCtx.t(key, { count, ...values })\n }\n // Fall back to vue-i18n's tc (which handles pipe-separated plurals)\n if (vueI18nGlobal.tc) {\n return vueI18nGlobal.tc(key, count, values ?? {})\n }\n // vue-i18n v10+ removed tc, use t with count\n return vueI18nGlobal.t(key, { count, ...values } as any)\n }\n\n function bridgedTe(key: string, locale?: string): boolean {\n return fluentCtx.te(key, locale) || vueI18nGlobal.te(key, locale)\n }\n\n function bridgedTm(key: string): unknown {\n // Prefer fluenti raw message if available\n if (priority === 'fluenti-first') {\n const raw = fluentCtx.tm(key)\n if (raw !== undefined) return raw\n }\n return vueI18nGlobal.tm(key)\n }\n\n const availableLocales = computed(() => {\n const locales = new Set<string>([\n ...fluentCtx.getLocales(),\n ...vueI18nGlobal.availableLocales,\n ])\n return [...locales].sort()\n })\n\n const context: BridgeContext = {\n t: bridgedT,\n tc: bridgedTc,\n te: bridgedTe,\n tm: bridgedTm,\n d: fluentCtx.d,\n n: fluentCtx.n,\n format: fluentCtx.format,\n locale: fluentCtx.locale,\n setLocale: async (locale: string) => {\n await fluentCtx.setLocale(locale)\n // setLocale already triggers the watcher, but ensure sync for non-reactive paths\n syncLocale('fluenti', locale)\n },\n availableLocales,\n isLoading: fluentCtx.isLoading,\n fluenti: fluentCtx,\n vueI18n: vueI18nGlobal,\n }\n\n return {\n install(app: App) {\n // Install both plugins\n app.use(vueI18n)\n app.use(fluenti)\n\n // Set up locale watchers (must be done after install since refs may be set up during install)\n watch(fluentCtx.locale, (newLocale) => {\n syncLocale('fluenti', newLocale)\n })\n watch(vueI18nGlobal.locale, (newLocale) => {\n syncLocale('vue-i18n', newLocale)\n })\n\n // Override global properties with bridged versions\n app.config.globalProperties['$t'] = bridgedT\n app.config.globalProperties['$te'] = bridgedTe\n app.config.globalProperties['$tc'] = bridgedTc\n\n // Provide bridge context\n app.provide(BRIDGE_KEY, context)\n },\n global: context,\n }\n}\n","import { inject } from 'vue'\nimport { BRIDGE_KEY } from './bridge'\nimport type { BridgeContext } from './types'\n\n/**\n * Unified composable that provides access to the bridge context.\n *\n * Returns a `BridgeContext` with translation methods that check both\n * vue-i18n and fluenti catalogs, locale management that syncs across\n * both libraries, and direct access to each underlying instance.\n *\n * @example\n * ```ts\n * const { t, tc, te, locale, setLocale, fluenti, vueI18n } = useI18n()\n * ```\n */\nexport function useI18n(): BridgeContext {\n const ctx = inject(BRIDGE_KEY)\n if (!ctx) {\n throw new Error(\n '[@fluenti/vue-i18n-compat] useI18n() requires the bridge plugin to be installed. ' +\n 'Call app.use(bridge) where bridge = createFluentBridge({ vueI18n, fluenti }).',\n )\n }\n return ctx\n}\n"],"mappings":"wFAIA,IAAa,EAA0C,OAAO,iBAAiB,CAkB/E,SAAgB,EAAmB,EAAsC,CACvE,GAAM,CAAE,UAAS,UAAS,WAAW,iBAAoB,EACnD,EAAY,EAAQ,OACpB,EAAgB,EAAQ,OAG1B,EAAU,GAEd,SAAS,EAAW,EAAgC,EAAmB,CACjE,MACJ,GAAU,GACV,GAAI,CACE,IAAW,UACT,EAAc,OAAO,QAAU,IACjC,EAAc,OAAO,MAAQ,GAG3B,EAAU,OAAO,QAAU,GAC7B,EAAU,UAAU,EAAU,QAG1B,CACR,EAAU,KAMd,SAAS,EAAS,EAAgD,EAA0C,CAC1G,IAAM,EAAY,OAAO,GAAQ,SAAW,EAAM,EAAI,GAWpD,OATE,IAAa,gBACX,EAAU,GAAG,EAAU,CAClB,EAAU,EAAE,EAAK,EAAO,CAE1B,EAAc,EAAE,EAAW,GAAU,EAAE,CAAC,CAE3C,EAAc,GAAG,EAAU,CACtB,EAAc,EAAE,EAAW,GAAU,EAAE,CAAC,CAE1C,EAAU,EAAE,EAAK,EAAO,CAInC,SAAS,EAAU,EAAa,EAAe,EAA0C,CAUvF,OARI,IAAa,iBAAmB,EAAU,GAAG,EAAI,CAC5C,EAAU,EAAE,EAAK,CAAE,QAAO,GAAG,EAAQ,CAAC,CAG3C,EAAc,GACT,EAAc,GAAG,EAAK,EAAO,GAAU,EAAE,CAAC,CAG5C,EAAc,EAAE,EAAK,CAAE,QAAO,GAAG,EAAQ,CAAQ,CAG1D,SAAS,EAAU,EAAa,EAA0B,CACxD,OAAO,EAAU,GAAG,EAAK,EAAO,EAAI,EAAc,GAAG,EAAK,EAAO,CAGnE,SAAS,EAAU,EAAsB,CAEvC,GAAI,IAAa,gBAAiB,CAChC,IAAM,EAAM,EAAU,GAAG,EAAI,CAC7B,GAAI,IAAQ,IAAA,GAAW,OAAO,EAEhC,OAAO,EAAc,GAAG,EAAI,CAG9B,IAAM,GAAA,EAAA,EAAA,cAKG,CAAC,GAJQ,IAAI,IAAY,CAC9B,GAAG,EAAU,YAAY,CACzB,GAAG,EAAc,iBAClB,CAAC,CACiB,CAAC,MAAM,CAC1B,CAEI,EAAyB,CAC7B,EAAG,EACH,GAAI,EACJ,GAAI,EACJ,GAAI,EACJ,EAAG,EAAU,EACb,EAAG,EAAU,EACb,OAAQ,EAAU,OAClB,OAAQ,EAAU,OAClB,UAAW,KAAO,IAAmB,CACnC,MAAM,EAAU,UAAU,EAAO,CAEjC,EAAW,UAAW,EAAO,EAE/B,mBACA,UAAW,EAAU,UACrB,QAAS,EACT,QAAS,EACV,CAED,MAAO,CACL,QAAQ,EAAU,CAEhB,EAAI,IAAI,EAAQ,CAChB,EAAI,IAAI,EAAQ,EAGhB,EAAA,EAAA,OAAM,EAAU,OAAS,GAAc,CACrC,EAAW,UAAW,EAAU,EAChC,EACF,EAAA,EAAA,OAAM,EAAc,OAAS,GAAc,CACzC,EAAW,WAAY,EAAU,EACjC,CAGF,EAAI,OAAO,iBAAiB,GAAQ,EACpC,EAAI,OAAO,iBAAiB,IAAS,EACrC,EAAI,OAAO,iBAAiB,IAAS,EAGrC,EAAI,QAAQ,EAAY,EAAQ,EAElC,OAAQ,EACT,CC/HH,SAAgB,GAAyB,CACvC,IAAM,GAAA,EAAA,EAAA,QAAa,EAAW,CAC9B,GAAI,CAAC,EACH,MAAU,MACR,iKAED,CAEH,OAAO"}
@@ -0,0 +1,4 @@
1
+ export { createFluentBridge, BRIDGE_KEY } from './bridge';
2
+ export { useI18n } from './composable';
3
+ export type { BridgeOptions, BridgeContext, BridgePlugin, BridgePriority, VueI18nInstance, VueI18nGlobal, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EACV,aAAa,EACb,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ import { computed as e, inject as t, watch as n } from "vue";
2
+ //#region src/bridge.ts
3
+ var r = Symbol("fluenti-bridge");
4
+ function i(t) {
5
+ let { vueI18n: i, fluenti: a, priority: o = "fluenti-first" } = t, s = a.global, c = i.global, l = !1;
6
+ function u(e, t) {
7
+ if (!l) {
8
+ l = !0;
9
+ try {
10
+ e === "fluenti" ? c.locale.value !== t && (c.locale.value = t) : s.locale.value !== t && s.setLocale(t);
11
+ } finally {
12
+ l = !1;
13
+ }
14
+ }
15
+ }
16
+ function d(e, t) {
17
+ let n = typeof e == "string" ? e : e.id;
18
+ return o === "fluenti-first" ? s.te(n) ? s.t(e, t) : c.t(n, t ?? {}) : c.te(n) ? c.t(n, t ?? {}) : s.t(e, t);
19
+ }
20
+ function f(e, t, n) {
21
+ return o === "fluenti-first" && s.te(e) ? s.t(e, {
22
+ count: t,
23
+ ...n
24
+ }) : c.tc ? c.tc(e, t, n ?? {}) : c.t(e, {
25
+ count: t,
26
+ ...n
27
+ });
28
+ }
29
+ function p(e, t) {
30
+ return s.te(e, t) || c.te(e, t);
31
+ }
32
+ function m(e) {
33
+ if (o === "fluenti-first") {
34
+ let t = s.tm(e);
35
+ if (t !== void 0) return t;
36
+ }
37
+ return c.tm(e);
38
+ }
39
+ let h = e(() => [...new Set([...s.getLocales(), ...c.availableLocales])].sort()), g = {
40
+ t: d,
41
+ tc: f,
42
+ te: p,
43
+ tm: m,
44
+ d: s.d,
45
+ n: s.n,
46
+ format: s.format,
47
+ locale: s.locale,
48
+ setLocale: async (e) => {
49
+ await s.setLocale(e), u("fluenti", e);
50
+ },
51
+ availableLocales: h,
52
+ isLoading: s.isLoading,
53
+ fluenti: s,
54
+ vueI18n: c
55
+ };
56
+ return {
57
+ install(e) {
58
+ e.use(i), e.use(a), n(s.locale, (e) => {
59
+ u("fluenti", e);
60
+ }), n(c.locale, (e) => {
61
+ u("vue-i18n", e);
62
+ }), e.config.globalProperties.$t = d, e.config.globalProperties.$te = p, e.config.globalProperties.$tc = f, e.provide(r, g);
63
+ },
64
+ global: g
65
+ };
66
+ }
67
+ //#endregion
68
+ //#region src/composable.ts
69
+ function a() {
70
+ let e = t(r);
71
+ if (!e) throw Error("[@fluenti/vue-i18n-compat] useI18n() requires the bridge plugin to be installed. Call app.use(bridge) where bridge = createFluentBridge({ vueI18n, fluenti }).");
72
+ return e;
73
+ }
74
+ //#endregion
75
+ export { r as BRIDGE_KEY, i as createFluentBridge, a as useI18n };
76
+
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/bridge.ts","../src/composable.ts"],"sourcesContent":["import { type App, type InjectionKey, computed, watch } from 'vue'\nimport type { BridgeOptions, BridgeContext, BridgePlugin } from './types'\n\n/** Injection key for the bridge context */\nexport const BRIDGE_KEY: InjectionKey<BridgeContext> = Symbol('fluenti-bridge')\n\n/**\n * Create a bridge plugin that connects vue-i18n and fluenti.\n *\n * Both libraries are installed, locale is synced bidirectionally,\n * and translation lookups fall through from one library to the other.\n *\n * @example\n * ```ts\n * const bridge = createFluentBridge({\n * vueI18n: i18n,\n * fluenti: fluent,\n * priority: 'fluenti-first',\n * })\n * app.use(bridge)\n * ```\n */\nexport function createFluentBridge(options: BridgeOptions): BridgePlugin {\n const { vueI18n, fluenti, priority = 'fluenti-first' } = options\n const fluentCtx = fluenti.global\n const vueI18nGlobal = vueI18n.global\n\n // --- Locale sync (bidirectional, with guard to prevent loops) ---\n let syncing = false\n\n function syncLocale(source: 'fluenti' | 'vue-i18n', newLocale: string) {\n if (syncing) return\n syncing = true\n try {\n if (source === 'fluenti') {\n if (vueI18nGlobal.locale.value !== newLocale) {\n vueI18nGlobal.locale.value = newLocale\n }\n } else {\n if (fluentCtx.locale.value !== newLocale) {\n fluentCtx.setLocale(newLocale)\n }\n }\n } finally {\n syncing = false\n }\n }\n\n // --- Bridged translation functions ---\n\n function bridgedT(key: string | { id: string; message?: string }, values?: Record<string, unknown>): string {\n const stringKey = typeof key === 'string' ? key : key.id\n\n if (priority === 'fluenti-first') {\n if (fluentCtx.te(stringKey)) {\n return fluentCtx.t(key, values)\n }\n return vueI18nGlobal.t(stringKey, values ?? {})\n } else {\n if (vueI18nGlobal.te(stringKey)) {\n return vueI18nGlobal.t(stringKey, values ?? {})\n }\n return fluentCtx.t(key, values)\n }\n }\n\n function bridgedTc(key: string, count: number, values?: Record<string, unknown>): string {\n // If fluenti has the key, use ICU plural resolution via t()\n if (priority === 'fluenti-first' && fluentCtx.te(key)) {\n return fluentCtx.t(key, { count, ...values })\n }\n // Fall back to vue-i18n's tc (which handles pipe-separated plurals)\n if (vueI18nGlobal.tc) {\n return vueI18nGlobal.tc(key, count, values ?? {})\n }\n // vue-i18n v10+ removed tc, use t with count\n return vueI18nGlobal.t(key, { count, ...values } as any)\n }\n\n function bridgedTe(key: string, locale?: string): boolean {\n return fluentCtx.te(key, locale) || vueI18nGlobal.te(key, locale)\n }\n\n function bridgedTm(key: string): unknown {\n // Prefer fluenti raw message if available\n if (priority === 'fluenti-first') {\n const raw = fluentCtx.tm(key)\n if (raw !== undefined) return raw\n }\n return vueI18nGlobal.tm(key)\n }\n\n const availableLocales = computed(() => {\n const locales = new Set<string>([\n ...fluentCtx.getLocales(),\n ...vueI18nGlobal.availableLocales,\n ])\n return [...locales].sort()\n })\n\n const context: BridgeContext = {\n t: bridgedT,\n tc: bridgedTc,\n te: bridgedTe,\n tm: bridgedTm,\n d: fluentCtx.d,\n n: fluentCtx.n,\n format: fluentCtx.format,\n locale: fluentCtx.locale,\n setLocale: async (locale: string) => {\n await fluentCtx.setLocale(locale)\n // setLocale already triggers the watcher, but ensure sync for non-reactive paths\n syncLocale('fluenti', locale)\n },\n availableLocales,\n isLoading: fluentCtx.isLoading,\n fluenti: fluentCtx,\n vueI18n: vueI18nGlobal,\n }\n\n return {\n install(app: App) {\n // Install both plugins\n app.use(vueI18n)\n app.use(fluenti)\n\n // Set up locale watchers (must be done after install since refs may be set up during install)\n watch(fluentCtx.locale, (newLocale) => {\n syncLocale('fluenti', newLocale)\n })\n watch(vueI18nGlobal.locale, (newLocale) => {\n syncLocale('vue-i18n', newLocale)\n })\n\n // Override global properties with bridged versions\n app.config.globalProperties['$t'] = bridgedT\n app.config.globalProperties['$te'] = bridgedTe\n app.config.globalProperties['$tc'] = bridgedTc\n\n // Provide bridge context\n app.provide(BRIDGE_KEY, context)\n },\n global: context,\n }\n}\n","import { inject } from 'vue'\nimport { BRIDGE_KEY } from './bridge'\nimport type { BridgeContext } from './types'\n\n/**\n * Unified composable that provides access to the bridge context.\n *\n * Returns a `BridgeContext` with translation methods that check both\n * vue-i18n and fluenti catalogs, locale management that syncs across\n * both libraries, and direct access to each underlying instance.\n *\n * @example\n * ```ts\n * const { t, tc, te, locale, setLocale, fluenti, vueI18n } = useI18n()\n * ```\n */\nexport function useI18n(): BridgeContext {\n const ctx = inject(BRIDGE_KEY)\n if (!ctx) {\n throw new Error(\n '[@fluenti/vue-i18n-compat] useI18n() requires the bridge plugin to be installed. ' +\n 'Call app.use(bridge) where bridge = createFluentBridge({ vueI18n, fluenti }).',\n )\n }\n return ctx\n}\n"],"mappings":";;AAIA,IAAa,IAA0C,OAAO,iBAAiB;AAkB/E,SAAgB,EAAmB,GAAsC;CACvE,IAAM,EAAE,YAAS,YAAS,cAAW,oBAAoB,GACnD,IAAY,EAAQ,QACpB,IAAgB,EAAQ,QAG1B,IAAU;CAEd,SAAS,EAAW,GAAgC,GAAmB;AACjE,UACJ;OAAU;AACV,OAAI;AACF,IAAI,MAAW,YACT,EAAc,OAAO,UAAU,MACjC,EAAc,OAAO,QAAQ,KAG3B,EAAU,OAAO,UAAU,KAC7B,EAAU,UAAU,EAAU;aAG1B;AACR,QAAU;;;;CAMd,SAAS,EAAS,GAAgD,GAA0C;EAC1G,IAAM,IAAY,OAAO,KAAQ,WAAW,IAAM,EAAI;AAWpD,SATE,MAAa,kBACX,EAAU,GAAG,EAAU,GAClB,EAAU,EAAE,GAAK,EAAO,GAE1B,EAAc,EAAE,GAAW,KAAU,EAAE,CAAC,GAE3C,EAAc,GAAG,EAAU,GACtB,EAAc,EAAE,GAAW,KAAU,EAAE,CAAC,GAE1C,EAAU,EAAE,GAAK,EAAO;;CAInC,SAAS,EAAU,GAAa,GAAe,GAA0C;AAUvF,SARI,MAAa,mBAAmB,EAAU,GAAG,EAAI,GAC5C,EAAU,EAAE,GAAK;GAAE;GAAO,GAAG;GAAQ,CAAC,GAG3C,EAAc,KACT,EAAc,GAAG,GAAK,GAAO,KAAU,EAAE,CAAC,GAG5C,EAAc,EAAE,GAAK;GAAE;GAAO,GAAG;GAAQ,CAAQ;;CAG1D,SAAS,EAAU,GAAa,GAA0B;AACxD,SAAO,EAAU,GAAG,GAAK,EAAO,IAAI,EAAc,GAAG,GAAK,EAAO;;CAGnE,SAAS,EAAU,GAAsB;AAEvC,MAAI,MAAa,iBAAiB;GAChC,IAAM,IAAM,EAAU,GAAG,EAAI;AAC7B,OAAI,MAAQ,KAAA,EAAW,QAAO;;AAEhC,SAAO,EAAc,GAAG,EAAI;;CAG9B,IAAM,IAAmB,QAKhB,CAAC,GAJQ,IAAI,IAAY,CAC9B,GAAG,EAAU,YAAY,EACzB,GAAG,EAAc,iBAClB,CAAC,CACiB,CAAC,MAAM,CAC1B,EAEI,IAAyB;EAC7B,GAAG;EACH,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,GAAG,EAAU;EACb,GAAG,EAAU;EACb,QAAQ,EAAU;EAClB,QAAQ,EAAU;EAClB,WAAW,OAAO,MAAmB;AAGnC,GAFA,MAAM,EAAU,UAAU,EAAO,EAEjC,EAAW,WAAW,EAAO;;EAE/B;EACA,WAAW,EAAU;EACrB,SAAS;EACT,SAAS;EACV;AAED,QAAO;EACL,QAAQ,GAAU;AAmBhB,GAjBA,EAAI,IAAI,EAAQ,EAChB,EAAI,IAAI,EAAQ,EAGhB,EAAM,EAAU,SAAS,MAAc;AACrC,MAAW,WAAW,EAAU;KAChC,EACF,EAAM,EAAc,SAAS,MAAc;AACzC,MAAW,YAAY,EAAU;KACjC,EAGF,EAAI,OAAO,iBAAiB,KAAQ,GACpC,EAAI,OAAO,iBAAiB,MAAS,GACrC,EAAI,OAAO,iBAAiB,MAAS,GAGrC,EAAI,QAAQ,GAAY,EAAQ;;EAElC,QAAQ;EACT;;;;AC/HH,SAAgB,IAAyB;CACvC,IAAM,IAAM,EAAO,EAAW;AAC9B,KAAI,CAAC,EACH,OAAU,MACR,iKAED;AAEH,QAAO"}
@@ -0,0 +1,72 @@
1
+ import { ComputedRef, Ref } from 'vue';
2
+ import { FluentVuePlugin, FluentVueContext } from '@fluenti/vue';
3
+ /** Lookup priority when resolving translations across both libraries */
4
+ export type BridgePriority = 'fluenti-first' | 'vue-i18n-first';
5
+ /** Options for creating the bridge plugin */
6
+ export interface BridgeOptions {
7
+ /** The vue-i18n instance (from createI18n()) */
8
+ vueI18n: VueI18nInstance;
9
+ /** The fluenti Vue plugin (from createFluentVue()) */
10
+ fluenti: FluentVuePlugin;
11
+ /** Which library to check first when resolving translations (default: 'fluenti-first') */
12
+ priority?: BridgePriority;
13
+ }
14
+ /**
15
+ * Minimal vue-i18n instance interface.
16
+ * We don't import vue-i18n types directly to avoid hard coupling.
17
+ */
18
+ export interface VueI18nInstance {
19
+ install: (app: any) => void;
20
+ global: VueI18nGlobal;
21
+ }
22
+ /** Minimal vue-i18n global composer interface */
23
+ export interface VueI18nGlobal {
24
+ locale: Ref<string>;
25
+ t: (key: string, ...args: any[]) => string;
26
+ te: (key: string, locale?: string) => boolean;
27
+ tm: (key: string) => unknown;
28
+ tc?: (key: string, count: number, ...args: any[]) => string;
29
+ d: (value: Date | number, ...args: any[]) => string;
30
+ n: (value: number, ...args: any[]) => string;
31
+ availableLocales: string[];
32
+ }
33
+ /** Context returned by the bridge's useI18n() composable */
34
+ export interface BridgeContext {
35
+ /** Translate a message — checks both libraries per priority setting */
36
+ t(key: string | {
37
+ id: string;
38
+ message?: string;
39
+ }, values?: Record<string, unknown>): string;
40
+ /** Pluralized translation (delegates to vue-i18n for unmigrated plural messages) */
41
+ tc(key: string, count: number, values?: Record<string, unknown>): string;
42
+ /** Check if a translation key exists in either library */
43
+ te(key: string, locale?: string): boolean;
44
+ /** Get raw message (from vue-i18n) */
45
+ tm(key: string): unknown;
46
+ /** Format a date */
47
+ d(value: Date | number, style?: string): string;
48
+ /** Format a number */
49
+ n(value: number, style?: string): string;
50
+ /** Format an ICU message string directly */
51
+ format(message: string, values?: Record<string, unknown>): string;
52
+ /** Reactive locale ref (synced across both libraries) */
53
+ locale: Readonly<Ref<string>>;
54
+ /** Change locale (syncs to both libraries) */
55
+ setLocale(locale: string): Promise<void>;
56
+ /** All available locales from both libraries */
57
+ availableLocales: ComputedRef<string[]>;
58
+ /** Whether fluenti is loading a locale chunk */
59
+ isLoading: Readonly<Ref<boolean>>;
60
+ /** Access the underlying fluenti context */
61
+ fluenti: FluentVueContext;
62
+ /** Access the underlying vue-i18n global composer */
63
+ vueI18n: VueI18nGlobal;
64
+ }
65
+ /** Return type of createFluentBridge() */
66
+ export interface BridgePlugin {
67
+ /** Vue plugin install method */
68
+ install(app: any): void;
69
+ /** The global bridge context */
70
+ global: BridgeContext;
71
+ }
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@fluenti/vue-i18n-compat",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Progressive migration bridge between vue-i18n and Fluenti — share locale, translate across both libraries",
6
+ "homepage": "https://fluenti.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/usefluenti/fluenti.git",
10
+ "directory": "packages/vue-i18n-compat"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/usefluenti/fluenti/issues"
14
+ },
15
+ "license": "MIT",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "keywords": [
20
+ "i18n",
21
+ "vue-i18n",
22
+ "compat",
23
+ "migration",
24
+ "bridge",
25
+ "fluenti",
26
+ "vue"
27
+ ],
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "import": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/index.d.ts",
39
+ "default": "./dist/index.cjs"
40
+ }
41
+ }
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "peerDependencies": {
47
+ "vue": "^3.5",
48
+ "vue-i18n": "^9 || ^10"
49
+ },
50
+ "dependencies": {
51
+ "@fluenti/core": "0.1.0",
52
+ "@fluenti/vue": "0.1.0"
53
+ },
54
+ "devDependencies": {
55
+ "@vitest/coverage-v8": "^4",
56
+ "typescript": "^5.9",
57
+ "vite": "^8",
58
+ "vite-plugin-dts": "^4",
59
+ "vitest": "^4",
60
+ "vue": "^3.5",
61
+ "vue-i18n": "^10",
62
+ "@vue/test-utils": "^2",
63
+ "happy-dom": "^20"
64
+ },
65
+ "scripts": {
66
+ "build": "vite build",
67
+ "dev": "vite build --watch",
68
+ "test": "vitest run",
69
+ "typecheck": "tsc --noEmit"
70
+ }
71
+ }