@maz-ui/mcp 4.0.0-beta.26
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 +264 -0
- package/bin/maz-ui-mcp.mjs +7 -0
- package/dist/mcp.d.mts +13 -0
- package/dist/mcp.d.ts +13 -0
- package/dist/mcp.mjs +586 -0
- package/docs/generated-docs/maz-accordion.doc.md +21 -0
- package/docs/generated-docs/maz-animated-counter.doc.md +17 -0
- package/docs/generated-docs/maz-animated-element.doc.md +14 -0
- package/docs/generated-docs/maz-animated-text.doc.md +14 -0
- package/docs/generated-docs/maz-avatar.doc.md +44 -0
- package/docs/generated-docs/maz-backdrop.doc.md +61 -0
- package/docs/generated-docs/maz-badge.doc.md +16 -0
- package/docs/generated-docs/maz-bottom-sheet.doc.md +21 -0
- package/docs/generated-docs/maz-btn.doc.md +30 -0
- package/docs/generated-docs/maz-card-spotlight.doc.md +16 -0
- package/docs/generated-docs/maz-card.doc.md +39 -0
- package/docs/generated-docs/maz-carousel.doc.md +16 -0
- package/docs/generated-docs/maz-chart.doc.md +10 -0
- package/docs/generated-docs/maz-checkbox.doc.md +34 -0
- package/docs/generated-docs/maz-checklist.doc.md +30 -0
- package/docs/generated-docs/maz-circular-progress-bar.doc.md +27 -0
- package/docs/generated-docs/maz-date-picker.doc.md +52 -0
- package/docs/generated-docs/maz-dialog-confirm.doc.md +24 -0
- package/docs/generated-docs/maz-dialog.doc.md +22 -0
- package/docs/generated-docs/maz-drawer.doc.md +26 -0
- package/docs/generated-docs/maz-dropdown.doc.md +42 -0
- package/docs/generated-docs/maz-dropzone.doc.md +82 -0
- package/docs/generated-docs/maz-expand-animation.doc.md +12 -0
- package/docs/generated-docs/maz-fullscreen-loader.doc.md +13 -0
- package/docs/generated-docs/maz-gallery.doc.md +17 -0
- package/docs/generated-docs/maz-icon.doc.md +18 -0
- package/docs/generated-docs/maz-input-code.doc.md +25 -0
- package/docs/generated-docs/maz-input-number.doc.md +31 -0
- package/docs/generated-docs/maz-input-phone-number.doc.md +56 -0
- package/docs/generated-docs/maz-input-price.doc.md +26 -0
- package/docs/generated-docs/maz-input-tags.doc.md +24 -0
- package/docs/generated-docs/maz-input.doc.md +54 -0
- package/docs/generated-docs/maz-lazy-img.doc.md +31 -0
- package/docs/generated-docs/maz-link.doc.md +31 -0
- package/docs/generated-docs/maz-loading-bar.doc.md +6 -0
- package/docs/generated-docs/maz-pagination.doc.md +22 -0
- package/docs/generated-docs/maz-popover.doc.md +70 -0
- package/docs/generated-docs/maz-pull-to-refresh.doc.md +31 -0
- package/docs/generated-docs/maz-radio-buttons.doc.md +33 -0
- package/docs/generated-docs/maz-radio.doc.md +33 -0
- package/docs/generated-docs/maz-reading-progress-bar.doc.md +18 -0
- package/docs/generated-docs/maz-select-country.doc.md +44 -0
- package/docs/generated-docs/maz-select.doc.md +65 -0
- package/docs/generated-docs/maz-slider.doc.md +20 -0
- package/docs/generated-docs/maz-spinner.doc.md +6 -0
- package/docs/generated-docs/maz-stepper.doc.md +29 -0
- package/docs/generated-docs/maz-switch.doc.md +31 -0
- package/docs/generated-docs/maz-table-cell.doc.md +5 -0
- package/docs/generated-docs/maz-table-row.doc.md +11 -0
- package/docs/generated-docs/maz-table-title.doc.md +5 -0
- package/docs/generated-docs/maz-table.doc.md +66 -0
- package/docs/generated-docs/maz-tabs-bar.doc.md +18 -0
- package/docs/generated-docs/maz-tabs-content-item.doc.md +11 -0
- package/docs/generated-docs/maz-tabs-content.doc.md +5 -0
- package/docs/generated-docs/maz-tabs.doc.md +17 -0
- package/docs/generated-docs/maz-textarea.doc.md +41 -0
- package/docs/src/components/index.md +8 -0
- package/docs/src/components/maz-accordion.md +80 -0
- package/docs/src/components/maz-animated-counter.md +124 -0
- package/docs/src/components/maz-animated-element.md +36 -0
- package/docs/src/components/maz-animated-text.md +36 -0
- package/docs/src/components/maz-avatar.md +179 -0
- package/docs/src/components/maz-backdrop.md +16 -0
- package/docs/src/components/maz-badge.md +222 -0
- package/docs/src/components/maz-bottom-sheet.md +398 -0
- package/docs/src/components/maz-btn.md +526 -0
- package/docs/src/components/maz-card-spotlight.md +163 -0
- package/docs/src/components/maz-card.md +447 -0
- package/docs/src/components/maz-carousel.md +127 -0
- package/docs/src/components/maz-chart.md +346 -0
- package/docs/src/components/maz-checkbox.md +168 -0
- package/docs/src/components/maz-checklist.md +414 -0
- package/docs/src/components/maz-circular-progress-bar.md +147 -0
- package/docs/src/components/maz-date-picker.md +1078 -0
- package/docs/src/components/maz-dialog-confirm.md +240 -0
- package/docs/src/components/maz-dialog.md +208 -0
- package/docs/src/components/maz-drawer.md +177 -0
- package/docs/src/components/maz-dropdown.md +650 -0
- package/docs/src/components/maz-dropzone.md +442 -0
- package/docs/src/components/maz-expand-animation.md +99 -0
- package/docs/src/components/maz-fullscreen-loader.md +58 -0
- package/docs/src/components/maz-gallery.md +85 -0
- package/docs/src/components/maz-icon.md +85 -0
- package/docs/src/components/maz-input-code.md +61 -0
- package/docs/src/components/maz-input-number.md +81 -0
- package/docs/src/components/maz-input-phone-number.md +867 -0
- package/docs/src/components/maz-input-price.md +58 -0
- package/docs/src/components/maz-input-tags.md +114 -0
- package/docs/src/components/maz-input.md +453 -0
- package/docs/src/components/maz-lazy-img.md +24 -0
- package/docs/src/components/maz-link.md +156 -0
- package/docs/src/components/maz-loading-bar.md +26 -0
- package/docs/src/components/maz-pagination.md +81 -0
- package/docs/src/components/maz-popover.md +1414 -0
- package/docs/src/components/maz-pull-to-refresh.md +49 -0
- package/docs/src/components/maz-radio-buttons.md +456 -0
- package/docs/src/components/maz-radio.md +141 -0
- package/docs/src/components/maz-reading-progress-bar.md +74 -0
- package/docs/src/components/maz-select-country.md +636 -0
- package/docs/src/components/maz-select.md +439 -0
- package/docs/src/components/maz-slider.md +191 -0
- package/docs/src/components/maz-spinner.md +93 -0
- package/docs/src/components/maz-stepper.md +418 -0
- package/docs/src/components/maz-switch.md +92 -0
- package/docs/src/components/maz-table.md +571 -0
- package/docs/src/components/maz-tabs.md +231 -0
- package/docs/src/components/maz-textarea.md +218 -0
- package/docs/src/composables/use-aos.md +34 -0
- package/docs/src/composables/use-breakpoints.md +35 -0
- package/docs/src/composables/use-dialog.md +88 -0
- package/docs/src/composables/use-display-names.md +174 -0
- package/docs/src/composables/use-form-validator.md +1149 -0
- package/docs/src/composables/use-idle-timeout.md +256 -0
- package/docs/src/composables/use-reading-time.md +168 -0
- package/docs/src/composables/use-string-matching.md +63 -0
- package/docs/src/composables/use-swipe.md +223 -0
- package/docs/src/composables/use-timer.md +130 -0
- package/docs/src/composables/use-toast.md +71 -0
- package/docs/src/composables/use-user-visibility.md +169 -0
- package/docs/src/composables/use-wait.md +62 -0
- package/docs/src/composables/use-window-size.md +18 -0
- package/docs/src/demo/DemoAuthPage.vue +178 -0
- package/docs/src/demo/DemoDashboardPage.vue +298 -0
- package/docs/src/demo/DemoProductPage.vue +135 -0
- package/docs/src/directives/click-outside.md +275 -0
- package/docs/src/directives/fullscreen-img.md +101 -0
- package/docs/src/directives/lazy-img.md +184 -0
- package/docs/src/directives/tooltip.md +458 -0
- package/docs/src/directives/zoom-img.md +127 -0
- package/docs/src/guide/cli.md +144 -0
- package/docs/src/guide/getting-started.md +284 -0
- package/docs/src/guide/icon-set.md +60 -0
- package/docs/src/guide/icons.md +481 -0
- package/docs/src/guide/mcp.md +210 -0
- package/docs/src/guide/migration-v4.md +898 -0
- package/docs/src/guide/nuxt.md +411 -0
- package/docs/src/guide/resolvers.md +697 -0
- package/docs/src/guide/themes.md +789 -0
- package/docs/src/guide/translations.md +1173 -0
- package/docs/src/guide/vue.md +243 -0
- package/docs/src/helpers/camel-case.md +14 -0
- package/docs/src/helpers/capitalize.md +51 -0
- package/docs/src/helpers/check-availability.md +14 -0
- package/docs/src/helpers/country-code-to-unicode-flag.md +213 -0
- package/docs/src/helpers/currency.md +67 -0
- package/docs/src/helpers/date.md +67 -0
- package/docs/src/helpers/debounce-callback.md +14 -0
- package/docs/src/helpers/debounce-id.md +14 -0
- package/docs/src/helpers/debounce.md +14 -0
- package/docs/src/helpers/get-country-flag-url.md +156 -0
- package/docs/src/helpers/is-client.md +14 -0
- package/docs/src/helpers/is-equal.md +14 -0
- package/docs/src/helpers/is-standalone-mode.md +14 -0
- package/docs/src/helpers/kebab-case.md +14 -0
- package/docs/src/helpers/normalize-string.md +14 -0
- package/docs/src/helpers/number.md +65 -0
- package/docs/src/helpers/pascal-case.md +14 -0
- package/docs/src/helpers/script-loader.md +14 -0
- package/docs/src/helpers/sleep.md +14 -0
- package/docs/src/helpers/snake-case.md +14 -0
- package/docs/src/helpers/throttle-id.md +14 -0
- package/docs/src/helpers/throttle.md +14 -0
- package/docs/src/index.md +555 -0
- package/docs/src/made-with-maz-ui.md +58 -0
- package/docs/src/plugins/aos.md +347 -0
- package/docs/src/plugins/dialog.md +411 -0
- package/docs/src/plugins/toast.md +349 -0
- package/docs/src/plugins/wait.md +109 -0
- package/package.json +84 -0
|
@@ -0,0 +1,1173 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Translations (i18n)
|
|
3
|
+
description: Internationalization for Maz-UI components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# {{ $frontmatter.title }}
|
|
7
|
+
|
|
8
|
+
{{ $frontmatter.description }}
|
|
9
|
+
|
|
10
|
+
<NpmBadge package="@maz-ui/translations"></NpmBadge>
|
|
11
|
+
|
|
12
|
+
## ✨ Features
|
|
13
|
+
|
|
14
|
+
- 🌍 **Internationalization** - Translate Maz-UI components into different languages
|
|
15
|
+
- 🔄 **Automatic Updates** - Switch languages and everything updates automatically
|
|
16
|
+
- 📦 **Lazy Loading** - Load translations only when needed for better performance
|
|
17
|
+
- 🛡️ **Strict Types** - Complete types for perfect DX
|
|
18
|
+
- 🔧 **Flexible API** - Easy to use and customize
|
|
19
|
+
- 🌐 **8 languages included** - English, French, Spanish, German, Italian, Portuguese, Japanese and Chinese
|
|
20
|
+
|
|
21
|
+
## Built-in Language Support
|
|
22
|
+
|
|
23
|
+
Maz-UI includes default translations for **8 languages** ready to use out of the box:
|
|
24
|
+
|
|
25
|
+
| Language | Code | Translations Status |
|
|
26
|
+
|----------|------|-------------------|
|
|
27
|
+
| 🇺🇸 **English** | `en` | Complete (default) |
|
|
28
|
+
| 🇫🇷 **French** | `fr` | Complete |
|
|
29
|
+
| 🇪🇸 **Spanish** | `es` | Complete |
|
|
30
|
+
| 🇩🇪 **German** | `de` | Complete |
|
|
31
|
+
| 🇮🇹 **Italian** | `it` | Complete |
|
|
32
|
+
| 🇵🇹 **Portuguese** | `pt` | Complete |
|
|
33
|
+
| 🇯🇵 **Japanese** | `ja` | Complete |
|
|
34
|
+
| 🇨🇳 **Chinese** | `zh-CN` | Complete |
|
|
35
|
+
|
|
36
|
+
### Translated Components
|
|
37
|
+
|
|
38
|
+
All these languages include translations for:
|
|
39
|
+
|
|
40
|
+
- 📱 **InputPhoneNumber** ([`MazInputPhoneNumber`](/components/maz-input-phone-number))
|
|
41
|
+
- 📁 **Dropzone** ([`MazDropzone`](/components/maz-dropzone))
|
|
42
|
+
- 📅 **DatePicker** ([`MazDatePicker`](/components/maz-date-picker))
|
|
43
|
+
- 📋 **Checklist** ([`MazChecklist`](/components/maz-checklist))
|
|
44
|
+
- 📤 **Dropdown** ([`MazDropdown`](/components/maz-dropdown))
|
|
45
|
+
- 🔍 **Select** ([`MazSelect`](/components/maz-select))
|
|
46
|
+
- 🗂️ **Table** ([`MazTable`](/components/maz-table))
|
|
47
|
+
- 📄 **Pagination** ([`MazPagination`](/components/maz-pagination))
|
|
48
|
+
- 🎠 **Carousel** ([`MazCarousel`](/components/maz-carousel))
|
|
49
|
+
- 🌍 **SelectCountry** ([`MazSelectCountry`](/components/maz-select-country))
|
|
50
|
+
|
|
51
|
+
### Basic Usage
|
|
52
|
+
|
|
53
|
+
::: warning
|
|
54
|
+
|
|
55
|
+
**By default Maz-UI will not load any translations to avoid unused code in your bundle.**
|
|
56
|
+
|
|
57
|
+
So, to avoid loading hydration issues, use the `messages` option to provide the translations for the language you want to use. Otherwise, the translations will be loaded asynchronously.
|
|
58
|
+
|
|
59
|
+
:::
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { fr } from '@maz-ui/translations'
|
|
63
|
+
|
|
64
|
+
app.use(MazUi, {
|
|
65
|
+
translations: {
|
|
66
|
+
locale: 'fr',
|
|
67
|
+
fallbackLocale: 'en',
|
|
68
|
+
messages: {
|
|
69
|
+
fr,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## How it works
|
|
76
|
+
|
|
77
|
+
1. 🌍 **You install the MazUi plugin** - This tells your app to use translations
|
|
78
|
+
2. 📝 **You provide your translations** - You give the plugin a list of words in different languages
|
|
79
|
+
3. 🔄 **Your app switches languages** - Users can change the language and everything updates automatically!
|
|
80
|
+
|
|
81
|
+
## Basic Setup
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { createApp } from 'vue'
|
|
85
|
+
import { MazUi } from 'maz-ui/plugins/maz-ui'
|
|
86
|
+
import App from './App.vue'
|
|
87
|
+
|
|
88
|
+
const app = createApp(App)
|
|
89
|
+
|
|
90
|
+
app.use(MazUi, {
|
|
91
|
+
// Your theme configuration...
|
|
92
|
+
theme: {
|
|
93
|
+
// ... your theme options
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
// Add your translations here!
|
|
97
|
+
translations: {
|
|
98
|
+
locale: 'fr', // Start with French
|
|
99
|
+
fallbackLocale: 'en', // Fallback language
|
|
100
|
+
preloadFallback: true, // Preload fallback language
|
|
101
|
+
messages: {
|
|
102
|
+
// French and English translations are already included!
|
|
103
|
+
// You can add your custom translations
|
|
104
|
+
fr: {
|
|
105
|
+
// Override translations
|
|
106
|
+
inputPhoneNumber: {
|
|
107
|
+
countrySelect: {
|
|
108
|
+
placeholder: 'Code pays',
|
|
109
|
+
error: 'Choisir le pays',
|
|
110
|
+
searchPlaceholder: 'Rechercher le pays'
|
|
111
|
+
},
|
|
112
|
+
phoneInput: {
|
|
113
|
+
example: 'Exemple: {example}'
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Add other languages
|
|
119
|
+
nl: {
|
|
120
|
+
inputPhoneNumber: {
|
|
121
|
+
countrySelect: {
|
|
122
|
+
placeholder: 'Country code',
|
|
123
|
+
error: 'Choose country',
|
|
124
|
+
searchPlaceholder: 'Search country'
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## preloadFallback Option
|
|
134
|
+
|
|
135
|
+
The `preloadFallback` option controls whether the fallback language is preloaded when the application starts.
|
|
136
|
+
|
|
137
|
+
### Default behavior (`preloadFallback: true`)
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
app.use(MazUi, {
|
|
141
|
+
translations: {
|
|
142
|
+
locale: 'fr',
|
|
143
|
+
fallbackLocale: 'en',
|
|
144
|
+
preloadFallback: true, // Default
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Advantages:**
|
|
150
|
+
- ✅ **No delay** - Fallback translations are immediately available
|
|
151
|
+
- ✅ **Smooth experience** - No missing text even if a translation doesn't exist
|
|
152
|
+
- ✅ **Reliability** - Guarantees there's always a translation available
|
|
153
|
+
|
|
154
|
+
**Disadvantages:**
|
|
155
|
+
- ❌ **Initial size** - Loads slightly more data at startup
|
|
156
|
+
|
|
157
|
+
### Disable preloading (`preloadFallback: false`)
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
app.use(MazUi, {
|
|
161
|
+
translations: {
|
|
162
|
+
locale: 'fr',
|
|
163
|
+
fallbackLocale: 'en',
|
|
164
|
+
preloadFallback: false, // Disable preloading
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Advantages:**
|
|
170
|
+
- ✅ **Smaller bundle** - Less data loaded at startup
|
|
171
|
+
- ✅ **Optimization** - Loading only on demand
|
|
172
|
+
|
|
173
|
+
**Disadvantages:**
|
|
174
|
+
- ❌ **Possible delay** - May temporarily display translation keys
|
|
175
|
+
- ❌ **Complexity** - Requires finer loading state management
|
|
176
|
+
|
|
177
|
+
### Recommendation
|
|
178
|
+
|
|
179
|
+
**Keep `preloadFallback: true`** in most cases, except if:
|
|
180
|
+
- You have very strict performance constraints
|
|
181
|
+
- Your application is very large
|
|
182
|
+
- You manually manage loading states
|
|
183
|
+
|
|
184
|
+
## Enhanced Lazy Loading
|
|
185
|
+
|
|
186
|
+
::: tip BUILT-IN FEATURE
|
|
187
|
+
All supported languages (fr, es, de, it, pt, ja, zh-CN) are automatically loaded lazily. You don't need to configure anything to benefit from this.
|
|
188
|
+
:::
|
|
189
|
+
|
|
190
|
+
The Maz-UI translation system natively supports **lazy loading**, a powerful feature to optimize your application's performance.
|
|
191
|
+
|
|
192
|
+
### What is lazy loading?
|
|
193
|
+
|
|
194
|
+
Lazy loading means translations are only loaded when the user needs them, rather than all at once at startup.
|
|
195
|
+
|
|
196
|
+
**Real example:**
|
|
197
|
+
- Your app starts in French → Only French translations are loaded
|
|
198
|
+
- User clicks "English" → English translations load at that moment
|
|
199
|
+
- User clicks "Español" → Spanish translations load at that moment
|
|
200
|
+
|
|
201
|
+
### Benefits of lazy loading
|
|
202
|
+
|
|
203
|
+
- 🚀 **Faster startup** - Less data to load initially
|
|
204
|
+
- 📦 **Smaller bundle** - Translations are in separate chunks
|
|
205
|
+
- 🌐 **Scalable** - Add as many languages as you want without performance impact
|
|
206
|
+
- 💾 **Bandwidth savings** - Users only download what they use
|
|
207
|
+
|
|
208
|
+
### Lazy loading configuration
|
|
209
|
+
|
|
210
|
+
#### Method 1: Dynamic imports (Recommended)
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { createApp } from 'vue'
|
|
214
|
+
import { MazUi } from 'maz-ui/plugins/maz-ui'
|
|
215
|
+
import App from './App.vue'
|
|
216
|
+
|
|
217
|
+
const app = createApp(App)
|
|
218
|
+
|
|
219
|
+
app.use(MazUi, {
|
|
220
|
+
translations: {
|
|
221
|
+
locale: 'en', // Starting language
|
|
222
|
+
fallbackLocale: 'en',
|
|
223
|
+
preloadFallback: false, // Optimization: no preloading
|
|
224
|
+
messages: {
|
|
225
|
+
// Default translations are automatically loaded lazily
|
|
226
|
+
// You can override with your own files
|
|
227
|
+
|
|
228
|
+
// French: loaded only when needed
|
|
229
|
+
fr: () => import('./locales/fr.ts'),
|
|
230
|
+
|
|
231
|
+
// Spanish: loaded only when needed
|
|
232
|
+
es: () => import('./locales/es.json'),
|
|
233
|
+
|
|
234
|
+
// German: loaded with default export
|
|
235
|
+
de: () => import('./locales/de.ts'),
|
|
236
|
+
|
|
237
|
+
// Dutch: custom translations
|
|
238
|
+
nl: () => import('./locales/nl.ts')
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Method 2: Loading from API
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
app.use(MazUi, {
|
|
248
|
+
translations: {
|
|
249
|
+
locale: 'en',
|
|
250
|
+
messages: {
|
|
251
|
+
// Load from your API
|
|
252
|
+
fr: async () => {
|
|
253
|
+
const response = await fetch('/api/translations/fr')
|
|
254
|
+
return response.json()
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// Combine multiple sources
|
|
258
|
+
es: async () => {
|
|
259
|
+
const [defaultTranslations, customTranslations] = await Promise.all([
|
|
260
|
+
// Default Maz-UI translations
|
|
261
|
+
import('@maz-ui/translations/locales/es').then(m => m.default),
|
|
262
|
+
// Your custom translations
|
|
263
|
+
fetch('/api/translations/es/custom').then(r => r.json())
|
|
264
|
+
])
|
|
265
|
+
return { ...defaultTranslations, ...customTranslations }
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Method 3: Mix immediate and lazy loading
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
app.use(MazUi, {
|
|
276
|
+
translations: {
|
|
277
|
+
locale: 'fr',
|
|
278
|
+
messages: {
|
|
279
|
+
// French: loaded immediately (direct object)
|
|
280
|
+
fr: {
|
|
281
|
+
inputPhoneNumber: {
|
|
282
|
+
countrySelect: {
|
|
283
|
+
placeholder: 'Country code',
|
|
284
|
+
error: 'Choose country'
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
// English: loaded lazily (function)
|
|
290
|
+
en: () => import('./locales/en.ts'),
|
|
291
|
+
|
|
292
|
+
// Spanish: loaded lazily (function)
|
|
293
|
+
es: () => import('./locales/es.ts')
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
})
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Create your translation files
|
|
300
|
+
|
|
301
|
+
Check the [all translations keys](#all-translations-keys) section to see all available keys.
|
|
302
|
+
|
|
303
|
+
Create separate files for each language:
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// locales/fr.ts
|
|
307
|
+
export default {
|
|
308
|
+
inputPhoneNumber: {
|
|
309
|
+
countrySelect: {
|
|
310
|
+
placeholder: 'Code pays',
|
|
311
|
+
error: 'Choisir le pays',
|
|
312
|
+
searchPlaceholder: 'Rechercher le pays'
|
|
313
|
+
},
|
|
314
|
+
phoneInput: {
|
|
315
|
+
placeholder: 'Numéro de téléphone',
|
|
316
|
+
example: 'Exemple: {example}'
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
dropzone: {
|
|
320
|
+
dragAndDrop: 'Déposez vos fichiers',
|
|
321
|
+
selectFile: 'Sélectionner un fichier',
|
|
322
|
+
divider: 'ou'
|
|
323
|
+
},
|
|
324
|
+
// You can omit translations you don't want to override
|
|
325
|
+
// Default Maz-UI translations will be used automatically
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// locales/nl.ts (new language)
|
|
331
|
+
export default {
|
|
332
|
+
inputPhoneNumber: {
|
|
333
|
+
countrySelect: {
|
|
334
|
+
placeholder: 'Landcode',
|
|
335
|
+
error: 'Kies land',
|
|
336
|
+
searchPlaceholder: 'Zoek het land'
|
|
337
|
+
},
|
|
338
|
+
phoneInput: {
|
|
339
|
+
placeholder: 'Telefoonnummer',
|
|
340
|
+
example: 'Bijvoorbeeld: {example}'
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
dropzone: {
|
|
344
|
+
dragAndDrop: 'Sleep je bestanden hierheen',
|
|
345
|
+
selectFile: 'Bestand selecteren',
|
|
346
|
+
divider: 'of'
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Using lazy loading in your components
|
|
352
|
+
|
|
353
|
+
```vue
|
|
354
|
+
<script setup>
|
|
355
|
+
import { useTranslations } from '@maz-ui/translations'
|
|
356
|
+
import { ref } from 'vue'
|
|
357
|
+
|
|
358
|
+
const { locale, setLocale } = useTranslations()
|
|
359
|
+
const isLoading = ref(false)
|
|
360
|
+
|
|
361
|
+
// Function to change language with loading state
|
|
362
|
+
async function switchLanguage(newLocale) {
|
|
363
|
+
isLoading.value = true
|
|
364
|
+
try {
|
|
365
|
+
await setLocale(newLocale) // This will load translations if needed
|
|
366
|
+
console.log(`Language changed to ${newLocale}`)
|
|
367
|
+
} catch (error) {
|
|
368
|
+
console.error('Failed to load translations:', error)
|
|
369
|
+
// Handle error (show toast, etc.)
|
|
370
|
+
} finally {
|
|
371
|
+
isLoading.value = false
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Function to preload a language (optional)
|
|
376
|
+
async function preloadLanguage(locale) {
|
|
377
|
+
try {
|
|
378
|
+
await setLocale(locale)
|
|
379
|
+
console.log(`Language ${locale} preloaded`)
|
|
380
|
+
} catch (error) {
|
|
381
|
+
console.error(`Failed to preload ${locale}:`, error)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
</script>
|
|
385
|
+
|
|
386
|
+
<template>
|
|
387
|
+
<div>
|
|
388
|
+
<div class="language-switcher">
|
|
389
|
+
<button
|
|
390
|
+
:disabled="isLoading"
|
|
391
|
+
@click="switchLanguage('fr')"
|
|
392
|
+
>
|
|
393
|
+
🇫🇷 {{ isLoading && locale === 'fr' ? 'Loading...' : 'Français' }}
|
|
394
|
+
</button>
|
|
395
|
+
|
|
396
|
+
<button
|
|
397
|
+
:disabled="isLoading"
|
|
398
|
+
@click="switchLanguage('es')"
|
|
399
|
+
>
|
|
400
|
+
🇪🇸 {{ isLoading && locale === 'es' ? 'Cargando...' : 'Español' }}
|
|
401
|
+
</button>
|
|
402
|
+
|
|
403
|
+
<button
|
|
404
|
+
:disabled="isLoading"
|
|
405
|
+
@click="switchLanguage('de')"
|
|
406
|
+
>
|
|
407
|
+
🇩🇪 {{ isLoading && locale === 'de' ? 'Laden...' : 'Deutsch' }}
|
|
408
|
+
</button>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<!-- Global loading indicator -->
|
|
412
|
+
<div v-if="isLoading" class="loading-overlay">
|
|
413
|
+
<div class="loading-spinner">
|
|
414
|
+
Loading translations...
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<!-- Button to preload a language -->
|
|
419
|
+
<button @click="preloadLanguage('it')" class="preload-btn">
|
|
420
|
+
Preload Italian
|
|
421
|
+
</button>
|
|
422
|
+
</div>
|
|
423
|
+
</template>
|
|
424
|
+
|
|
425
|
+
<style scoped>
|
|
426
|
+
.loading-overlay {
|
|
427
|
+
position: fixed;
|
|
428
|
+
top: 0;
|
|
429
|
+
left: 0;
|
|
430
|
+
right: 0;
|
|
431
|
+
bottom: 0;
|
|
432
|
+
background: rgba(0, 0, 0, 0.5);
|
|
433
|
+
display: flex;
|
|
434
|
+
justify-content: center;
|
|
435
|
+
align-items: center;
|
|
436
|
+
z-index: 1000;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.loading-spinner {
|
|
440
|
+
background: white;
|
|
441
|
+
padding: 1rem 2rem;
|
|
442
|
+
border-radius: 8px;
|
|
443
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
444
|
+
}
|
|
445
|
+
</style>
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Advanced lazy loading strategies
|
|
449
|
+
|
|
450
|
+
#### 1. Conditional loading based on geolocation
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// Automatic language detection based on location
|
|
454
|
+
async function detectUserLanguage() {
|
|
455
|
+
try {
|
|
456
|
+
// Try to detect from browser
|
|
457
|
+
const browserLang = navigator.language.split('-')[0]
|
|
458
|
+
|
|
459
|
+
// Check if we support this language
|
|
460
|
+
const supportedLanguages = ['en', 'fr', 'es', 'de', 'it', 'pt', 'ja', 'zh']
|
|
461
|
+
|
|
462
|
+
if (supportedLanguages.includes(browserLang)) {
|
|
463
|
+
return browserLang
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Fallback to English
|
|
467
|
+
return 'en'
|
|
468
|
+
} catch {
|
|
469
|
+
return 'en'
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Configuration with automatic detection
|
|
474
|
+
app.use(MazUi, {
|
|
475
|
+
translations: {
|
|
476
|
+
locale: await detectUserLanguage(),
|
|
477
|
+
messages: {
|
|
478
|
+
fr: () => import('./locales/fr.ts'),
|
|
479
|
+
es: () => import('./locales/es.ts'),
|
|
480
|
+
de: () => import('./locales/de.ts'),
|
|
481
|
+
// ... other languages
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
})
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### 2. Smart caching
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// Custom cache for translations
|
|
491
|
+
const translationCache = new Map()
|
|
492
|
+
|
|
493
|
+
const messages = {
|
|
494
|
+
fr: async () => {
|
|
495
|
+
if (translationCache.has('fr')) {
|
|
496
|
+
return translationCache.get('fr')
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const translations = await import('./locales/fr.ts').then(m => m.default)
|
|
500
|
+
translationCache.set('fr', translations)
|
|
501
|
+
return translations
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## Using translations in your components
|
|
507
|
+
|
|
508
|
+
Once you've configured the plugin, you can control the language in your Vue components:
|
|
509
|
+
|
|
510
|
+
```vue
|
|
511
|
+
<script setup>
|
|
512
|
+
import { useTranslations } from '@maz-ui/translations'
|
|
513
|
+
|
|
514
|
+
// Get the translation tools
|
|
515
|
+
const { locale, setLocale } = useTranslations()
|
|
516
|
+
|
|
517
|
+
// Functions to change language
|
|
518
|
+
function switchToFrench() {
|
|
519
|
+
setLocale('fr')
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function switchToSpanish() {
|
|
523
|
+
setLocale('es')
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function switchToEnglish() {
|
|
527
|
+
setLocale('en')
|
|
528
|
+
}
|
|
529
|
+
</script>
|
|
530
|
+
|
|
531
|
+
<template>
|
|
532
|
+
<div>
|
|
533
|
+
<!-- Language switcher buttons -->
|
|
534
|
+
<div class="language-switcher">
|
|
535
|
+
<button @click="switchToEnglish">
|
|
536
|
+
🇺🇸 English
|
|
537
|
+
</button>
|
|
538
|
+
<button @click="switchToFrench">
|
|
539
|
+
🇫🇷 Français
|
|
540
|
+
</button>
|
|
541
|
+
<button @click="switchToSpanish">
|
|
542
|
+
🇪🇸 Español
|
|
543
|
+
</button>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<!-- Show current language -->
|
|
547
|
+
<p>Current language: {{ locale }}</p>
|
|
548
|
+
|
|
549
|
+
<!-- Your Maz-UI components will automatically use the right language! -->
|
|
550
|
+
<MazInput />
|
|
551
|
+
<MazBtn />
|
|
552
|
+
<MazSelect />
|
|
553
|
+
</div>
|
|
554
|
+
</template>
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## Lazy Loading (Performance Optimization)
|
|
558
|
+
|
|
559
|
+
### Benefits of lazy loading
|
|
560
|
+
|
|
561
|
+
- **Faster startup** - Less data to load initially
|
|
562
|
+
- **Smaller bundle** - Translations are in separate chunks
|
|
563
|
+
- **Scalable** - Add as many languages as you want without performance impact
|
|
564
|
+
- **Bandwidth savings** - Users only download what they use
|
|
565
|
+
|
|
566
|
+
For better performance, you can load translation files only when they're needed. This is perfect for large applications with many languages:
|
|
567
|
+
|
|
568
|
+
### Option 1: Simple lazy loading with dynamic imports
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import { createApp } from 'vue'
|
|
572
|
+
import { MazUi } from 'maz-ui/plugins/maz-ui'
|
|
573
|
+
import App from './App.vue'
|
|
574
|
+
|
|
575
|
+
const app = createApp(App)
|
|
576
|
+
|
|
577
|
+
app.use(MazUi, {
|
|
578
|
+
translations: {
|
|
579
|
+
locale: 'en', // Start with English (already loaded)
|
|
580
|
+
messages: {
|
|
581
|
+
// French will be loaded only when user switches to French
|
|
582
|
+
fr: () => import('./locales/fr.ts').then(m => m.default),
|
|
583
|
+
|
|
584
|
+
// Spanish will be loaded only when user switches to Spanish
|
|
585
|
+
es: () => import('./locales/es.json'),
|
|
586
|
+
|
|
587
|
+
// German will be loaded only when user switches to German
|
|
588
|
+
de: () => import('./locales/de.ts').then(m => m.default)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
app.mount('#app')
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Option 2: Loading from API
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
app.use(MazUi, {
|
|
600
|
+
translations: {
|
|
601
|
+
locale: 'en',
|
|
602
|
+
messages: {
|
|
603
|
+
// Load French translations from your API
|
|
604
|
+
fr: async () => {
|
|
605
|
+
const response = await fetch('/api/translations/fr')
|
|
606
|
+
return response.json()
|
|
607
|
+
},
|
|
608
|
+
|
|
609
|
+
// Load from multiple sources
|
|
610
|
+
es: async () => {
|
|
611
|
+
const [componentTranslations, customTranslations] = await Promise.all([
|
|
612
|
+
fetch('/api/translations/es/components').then(r => r.json()),
|
|
613
|
+
fetch('/api/translations/es/custom').then(r => r.json())
|
|
614
|
+
])
|
|
615
|
+
return { ...componentTranslations, ...customTranslations }
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
})
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Create translation files
|
|
623
|
+
|
|
624
|
+
Create separate files for each language:
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
// locales/fr.ts
|
|
628
|
+
export default {
|
|
629
|
+
inputPhoneNumber: {
|
|
630
|
+
countrySelect: {
|
|
631
|
+
placeholder: 'Code pays',
|
|
632
|
+
error: 'Choisir un pays',
|
|
633
|
+
searchPlaceholder: 'Rechercher le pays'
|
|
634
|
+
},
|
|
635
|
+
phoneInput: {
|
|
636
|
+
placeholder: 'Numéro de téléphone',
|
|
637
|
+
example: 'Exemple: {example}'
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
dropzone: {
|
|
641
|
+
dragAndDrop: 'Déposez vos fichiers',
|
|
642
|
+
selectFile: 'Sélectionner un fichier',
|
|
643
|
+
divider: 'ou'
|
|
644
|
+
}
|
|
645
|
+
// ... other translations
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
// locales/es.ts
|
|
651
|
+
export default {
|
|
652
|
+
inputPhoneNumber: {
|
|
653
|
+
countrySelect: {
|
|
654
|
+
placeholder: 'Código de país',
|
|
655
|
+
error: 'Elegir país',
|
|
656
|
+
searchPlaceholder: 'Buscar el país'
|
|
657
|
+
},
|
|
658
|
+
phoneInput: {
|
|
659
|
+
placeholder: 'Número de teléfono',
|
|
660
|
+
example: 'Ejemplo: {example}'
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
dropzone: {
|
|
664
|
+
dragAndDrop: 'Suelta tus archivos',
|
|
665
|
+
selectFile: 'Seleccionar archivo',
|
|
666
|
+
divider: 'o'
|
|
667
|
+
}
|
|
668
|
+
// ... other translations
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Using lazy loading in your components
|
|
673
|
+
|
|
674
|
+
```vue
|
|
675
|
+
<script setup>
|
|
676
|
+
import { useTranslations } from '@maz-ui/translations'
|
|
677
|
+
import { ref } from 'vue'
|
|
678
|
+
|
|
679
|
+
const { locale, setLocale } = useTranslations()
|
|
680
|
+
const isLoading = ref(false)
|
|
681
|
+
|
|
682
|
+
// Function to change language with loading state
|
|
683
|
+
async function switchLanguage(newLocale) {
|
|
684
|
+
isLoading.value = true
|
|
685
|
+
try {
|
|
686
|
+
await setLocale(newLocale) // This will load translations if needed
|
|
687
|
+
console.log(`Language changed to ${newLocale}`)
|
|
688
|
+
} catch (error) {
|
|
689
|
+
console.error('Failed to load translations:', error)
|
|
690
|
+
// Handle error (show toast, etc.)
|
|
691
|
+
} finally {
|
|
692
|
+
isLoading.value = false
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Function to preload a language (optional)
|
|
697
|
+
async function preloadLanguage(locale) {
|
|
698
|
+
try {
|
|
699
|
+
await setLocale(locale)
|
|
700
|
+
console.log(`Language ${locale} preloaded`)
|
|
701
|
+
} catch (error) {
|
|
702
|
+
console.error(`Failed to preload ${locale}:`, error)
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
</script>
|
|
706
|
+
|
|
707
|
+
<template>
|
|
708
|
+
<div>
|
|
709
|
+
<div class="language-switcher">
|
|
710
|
+
<button
|
|
711
|
+
:disabled="isLoading"
|
|
712
|
+
@click="switchLanguage('fr')"
|
|
713
|
+
>
|
|
714
|
+
🇫🇷 {{ isLoading && locale === 'fr' ? 'Loading...' : 'Français' }}
|
|
715
|
+
</button>
|
|
716
|
+
|
|
717
|
+
<button
|
|
718
|
+
:disabled="isLoading"
|
|
719
|
+
@click="switchLanguage('es')"
|
|
720
|
+
>
|
|
721
|
+
🇪🇸 {{ isLoading && locale === 'es' ? 'Cargando...' : 'Español' }}
|
|
722
|
+
</button>
|
|
723
|
+
|
|
724
|
+
<button
|
|
725
|
+
:disabled="isLoading"
|
|
726
|
+
@click="switchLanguage('de')"
|
|
727
|
+
>
|
|
728
|
+
🇩🇪 {{ isLoading && locale === 'de' ? 'Laden...' : 'Deutsch' }}
|
|
729
|
+
</button>
|
|
730
|
+
</div>
|
|
731
|
+
|
|
732
|
+
<!-- Global loading indicator -->
|
|
733
|
+
<div v-if="isLoading" class="loading-overlay">
|
|
734
|
+
<div class="loading-spinner">
|
|
735
|
+
Loading translations...
|
|
736
|
+
</div>
|
|
737
|
+
</div>
|
|
738
|
+
|
|
739
|
+
<!-- Button to preload a language -->
|
|
740
|
+
<button @click="preloadLanguage('it')" class="preload-btn">
|
|
741
|
+
Preload Italian
|
|
742
|
+
</button>
|
|
743
|
+
</div>
|
|
744
|
+
</template>
|
|
745
|
+
|
|
746
|
+
<style scoped>
|
|
747
|
+
.loading-overlay {
|
|
748
|
+
position: fixed;
|
|
749
|
+
top: 0;
|
|
750
|
+
left: 0;
|
|
751
|
+
right: 0;
|
|
752
|
+
bottom: 0;
|
|
753
|
+
background: rgba(0, 0, 0, 0.5);
|
|
754
|
+
display: flex;
|
|
755
|
+
justify-content: center;
|
|
756
|
+
align-items: center;
|
|
757
|
+
z-index: 1000;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.loading-spinner {
|
|
761
|
+
background: white;
|
|
762
|
+
padding: 1rem 2rem;
|
|
763
|
+
border-radius: 8px;
|
|
764
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
765
|
+
}
|
|
766
|
+
</style>
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Advanced lazy loading strategies
|
|
770
|
+
|
|
771
|
+
#### 1. Conditional loading based on geolocation
|
|
772
|
+
|
|
773
|
+
```typescript
|
|
774
|
+
// Automatic language detection based on location
|
|
775
|
+
async function detectUserLanguage() {
|
|
776
|
+
try {
|
|
777
|
+
// Try to detect from browser
|
|
778
|
+
const browserLang = navigator.language.split('-')[0]
|
|
779
|
+
|
|
780
|
+
// Check if we support this language
|
|
781
|
+
const supportedLanguages = ['en', 'fr', 'es', 'de', 'it', 'pt', 'ja', 'zh']
|
|
782
|
+
|
|
783
|
+
if (supportedLanguages.includes(browserLang)) {
|
|
784
|
+
return browserLang
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Fallback to English
|
|
788
|
+
return 'en'
|
|
789
|
+
} catch {
|
|
790
|
+
return 'en'
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Configuration with automatic detection
|
|
795
|
+
app.use(MazUi, {
|
|
796
|
+
translations: {
|
|
797
|
+
locale: await detectUserLanguage(),
|
|
798
|
+
messages: {
|
|
799
|
+
fr: () => import('./locales/fr.ts'),
|
|
800
|
+
es: () => import('./locales/es.ts'),
|
|
801
|
+
de: () => import('./locales/de.ts'),
|
|
802
|
+
// ... other languages
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
})
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
#### 2. Smart caching
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
// Custom cache for translations
|
|
812
|
+
const translationCache = new Map()
|
|
813
|
+
|
|
814
|
+
const messages = {
|
|
815
|
+
fr: async () => {
|
|
816
|
+
if (translationCache.has('fr')) {
|
|
817
|
+
return translationCache.get('fr')
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const translations = await import('./locales/fr.ts').then(m => m.default)
|
|
821
|
+
translationCache.set('fr', translations)
|
|
822
|
+
return translations
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
## Variables in translations
|
|
828
|
+
|
|
829
|
+
Some translations have variables (words in curly braces like `{example}` or `{page}`). These get replaced automatically:
|
|
830
|
+
|
|
831
|
+
```typescript
|
|
832
|
+
// Your translation
|
|
833
|
+
phoneInput: {
|
|
834
|
+
example: 'Example: {example}'
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Becomes something like
|
|
838
|
+
// "Example: +33 6 12 34 56 78"
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
```typescript
|
|
842
|
+
// Your translation
|
|
843
|
+
pagination: {
|
|
844
|
+
screenReaderPage: 'Page {page}'
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Becomes something like
|
|
848
|
+
// "Page 3"
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
## Complete example with multiple languages
|
|
852
|
+
|
|
853
|
+
Here's a full example with English, French, and Spanish:
|
|
854
|
+
|
|
855
|
+
```typescript
|
|
856
|
+
import { createApp } from 'vue'
|
|
857
|
+
import { MazUi } from 'maz-ui/plugins/maz-ui'
|
|
858
|
+
import App from './App.vue'
|
|
859
|
+
|
|
860
|
+
const app = createApp(App)
|
|
861
|
+
|
|
862
|
+
app.use(MazUi, {
|
|
863
|
+
translations: {
|
|
864
|
+
locale: 'en', // Start with English
|
|
865
|
+
messages: {
|
|
866
|
+
// English (default - you don't need to provide this unless you want to override the default translations)
|
|
867
|
+
en: {
|
|
868
|
+
inputPhoneNumber: {
|
|
869
|
+
countrySelect: {
|
|
870
|
+
placeholder: 'Country code',
|
|
871
|
+
error: 'Choose country',
|
|
872
|
+
searchPlaceholder: 'Search the country'
|
|
873
|
+
},
|
|
874
|
+
phoneInput: {
|
|
875
|
+
placeholder: 'Phone number',
|
|
876
|
+
example: 'Example: {example}'
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
|
|
881
|
+
// French
|
|
882
|
+
fr: {
|
|
883
|
+
inputPhoneNumber: {
|
|
884
|
+
countrySelect: {
|
|
885
|
+
placeholder: 'Code pays',
|
|
886
|
+
error: 'Choisir un pays',
|
|
887
|
+
searchPlaceholder: 'Rechercher le pays'
|
|
888
|
+
},
|
|
889
|
+
phoneInput: {
|
|
890
|
+
placeholder: 'Numéro de téléphone',
|
|
891
|
+
example: 'Exemple: {example}'
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
dropzone: {
|
|
895
|
+
dragAndDrop: 'Déposez vos fichiers',
|
|
896
|
+
selectFile: 'Sélectionner un fichier',
|
|
897
|
+
divider: 'ou',
|
|
898
|
+
fileMaxCount: 'Maximum {count} fichiers',
|
|
899
|
+
fileMaxSize: 'Maximum {size} MB',
|
|
900
|
+
fileTypes: 'Types de fichiers autorisés: {types}'
|
|
901
|
+
},
|
|
902
|
+
pagination: {
|
|
903
|
+
navAriaLabel: 'navigation de page',
|
|
904
|
+
screenReader: {
|
|
905
|
+
firstPage: 'Première page, page {page}',
|
|
906
|
+
previousPage: 'Page précédente, page {page}',
|
|
907
|
+
page: 'Page {page}',
|
|
908
|
+
nextPage: 'Page suivante, page {page}',
|
|
909
|
+
lastPage: 'Dernière page, page {page}'
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
},
|
|
913
|
+
|
|
914
|
+
// Spanish
|
|
915
|
+
es: {
|
|
916
|
+
inputPhoneNumber: {
|
|
917
|
+
countrySelect: {
|
|
918
|
+
placeholder: 'Código de país',
|
|
919
|
+
error: 'Elegir país',
|
|
920
|
+
searchPlaceholder: 'Buscar el país'
|
|
921
|
+
},
|
|
922
|
+
phoneInput: {
|
|
923
|
+
placeholder: 'Número de teléfono',
|
|
924
|
+
example: 'Ejemplo: {example}'
|
|
925
|
+
}
|
|
926
|
+
},
|
|
927
|
+
dropzone: {
|
|
928
|
+
dragAndDrop: 'Suelta tus archivos',
|
|
929
|
+
selectFile: 'Seleccionar archivo',
|
|
930
|
+
divider: 'o',
|
|
931
|
+
fileMaxCount: 'Máximo {count} archivos',
|
|
932
|
+
fileMaxSize: 'Máximo {size} MB',
|
|
933
|
+
fileTypes: 'Tipos de archivo permitidos: {types}'
|
|
934
|
+
},
|
|
935
|
+
pagination: {
|
|
936
|
+
navAriaLabel: 'navegación de página',
|
|
937
|
+
screenReader: {
|
|
938
|
+
firstPage: 'Primera página, página {page}',
|
|
939
|
+
previousPage: 'Página anterior, página {page}',
|
|
940
|
+
page: 'Página {page}',
|
|
941
|
+
nextPage: 'Página siguiente, página {page}',
|
|
942
|
+
lastPage: 'Última página, página {page}'
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
app.mount('#app')
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
## Creating a language switcher component
|
|
954
|
+
|
|
955
|
+
Here's a nice language switcher you can use in your app:
|
|
956
|
+
|
|
957
|
+
```vue
|
|
958
|
+
<script setup lang="ts">
|
|
959
|
+
import { useTranslations } from '@maz-ui/translations'
|
|
960
|
+
import type { MazDropdownProps } from 'maz-ui/components'
|
|
961
|
+
|
|
962
|
+
const { locale, setLocale } = useTranslations()
|
|
963
|
+
|
|
964
|
+
const languages: MazDropdownProps['items'] = [
|
|
965
|
+
{ label: '🇺🇸 English', onClick: () => setLocale('en'), },
|
|
966
|
+
{ label: '🇫🇷 Français', onClick: () => setLocale('fr'), },
|
|
967
|
+
{ label: '🇪🇸 Español', onClick: () => setLocale('es'), },
|
|
968
|
+
{ label: '🇩🇪 Deutsch', onClick: () => setLocale('de'), },
|
|
969
|
+
{ label: '🇮🇹 Italiano', onClick: () => setLocale('it'), }
|
|
970
|
+
]
|
|
971
|
+
</script>
|
|
972
|
+
|
|
973
|
+
<template>
|
|
974
|
+
<MazDropdown class="language-switcher" :items="languages" trigger="click">
|
|
975
|
+
{{ locale }}
|
|
976
|
+
</MazDropdown>
|
|
977
|
+
</template>
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
## All translations keys
|
|
981
|
+
|
|
982
|
+
```typescript
|
|
983
|
+
export default {
|
|
984
|
+
/**
|
|
985
|
+
* This is the translation for the input phone number component.
|
|
986
|
+
* The keys are:
|
|
987
|
+
* - countrySelect: The translation for the country select.
|
|
988
|
+
* - phoneInput: The translation for the phone input.
|
|
989
|
+
*/
|
|
990
|
+
selectCountry: {
|
|
991
|
+
searchPlaceholder: 'Search country',
|
|
992
|
+
},
|
|
993
|
+
inputPhoneNumber: {
|
|
994
|
+
/**
|
|
995
|
+
* This is the translation for the country select component.
|
|
996
|
+
* The keys are:
|
|
997
|
+
* - placeholder: The translation for the placeholder text.
|
|
998
|
+
* - error: The translation for the error text.
|
|
999
|
+
* - searchPlaceholder: The translation for the search placeholder text.
|
|
1000
|
+
*/
|
|
1001
|
+
countrySelect: {
|
|
1002
|
+
placeholder: 'Country code',
|
|
1003
|
+
error: 'Choose country',
|
|
1004
|
+
searchPlaceholder: 'Search the country',
|
|
1005
|
+
},
|
|
1006
|
+
/**
|
|
1007
|
+
* This is the translation for the phone input component.
|
|
1008
|
+
* The keys are:
|
|
1009
|
+
* - placeholder: The translation for the placeholder text.
|
|
1010
|
+
* - example: The translation for the example text.
|
|
1011
|
+
*/
|
|
1012
|
+
phoneInput: {
|
|
1013
|
+
placeholder: 'Phone number',
|
|
1014
|
+
example: 'Example: {example}',
|
|
1015
|
+
},
|
|
1016
|
+
},
|
|
1017
|
+
/**
|
|
1018
|
+
* This is the translation for the dropzone component.
|
|
1019
|
+
* The keys are:
|
|
1020
|
+
* - dragAndDrop: The translation for the drag and drop text.
|
|
1021
|
+
* - selectFile: The translation for the select file button.
|
|
1022
|
+
* - divider: The translation for the divider text.
|
|
1023
|
+
* - fileMaxCount: The translation for the maximum number of files.
|
|
1024
|
+
* - fileMaxSize: The translation for the maximum size of the files.
|
|
1025
|
+
* - fileTypes: The translation for the allowed file types.
|
|
1026
|
+
*/
|
|
1027
|
+
dropzone: {
|
|
1028
|
+
dragAndDrop: 'Drop your files',
|
|
1029
|
+
selectFile: 'Select file',
|
|
1030
|
+
divider: 'or',
|
|
1031
|
+
fileMaxCount: 'Maximum {count} files',
|
|
1032
|
+
fileMaxSize: 'Maximum {size} MB',
|
|
1033
|
+
fileTypes: 'Allowed file types: {types}',
|
|
1034
|
+
},
|
|
1035
|
+
/**
|
|
1036
|
+
* This is the translation for the date picker component.
|
|
1037
|
+
* The keys are:
|
|
1038
|
+
* - shortcuts: The translation for the shortcuts.
|
|
1039
|
+
*/
|
|
1040
|
+
datePicker: {
|
|
1041
|
+
shortcuts: {
|
|
1042
|
+
lastSevenDays: 'Last 7 days',
|
|
1043
|
+
lastThirtyDays: 'Last 30 days',
|
|
1044
|
+
thisWeek: 'This week',
|
|
1045
|
+
lastWeek: 'Last week',
|
|
1046
|
+
thisMonth: 'This month',
|
|
1047
|
+
thisYear: 'This year',
|
|
1048
|
+
lastYear: 'Last year',
|
|
1049
|
+
},
|
|
1050
|
+
},
|
|
1051
|
+
/**
|
|
1052
|
+
* This is the translation for the dropdown component.
|
|
1053
|
+
* The keys are:
|
|
1054
|
+
* - screenReaderDescription: The translation for the screen reader description.
|
|
1055
|
+
*/
|
|
1056
|
+
dropdown: {
|
|
1057
|
+
screenReaderDescription: 'Open menu dropdown',
|
|
1058
|
+
},
|
|
1059
|
+
/**
|
|
1060
|
+
* This is the translation for the select component.
|
|
1061
|
+
* The keys are:
|
|
1062
|
+
* - searchPlaceholder: The translation for the search placeholder text.
|
|
1063
|
+
*/
|
|
1064
|
+
select: {
|
|
1065
|
+
searchPlaceholder: 'Search',
|
|
1066
|
+
},
|
|
1067
|
+
/**
|
|
1068
|
+
* This is the translation for the table component.
|
|
1069
|
+
* The keys are:
|
|
1070
|
+
* - noResults: The translation for the no results text.
|
|
1071
|
+
* - actionColumnTitle: The translation for the action column title.
|
|
1072
|
+
* - searchByInput: The translation for the search by input.
|
|
1073
|
+
* - searchInput: The translation for the search input.
|
|
1074
|
+
* - pagination: The translation for the pagination component.
|
|
1075
|
+
*/
|
|
1076
|
+
table: {
|
|
1077
|
+
noResults: 'No results',
|
|
1078
|
+
actionColumnTitle: 'Actions',
|
|
1079
|
+
searchByInput: {
|
|
1080
|
+
all: 'All',
|
|
1081
|
+
placeholder: 'Search by',
|
|
1082
|
+
},
|
|
1083
|
+
searchInput: {
|
|
1084
|
+
placeholder: 'Search',
|
|
1085
|
+
},
|
|
1086
|
+
pagination: {
|
|
1087
|
+
all: 'All',
|
|
1088
|
+
rowsPerPage: 'Rows per page',
|
|
1089
|
+
of: 'of',
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
/**
|
|
1093
|
+
* This is the translation for the pagination component.
|
|
1094
|
+
* The keys are:
|
|
1095
|
+
* - navAriaLabel: The aria-label for the navigation (nav) element.
|
|
1096
|
+
* - screenReader.firstPage: The translation for the first page button (screen reader).
|
|
1097
|
+
* - screenReader.previousPage: The translation for the previous page button (screen reader).
|
|
1098
|
+
* - screenReader.page: The translation for the current page button (screen reader).
|
|
1099
|
+
* - screenReader.nextPage: The translation for the next page button (screen reader).
|
|
1100
|
+
* - screenReader.lastPage: The translation for the last page button (screen reader).
|
|
1101
|
+
*/
|
|
1102
|
+
pagination: {
|
|
1103
|
+
navAriaLabel: 'page navigation',
|
|
1104
|
+
screenReader: {
|
|
1105
|
+
firstPage: 'First Page, page {page}',
|
|
1106
|
+
previousPage: 'Previous Page, page {page}',
|
|
1107
|
+
page: 'Page {page}',
|
|
1108
|
+
nextPage: 'Next Page, page {page}',
|
|
1109
|
+
lastPage: 'Last Page, page {page}',
|
|
1110
|
+
},
|
|
1111
|
+
},
|
|
1112
|
+
/**
|
|
1113
|
+
* This is the translation for the carousel component.
|
|
1114
|
+
* The keys are:
|
|
1115
|
+
* - ariaLabel.previousButton: The aria-label for the previous button.
|
|
1116
|
+
* - ariaLabel.nextButton: The aria-label for the next button.
|
|
1117
|
+
*/
|
|
1118
|
+
carousel: {
|
|
1119
|
+
ariaLabel: {
|
|
1120
|
+
previousButton: 'Scroll to previous items',
|
|
1121
|
+
nextButton: 'Scroll to next items',
|
|
1122
|
+
},
|
|
1123
|
+
},
|
|
1124
|
+
/**
|
|
1125
|
+
* This is the translation for the checklist component.
|
|
1126
|
+
* The keys are:
|
|
1127
|
+
* - noResultsFound: The translation for the no results found text.
|
|
1128
|
+
* - searchInput.placeholder: The translation for the search input placeholder.
|
|
1129
|
+
*/
|
|
1130
|
+
checklist: {
|
|
1131
|
+
noResultsFound: 'No results found',
|
|
1132
|
+
searchInput: {
|
|
1133
|
+
placeholder: 'Search',
|
|
1134
|
+
},
|
|
1135
|
+
},
|
|
1136
|
+
}
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
## Important Notes
|
|
1140
|
+
|
|
1141
|
+
1. **All languages are included by default (fr, es, de, it, pt, ja, zh-CN)** - You don't need to provide these languages unless you want to modify them.
|
|
1142
|
+
|
|
1143
|
+
2. **Translate only what you need** - You're not required to translate every key. Add only those for the components you use.
|
|
1144
|
+
|
|
1145
|
+
3. **The magic happens automatically** - Once you configure translations, all Maz-UI components will automatically use the right language when you call `setLocale()`.
|
|
1146
|
+
|
|
1147
|
+
4. **Variables are replaced automatically** - Don't worry about `{example}`, `{page}`, etc. - Maz-UI handles them for you.
|
|
1148
|
+
|
|
1149
|
+
5. **Fallback to English** - If a translation is missing in your language and in your fallback language, it will fall back to English.
|
|
1150
|
+
|
|
1151
|
+
6. **Lazy loading is asynchronous** - When using lazy loading, `setLocale()` returns a Promise. Use `await setLocale('fr')` in your code.
|
|
1152
|
+
|
|
1153
|
+
7. **Translations are cached** - Once a language is loaded, it stays in memory. Switching back to a previously loaded language is instant.
|
|
1154
|
+
|
|
1155
|
+
8. **preloadFallback option** - By default (`preloadFallback: true`), the fallback language is preloaded at startup for a smoother experience. Set to `false` to optimize initial loading.
|
|
1156
|
+
|
|
1157
|
+
9. **8 ready-to-use languages** - Maz-UI includes complete translations for 8 languages that are automatically loaded with lazy loading.
|
|
1158
|
+
|
|
1159
|
+
10. **Partial translations** - You can provide partial translations. Maz-UI will automatically use default translations for missing keys.
|
|
1160
|
+
|
|
1161
|
+
## That's it! 🎉
|
|
1162
|
+
|
|
1163
|
+
Now your Maz-UI components can speak any language you want. Your users can change languages and everything updates instantly!
|
|
1164
|
+
|
|
1165
|
+
With **8 languages included by default** and **automatic lazy loading**, you have a complete and optimized internationalization solution ready to use.
|
|
1166
|
+
|
|
1167
|
+
## Need help?
|
|
1168
|
+
|
|
1169
|
+
- Check that your translation keys match the examples above
|
|
1170
|
+
- Make sure to call `setLocale()` with the correct language code
|
|
1171
|
+
- Remember that component text changes automatically - you don't need to do anything special
|
|
1172
|
+
- Use `preloadFallback: false` if you want to optimize initial loading
|
|
1173
|
+
- Default translations are automatically loaded with lazy loading
|