@asafarim/shared-i18n 0.8.0 β 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.
- package/README.md +266 -280
- package/demo/README.md +119 -0
- package/demo/index.html +12 -1
- package/demo/node_modules/.bin/kill-port +17 -0
- package/demo/node_modules/.bin/tsc +5 -9
- package/demo/node_modules/.bin/tsserver +5 -9
- package/demo/node_modules/.bin/vite +5 -9
- package/demo/package.json +7 -4
- package/demo/public/404.html +24 -0
- package/demo/public/favicon.svg +4 -4
- package/demo/public/logo.svg +24 -24
- package/demo/src/App.tsx +178 -129
- package/demo/src/components/CountryLanguageSelectorsPage.tsx +240 -0
- package/demo/src/components/GetStartedSection.tsx +56 -56
- package/demo/src/components/KeyTable.tsx +29 -29
- package/demo/src/components/LanguageBar.tsx +145 -103
- package/demo/src/components/LanguageSwitcherDemo.module.css +114 -114
- package/demo/src/components/LanguageSwitchersPage.tsx +245 -0
- package/demo/src/components/Logo.tsx +6 -6
- package/demo/src/components/OverviewSection.tsx +58 -43
- package/demo/src/components/Panel.tsx +15 -15
- package/demo/src/components/RoutingLabPage.tsx +147 -0
- package/demo/src/components/StatusCard.tsx +109 -109
- package/demo/src/data/countries.ts +48 -0
- package/demo/src/i18n/localeAdapter.ts +91 -0
- package/demo/src/i18n/localeRouting.ts +77 -0
- package/demo/src/index.css +1075 -644
- package/demo/src/locales/de/demo.json +202 -84
- package/demo/src/locales/en/demo.json +201 -85
- package/demo/src/locales/fr/demo.json +203 -85
- package/demo/src/locales/it/demo.json +202 -84
- package/demo/src/locales/lb/demo.json +201 -0
- package/demo/src/locales/nl/demo.json +203 -85
- package/demo/src/main.tsx +32 -29
- package/demo/tsconfig.json +18 -18
- package/demo/tsconfig.node.json +10 -10
- package/demo/tsconfig.tsbuildinfo +1 -1
- package/demo/vite-env.d.ts +7 -7
- package/demo/vite.config.d.ts +2 -2
- package/demo/vite.config.js +10 -10
- package/dist/components/LanguageSwitcher.module.css +303 -303
- package/dist/country-language-selector.css +431 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +87 -85
- package/demo/dist/Icon Dropdown_Limited Languages.png +0 -0
- package/demo/dist/Select Dropdown_Text Only.png +0 -0
- package/demo/dist/assets/favicon-BZYZvBLo.svg +0 -4
- package/demo/dist/assets/index-BdjqKw_N.css +0 -1
- package/demo/dist/assets/index-C1Tq1uEr.js +0 -191
- package/demo/dist/favicon.svg +0 -4
- package/demo/dist/index.html +0 -27
- package/demo/dist/logo.svg +0 -24
- package/demo/node_modules/.bin/browserslist +0 -21
- package/demo/node_modules/.bin/browserslist.CMD +0 -12
- package/demo/node_modules/.bin/browserslist.ps1 +0 -41
- package/demo/node_modules/.bin/tsc.CMD +0 -12
- package/demo/node_modules/.bin/tsc.ps1 +0 -41
- package/demo/node_modules/.bin/tsserver.CMD +0 -12
- package/demo/node_modules/.bin/tsserver.ps1 +0 -41
- package/demo/node_modules/.bin/vite.CMD +0 -12
- package/demo/node_modules/.bin/vite.ps1 +0 -41
- package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js +0 -848
- package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js.map +0 -7
- package/demo/node_modules/.vite/deps/_metadata.json +0 -76
- package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js +0 -30
- package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +0 -7
- package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js +0 -1004
- package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js.map +0 -7
- package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js +0 -292
- package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js.map +0 -7
- package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js +0 -280
- package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js.map +0 -7
- package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js +0 -400
- package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js.map +0 -7
- package/demo/node_modules/.vite/deps/i18next.js +0 -2392
- package/demo/node_modules/.vite/deps/i18next.js.map +0 -7
- package/demo/node_modules/.vite/deps/package.json +0 -3
- package/demo/node_modules/.vite/deps/react-dom.js +0 -6
- package/demo/node_modules/.vite/deps/react-dom.js.map +0 -7
- package/demo/node_modules/.vite/deps/react-dom_client.js +0 -20217
- package/demo/node_modules/.vite/deps/react-dom_client.js.map +0 -7
- package/demo/node_modules/.vite/deps/react-i18next.js +0 -869
- package/demo/node_modules/.vite/deps/react-i18next.js.map +0 -7
- package/demo/node_modules/.vite/deps/react.js +0 -5
- package/demo/node_modules/.vite/deps/react.js.map +0 -7
- package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +0 -278
- package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +0 -7
- package/demo/node_modules/.vite/deps/react_jsx-runtime.js +0 -6
- package/demo/node_modules/.vite/deps/react_jsx-runtime.js.map +0 -7
- package/demo/src/components/CountryLanguageDemo.tsx +0 -140
- package/demo/src/components/LanguageSwitcherDemo.tsx +0 -256
package/README.md
CHANGED
|
@@ -1,280 +1,266 @@
|
|
|
1
|
-
# @asafarim/shared-i18n
|
|
2
|
-
|
|
3
|
-
Lightweight
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- π Works in any React + TypeScript project (monorepo or standalone)
|
|
10
|
-
- ποΈ JSON-based translations per language and namespace
|
|
11
|
-
- π Cookie-based language persistence
|
|
12
|
-
- βοΈ Optional backend sync for user language preferences
|
|
13
|
-
- β‘ Lazy loading support for app-specific translations
|
|
14
|
-
- πͺ React hooks
|
|
15
|
-
- π¨
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
npm i @asafarim/shared-i18n
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
### 1
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
import
|
|
36
|
-
|
|
37
|
-
import
|
|
38
|
-
import
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
To point to a backend, optionally set:
|
|
269
|
-
|
|
270
|
-
```env
|
|
271
|
-
VITE_IDENTITY_API_URL=https://your-identity.example.com
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## Built-in translations
|
|
275
|
-
|
|
276
|
-
This package ships with default English and Dutch common translations. You can ignore them and supply your own resources if preferred.
|
|
277
|
-
|
|
278
|
-
## License
|
|
279
|
-
|
|
280
|
-
MIT Β© ASafariM
|
|
1
|
+
# @asafarim/shared-i18n
|
|
2
|
+
|
|
3
|
+
Lightweight React + TypeScript i18n package built on top of i18next and react-i18next. Ships with sensible defaults (English and Dutch) but supports any language. Includes a **LanguageSwitcher** and, new in v0.9, re-exports the full **CountryLanguageSelector** from `@asafarim/country-language-selector` β so consumers install only one package.
|
|
4
|
+
|
|
5
|
+
* Live demo: [https://alisafari-it.github.io/shared-i18n/](https://alisafari-it.github.io/shared-i18n/)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- π Works in any React + TypeScript project (monorepo or standalone)
|
|
10
|
+
- ποΈ JSON-based translations per language and namespace
|
|
11
|
+
- π Cookie-based language persistence with automatic browser detection
|
|
12
|
+
- βοΈ Optional backend sync for user language preferences
|
|
13
|
+
- β‘ Lazy loading support for app-specific translations
|
|
14
|
+
- πͺ React hooks: `useLanguage`, `useTranslation`
|
|
15
|
+
- π¨ **LanguageSwitcher** β three variants: buttons, select, icon-dropdown
|
|
16
|
+
- πΊοΈ **CountryLanguageSelector** β re-exported, image or emoji flags, locale-aware URLs
|
|
17
|
+
- π Configurable API URL resolution for flexible backend integration
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @asafarim/shared-i18n
|
|
23
|
+
# or: npm i @asafarim/shared-i18n
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That is the only package you need. `@asafarim/country-language-selector` is a bundled dependency and re-exported for you.
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### 1. Initialize i18n
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// main.tsx
|
|
34
|
+
import { initI18n } from '@asafarim/shared-i18n';
|
|
35
|
+
import '@asafarim/shared-i18n/country-language-selector.css'; // if using CountryLanguageSelector
|
|
36
|
+
|
|
37
|
+
import enApp from './locales/en/app.json';
|
|
38
|
+
import nlApp from './locales/nl/app.json';
|
|
39
|
+
|
|
40
|
+
initI18n({
|
|
41
|
+
defaultLanguage: 'en',
|
|
42
|
+
defaultNS: 'common',
|
|
43
|
+
ns: ['common', 'app'],
|
|
44
|
+
resources: {
|
|
45
|
+
en: { app: enApp },
|
|
46
|
+
nl: { app: nlApp }
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Translate in components
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { useTranslation } from '@asafarim/shared-i18n';
|
|
55
|
+
|
|
56
|
+
function MyComponent() {
|
|
57
|
+
const { t } = useTranslation('app');
|
|
58
|
+
return <h1>{t('welcome')}</h1>;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## LanguageSwitcher
|
|
65
|
+
|
|
66
|
+
Language-only switcher with cookie persistence.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { LanguageSwitcher } from '@asafarim/shared-i18n';
|
|
70
|
+
|
|
71
|
+
// Buttons
|
|
72
|
+
<LanguageSwitcher variant="buttons" />
|
|
73
|
+
|
|
74
|
+
// Select dropdown (no emoji)
|
|
75
|
+
<LanguageSwitcher variant="select" showEmoji={false} />
|
|
76
|
+
|
|
77
|
+
// Icon dropdown with flag emoji
|
|
78
|
+
<LanguageSwitcher variant="icon-dropdown" />
|
|
79
|
+
|
|
80
|
+
// Toggle between exactly 2 languages
|
|
81
|
+
<LanguageSwitcher variant="select" languages={['en', 'nl']} isToggler={true} />
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Props
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default | Description |
|
|
87
|
+
|------|------|---------|-------------|
|
|
88
|
+
| `variant` | `"buttons" \| "select" \| "icon-dropdown"` | `"buttons"` | UI variant |
|
|
89
|
+
| `languages` | `SupportedLanguage[]` | all supported | Subset of languages to show |
|
|
90
|
+
| `showEmoji` | `boolean` | `true` | Show flag emoji in select/icon variants |
|
|
91
|
+
| `showLabel` | `boolean` | `true` | Show language name label |
|
|
92
|
+
| `isToggler` | `boolean` | `true` | Renders as toggle when exactly 2 languages given |
|
|
93
|
+
| `onChanged` | `(lang: SupportedLanguage) => void` | β | Callback on language change |
|
|
94
|
+
| `unstyled` | `boolean` | `false` | Omit built-in styles |
|
|
95
|
+
|
|
96
|
+
### Limitation β country awareness
|
|
97
|
+
|
|
98
|
+
`LanguageSwitcher` emits only a language code (e.g. `"en"`). It cannot distinguish `be-en` from `gb-en`. For locale-aware URLs, use `resolveLocaleFromLanguage` as an adapter:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { LanguageSwitcher } from '@asafarim/shared-i18n';
|
|
102
|
+
import { resolveLocaleFromLanguage } from './i18n/localeAdapter';
|
|
103
|
+
|
|
104
|
+
<LanguageSwitcher
|
|
105
|
+
variant="buttons"
|
|
106
|
+
onChanged={(lang) => {
|
|
107
|
+
const { locale, reason, message } = resolveLocaleFromLanguage(currentLocale, lang, countries);
|
|
108
|
+
if (reason === 'fallback-country') showNotice(message);
|
|
109
|
+
if (reason !== 'unsupported') navigate(locale);
|
|
110
|
+
}}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## CountryLanguageSelector
|
|
117
|
+
|
|
118
|
+
Country + language selector. Re-exported from `@asafarim/country-language-selector`.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import {
|
|
122
|
+
CountryLanguageSelector,
|
|
123
|
+
type Country,
|
|
124
|
+
type Locale,
|
|
125
|
+
} from '@asafarim/shared-i18n';
|
|
126
|
+
|
|
127
|
+
const countries: Country[] = [
|
|
128
|
+
{
|
|
129
|
+
code: 'BE', name: 'Belgium', nativeName: 'BelgiΓ«', flag: 'π§πͺ',
|
|
130
|
+
languages: [
|
|
131
|
+
{ code: 'en', label: 'English', nativeLabel: 'English' },
|
|
132
|
+
{ code: 'nl', label: 'Dutch', nativeLabel: 'Nederlands' },
|
|
133
|
+
{ code: 'fr', label: 'French', nativeLabel: 'FranΓ§ais' },
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
code: 'NL', name: 'Netherlands', nativeName: 'Nederland', flag: 'π³π±',
|
|
138
|
+
languages: [
|
|
139
|
+
{ code: 'nl', label: 'Dutch', nativeLabel: 'Nederlands' },
|
|
140
|
+
{ code: 'en', label: 'English', nativeLabel: 'English' },
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
code: 'GB', name: 'United Kingdom', nativeName: 'United Kingdom', flag: 'π¬π§',
|
|
145
|
+
languages: [
|
|
146
|
+
{ code: 'en', label: 'English', nativeLabel: 'English' },
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
function LocaleBar({ locale, onLocaleChange }) {
|
|
152
|
+
const { i18n } = useTranslation();
|
|
153
|
+
return (
|
|
154
|
+
<CountryLanguageSelector
|
|
155
|
+
countries={countries}
|
|
156
|
+
value={locale}
|
|
157
|
+
onChange={(next) => {
|
|
158
|
+
i18n.changeLanguage(next.language);
|
|
159
|
+
onLocaleChange(next);
|
|
160
|
+
}}
|
|
161
|
+
triggerVariant="compact"
|
|
162
|
+
flagMode="image"
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Key Props
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Default | Description |
|
|
171
|
+
|------|------|---------|-------------|
|
|
172
|
+
| `countries` | `Country[]` | built-in list | Countries to offer |
|
|
173
|
+
| `value` | `Locale` | β | Controlled value |
|
|
174
|
+
| `defaultValue` | `Locale` | β | Uncontrolled initial value |
|
|
175
|
+
| `onChange` | `(locale, meta) => void` | β | Fired on every change |
|
|
176
|
+
| `triggerVariant` | `"compact" \| "full" \| "flag"` | `"compact"` | Trigger display |
|
|
177
|
+
| `flagMode` | `"emoji" \| "image"` | `"emoji"` | Flag rendering strategy |
|
|
178
|
+
| `align` | `"start" \| "end"` | `"end"` | Popover alignment |
|
|
179
|
+
| `renderTrigger` | `(ctx) => ReactNode` | β | Custom trigger render prop |
|
|
180
|
+
| `persistKey` | `string` | β | localStorage key (uncontrolled only) |
|
|
181
|
+
|
|
182
|
+
### Comparison: LanguageSwitcher vs CountryLanguageSelector
|
|
183
|
+
|
|
184
|
+
| Capability | LanguageSwitcher | CountryLanguageSelector |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| Changes i18n language | β
| β
via `locale.language` |
|
|
187
|
+
| Knows country | β | β
|
|
|
188
|
+
| Represents `be-en` | β | β
|
|
|
189
|
+
| Distinguishes `be-en` from `gb-en` | β | β
|
|
|
190
|
+
| Best for localized URLs | β needs adapter | β
|
|
|
191
|
+
| Best for translation-only apps | β
| optional |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## CSS Import
|
|
196
|
+
|
|
197
|
+
When using `CountryLanguageSelector`, import its stylesheet once in your entry point:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import '@asafarim/shared-i18n/country-language-selector.css';
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## More Languages
|
|
206
|
+
|
|
207
|
+
Add any language by including its JSON files:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
initI18n({
|
|
211
|
+
ns: ['common', 'app'],
|
|
212
|
+
resources: {
|
|
213
|
+
en: { app: enApp },
|
|
214
|
+
nl: { app: nlApp },
|
|
215
|
+
fr: { app: frApp }
|
|
216
|
+
},
|
|
217
|
+
supportedLngs: ['en', 'nl', 'fr'],
|
|
218
|
+
defaultLanguage: 'en'
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## API Reference
|
|
225
|
+
|
|
226
|
+
### `initI18n(config?)`
|
|
227
|
+
|
|
228
|
+
| Param | Type | Description |
|
|
229
|
+
|-------|------|-------------|
|
|
230
|
+
| `defaultNS` | `string` | Default namespace (default: `'common'`) |
|
|
231
|
+
| `ns` | `string[]` | Namespaces to load |
|
|
232
|
+
| `resources` | object | App-specific translation resources |
|
|
233
|
+
| `supportedLngs` | `string[]` | Override supported languages |
|
|
234
|
+
| `defaultLanguage` | `string` | Fallback language code |
|
|
235
|
+
|
|
236
|
+
### `useLanguage()`
|
|
237
|
+
|
|
238
|
+
Returns `{ language, changeLanguage, isChanging }`.
|
|
239
|
+
|
|
240
|
+
### `useTranslation(ns?)`
|
|
241
|
+
|
|
242
|
+
Re-exported from react-i18next.
|
|
243
|
+
|
|
244
|
+
### `getApiUrl(envVarName?, defaultUrl?)`
|
|
245
|
+
|
|
246
|
+
Configurable API URL resolver.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Cookie & Backend Integration
|
|
251
|
+
|
|
252
|
+
User language preference is persisted in a `preferredLanguage` cookie. To sync with a backend, set:
|
|
253
|
+
|
|
254
|
+
```env
|
|
255
|
+
VITE_IDENTITY_API_URL=https://your-identity.example.com
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Built-in Translations
|
|
261
|
+
|
|
262
|
+
Ships with English and Dutch for the `common` namespace. Supply your own resources via `initI18n` to override or extend.
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT Β© ASafariM
|