@fluenti/vue 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 +21 -0
- package/README.md +380 -0
- package/dist/compile-time-t.d.ts +3 -0
- package/dist/compile-time-t.d.ts.map +1 -0
- package/dist/components/DateTime.d.ts +60 -0
- package/dist/components/DateTime.d.ts.map +1 -0
- package/dist/components/NumberFormat.d.ts +60 -0
- package/dist/components/NumberFormat.d.ts.map +1 -0
- package/dist/components/Plural.d.ts +138 -0
- package/dist/components/Plural.d.ts.map +1 -0
- package/dist/components/Select.d.ts +135 -0
- package/dist/components/Select.d.ts.map +1 -0
- package/dist/components/Trans.d.ts +63 -0
- package/dist/components/Trans.d.ts.map +1 -0
- package/dist/components/rich-text.d.ts +17 -0
- package/dist/components/rich-text.d.ts.map +1 -0
- package/dist/hooks/__useI18n.d.ts +12 -0
- package/dist/hooks/__useI18n.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +427 -0
- package/dist/index.js.map +1 -0
- package/dist/msg.d.ts +2 -0
- package/dist/msg.d.ts.map +1 -0
- package/dist/plugin.d.ts +84 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/server.d.ts +69 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/use-i18n.d.ts +11 -0
- package/dist/use-i18n.d.ts.map +1 -0
- package/package.json +70 -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,380 @@
|
|
|
1
|
+
# @fluenti/vue
|
|
2
|
+
|
|
3
|
+
**Compile-time i18n for Vue 3. Zero runtime parsing. Type-safe templates.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@fluenti/vue)
|
|
6
|
+
[](https://bundlephobia.com/package/@fluenti/vue)
|
|
7
|
+
[](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
Your translations are compiled at build time into optimized functions — no ICU parser ships to the browser, no runtime overhead, just fast string lookups. Write natural language in your templates; Fluenti handles the rest.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The Magic: Write Natural Language, Ship Optimized Code
|
|
14
|
+
|
|
15
|
+
### The `v-t` directive (compiled away at build time)
|
|
16
|
+
|
|
17
|
+
`v-t` is not a runtime directive. It is a **Vue compiler transform** that rewrites your templates during build. What you write and what ships to production are two different things:
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<!-- What you write -->
|
|
21
|
+
<template>
|
|
22
|
+
<h1 v-t>Welcome to our app!</h1>
|
|
23
|
+
<p v-t>Hello, {name}!</p>
|
|
24
|
+
<p v-t.plural="count">one apple | {count} apples</p>
|
|
25
|
+
<img v-t.alt alt="Hero banner" src="/hero.png" />
|
|
26
|
+
</template>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```vue
|
|
30
|
+
<!-- What ships to the browser (conceptual) -->
|
|
31
|
+
<template>
|
|
32
|
+
<h1>{{ $t('a1b2c3') }}</h1>
|
|
33
|
+
<p>{{ $t('d4e5f6', { name }) }}</p>
|
|
34
|
+
<p>{{ $t('{count, plural, one {# apple} other {# apples}}', { count }) }}</p>
|
|
35
|
+
<img :alt="$t('f7g8h9')" src="/hero.png" />
|
|
36
|
+
</template>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
No parsing. No interpretation. Just a hash lookup into a pre-compiled catalog. This is what compile-time i18n means.
|
|
40
|
+
|
|
41
|
+
### The `t` tagged template (in `<script setup>`)
|
|
42
|
+
|
|
43
|
+
For programmatic translations outside of templates, use `msg` with `useI18n()`:
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<script setup lang="ts">
|
|
47
|
+
import { useI18n } from '@fluenti/vue'
|
|
48
|
+
|
|
49
|
+
const { t } = useI18n()
|
|
50
|
+
|
|
51
|
+
const greeting = t('Hello, {name}!', { name: 'World' })
|
|
52
|
+
const formatted = t('You have {count} items', { count: 42 })
|
|
53
|
+
</script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
### 1. Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm add @fluenti/core @fluenti/vue @fluenti/vite-plugin
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. Configure Vite
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// vite.config.ts
|
|
70
|
+
import vue from '@vitejs/plugin-vue'
|
|
71
|
+
import fluenti from '@fluenti/vite-plugin'
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
plugins: [vue(), fluenti({ framework: 'vue' })],
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Create the plugin
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// main.ts
|
|
82
|
+
import { createApp } from 'vue'
|
|
83
|
+
import { createFluentVue } from '@fluenti/vue'
|
|
84
|
+
import App from './App.vue'
|
|
85
|
+
import en from './locales/compiled/en'
|
|
86
|
+
import ja from './locales/compiled/ja'
|
|
87
|
+
|
|
88
|
+
const fluent = createFluentVue({
|
|
89
|
+
locale: 'en',
|
|
90
|
+
fallbackLocale: 'en',
|
|
91
|
+
messages: { en, ja },
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const app = createApp(App)
|
|
95
|
+
app.use(fluent)
|
|
96
|
+
app.mount('#app')
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Use in your SFC
|
|
100
|
+
|
|
101
|
+
```vue
|
|
102
|
+
<script setup>
|
|
103
|
+
import { useI18n } from '@fluenti/vue'
|
|
104
|
+
|
|
105
|
+
const { locale, setLocale } = useI18n()
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<template>
|
|
109
|
+
<h1 v-t>Hello, world!</h1>
|
|
110
|
+
<p v-t>Welcome to our application.</p>
|
|
111
|
+
|
|
112
|
+
<button @click="setLocale('ja')">日本語</button>
|
|
113
|
+
</template>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
That's it. Four files, zero boilerplate.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Components
|
|
121
|
+
|
|
122
|
+
### `<Trans>` — Rich Text with HTML and Components
|
|
123
|
+
|
|
124
|
+
Translate text that contains inline HTML elements or Vue components. Child elements are preserved through the translation round-trip:
|
|
125
|
+
|
|
126
|
+
```vue
|
|
127
|
+
<template>
|
|
128
|
+
<Trans>Read the <a href="/docs">documentation</a></Trans>
|
|
129
|
+
<Trans>Click <RouterLink to="/next">here</RouterLink> to continue.</Trans>
|
|
130
|
+
</template>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| Prop | Type | Default | Description |
|
|
134
|
+
|-------|----------|----------|-----------------|
|
|
135
|
+
| `tag` | `string` | `'span'` | Wrapper element |
|
|
136
|
+
|
|
137
|
+
### `<Plural>` — Plural Forms
|
|
138
|
+
|
|
139
|
+
Full ICU plural support as a component. Use string props for simple cases, or named slots for rich text:
|
|
140
|
+
|
|
141
|
+
```vue
|
|
142
|
+
<template>
|
|
143
|
+
<!-- Simple: string props -->
|
|
144
|
+
<Plural :value="count" zero="No items" one="1 item" other="{count} items" />
|
|
145
|
+
|
|
146
|
+
<!-- Rich: named slots -->
|
|
147
|
+
<Plural :value="count">
|
|
148
|
+
<template #zero>No <strong>items</strong> left</template>
|
|
149
|
+
<template #one><em>1</em> item remaining</template>
|
|
150
|
+
<template #other><strong>{{ count }}</strong> items remaining</template>
|
|
151
|
+
</Plural>
|
|
152
|
+
</template>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Prop | Type | Default | Description |
|
|
156
|
+
|---------|----------|----------|--------------------------------------|
|
|
157
|
+
| `value` | `number` | required | The count to pluralize on |
|
|
158
|
+
| `zero` | `string` | -- | Text for zero items (ICU `=0`) |
|
|
159
|
+
| `one` | `string` | -- | Singular form |
|
|
160
|
+
| `two` | `string` | -- | Dual form |
|
|
161
|
+
| `few` | `string` | -- | Few form (some languages) |
|
|
162
|
+
| `many` | `string` | -- | Many form (some languages) |
|
|
163
|
+
| `other` | `string` | `''` | Default/fallback form |
|
|
164
|
+
| `tag` | `string` | `'span'` | Wrapper element |
|
|
165
|
+
|
|
166
|
+
Slots: `#zero`, `#one`, `#two`, `#few`, `#many`, `#other` -- each receives `{ count }` as slot props.
|
|
167
|
+
|
|
168
|
+
### `<Select>` — Gender / Option Selection
|
|
169
|
+
|
|
170
|
+
ICU select patterns as a component:
|
|
171
|
+
|
|
172
|
+
```vue
|
|
173
|
+
<template>
|
|
174
|
+
<!-- String props -->
|
|
175
|
+
<Select :value="gender" male="He liked this" female="She liked this" other="They liked this" />
|
|
176
|
+
|
|
177
|
+
<!-- Options map (recommended for dynamic keys) -->
|
|
178
|
+
<Select :value="role" :options="{ admin: 'Administrator', editor: 'Editor' }" other="Viewer" />
|
|
179
|
+
|
|
180
|
+
<!-- Rich text via slots -->
|
|
181
|
+
<Select :value="gender">
|
|
182
|
+
<template #male><strong>He</strong> liked this</template>
|
|
183
|
+
<template #female><strong>She</strong> liked this</template>
|
|
184
|
+
<template #other><em>They</em> liked this</template>
|
|
185
|
+
</Select>
|
|
186
|
+
</template>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Prop | Type | Default | Description |
|
|
190
|
+
|-----------|---------------------------|----------|------------------------------------|
|
|
191
|
+
| `value` | `string` | required | The value to match against |
|
|
192
|
+
| `options` | `Record<string, string>` | -- | Named options map |
|
|
193
|
+
| `other` | `string` | `''` | Fallback when no option matches |
|
|
194
|
+
| `tag` | `string` | `'span'` | Wrapper element |
|
|
195
|
+
|
|
196
|
+
Slots: Named slots matching option keys, each receives `{ value }` as slot props.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## `v-t` Directive Reference
|
|
201
|
+
|
|
202
|
+
| Modifier | Effect |
|
|
203
|
+
|----------------|-----------------------------------|
|
|
204
|
+
| _(none)_ | Translates text content |
|
|
205
|
+
| `.plural` | Enables plural forms (pipe syntax)|
|
|
206
|
+
| `.alt` | Translates the `alt` attribute |
|
|
207
|
+
| `.placeholder` | Translates the `placeholder` attribute |
|
|
208
|
+
| `.title` | Translates the `title` attribute |
|
|
209
|
+
| `.{attr}` | Translates any named attribute |
|
|
210
|
+
|
|
211
|
+
```vue
|
|
212
|
+
<template>
|
|
213
|
+
<h1 v-t>Hello, world!</h1>
|
|
214
|
+
<p v-t.plural="count">one apple | {count} apples</p>
|
|
215
|
+
<img v-t.alt alt="Welcome banner" src="banner.png" />
|
|
216
|
+
<input v-t.placeholder placeholder="Search..." />
|
|
217
|
+
</template>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## `useI18n()` Composable
|
|
223
|
+
|
|
224
|
+
The full API surface, available inside any component with the plugin installed:
|
|
225
|
+
|
|
226
|
+
```vue
|
|
227
|
+
<script setup>
|
|
228
|
+
import { useI18n } from '@fluenti/vue'
|
|
229
|
+
|
|
230
|
+
const { t, d, n, locale, setLocale } = useI18n()
|
|
231
|
+
</script>
|
|
232
|
+
|
|
233
|
+
<template>
|
|
234
|
+
<p>{{ t('Hello, {name}!', { name: 'World' }) }}</p>
|
|
235
|
+
<p>{{ d(new Date(), 'long') }}</p>
|
|
236
|
+
<p>{{ n(1234.5, 'currency') }}</p>
|
|
237
|
+
<button @click="setLocale('ja')">日本語</button>
|
|
238
|
+
</template>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
| Method | Signature | Description |
|
|
242
|
+
|-----------------|----------------------------------------------------------------|----------------------------------------------------------|
|
|
243
|
+
| `t` | `(id: string \| MessageDescriptor, values?) => string` | Translate a key with optional interpolation |
|
|
244
|
+
| `d` | `(value: Date \| number, style?) => string` | Format a date using `dateFormats` presets or Intl |
|
|
245
|
+
| `n` | `(value: number, style?) => string` | Format a number using `numberFormats` presets or Intl |
|
|
246
|
+
| `format` | `(message: string, values?) => string` | Format an ICU message string directly (no catalog lookup)|
|
|
247
|
+
| `te` | `(key: string, locale?) => boolean` | Check if a translation key exists |
|
|
248
|
+
| `tm` | `(key: string, locale?) => CompiledMessage \| undefined` | Get the raw compiled message without interpolation |
|
|
249
|
+
| `locale` | `Ref<string>` (readonly) | Reactive ref for the current locale |
|
|
250
|
+
| `setLocale` | `(locale: string) => Promise<void>` | Change locale (async when lazy locale loading is enabled) |
|
|
251
|
+
| `loadMessages` | `(locale: string, messages: Messages) => void` | Dynamically add messages for a locale at runtime |
|
|
252
|
+
| `getLocales` | `() => string[]` | Get all locales that have loaded messages |
|
|
253
|
+
| `preloadLocale` | `(locale: string) => void` | Preload a locale chunk in the background |
|
|
254
|
+
| `isLoading` | `Ref<boolean>` (readonly) | Whether a locale chunk is currently being loaded |
|
|
255
|
+
| `loadedLocales` | `Ref<ReadonlySet<string>>` (readonly) | Set of locales whose messages have been loaded |
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Plugin Options
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
const fluent = createFluentVue({
|
|
263
|
+
// Required
|
|
264
|
+
locale: 'en',
|
|
265
|
+
messages: { en, ja, zh },
|
|
266
|
+
|
|
267
|
+
// Optional
|
|
268
|
+
fallbackLocale: 'en',
|
|
269
|
+
fallbackChain: { 'zh-TW': ['zh', 'en'], '*': ['en'] },
|
|
270
|
+
dateFormats: {
|
|
271
|
+
short: { year: 'numeric', month: 'short', day: 'numeric' },
|
|
272
|
+
long: { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' },
|
|
273
|
+
relative: 'relative',
|
|
274
|
+
},
|
|
275
|
+
numberFormats: {
|
|
276
|
+
currency: { style: 'currency', currency: 'USD' },
|
|
277
|
+
percent: { style: 'percent', minimumFractionDigits: 1 },
|
|
278
|
+
},
|
|
279
|
+
missing: (locale, id) => `[missing: ${id}]`,
|
|
280
|
+
componentPrefix: 'I18n', // registers I18nTrans, I18nPlural, I18nSelect
|
|
281
|
+
lazyLocaleLoading: true,
|
|
282
|
+
chunkLoader: (locale) => import(`./locales/${locale}.js`),
|
|
283
|
+
|
|
284
|
+
// Post-translation transform applied to every resolved message
|
|
285
|
+
transform: (result, id, locale) => result,
|
|
286
|
+
|
|
287
|
+
// Callback fired whenever the locale changes
|
|
288
|
+
onLocaleChange: (newLocale, prevLocale) => {
|
|
289
|
+
document.documentElement.lang = newLocale
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
// Custom ICU function formatters (e.g. {items, list})
|
|
293
|
+
formatters: {
|
|
294
|
+
list: (value, style, locale) =>
|
|
295
|
+
new Intl.ListFormat(locale, { type: style || 'conjunction' }).format(value),
|
|
296
|
+
},
|
|
297
|
+
})
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
| Option | Type | Default | Description |
|
|
301
|
+
|-------------------|------------------------------------|---------|----------------------------------------------------------|
|
|
302
|
+
| `locale` | `string` | -- | Active locale code (required) |
|
|
303
|
+
| `messages` | `Record<string, Messages>` | -- | Pre-loaded message catalogs (required) |
|
|
304
|
+
| `fallbackLocale` | `string` | -- | Locale to try when a key is missing |
|
|
305
|
+
| `fallbackChain` | `Record<string, string[]>` | -- | Locale-specific fallback chains (`'*'` for default) |
|
|
306
|
+
| `dateFormats` | `Record<string, DateTimeFormatOptions \| 'relative'>` | -- | Named date format presets for `d()` |
|
|
307
|
+
| `numberFormats` | `Record<string, NumberFormatOptions>` | -- | Named number format presets for `n()` |
|
|
308
|
+
| `missing` | `(locale, id) => string \| undefined` | -- | Handler called when a translation key is not found |
|
|
309
|
+
| `componentPrefix` | `string` | `''` | Prefix for globally registered components |
|
|
310
|
+
| `lazyLocaleLoading` | `boolean` | `false` | Enable async locale loading through `chunkLoader` |
|
|
311
|
+
| `chunkLoader` | `(locale) => Promise<Messages>` | -- | Async loader for locale chunks (requires `lazyLocaleLoading`) |
|
|
312
|
+
| `transform` | `(result: string, id: string, locale: string) => string` | -- | Post-interpolation hook applied to every resolved message |
|
|
313
|
+
| `onLocaleChange` | `(newLocale: string, prevLocale: string) => void` | -- | Callback fired whenever the locale changes via `setLocale()` |
|
|
314
|
+
| `formatters` | `Record<string, CustomFormatter>` | -- | Custom ICU function formatters keyed by function name |
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Code Splitting
|
|
319
|
+
|
|
320
|
+
For large apps, load locale messages on demand instead of bundling everything upfront:
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
const fluent = createFluentVue({
|
|
324
|
+
locale: 'en',
|
|
325
|
+
messages: { en }, // only the default locale is bundled
|
|
326
|
+
lazyLocaleLoading: true,
|
|
327
|
+
chunkLoader: (locale) => import(`./locales/compiled/${locale}.js`),
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
// Later: switching locale triggers async loading
|
|
331
|
+
await fluent.global.setLocale('ja') // loads ja chunk, then switches
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Preload locales in the background for instant switching:
|
|
335
|
+
|
|
336
|
+
```vue
|
|
337
|
+
<script setup>
|
|
338
|
+
const { setLocale, isLoading, preloadLocale } = useI18n()
|
|
339
|
+
</script>
|
|
340
|
+
|
|
341
|
+
<template>
|
|
342
|
+
<button @mouseenter="preloadLocale('ja')" @click="setLocale('ja')" :disabled="isLoading">
|
|
343
|
+
{{ isLoading ? 'Loading...' : '日本語' }}
|
|
344
|
+
</button>
|
|
345
|
+
</template>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## SSR / SSG Support
|
|
351
|
+
|
|
352
|
+
`createFluentVue()` creates entirely fresh state per call -- no module-level singletons. Call it once per SSR request to avoid locale leaking between users.
|
|
353
|
+
|
|
354
|
+
For server-side i18n in Nuxt or custom Vue SSR setups, use the dedicated server utilities:
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
import { createServerI18n, detectLocale, getSSRLocaleScript } from '@fluenti/vue/server'
|
|
358
|
+
|
|
359
|
+
const { setLocale, getI18n } = createServerI18n({
|
|
360
|
+
loadMessages: (locale) => import(`./locales/compiled/${locale}.js`),
|
|
361
|
+
fallbackLocale: 'en',
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
SSR utilities included:
|
|
366
|
+
- `createServerI18n()` -- per-request i18n with lazy message loading and caching
|
|
367
|
+
- `detectLocale()` -- locale detection from cookies, headers, path, or query
|
|
368
|
+
- `getSSRLocaleScript()` -- inline script tag for hydration
|
|
369
|
+
- `getHydratedLocale()` -- read the hydrated locale on the client
|
|
370
|
+
- `isRTL()` / `getDirection()` -- RTL/LTR detection
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Documentation
|
|
375
|
+
|
|
376
|
+
Full documentation at [fluenti.dev](https://fluenti.dev).
|
|
377
|
+
|
|
378
|
+
## License
|
|
379
|
+
|
|
380
|
+
[MIT](https://github.com/usefluenti/fluenti/blob/main/LICENSE)
|
|
@@ -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,60 @@
|
|
|
1
|
+
import { ExtractPropTypes, PropType } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* `<DateTime>` component for formatting dates according to locale.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```vue
|
|
7
|
+
* <DateTime :value="new Date()" />
|
|
8
|
+
* <DateTime :value="Date.now()" style="short" />
|
|
9
|
+
* <DateTime :value="event.date" style="long" tag="time" />
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
declare const dateTimeProps: {
|
|
13
|
+
readonly value: {
|
|
14
|
+
readonly type: PropType<Date | number>;
|
|
15
|
+
readonly required: true;
|
|
16
|
+
};
|
|
17
|
+
readonly style: {
|
|
18
|
+
readonly type: StringConstructor;
|
|
19
|
+
readonly default: undefined;
|
|
20
|
+
};
|
|
21
|
+
readonly tag: {
|
|
22
|
+
readonly type: StringConstructor;
|
|
23
|
+
readonly default: "span";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type DateTimeProps = Readonly<ExtractPropTypes<typeof dateTimeProps>>;
|
|
27
|
+
export declare const DateTime: import('vue').DefineComponent<ExtractPropTypes<{
|
|
28
|
+
readonly value: {
|
|
29
|
+
readonly type: PropType<Date | number>;
|
|
30
|
+
readonly required: true;
|
|
31
|
+
};
|
|
32
|
+
readonly style: {
|
|
33
|
+
readonly type: StringConstructor;
|
|
34
|
+
readonly default: undefined;
|
|
35
|
+
};
|
|
36
|
+
readonly tag: {
|
|
37
|
+
readonly type: StringConstructor;
|
|
38
|
+
readonly default: "span";
|
|
39
|
+
};
|
|
40
|
+
}>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ExtractPropTypes<{
|
|
43
|
+
readonly value: {
|
|
44
|
+
readonly type: PropType<Date | number>;
|
|
45
|
+
readonly required: true;
|
|
46
|
+
};
|
|
47
|
+
readonly style: {
|
|
48
|
+
readonly type: StringConstructor;
|
|
49
|
+
readonly default: undefined;
|
|
50
|
+
};
|
|
51
|
+
readonly tag: {
|
|
52
|
+
readonly type: StringConstructor;
|
|
53
|
+
readonly default: "span";
|
|
54
|
+
};
|
|
55
|
+
}>> & Readonly<{}>, {
|
|
56
|
+
readonly style: string;
|
|
57
|
+
readonly tag: string;
|
|
58
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=DateTime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateTime.d.ts","sourceRoot":"","sources":["../../src/components/DateTime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAA;AAGrD;;;;;;;;;GASG;AACH,QAAA,MAAM,aAAa;;uBACgB,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC;;;;;;;;;;;CAGhD,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,gBAAgB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAA;AAE5E,eAAO,MAAM,QAAQ;;uBAPc,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC;;;;;;;;;;;;;;;uBAAvB,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC;;;;;;;;;;;;;;4EAcxD,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ExtractPropTypes } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* `<NumberFormat>` component for formatting numbers according to locale.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```vue
|
|
7
|
+
* <NumberFormat :value="1234.56" />
|
|
8
|
+
* <NumberFormat :value="0.75" style="percent" />
|
|
9
|
+
* <NumberFormat :value="99.99" style="currency" tag="strong" />
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
declare const numberFormatProps: {
|
|
13
|
+
readonly value: {
|
|
14
|
+
readonly type: NumberConstructor;
|
|
15
|
+
readonly required: true;
|
|
16
|
+
};
|
|
17
|
+
readonly style: {
|
|
18
|
+
readonly type: StringConstructor;
|
|
19
|
+
readonly default: undefined;
|
|
20
|
+
};
|
|
21
|
+
readonly tag: {
|
|
22
|
+
readonly type: StringConstructor;
|
|
23
|
+
readonly default: "span";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type NumberFormatProps = Readonly<ExtractPropTypes<typeof numberFormatProps>>;
|
|
27
|
+
export declare const NumberFormat: import('vue').DefineComponent<ExtractPropTypes<{
|
|
28
|
+
readonly value: {
|
|
29
|
+
readonly type: NumberConstructor;
|
|
30
|
+
readonly required: true;
|
|
31
|
+
};
|
|
32
|
+
readonly style: {
|
|
33
|
+
readonly type: StringConstructor;
|
|
34
|
+
readonly default: undefined;
|
|
35
|
+
};
|
|
36
|
+
readonly tag: {
|
|
37
|
+
readonly type: StringConstructor;
|
|
38
|
+
readonly default: "span";
|
|
39
|
+
};
|
|
40
|
+
}>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ExtractPropTypes<{
|
|
43
|
+
readonly value: {
|
|
44
|
+
readonly type: NumberConstructor;
|
|
45
|
+
readonly required: true;
|
|
46
|
+
};
|
|
47
|
+
readonly style: {
|
|
48
|
+
readonly type: StringConstructor;
|
|
49
|
+
readonly default: undefined;
|
|
50
|
+
};
|
|
51
|
+
readonly tag: {
|
|
52
|
+
readonly type: StringConstructor;
|
|
53
|
+
readonly default: "span";
|
|
54
|
+
};
|
|
55
|
+
}>> & Readonly<{}>, {
|
|
56
|
+
readonly style: string;
|
|
57
|
+
readonly tag: string;
|
|
58
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=NumberFormat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NumberFormat.d.ts","sourceRoot":"","sources":["../../src/components/NumberFormat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAA;AAG3C;;;;;;;;;GASG;AACH,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;CAIb,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,gBAAgB,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAA;AAEpF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAOvB,CAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ExtractPropTypes } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* `<Plural>` component — shorthand for ICU plural patterns.
|
|
4
|
+
*
|
|
5
|
+
* Plural form props (`zero`, `one`, `two`, `few`, `many`, `other`) are treated
|
|
6
|
+
* as source-language messages. The component builds an ICU plural message,
|
|
7
|
+
* looks it up via `t()` in the catalog, and interpolates the translated result.
|
|
8
|
+
*
|
|
9
|
+
* When no catalog translation exists, the component falls back to interpolating
|
|
10
|
+
* the source-language ICU message directly via the `message` field of the
|
|
11
|
+
* MessageDescriptor.
|
|
12
|
+
*
|
|
13
|
+
* Rich text is supported via named slots:
|
|
14
|
+
* ```vue
|
|
15
|
+
* <Plural :value="count">
|
|
16
|
+
* <template #zero>No <strong>items</strong></template>
|
|
17
|
+
* <template #one><em>1</em> item</template>
|
|
18
|
+
* <template #other><strong>{{ count }}</strong> items</template>
|
|
19
|
+
* </Plural>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* String props still work (backward compatible):
|
|
23
|
+
* ```vue
|
|
24
|
+
* <Plural :value="count" zero="No items" one="# item" other="# items" />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare const pluralProps: {
|
|
28
|
+
/** The numeric value to pluralise on */
|
|
29
|
+
readonly value: {
|
|
30
|
+
readonly type: NumberConstructor;
|
|
31
|
+
readonly required: true;
|
|
32
|
+
};
|
|
33
|
+
/** Override the auto-generated synthetic ICU message id */
|
|
34
|
+
readonly id: StringConstructor;
|
|
35
|
+
/** Message context used for identity and translator disambiguation */
|
|
36
|
+
readonly context: StringConstructor;
|
|
37
|
+
/** Translator-facing note preserved in extraction catalogs */
|
|
38
|
+
readonly comment: StringConstructor;
|
|
39
|
+
/** Text for zero items (maps to `=0`) */
|
|
40
|
+
readonly zero: StringConstructor;
|
|
41
|
+
/** Text for singular (maps to `one`) */
|
|
42
|
+
readonly one: StringConstructor;
|
|
43
|
+
/** Text for dual (maps to `two`) */
|
|
44
|
+
readonly two: StringConstructor;
|
|
45
|
+
/** Text for few (maps to `few`) */
|
|
46
|
+
readonly few: StringConstructor;
|
|
47
|
+
/** Text for many (maps to `many`) */
|
|
48
|
+
readonly many: StringConstructor;
|
|
49
|
+
/** Text for the default/other category */
|
|
50
|
+
readonly other: {
|
|
51
|
+
readonly type: StringConstructor;
|
|
52
|
+
readonly default: undefined;
|
|
53
|
+
};
|
|
54
|
+
/** Offset from value before selecting form */
|
|
55
|
+
readonly offset: NumberConstructor;
|
|
56
|
+
/** Wrapper element tag name (default: `span`) */
|
|
57
|
+
readonly tag: {
|
|
58
|
+
readonly type: StringConstructor;
|
|
59
|
+
readonly default: "span";
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export type PluralProps = Readonly<ExtractPropTypes<typeof pluralProps>>;
|
|
63
|
+
export declare const Plural: import('vue').DefineComponent<ExtractPropTypes<{
|
|
64
|
+
/** The numeric value to pluralise on */
|
|
65
|
+
readonly value: {
|
|
66
|
+
readonly type: NumberConstructor;
|
|
67
|
+
readonly required: true;
|
|
68
|
+
};
|
|
69
|
+
/** Override the auto-generated synthetic ICU message id */
|
|
70
|
+
readonly id: StringConstructor;
|
|
71
|
+
/** Message context used for identity and translator disambiguation */
|
|
72
|
+
readonly context: StringConstructor;
|
|
73
|
+
/** Translator-facing note preserved in extraction catalogs */
|
|
74
|
+
readonly comment: StringConstructor;
|
|
75
|
+
/** Text for zero items (maps to `=0`) */
|
|
76
|
+
readonly zero: StringConstructor;
|
|
77
|
+
/** Text for singular (maps to `one`) */
|
|
78
|
+
readonly one: StringConstructor;
|
|
79
|
+
/** Text for dual (maps to `two`) */
|
|
80
|
+
readonly two: StringConstructor;
|
|
81
|
+
/** Text for few (maps to `few`) */
|
|
82
|
+
readonly few: StringConstructor;
|
|
83
|
+
/** Text for many (maps to `many`) */
|
|
84
|
+
readonly many: StringConstructor;
|
|
85
|
+
/** Text for the default/other category */
|
|
86
|
+
readonly other: {
|
|
87
|
+
readonly type: StringConstructor;
|
|
88
|
+
readonly default: undefined;
|
|
89
|
+
};
|
|
90
|
+
/** Offset from value before selecting form */
|
|
91
|
+
readonly offset: NumberConstructor;
|
|
92
|
+
/** Wrapper element tag name (default: `span`) */
|
|
93
|
+
readonly tag: {
|
|
94
|
+
readonly type: StringConstructor;
|
|
95
|
+
readonly default: "span";
|
|
96
|
+
};
|
|
97
|
+
}>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
|
|
98
|
+
[key: string]: any;
|
|
99
|
+
}>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ExtractPropTypes<{
|
|
100
|
+
/** The numeric value to pluralise on */
|
|
101
|
+
readonly value: {
|
|
102
|
+
readonly type: NumberConstructor;
|
|
103
|
+
readonly required: true;
|
|
104
|
+
};
|
|
105
|
+
/** Override the auto-generated synthetic ICU message id */
|
|
106
|
+
readonly id: StringConstructor;
|
|
107
|
+
/** Message context used for identity and translator disambiguation */
|
|
108
|
+
readonly context: StringConstructor;
|
|
109
|
+
/** Translator-facing note preserved in extraction catalogs */
|
|
110
|
+
readonly comment: StringConstructor;
|
|
111
|
+
/** Text for zero items (maps to `=0`) */
|
|
112
|
+
readonly zero: StringConstructor;
|
|
113
|
+
/** Text for singular (maps to `one`) */
|
|
114
|
+
readonly one: StringConstructor;
|
|
115
|
+
/** Text for dual (maps to `two`) */
|
|
116
|
+
readonly two: StringConstructor;
|
|
117
|
+
/** Text for few (maps to `few`) */
|
|
118
|
+
readonly few: StringConstructor;
|
|
119
|
+
/** Text for many (maps to `many`) */
|
|
120
|
+
readonly many: StringConstructor;
|
|
121
|
+
/** Text for the default/other category */
|
|
122
|
+
readonly other: {
|
|
123
|
+
readonly type: StringConstructor;
|
|
124
|
+
readonly default: undefined;
|
|
125
|
+
};
|
|
126
|
+
/** Offset from value before selecting form */
|
|
127
|
+
readonly offset: NumberConstructor;
|
|
128
|
+
/** Wrapper element tag name (default: `span`) */
|
|
129
|
+
readonly tag: {
|
|
130
|
+
readonly type: StringConstructor;
|
|
131
|
+
readonly default: "span";
|
|
132
|
+
};
|
|
133
|
+
}>> & Readonly<{}>, {
|
|
134
|
+
readonly other: string;
|
|
135
|
+
readonly tag: string;
|
|
136
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
137
|
+
export {};
|
|
138
|
+
//# sourceMappingURL=Plural.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plural.d.ts","sourceRoot":"","sources":["../../src/components/Plural.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAA4B,MAAM,KAAK,CAAA;AAsCrE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,QAAA,MAAM,WAAW;IACf,wCAAwC;;;;;IAExC,2DAA2D;;IAE3D,sEAAsE;;IAEtE,8DAA8D;;IAE9D,yCAAyC;;IAEzC,wCAAwC;;IAExC,oCAAoC;;IAEpC,mCAAmC;;IAEnC,qCAAqC;;IAErC,0CAA0C;;;;;IAE1C,8CAA8C;;IAE9C,iDAAiD;;;;;CAEzC,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,gBAAgB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;AAExE,eAAO,MAAM,MAAM;IA5BjB,wCAAwC;;;;;IAExC,2DAA2D;;IAE3D,sEAAsE;;IAEtE,8DAA8D;;IAE9D,yCAAyC;;IAEzC,wCAAwC;;IAExC,oCAAoC;;IAEpC,mCAAmC;;IAEnC,qCAAqC;;IAErC,0CAA0C;;;;;IAE1C,8CAA8C;;IAE9C,iDAAiD;;;;;;;;IAtBjD,wCAAwC;;;;;IAExC,2DAA2D;;IAE3D,sEAAsE;;IAEtE,8DAA8D;;IAE9D,yCAAyC;;IAEzC,wCAAwC;;IAExC,oCAAoC;;IAEpC,mCAAmC;;IAEnC,qCAAqC;;IAErC,0CAA0C;;;;;IAE1C,8CAA8C;;IAE9C,iDAAiD;;;;;;;;4EAuDjD,CAAA"}
|