@asafarim/shared-i18n 0.8.1 → 0.9.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.
Files changed (94) hide show
  1. package/README.md +266 -350
  2. package/demo/README.md +119 -148
  3. package/demo/index.html +12 -1
  4. package/demo/node_modules/.bin/kill-port +17 -0
  5. package/demo/node_modules/.bin/tsc +5 -9
  6. package/demo/node_modules/.bin/tsserver +5 -9
  7. package/demo/node_modules/.bin/vite +5 -9
  8. package/demo/package.json +7 -4
  9. package/demo/public/404.html +24 -0
  10. package/demo/public/favicon.svg +4 -4
  11. package/demo/public/logo.svg +24 -24
  12. package/demo/src/App.tsx +178 -129
  13. package/demo/src/components/CountryLanguageSelectorsPage.tsx +240 -0
  14. package/demo/src/components/GetStartedSection.tsx +56 -56
  15. package/demo/src/components/KeyTable.tsx +29 -29
  16. package/demo/src/components/LanguageBar.tsx +145 -103
  17. package/demo/src/components/LanguageSwitcherDemo.module.css +114 -114
  18. package/demo/src/components/LanguageSwitchersPage.tsx +245 -0
  19. package/demo/src/components/Logo.tsx +6 -6
  20. package/demo/src/components/OverviewSection.tsx +58 -43
  21. package/demo/src/components/Panel.tsx +15 -15
  22. package/demo/src/components/RoutingLabPage.tsx +147 -0
  23. package/demo/src/components/StatusCard.tsx +109 -109
  24. package/demo/src/data/countries.ts +48 -0
  25. package/demo/src/i18n/localeAdapter.ts +91 -0
  26. package/demo/src/i18n/localeRouting.ts +77 -0
  27. package/demo/src/index.css +1075 -644
  28. package/demo/src/locales/de/demo.json +202 -84
  29. package/demo/src/locales/en/demo.json +201 -85
  30. package/demo/src/locales/fr/demo.json +203 -85
  31. package/demo/src/locales/it/demo.json +202 -84
  32. package/demo/src/locales/lb/demo.json +201 -0
  33. package/demo/src/locales/nl/demo.json +203 -85
  34. package/demo/src/main.tsx +32 -29
  35. package/demo/tsconfig.json +18 -18
  36. package/demo/tsconfig.node.json +10 -10
  37. package/demo/tsconfig.tsbuildinfo +1 -1
  38. package/demo/vite-env.d.ts +7 -7
  39. package/demo/vite.config.d.ts +2 -2
  40. package/demo/vite.config.js +10 -10
  41. package/dist/components/LanguageSwitcher.module.css +303 -303
  42. package/dist/country-language-selector.css +431 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +2 -0
  46. package/dist/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +8 -5
  48. package/demo/dist/Icon Dropdown_Limited Languages.png +0 -0
  49. package/demo/dist/Select Dropdown_Text Only.png +0 -0
  50. package/demo/dist/assets/favicon-BZYZvBLo.svg +0 -4
  51. package/demo/dist/assets/index-BdjqKw_N.css +0 -1
  52. package/demo/dist/assets/index-C1Tq1uEr.js +0 -191
  53. package/demo/dist/favicon.svg +0 -4
  54. package/demo/dist/index.html +0 -27
  55. package/demo/dist/logo.svg +0 -24
  56. package/demo/node_modules/.bin/browserslist +0 -21
  57. package/demo/node_modules/.bin/browserslist.CMD +0 -12
  58. package/demo/node_modules/.bin/browserslist.ps1 +0 -41
  59. package/demo/node_modules/.bin/tsc.CMD +0 -12
  60. package/demo/node_modules/.bin/tsc.ps1 +0 -41
  61. package/demo/node_modules/.bin/tsserver.CMD +0 -12
  62. package/demo/node_modules/.bin/tsserver.ps1 +0 -41
  63. package/demo/node_modules/.bin/vite.CMD +0 -12
  64. package/demo/node_modules/.bin/vite.ps1 +0 -41
  65. package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js +0 -848
  66. package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js.map +0 -7
  67. package/demo/node_modules/.vite/deps/_metadata.json +0 -76
  68. package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js +0 -30
  69. package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +0 -7
  70. package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js +0 -1004
  71. package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js.map +0 -7
  72. package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js +0 -292
  73. package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js.map +0 -7
  74. package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js +0 -280
  75. package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js.map +0 -7
  76. package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js +0 -400
  77. package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js.map +0 -7
  78. package/demo/node_modules/.vite/deps/i18next.js +0 -2392
  79. package/demo/node_modules/.vite/deps/i18next.js.map +0 -7
  80. package/demo/node_modules/.vite/deps/package.json +0 -3
  81. package/demo/node_modules/.vite/deps/react-dom.js +0 -6
  82. package/demo/node_modules/.vite/deps/react-dom.js.map +0 -7
  83. package/demo/node_modules/.vite/deps/react-dom_client.js +0 -20217
  84. package/demo/node_modules/.vite/deps/react-dom_client.js.map +0 -7
  85. package/demo/node_modules/.vite/deps/react-i18next.js +0 -869
  86. package/demo/node_modules/.vite/deps/react-i18next.js.map +0 -7
  87. package/demo/node_modules/.vite/deps/react.js +0 -5
  88. package/demo/node_modules/.vite/deps/react.js.map +0 -7
  89. package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +0 -278
  90. package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +0 -7
  91. package/demo/node_modules/.vite/deps/react_jsx-runtime.js +0 -6
  92. package/demo/node_modules/.vite/deps/react_jsx-runtime.js.map +0 -7
  93. package/demo/src/components/CountryLanguageDemo.tsx +0 -140
  94. package/demo/src/components/LanguageSwitcherDemo.tsx +0 -256
