@arc-js/intl 0.0.2
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/README.md +575 -0
- package/config.d.ts +13 -0
- package/config.js +913 -0
- package/config.min.js +2 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/index.min.js +2 -0
- package/package.json +26 -0
- package/providers/IntlProvider.jsx +55 -0
- package/providers/IntlProvider.tsx +76 -0
- package/tsconfig.json +27 -0
- package/utils.d.ts +3 -0
- package/utils.js +901 -0
- package/utils.min.js +2 -0
- package/vite.config.ts +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# @arc-js/intl
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
**@arc-js/intl** est un système de gestion d'internationalisation (i18n) modulaire et performant pour les applications React avec TypeScript/JavaScript. Il fournit une gestion avancée des traductions, un chargement dynamique des modules, et une intégration transparente avec l'écosystème Arc.
|
|
9
|
+
|
|
10
|
+
## ✨ Fonctionnalités Principales
|
|
11
|
+
|
|
12
|
+
### 🌍 Gestion Multi-Langue Avancée
|
|
13
|
+
- **Support de plusieurs locales** avec détection automatique
|
|
14
|
+
- **Chargement dynamique** des fichiers de traduction
|
|
15
|
+
- **Gestion des pluriels** basée sur les règles Intl
|
|
16
|
+
- **Interpolation de variables** dans les traductions
|
|
17
|
+
|
|
18
|
+
### 📦 Architecture Modulaire
|
|
19
|
+
- **Traductions par module** avec isolation complète
|
|
20
|
+
- **Chargement à la demande** des traductions des modules
|
|
21
|
+
- **Fusion intelligente** des traductions hiérarchiques
|
|
22
|
+
- **Support des namespaces** pour une organisation claire
|
|
23
|
+
|
|
24
|
+
### ⚡ Performance Optimisée
|
|
25
|
+
- **Chargement paresseux** des fichiers de traduction
|
|
26
|
+
- **Mémoire cache** des traductions chargées
|
|
27
|
+
- **Minimal bundle size** grâce au code splitting
|
|
28
|
+
- **Hot reload** pendant le développement
|
|
29
|
+
|
|
30
|
+
### 🔧 Intégration Facile
|
|
31
|
+
- **Provider React** simple à configurer
|
|
32
|
+
- **Hooks personnalisés** pour une utilisation intuitive
|
|
33
|
+
- **Compatibilité totale** avec TypeScript
|
|
34
|
+
- **Intégration avec @arc-js/cooks** pour la persistance
|
|
35
|
+
|
|
36
|
+
## 📦 Installation
|
|
37
|
+
|
|
38
|
+
### Via npm/yarn/pnpm
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @arc-js/intl @arc-js/cooks react
|
|
42
|
+
# ou
|
|
43
|
+
yarn add @arc-js/intl @arc-js/cooks react
|
|
44
|
+
# ou
|
|
45
|
+
pnpm add @arc-js/intl @arc-js/cooks react
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Dépendances requises
|
|
49
|
+
- React 19+
|
|
50
|
+
- @arc-js/cooks 0.0.3+
|
|
51
|
+
- TypeScript 5.0+ (recommandé)
|
|
52
|
+
- Vite (pour le chargement dynamique)
|
|
53
|
+
|
|
54
|
+
## 🚀 Démarrage Rapide
|
|
55
|
+
|
|
56
|
+
### Structure de projet recommandée
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
src/
|
|
60
|
+
├── locales/
|
|
61
|
+
│ ├── en.json # Traductions anglaises de base
|
|
62
|
+
│ └── fr.json # Traductions françaises de base
|
|
63
|
+
├── modules/
|
|
64
|
+
│ ├── admin/
|
|
65
|
+
│ │ └── locales/
|
|
66
|
+
│ │ ├── en.json # Traductions admin anglaises
|
|
67
|
+
│ │ └── fr.json # Traductions admin françaises
|
|
68
|
+
│ └── dashboard/
|
|
69
|
+
│ └── locales/
|
|
70
|
+
│ ├── en.json # Traductions dashboard anglaises
|
|
71
|
+
│ └── fr.json # Traductions dashboard françaises
|
|
72
|
+
└── main.tsx
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Configuration de base
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// main.tsx
|
|
79
|
+
import React from 'react';
|
|
80
|
+
import ReactDOM from 'react-dom/client';
|
|
81
|
+
import { ArcIntlProvider } from '@arc-js/intl';
|
|
82
|
+
|
|
83
|
+
const App = () => {
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<h1>Mon Application Internationalisée</h1>
|
|
87
|
+
{/* Votre contenu ici */}
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
93
|
+
<React.StrictMode>
|
|
94
|
+
<ArcIntlProvider supportedLocales={['en', 'fr', 'es']}>
|
|
95
|
+
<App />
|
|
96
|
+
</ArcIntlProvider>
|
|
97
|
+
</React.StrictMode>
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Fichiers de traduction
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
// locales/en.json
|
|
105
|
+
{
|
|
106
|
+
"common": {
|
|
107
|
+
"welcome": "Welcome to our application",
|
|
108
|
+
"login": "Sign in",
|
|
109
|
+
"logout": "Sign out",
|
|
110
|
+
"save": "Save changes"
|
|
111
|
+
},
|
|
112
|
+
"errors": {
|
|
113
|
+
"required": "This field is required",
|
|
114
|
+
"email": "Please enter a valid email address"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// modules/admin/locales/en.json
|
|
119
|
+
{
|
|
120
|
+
"admin": {
|
|
121
|
+
"dashboard": {
|
|
122
|
+
"title": "Admin Dashboard",
|
|
123
|
+
"users": "Manage Users",
|
|
124
|
+
"settings": "System Settings"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 📚 Documentation API
|
|
131
|
+
|
|
132
|
+
### Hook useTranslation
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { useTranslation } from '@arc-js/intl';
|
|
136
|
+
|
|
137
|
+
const MyComponent = () => {
|
|
138
|
+
const {
|
|
139
|
+
t, // Fonction de traduction principale
|
|
140
|
+
changeLocale, // Changer la locale
|
|
141
|
+
currentLocale, // Locale actuelle
|
|
142
|
+
isLoading // État de chargement
|
|
143
|
+
} = useTranslation('admin'); // Optionnel: nom du module
|
|
144
|
+
|
|
145
|
+
// Exemple d'utilisation
|
|
146
|
+
const handleChangeLanguage = () => {
|
|
147
|
+
changeLocale(currentLocale === 'en' ? 'fr' : 'en');
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div>
|
|
152
|
+
<h1>{t('admin.dashboard.title')}</h1>
|
|
153
|
+
<p>{t('common.welcome')}</p>
|
|
154
|
+
<button onClick={handleChangeLanguage}>
|
|
155
|
+
{t('common.change_language')}
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### ArcIntlProvider
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { ArcIntlProvider } from '@arc-js/intl';
|
|
166
|
+
|
|
167
|
+
// Configuration avec locales personnalisées
|
|
168
|
+
<ArcIntlProvider
|
|
169
|
+
supportedLocales={['en', 'fr', 'es', 'de']}
|
|
170
|
+
>
|
|
171
|
+
{children}
|
|
172
|
+
</ArcIntlProvider>
|
|
173
|
+
|
|
174
|
+
// Configuration par défaut (en, fr)
|
|
175
|
+
<ArcIntlProvider>
|
|
176
|
+
{children}
|
|
177
|
+
</ArcIntlProvider>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## 🔧 Utilisation Avancée
|
|
181
|
+
|
|
182
|
+
### Traductions avec paramètres
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// locales/en.json
|
|
186
|
+
{
|
|
187
|
+
"greeting": "Hello, {name}!",
|
|
188
|
+
"items_count": "You have {count} item{count, plural, one {} other {s}}"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Utilisation dans le composant
|
|
192
|
+
const Greeting = ({ userName, itemCount }) => {
|
|
193
|
+
const { t } = useTranslation();
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div>
|
|
197
|
+
<p>{t('greeting', { name: userName })}</p>
|
|
198
|
+
<p>{t('items_count', { count: itemCount })}</p>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Pluriels et contextes
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// locales/en.json
|
|
208
|
+
{
|
|
209
|
+
"messages": {
|
|
210
|
+
"unread": {
|
|
211
|
+
"one": "You have one unread message",
|
|
212
|
+
"other": "You have {count} unread messages"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"action": {
|
|
216
|
+
"save": "Save",
|
|
217
|
+
"save_context": {
|
|
218
|
+
"draft": "Save as draft",
|
|
219
|
+
"final": "Save and publish"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Utilisation
|
|
225
|
+
const Notification = ({ unreadCount }) => {
|
|
226
|
+
const { t } = useTranslation();
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<div>
|
|
230
|
+
{/* Pluriel automatique */}
|
|
231
|
+
<p>{t('messages.unread', { count: unreadCount })}</p>
|
|
232
|
+
|
|
233
|
+
{/* Contexte spécifique */}
|
|
234
|
+
<button>{t('action.save', {}, { context: 'draft' })}</button>
|
|
235
|
+
<button>{t('action.save', {}, { context: 'final' })}</button>
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
};
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Chargement dynamique de modules
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import { useEffect } from 'react';
|
|
245
|
+
import { useArcIntl } from '@arc-js/intl';
|
|
246
|
+
|
|
247
|
+
const AdminModule = () => {
|
|
248
|
+
const { loadModuleTranslations, t } = useArcIntl();
|
|
249
|
+
|
|
250
|
+
useEffect(() => {
|
|
251
|
+
// Charger les traductions du module admin à la demande
|
|
252
|
+
loadModuleTranslations('admin');
|
|
253
|
+
}, []);
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div>
|
|
257
|
+
<h1>{t('admin.dashboard.title', {}, { moduleName: 'admin' })}</h1>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 🎯 Exemples Complets
|
|
264
|
+
|
|
265
|
+
### Exemple 1 : Sélecteur de langue
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { useTranslation } from '@arc-js/intl';
|
|
269
|
+
|
|
270
|
+
const LanguageSwitcher = () => {
|
|
271
|
+
const { currentLocale, changeLocale, t } = useTranslation();
|
|
272
|
+
|
|
273
|
+
const languages = [
|
|
274
|
+
{ code: 'en', name: 'English' },
|
|
275
|
+
{ code: 'fr', name: 'Français' },
|
|
276
|
+
{ code: 'es', name: 'Español' },
|
|
277
|
+
{ code: 'de', name: 'Deutsch' }
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<div className="language-switcher">
|
|
282
|
+
<span>{t('common.language')}:</span>
|
|
283
|
+
<select
|
|
284
|
+
value={currentLocale}
|
|
285
|
+
onChange={(e) => changeLocale(e.target.value)}
|
|
286
|
+
>
|
|
287
|
+
{languages.map(lang => (
|
|
288
|
+
<option key={lang.code} value={lang.code}>
|
|
289
|
+
{lang.name}
|
|
290
|
+
</option>
|
|
291
|
+
))}
|
|
292
|
+
</select>
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
295
|
+
};
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Exemple 2 : Formulaire internationalisé
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { useTranslation } from '@arc-js/intl';
|
|
302
|
+
import { useState } from 'react';
|
|
303
|
+
|
|
304
|
+
const ContactForm = () => {
|
|
305
|
+
const { t } = useTranslation();
|
|
306
|
+
const [formData, setFormData] = useState({
|
|
307
|
+
name: '',
|
|
308
|
+
email: '',
|
|
309
|
+
message: ''
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const handleSubmit = (e) => {
|
|
313
|
+
e.preventDefault();
|
|
314
|
+
// Soumettre le formulaire
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return (
|
|
318
|
+
<form onSubmit={handleSubmit} className="contact-form">
|
|
319
|
+
<div className="form-group">
|
|
320
|
+
<label>{t('form.name')}</label>
|
|
321
|
+
<input
|
|
322
|
+
value={formData.name}
|
|
323
|
+
onChange={e => setFormData({...formData, name: e.target.value})}
|
|
324
|
+
placeholder={t('form.name_placeholder')}
|
|
325
|
+
/>
|
|
326
|
+
{!formData.name && (
|
|
327
|
+
<span className="error">{t('errors.required')}</span>
|
|
328
|
+
)}
|
|
329
|
+
</div>
|
|
330
|
+
|
|
331
|
+
<div className="form-group">
|
|
332
|
+
<label>{t('form.email')}</label>
|
|
333
|
+
<input
|
|
334
|
+
type="email"
|
|
335
|
+
value={formData.email}
|
|
336
|
+
onChange={e => setFormData({...formData, email: e.target.value})}
|
|
337
|
+
placeholder={t('form.email_placeholder')}
|
|
338
|
+
/>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<div className="form-group">
|
|
342
|
+
<label>{t('form.message')}</label>
|
|
343
|
+
<textarea
|
|
344
|
+
value={formData.message}
|
|
345
|
+
onChange={e => setFormData({...formData, message: e.target.value})}
|
|
346
|
+
placeholder={t('form.message_placeholder')}
|
|
347
|
+
rows={4}
|
|
348
|
+
/>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<button type="submit">
|
|
352
|
+
{t('form.submit')}
|
|
353
|
+
</button>
|
|
354
|
+
</form>
|
|
355
|
+
);
|
|
356
|
+
};
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Exemple 3 : Dashboard avec modules multiples
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { useArcIntl } from '@arc-js/intl';
|
|
363
|
+
import { useEffect } from 'react';
|
|
364
|
+
|
|
365
|
+
const Dashboard = () => {
|
|
366
|
+
const { t, loadModuleTranslations, currentLocale } = useArcIntl();
|
|
367
|
+
|
|
368
|
+
// Charger les traductions de plusieurs modules
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
const loadModules = async () => {
|
|
371
|
+
await loadModuleTranslations('admin');
|
|
372
|
+
await loadModuleTranslations('analytics');
|
|
373
|
+
await loadModuleTranslations('reports');
|
|
374
|
+
};
|
|
375
|
+
loadModules();
|
|
376
|
+
}, [currentLocale]);
|
|
377
|
+
|
|
378
|
+
return (
|
|
379
|
+
<div className="dashboard">
|
|
380
|
+
<header>
|
|
381
|
+
<h1>{t('dashboard.title', {}, { moduleName: 'admin' })}</h1>
|
|
382
|
+
<p>{t('dashboard.welcome_message', { user: 'John Doe' })}</p>
|
|
383
|
+
</header>
|
|
384
|
+
|
|
385
|
+
<section className="stats">
|
|
386
|
+
<div className="stat-card">
|
|
387
|
+
<h3>{t('analytics.visitors', {}, { moduleName: 'analytics' })}</h3>
|
|
388
|
+
<p>1,234</p>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
<div className="stat-card">
|
|
392
|
+
<h3>{t('reports.monthly', {}, { moduleName: 'reports' })}</h3>
|
|
393
|
+
<p>{t('reports.growth', { percent: '15%' })}</p>
|
|
394
|
+
</div>
|
|
395
|
+
</section>
|
|
396
|
+
|
|
397
|
+
<footer>
|
|
398
|
+
<p>{t('common.last_updated', { date: new Date().toLocaleDateString(currentLocale) })}</p>
|
|
399
|
+
</footer>
|
|
400
|
+
</div>
|
|
401
|
+
);
|
|
402
|
+
};
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## 🔧 Configuration Avancée
|
|
406
|
+
|
|
407
|
+
### Configuration Vite
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// vite.config.ts
|
|
411
|
+
import { defineConfig } from 'vite';
|
|
412
|
+
import react from '@vitejs/plugin-react';
|
|
413
|
+
|
|
414
|
+
export default defineConfig({
|
|
415
|
+
plugins: [react()],
|
|
416
|
+
resolve: {
|
|
417
|
+
alias: {
|
|
418
|
+
'@arc-js/intl': '@arc-js/intl/index.js'
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Configuration TypeScript
|
|
425
|
+
|
|
426
|
+
```json
|
|
427
|
+
{
|
|
428
|
+
"compilerOptions": {
|
|
429
|
+
"target": "ES2020",
|
|
430
|
+
"lib": ["DOM", "DOM.Iterable", "ES2020"],
|
|
431
|
+
"module": "ESNext",
|
|
432
|
+
"moduleResolution": "bundler",
|
|
433
|
+
"allowImportingTsExtensions": true,
|
|
434
|
+
"resolveJsonModule": true,
|
|
435
|
+
"strict": true,
|
|
436
|
+
"types": ["vite/client"]
|
|
437
|
+
},
|
|
438
|
+
"include": ["src", "node_modules/@arc-js/intl/**/*"]
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Variables d'environnement
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
# .env
|
|
446
|
+
VITE_DEFAULT_LOCALE=en
|
|
447
|
+
VITE_SUPPORTED_LOCALES=en,fr,es
|
|
448
|
+
VITE_TRANSLATION_DEBUG=true
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## 🛡️ Gestion des Erreurs
|
|
452
|
+
|
|
453
|
+
### Fallback et logs
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// En mode développement, les clés manquantes sont loggées
|
|
457
|
+
const MissingKeyHandler = () => {
|
|
458
|
+
const { t } = useTranslation();
|
|
459
|
+
|
|
460
|
+
// Si la clé n'existe pas, elle est retournée telle quelle
|
|
461
|
+
const title = t('nonexistent.key'); // Retourne: "nonexistent.key"
|
|
462
|
+
|
|
463
|
+
// Avec une valeur par défaut
|
|
464
|
+
const subtitle = t('another.missing.key', {}, {
|
|
465
|
+
defaultValue: 'Default text'
|
|
466
|
+
}); // Retourne: "Default text"
|
|
467
|
+
|
|
468
|
+
return (
|
|
469
|
+
<div>
|
|
470
|
+
<h1>{title}</h1>
|
|
471
|
+
<p>{subtitle}</p>
|
|
472
|
+
</div>
|
|
473
|
+
);
|
|
474
|
+
};
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Validation des traductions
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// Script de validation des traductions
|
|
481
|
+
import fs from 'fs';
|
|
482
|
+
import path from 'path';
|
|
483
|
+
|
|
484
|
+
const validateTranslations = (locale: string) => {
|
|
485
|
+
const basePath = path.join(__dirname, 'locales', `\${locale}.json`);
|
|
486
|
+
const baseTranslations = JSON.parse(fs.readFileSync(basePath, 'utf-8'));
|
|
487
|
+
|
|
488
|
+
// Vérifier les clés de base
|
|
489
|
+
const requiredKeys = ['common', 'errors', 'form'];
|
|
490
|
+
requiredKeys.forEach(key => {
|
|
491
|
+
if (!baseTranslations[key]) {
|
|
492
|
+
console.warn(`Missing required namespace "\${key}" in \${locale}`);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// Vérifier la structure des pluriels
|
|
497
|
+
Object.entries(baseTranslations).forEach(([namespace, translations]) => {
|
|
498
|
+
// Logique de validation spécifique
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## 📋 Table des Conventions
|
|
504
|
+
|
|
505
|
+
### Structure des fichiers JSON
|
|
506
|
+
|
|
507
|
+
| Chemin | Description | Exemple |
|
|
508
|
+
|--------|-------------|---------|
|
|
509
|
+
| `locales/{locale}.json` | Traductions de base | `locales/en.json` |
|
|
510
|
+
| `modules/{module}/locales/{locale}.json` | Traductions du module | `modules/admin/locales/fr.json` |
|
|
511
|
+
| `public/locales/{locale}.json` | Traductions statiques (optionnel) | `public/locales/es.json` |
|
|
512
|
+
|
|
513
|
+
### Clés de traduction
|
|
514
|
+
|
|
515
|
+
| Format | Description | Exemple |
|
|
516
|
+
|--------|-------------|---------|
|
|
517
|
+
| `namespace.key` | Clé simple | `common.save` |
|
|
518
|
+
| `namespace.nested.key` | Clé imbriquée | `form.contact.email` |
|
|
519
|
+
| `key_{context}` | Avec contexte | `save_draft`, `save_final` |
|
|
520
|
+
| `key_{pluralForm}` | Forme plurielle | `item_one`, `item_other` |
|
|
521
|
+
|
|
522
|
+
### Paramètres supportés
|
|
523
|
+
|
|
524
|
+
| Paramètre | Type | Description |
|
|
525
|
+
|-----------|------|-------------|
|
|
526
|
+
| `count` | number | Pour la gestion des pluriels |
|
|
527
|
+
| `context` | string | Contexte spécifique (draft, final, etc.) |
|
|
528
|
+
| `moduleName` | string | Module cible pour la traduction |
|
|
529
|
+
| `defaultValue` | string | Valeur par défaut si la clé n'existe pas |
|
|
530
|
+
|
|
531
|
+
## 🔧 Build et Développement
|
|
532
|
+
|
|
533
|
+
### Scripts recommandés
|
|
534
|
+
|
|
535
|
+
```json
|
|
536
|
+
{
|
|
537
|
+
"scripts": {
|
|
538
|
+
"dev": "vite",
|
|
539
|
+
"build": "tsc && vite build",
|
|
540
|
+
"preview": "vite preview",
|
|
541
|
+
"type-check": "tsc --noEmit",
|
|
542
|
+
"extract-translations": "node scripts/extract-keys.js",
|
|
543
|
+
"validate-translations": "node scripts/validate-translations.js"
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Extraction des clés de traduction
|
|
549
|
+
|
|
550
|
+
```javascript
|
|
551
|
+
// scripts/extract-keys.js
|
|
552
|
+
import { extractKeysFromFiles } from './translation-utils';
|
|
553
|
+
|
|
554
|
+
// Extraire toutes les clés utilisées dans les composants
|
|
555
|
+
const keys = extractKeysFromFiles('src/**/*.{tsx,ts}');
|
|
556
|
+
fs.writeFileSync('translation-keys.json', JSON.stringify(keys, null, 2));
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## 📄 Licence
|
|
560
|
+
|
|
561
|
+
MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
|
562
|
+
|
|
563
|
+
## 🐛 Signaler un Bug
|
|
564
|
+
|
|
565
|
+
Envoyez-nous un mail à l'adresse `contact.inicode@gmail.com` pour :
|
|
566
|
+
- Signaler un bug
|
|
567
|
+
- Proposer une amélioration
|
|
568
|
+
- Poser une question sur l'utilisation
|
|
569
|
+
- Demander une nouvelle fonctionnalité
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
**@arc-js/intl** - La solution d'internationalisation modulaire pour React et TypeScript.
|
|
574
|
+
|
|
575
|
+
*Développé par l'équipe INICODE*
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const DEFAULT_LOCALE = "en";
|
|
2
|
+
declare const SUPPORTED_LOCALES: string[];
|
|
3
|
+
declare const COOKIE_NAME = "app_locale";
|
|
4
|
+
type Locale = typeof SUPPORTED_LOCALES[number];
|
|
5
|
+
declare const getSavedLocale: (supportedLocales?: string[]) => string;
|
|
6
|
+
declare const saveLocale: (locale: string) => void;
|
|
7
|
+
declare const PATH_CONFIG: {
|
|
8
|
+
SRC_DIR: string;
|
|
9
|
+
};
|
|
10
|
+
declare const SRC_DIR: string;
|
|
11
|
+
|
|
12
|
+
export { COOKIE_NAME, DEFAULT_LOCALE, PATH_CONFIG, SRC_DIR, SUPPORTED_LOCALES, getSavedLocale, saveLocale };
|
|
13
|
+
export type { Locale };
|