@@ -1,85 +1,203 @@
1
- {
2
- "title": "Démonstration Shared i18n",
3
- "subtitle": "Un wrapper React i18next léger avec persistance des cookies.",
4
- "cta": "Changer de langue",
5
- "overview": {
6
- "heading": "Aperçu",
7
- "description": "@asafarim/shared-i18n est un package d'internationalisation (i18n) de qualité production pour les applications React.",
8
- "features": {
9
- "title": "Fonctionnalités Principales",
10
- "items": [
11
- "Support multi-langues avec persistance des cookies",
12
- "Détection de langue et fallback intégrés",
13
- "Support TypeScript avec sécurité typage complet",
14
- "Espaces de noms common et identity-portal préconfigurés",
15
- "Intégration transparente avec react-i18next",
16
- "Synchronisation des préférences de langue avec le backend",
17
- "Utilitaires SSR-safe pour le rendu côté serveur"
18
- ]
19
- },
20
- "useCases": {
21
- "title": "Idéal Pour",
22
- "items": [
23
- "Applications globales nécessitant un support multi-langues",
24
- "Plateformes enterprise avec préférences de langue utilisateur",
25
- "Systèmes d'identité et d'authentification",
26
- "Systèmes de gestion de contenu avec localisation",
27
- "Applications SaaS servant des utilisateurs internationaux"
28
- ]
29
- }
30
- },
31
- "getStarted": {
32
- "heading": "Premiers Pas",
33
- "intro": "Apprenez à intégrer @asafarim/shared-i18n dans votre application React en quelques minutes.",
34
- "steps": [
35
- {
36
- "title": "1. Installer le Package",
37
- "description": "Ajoutez le package aux dépendances de votre projet.",
38
- "code": "pnpm add @asafarim/shared-i18n"
39
- },
40
- {
41
- "title": "2. Initialiser i18n dans Votre App",
42
- "description": "Appelez initI18n au démarrage de l'application pour configurer les paramètres de langue.",
43
- "code": "import { initI18n } from '@asafarim/shared-i18n';\n\ninitI18n({\n defaultNS: 'common',\n ns: ['common', 'identityPortal'],\n resources: /* vos traductions */\n});"
44
- },
45
- {
46
- "title": "3. Utiliser le Hook useLanguage",
47
- "description": "Accédez au changement de langue et à l'état de langue actuel dans vos composants.",
48
- "code": "const { changeLanguage, isChanging } = useLanguage();\n\n<button onClick={() => changeLanguage('en')}>\n Vers Anglais\n</button>"
49
- },
50
- {
51
- "title": "4. Traduire avec useTranslation",
52
- "description": "Utilisez le hook useTranslation pour accéder aux chaînes traduites.",
53
- "code": "const { t } = useTranslation('common');\n\n<h1>{t('welcome')}</h1>"
54
- },
55
- {
56
- "title": "5. Profiter de la Persistance des Cookies",
57
- "description": "Les préférences de langue des utilisateurs sont automatiquement sauvegardées et restaurées.",
58
- "code": "// Sauvegardé automatiquement via cookies\n// Aucune configuration supplémentaire requise !"
59
- },
60
- {
61
- "title": "6. Synchroniser avec le Backend (Optionnel)",
62
- "description": "Mettez à jour les préférences de langue des utilisateurs sur votre backend.",
63
- "code": "import { updateUserLanguagePreference } from '@asafarim/shared-i18n';\n\nawait updateUserLanguagePreference('fr');"
64
- }
65
- ],
66
- "tips": {
67
- "title": "Conseils Pro",
68
- "items": [
69
- "Utilisez les espaces de noms pour organiser les traductions par fonctionnalité",
70
- "Profitez du composant Trans pour les traductions complexes avec variables",
71
- "Configurez VITE_IDENTITY_API_URL pour la synchronisation backend",
72
- "Vérifiez la détection de langue du navigateur avec getInitialLanguage()",
73
- "Combinez avec les design tokens pour des thèmes cohérents dans toutes les langues"
74
- ]
75
- }
76
- },
77
- "status": {
78
- "heading": "Statut en direct",
79
- "cookie": "Cookie",
80
- "backend": "Backend",
81
- "simulate": "Simuler la synchronisation backend",
82
- "resultOk": "Synchronisation backend réussie",
83
- "resultFail": "Échec de la synchronisation backend"
84
- }
85
- }
1
+ {
2
+ "title": "Démonstration Shared i18n",
3
+ "subtitle": "Un wrapper React i18next léger avec persistance des cookies.",
4
+ "cta": "Changer de langue",
5
+ "overview": {
6
+ "heading": "Aperçu",
7
+ "description": "@asafarim/shared-i18n est un package d'internationalisation (i18n) de qualité production pour les applications React.",
8
+ "features": {
9
+ "title": "Fonctionnalités Principales",
10
+ "items": [
11
+ "Support multi-langues avec persistance des cookies",
12
+ "Détection de langue et fallback intégrés",
13
+ "Support TypeScript avec sécurité typage complet",
14
+ "Espaces de noms common et identity-portal préconfigurés",
15
+ "Intégration transparente avec react-i18next",
16
+ "Synchronisation des préférences de langue avec le backend",
17
+ "Utilitaires SSR-safe pour le rendu côté serveur"
18
+ ]
19
+ },
20
+ "selectors": {
21
+ "title": "CountryLanguageSelector",
22
+ "items": [
23
+ "Contient à la fois le pays ET la langue: { country: 'BE', language: 'en' }",
24
+ "Peut distinguer be-en de nl-en, lu-en, gb-en",
25
+ "Drapeaux images (flagcdn.com) ou drapeaux emoji",
26
+ "Variantes compacte, complète, drapeau seul et déclencheur personnalisé",
27
+ "Idéal pour les URLs localisées comme /be-en/get-started"
28
+ ]
29
+ },
30
+ "useCases": {
31
+ "title": "Idéal Pour",
32
+ "items": [
33
+ "Applications globales nécessitant un support multi-langues",
34
+ "Plateformes enterprise avec préférences de langue utilisateur",
35
+ "Systèmes d'identité et d'authentification",
36
+ "Systèmes de gestion de contenu avec localisation",
37
+ "Applications SaaS servant des utilisateurs internationaux"
38
+ ]
39
+ }
40
+ },
41
+ "getStarted": {
42
+ "heading": "Premiers Pas",
43
+ "intro": "Apprenez à intégrer @asafarim/shared-i18n dans votre application React en quelques minutes.",
44
+ "steps": [
45
+ {
46
+ "title": "1. Installer le Package",
47
+ "description": "Ajoutez le package aux dépendances de votre projet.",
48
+ "code": "pnpm add @asafarim/shared-i18n"
49
+ },
50
+ {
51
+ "title": "2. Initialiser i18n dans Votre App",
52
+ "description": "Appelez initI18n au démarrage de l'application pour configurer les paramètres de langue.",
53
+ "code": "import { initI18n } from '@asafarim/shared-i18n';\n\ninitI18n({\n defaultNS: 'common',\n ns: ['common', 'identityPortal'],\n resources: /* vos traductions */\n});"
54
+ },
55
+ {
56
+ "title": "3. Utiliser le Hook useLanguage",
57
+ "description": "Accédez au changement de langue et à l'état de langue actuel dans vos composants.",
58
+ "code": "const { changeLanguage, isChanging } = useLanguage();\n\n<button onClick={() => changeLanguage('en')}>\n Vers Anglais\n</button>"
59
+ },
60
+ {
61
+ "title": "4. Traduire avec useTranslation",
62
+ "description": "Utilisez le hook useTranslation pour accéder aux chaînes traduites.",
63
+ "code": "const { t } = useTranslation('common');\n\n<h1>{t('welcome')}</h1>"
64
+ },
65
+ {
66
+ "title": "5. Profiter de la Persistance des Cookies",
67
+ "description": "Les préférences de langue des utilisateurs sont automatiquement sauvegardées et restaurées.",
68
+ "code": "// Sauvegardé automatiquement via cookies\n// Aucune configuration supplémentaire requise !"
69
+ },
70
+ {
71
+ "title": "6. Synchroniser avec le Backend (Optionnel)",
72
+ "description": "Mettez à jour les préférences de langue des utilisateurs sur votre backend.",
73
+ "code": "import { updateUserLanguagePreference } from '@asafarim/shared-i18n';\n\nawait updateUserLanguagePreference('fr');"
74
+ }
75
+ ],
76
+ "tips": {
77
+ "title": "Conseils Pro",
78
+ "items": [
79
+ "Utilisez les espaces de noms pour organiser les traductions par fonctionnalité",
80
+ "Profitez du composant Trans pour les traductions complexes avec variables",
81
+ "Configurez VITE_IDENTITY_API_URL pour la synchronisation backend",
82
+ "Vérifiez la détection de langue du navigateur avec getInitialLanguage()",
83
+ "Combinez avec les design tokens pour des thèmes cohérents dans toutes les langues"
84
+ ]
85
+ }
86
+ },
87
+ "routingContract": {
88
+ "heading": "Contrat de routage",
89
+ "description": "L'URL est la source de vérité pour à la fois la locale et la page active.",
90
+ "items": [
91
+ "{base} redirige vers {target}",
92
+ "{pattern} pilote l'UI",
93
+ "Changement CountryLanguageSelector → mise à jour locale complète",
94
+ "Changement LanguageSwitcher → langue résolue via resolveLocaleFromLanguage",
95
+ "Slug invalide → {defaultSlug}; page invalide → {defaultPage}"
96
+ ]
97
+ },
98
+ "languageSwitchers": {
99
+ "heading": "Changeurs de langue",
100
+ "intro": "LanguageSwitcher est langue-uniquement — il ne sait pas dans quel pays se trouve l'utilisateur. Chaque variante ci-dessous est connectée via resolveLocaleFromLanguage afin que sélectionner une langue produise toujours une URL locale valide.",
101
+ "distinction": {
102
+ "title": "Pourquoi LanguageSwitcher ne peut pas remplacer CountryLanguageSelector",
103
+ "p1": "Ces quatre slugs de locale portent la même langue (anglais) mais des pays différents. LanguageSwitcher ne peut pas les distinguer:",
104
+ "p2": "CountryLanguageSelector porte à la fois le pays et la langue, il peut donc représenter et distinguer les quatre.",
105
+ "link": "Voir l'onglet Country Language Selectors pour cela."
106
+ },
107
+ "comparison": {
108
+ "title": "Comparaison",
109
+ "capability": "Capacité",
110
+ "ls": "LanguageSwitcher",
111
+ "cls": "CountryLanguageSelector",
112
+ "yes": "Oui",
113
+ "no": "Non",
114
+ "needsAdapter": "Non — a besoin d'un adaptateur",
115
+ "optional": "Optionnel",
116
+ "yesVia": "Oui, via locale.language",
117
+ "changesLang": "Change la langue i18n",
118
+ "knowsCountry": "Connaît le pays",
119
+ "representsBeEn": "Peut représenter be-en",
120
+ "distinguishes": "Peut distinguer be-en de gb-en",
121
+ "bestUrls": "Idéal pour URLs localisées",
122
+ "bestTransOnly": "Idéal pour apps traduction-uniquement"
123
+ },
124
+ "variants": [
125
+ { "title": "Variante boutons", "desc": "Boutons individuels pour chaque langue. Déclenche onChanged avec un code de langue." },
126
+ { "title": "Select dropdown — texte uniquement", "desc": "<select> natif avec noms de langues. Pas d'emoji." },
127
+ { "title": "Icon dropdown — toutes les langues", "desc": "Dropdown compact drapeau-emoji affichant toutes les langues supportées." },
128
+ { "title": "Icon dropdown — langues limitées", "desc": "Limité à l'anglais et au néerlandais uniquement. Utile pour correspondre à la portée pays de la démo." },
129
+ { "title": "Icon dropdown — avec labels", "desc": "Identique ci-dessus mais affiche les noms de langues à côté de l'emoji drapeau." },
130
+ { "title": "Bouton toggle (2 langues)", "desc": "Quand exactement 2 langues sont fournies et isToggler=true, rend un seul bouton toggle." }
131
+ ],
132
+ "note": "Ce contrôle change uniquement la langue. La démo mappe la langue sélectionnée vers une locale complète via resolveLocaleFromLanguage pour que l'URL reste valide.",
133
+ "preview": "Aperçu",
134
+ "code": "Code"
135
+ },
136
+ "routingLab": {
137
+ "heading": "Lab de routage",
138
+ "intro": "Comparaison côte à côte de comment LanguageSwitcher et CountryLanguageSelector se comportent lors du changement de locale. L'URL se met à jour en direct.",
139
+ "currentLocale": "Locale actuelle",
140
+ "slug": "Slug",
141
+ "urlPath": "Chemin URL",
142
+ "langOnly": {
143
+ "title": "Action langue-uniquement",
144
+ "desc": "LanguageSwitcher déclenche un code de langue. La démo utilise resolveLocaleFromLanguage pour le mapper vers une locale complète valide. Si le pays actuel ne supporte pas la langue, un avis de fallback est affiché.",
145
+ "resolved": "Locale résolue:"
146
+ },
147
+ "countryLang": {
148
+ "title": "Action pays-langue",
149
+ "desc": "CountryLanguageSelector déclenche directement un objet complet { country, language } — pas d'adaptateur nécessaire. L'URL a toujours le bon pays + langue.",
150
+ "resolved": "Locale résolue:"
151
+ },
152
+ "scenarios": {
153
+ "title": "Scénarios scriptés",
154
+ "desc": "Cliquez sur une ligne pour appliquer le scénario et observez la mise à jour de l'URL et de la puce de locale.",
155
+ "expected": "Attendu:"
156
+ }
157
+ },
158
+ "status": {
159
+ "heading": "Statut en direct",
160
+ "cookie": "Cookie",
161
+ "backend": "Backend",
162
+ "simulate": "Simuler la synchronisation backend",
163
+ "resultOk": "Synchronisation backend réussie",
164
+ "resultFail": "Échec de la synchronisation backend"
165
+ },
166
+ "nav": {
167
+ "overview": "Aperçu",
168
+ "getStarted": "Premiers pas",
169
+ "languageSwitchers": "Changeurs de langue",
170
+ "countrySelectors": "Sélecteurs de pays",
171
+ "routingLab": "Lab de routage",
172
+ "tagline": "Démo routage locale Benelux + UK"
173
+ },
174
+ "footer": {
175
+ "activeRoute": "Route active",
176
+ "builtWith": "Construit avec"
177
+ },
178
+ "hero": {
179
+ "getStarted": "Premiers pas",
180
+ "trySelector": "Essayer le sélecteur",
181
+ "liveRoutePreview": "Aperçu de la route en direct"
182
+ },
183
+ "countryLanguageSelectors": {
184
+ "heading": "Sélecteurs Pays Langue",
185
+ "intro": "CountryLanguageSelector porte à la fois le pays et la langue, ce qui en fait le bon choix pour les URLs localisées. Toutes les variantes ci-dessous partagent la même locale contrôlée — changer l'une met à jour l'URL et les deux sélecteurs de navbar.",
186
+ "country": "Pays",
187
+ "language": "Langue",
188
+ "slug": "Slug",
189
+ "url": "URL",
190
+ "preview": "Aperçu",
191
+ "code": "Code",
192
+ "variants": [
193
+ { "title": "Drapeaux images · trigger compact", "desc": "Utilise des drapeaux SVG de flagcdn.com — fonctionne sur Windows où les drapeaux emoji s'affichent comme des codes ISO." },
194
+ { "title": "État désactivé", "desc": "Le sélecteur peut être désactivé pendant le chargement ou lorsque l'utilisateur n'a pas la permission de changer la locale." },
195
+ { "title": "Noms complets · drapeaux images", "desc": "Affiche les noms complets du pays et de la langue — utile quand l'espace n'est pas contraint." },
196
+ { "title": "Trigger drapeau uniquement", "desc": "Seul le drapeau est affiché dans le trigger — idéal pour les navbars très compactes." },
197
+ { "title": "Trigger personnalisé via renderTrigger", "desc": "Contrôle total sur le bouton trigger via la render prop renderTrigger. Utilise une image de drapeau inline pour fonctionner sur Windows." },
198
+ { "title": "Popover aligné au début", "desc": "Alignez la popover dropdown sur le bord gauche du trigger via align='start'." }
199
+ ],
200
+ "open": "Ouvrir",
201
+ "close": "Fermer"
202
+ }
203
+ }
@@ -1,85 +1,203 @@
1
- {
2
- "title": "Demo i18n condiviso",
3
- "subtitle": "Un wrapper leggero React i18next con persistenza dei cookie.",
4
- "cta": "Cambia lingua",
5
- "overview": {
6
- "heading": "Panoramica",
7
- "description": "@asafarim/shared-i18n è un pacchetto di internazionalizzazione (i18n) di livello produzione per applicazioni React.",
8
- "features": {
9
- "title": "Caratteristiche Principali",
10
- "items": [
11
- "Supporto multi-lingua con persistenza dei cookie",
12
- "Rilevamento automatico della lingua e fallback",
13
- "Supporto TypeScript con sicurezza completa dei tipi",
14
- "Pre-configurato con namespace comuni e identity-portal",
15
- "Integrazione perfetta con react-i18next",
16
- "Sincronizzazione delle preferenze linguistiche del backend",
17
- "Utilità sicure per SSR per il rendering lato server"
18
- ]
19
- },
20
- "useCases": {
21
- "title": "Perfetto Per",
22
- "items": [
23
- "Applicazioni globali che richiedono supporto multi-lingua",
24
- "Piattaforme enterprise con preferenze linguistiche degli utenti",
25
- "Sistemi di identità e autenticazione",
26
- "Sistemi di gestione contenuti con localizzazione",
27
- "Applicazioni SaaS che servono utenti internazionali"
28
- ]
29
- }
30
- },
31
- "getStarted": {
32
- "heading": "Inizia",
33
- "intro": "Scopri come integrare @asafarim/shared-i18n nella tua applicazione React in pochi minuti.",
34
- "steps": [
35
- {
36
- "title": "1. Installa il Pacchetto",
37
- "description": "Aggiungi il pacchetto alle dipendenze del tuo progetto.",
38
- "code": "pnpm add @asafarim/shared-i18n"
39
- },
40
- {
41
- "title": "2. Inizializza i18n nella Tua App",
42
- "description": "Chiama initI18n all'avvio dell'applicazione per configurare le impostazioni linguistiche.",
43
- "code": "import { initI18n } from '@asafarim/shared-i18n';\n\ninitI18n({\n defaultNS: 'common',\n ns: ['common', 'identityPortal'],\n resources: { /* your translations */ }\n});"
44
- },
45
- {
46
- "title": "3. Usa l'Hook useLanguage",
47
- "description": "Accedi al cambio lingua e allo stato della lingua corrente nei tuoi componenti.",
48
- "code": "const { changeLanguage, isChanging } = useLanguage();\n\n<button onClick={() => changeLanguage('nl')}>\n Passa all'olandese\n</button>"
49
- },
50
- {
51
- "title": "4. Traduci con useTranslation",
52
- "description": "Usa l'hook useTranslation per accedere alle stringhe tradotte.",
53
- "code": "const { t } = useTranslation('common');\n\n<h1>{t('welcome')}</h1>"
54
- },
55
- {
56
- "title": "5. Sfrutta la Persistenza dei Cookie",
57
- "description": "Le preferenze linguistiche degli utenti vengono automaticamente salvate e ripristinate.",
58
- "code": "// Automaticamente persistito tramite cookie\n// Nessuna configurazione aggiuntiva richiesta!"
59
- },
60
- {
61
- "title": "6. Sincronizza con il Backend (Opzionale)",
62
- "description": "Aggiorna le preferenze linguistiche degli utenti sul tuo backend.",
63
- "code": "import { updateUserLanguagePreference } from '@asafarim/shared-i18n';\n\nawait updateUserLanguagePreference('en');"
64
- }
65
- ],
66
- "tips": {
67
- "title": "Suggerimenti Pro",
68
- "items": [
69
- "Usa i namespace per organizzare le traduzioni per funzionalità",
70
- "Sfrutta il componente Trans per traduzioni complesse con variabili",
71
- "Imposta VITE_IDENTITY_API_URL per la sincronizzazione del backend",
72
- "Verifica il rilevamento della lingua del browser con getInitialLanguage()",
73
- "Combina con i design token per un tema consistente tra le lingue"
74
- ]
75
- }
76
- },
77
- "status": {
78
- "heading": "Stato live",
79
- "cookie": "Cookie",
80
- "backend": "Backend",
81
- "simulate": "Simula sincronizzazione backend",
82
- "resultOk": "Sincronizzazione backend riuscita",
83
- "resultFail": "Sincronizzazione backend fallita"
84
- }
1
+ {
2
+ "title": "Demo i18n condiviso",
3
+ "subtitle": "Un wrapper leggero React i18next con persistenza dei cookie.",
4
+ "cta": "Cambia lingua",
5
+ "overview": {
6
+ "heading": "Panoramica",
7
+ "description": "@asafarim/shared-i18n è un pacchetto di internazionalizzazione (i18n) di livello produzione per applicazioni React.",
8
+ "features": {
9
+ "title": "Caratteristiche Principali",
10
+ "items": [
11
+ "Supporto multi-lingua con persistenza dei cookie",
12
+ "Rilevamento automatico della lingua e fallback",
13
+ "Supporto TypeScript con sicurezza completa dei tipi",
14
+ "Pre-configurato con namespace comuni e identity-portal",
15
+ "Integrazione perfetta con react-i18next",
16
+ "Sincronizzazione delle preferenze linguistiche del backend",
17
+ "Utilità sicure per SSR per il rendering lato server"
18
+ ]
19
+ },
20
+ "selectors": {
21
+ "title": "CountryLanguageSelector",
22
+ "items": [
23
+ "Contiene sia il paese CHE la lingua: { country: 'BE', language: 'en' }",
24
+ "Può distinguere be-en da nl-en, lu-en, gb-en",
25
+ "Bandiere immagine (flagcdn.com) o bandiere emoji",
26
+ "Varianti compatte, complete, solo-bandiera e trigger personalizzato",
27
+ "Ideale per URL localizzati come /be-en/get-started"
28
+ ]
29
+ },
30
+ "useCases": {
31
+ "title": "Perfetto Per",
32
+ "items": [
33
+ "Applicazioni globali che richiedono supporto multi-lingua",
34
+ "Piattaforme enterprise con preferenze linguistiche degli utenti",
35
+ "Sistemi di identità e autenticazione",
36
+ "Sistemi di gestione contenuti con localizzazione",
37
+ "Applicazioni SaaS che servono utenti internazionali"
38
+ ]
39
+ }
40
+ },
41
+ "getStarted": {
42
+ "heading": "Inizia",
43
+ "intro": "Scopri come integrare @asafarim/shared-i18n nella tua applicazione React in pochi minuti.",
44
+ "steps": [
45
+ {
46
+ "title": "1. Installa il Pacchetto",
47
+ "description": "Aggiungi il pacchetto alle dipendenze del tuo progetto.",
48
+ "code": "pnpm add @asafarim/shared-i18n"
49
+ },
50
+ {
51
+ "title": "2. Inizializza i18n nella Tua App",
52
+ "description": "Chiama initI18n all'avvio dell'applicazione per configurare le impostazioni linguistiche.",
53
+ "code": "import { initI18n } from '@asafarim/shared-i18n';\n\ninitI18n({\n defaultNS: 'common',\n ns: ['common', 'identityPortal'],\n resources: { /* your translations */ }\n});"
54
+ },
55
+ {
56
+ "title": "3. Usa l'Hook useLanguage",
57
+ "description": "Accedi al cambio lingua e allo stato della lingua corrente nei tuoi componenti.",
58
+ "code": "const { changeLanguage, isChanging } = useLanguage();\n\n<button onClick={() => changeLanguage('nl')}>\n Passa all'olandese\n</button>"
59
+ },
60
+ {
61
+ "title": "4. Traduci con useTranslation",
62
+ "description": "Usa l'hook useTranslation per accedere alle stringhe tradotte.",
63
+ "code": "const { t } = useTranslation('common');\n\n<h1>{t('welcome')}</h1>"
64
+ },
65
+ {
66
+ "title": "5. Sfrutta la Persistenza dei Cookie",
67
+ "description": "Le preferenze linguistiche degli utenti vengono automaticamente salvate e ripristinate.",
68
+ "code": "// Automaticamente persistito tramite cookie\n// Nessuna configurazione aggiuntiva richiesta!"
69
+ },
70
+ {
71
+ "title": "6. Sincronizza con il Backend (Opzionale)",
72
+ "description": "Aggiorna le preferenze linguistiche degli utenti sul tuo backend.",
73
+ "code": "import { updateUserLanguagePreference } from '@asafarim/shared-i18n';\n\nawait updateUserLanguagePreference('en');"
74
+ }
75
+ ],
76
+ "tips": {
77
+ "title": "Suggerimenti Pro",
78
+ "items": [
79
+ "Usa i namespace per organizzare le traduzioni per funzionalità",
80
+ "Sfrutta il componente Trans per traduzioni complesse con variabili",
81
+ "Imposta VITE_IDENTITY_API_URL per la sincronizzazione del backend",
82
+ "Verifica il rilevamento della lingua del browser con getInitialLanguage()",
83
+ "Combina con i design token per un tema consistente tra le lingue"
84
+ ]
85
+ }
86
+ },
87
+ "routingContract": {
88
+ "heading": "Contratto di routing",
89
+ "description": "L'URL è la fonte di verità per sia la locale che la pagina attiva.",
90
+ "items": [
91
+ "{base} reindirizza a {target}",
92
+ "{pattern} guida la UI",
93
+ "Cambio CountryLanguageSelector → aggiornamento locale completo",
94
+ "Cambio LanguageSwitcher → lingua risolta via resolveLocaleFromLanguage",
95
+ "Slug non valido → {defaultSlug}; pagina non valida → {defaultPage}"
96
+ ]
97
+ },
98
+ "languageSwitchers": {
99
+ "heading": "Selettori lingua",
100
+ "intro": "LanguageSwitcher è solo-lingua — non sa in quale paese si trova l'utente. Ogni variante qui sotto è collegata via resolveLocaleFromLanguage così che selezionare una lingua produca comunque un URL locale valido.",
101
+ "distinction": {
102
+ "title": "Perché LanguageSwitcher non può sostituire CountryLanguageSelector",
103
+ "p1": "Queste quattro slug di locale portano la stessa lingua (inglese) ma paesi diversi. LanguageSwitcher non può distinguerli:",
104
+ "p2": "CountryLanguageSelector porta sia paese che lingua, quindi può rappresentare e distinguere tutti e quattro.",
105
+ "link": "Vedi la scheda Country Language Selectors per quello."
106
+ },
107
+ "comparison": {
108
+ "title": "Confronto",
109
+ "capability": "Capacità",
110
+ "ls": "LanguageSwitcher",
111
+ "cls": "CountryLanguageSelector",
112
+ "yes": "Sì",
113
+ "no": "No",
114
+ "needsAdapter": "No — ha bisogno di adattatore",
115
+ "optional": "Opzionale",
116
+ "yesVia": "Sì, via locale.language",
117
+ "changesLang": "Cambia lingua i18n",
118
+ "knowsCountry": "Conosce paese",
119
+ "representsBeEn": "Può rappresentare be-en",
120
+ "distinguishes": "Può distinguere be-en da gb-en",
121
+ "bestUrls": "Migliore per URL localizzati",
122
+ "bestTransOnly": "Migliore per app solo-traduzione"
123
+ },
124
+ "variants": [
125
+ { "title": "Variante pulsanti", "desc": "Pulsanti individuali per ogni lingua. Attiva onChanged con un codice lingua." },
126
+ { "title": "Select dropdown — solo testo", "desc": "<select> nativo con nomi lingua. Nessun emoji." },
127
+ { "title": "Icon dropdown — tutte le lingue", "desc": "Dropdown bandiera-emoji compatto che mostra tutte le lingue supportate." },
128
+ { "title": "Icon dropdown — lingue limitate", "desc": "Limitato solo a inglese e olandese. Utile per corrispondere alla portata paesi della demo." },
129
+ { "title": "Icon dropdown — con etichette", "desc": "Come sopra ma mostra nomi lingua accanto all'emoji bandiera." },
130
+ { "title": "Pulsante toggle (2 lingue)", "desc": "Quando esattamente 2 lingue sono fornite e isToggler=true, renderizza un singolo pulsante toggle." }
131
+ ],
132
+ "note": "Questo controllo cambia solo la lingua. La demo mappa la lingua selezionata a una locale completa via resolveLocaleFromLanguage così che l'URL rimanga valido.",
133
+ "preview": "Anteprima",
134
+ "code": "Codice"
135
+ },
136
+ "routingLab": {
137
+ "heading": "Lab di routing",
138
+ "intro": "Confronto affiancato di come LanguageSwitcher e CountryLanguageSelector si comportano quando si cambia locale. L'URL si aggiorna in tempo reale.",
139
+ "currentLocale": "Locale attuale",
140
+ "slug": "Slug",
141
+ "urlPath": "Percorso URL",
142
+ "langOnly": {
143
+ "title": "Azione solo-lingua",
144
+ "desc": "LanguageSwitcher attiva un codice lingua. La demo usa resolveLocaleFromLanguage per mapparlo a una locale completa valida. Se il paese attuale non supporta la lingua, viene mostrato un avviso di fallback.",
145
+ "resolved": "Locale risolta:"
146
+ },
147
+ "countryLang": {
148
+ "title": "Azione paese-lingua",
149
+ "desc": "CountryLanguageSelector attiva direttamente un oggetto completo { country, language } — nessun adattatore necessario. L'URL ha sempre il giusto paese + lingua.",
150
+ "resolved": "Locale risolta:"
151
+ },
152
+ "scenarios": {
153
+ "title": "Scenari scriptati",
154
+ "desc": "Clicca su una riga per applicare lo scenario e osserva l'aggiornamento dell'URL e del chip locale.",
155
+ "expected": "Atteso:"
156
+ }
157
+ },
158
+ "status": {
159
+ "heading": "Stato live",
160
+ "cookie": "Cookie",
161
+ "backend": "Backend",
162
+ "simulate": "Simula sincronizzazione backend",
163
+ "resultOk": "Sincronizzazione backend riuscita",
164
+ "resultFail": "Sincronizzazione backend fallita"
165
+ },
166
+ "nav": {
167
+ "overview": "Panoramica",
168
+ "getStarted": "Inizia",
169
+ "languageSwitchers": "Selettori lingua",
170
+ "countrySelectors": "Selettori paese",
171
+ "routingLab": "Lab di routing",
172
+ "tagline": "Demo routing locale Benelux + UK"
173
+ },
174
+ "footer": {
175
+ "activeRoute": "Route attiva",
176
+ "builtWith": "Costruito con"
177
+ },
178
+ "hero": {
179
+ "getStarted": "Inizia",
180
+ "trySelector": "Prova il selettore",
181
+ "liveRoutePreview": "Anteprima route live"
182
+ },
183
+ "countryLanguageSelectors": {
184
+ "heading": "Selettori Paese Lingua",
185
+ "intro": "CountryLanguageSelector porta sia il paese che la lingua, rendendolo la scelta giusta per URL localizzati. Tutte le varianti qui sotto condividono la stessa locale controllata — cambiandone una si aggiorna l'URL e entrambi i selettori della navbar.",
186
+ "country": "Paese",
187
+ "language": "Lingua",
188
+ "slug": "Slug",
189
+ "url": "URL",
190
+ "preview": "Anteprima",
191
+ "code": "Codice",
192
+ "variants": [
193
+ { "title": "Bandiere immagine · trigger compatto", "desc": "Utilizza bandiere SVG da flagcdn.com — funziona su Windows dove le bandiere emoji vengono visualizzate come codici ISO." },
194
+ { "title": "Stato disabilitato", "desc": "Il selettore può essere disabilitato durante il caricamento o quando l'utente non ha il permesso di cambiare la locale." },
195
+ { "title": "Nomi completi · bandiere immagine", "desc": "Mostra i nomi completi del paese e della lingua — utile quando lo spazio non è limitato." },
196
+ { "title": "Trigger solo-bandiera", "desc": "Solo la bandiera viene mostrata nel trigger — ideale per navbar molto compatte." },
197
+ { "title": "Trigger personalizzato via renderTrigger", "desc": "Controllo totale sul pulsante trigger tramite la render prop renderTrigger. Utilizza un'immagine bandiera inline per funzionare su Windows." },
198
+ { "title": "Popover allineato all'inizio", "desc": "Allinea la popover dropdown al bordo sinistro del trigger tramite align='start'." }
199
+ ],
200
+ "open": "Apri",
201
+ "close": "Chiudi"
202
+ }
85
203
  }