feat(web): i18n with react-i18next — Albanian default, English second

Add react-i18next with two key-parity-checked catalogs (sq default/fallback, en).
Active language driven by the logged-in user's stored preference (applied after
/me resolves); SQ/EN toggle in the header persists via PUT /api/auth/language.
Translate the booth (screen, pay/exit modal, active sessions, snapshots, status),
Login, ShiftControl, SiteSettings, PermitManager, TariffComposer.

SetupWizard deferred (its content is server-provided; needs backend catalog i18n).
This commit is contained in:
2026-06-18 11:47:39 +02:00
parent 445bca0bf6
commit 14c83e182a
19 changed files with 840 additions and 201 deletions
+64
View File
@@ -87,12 +87,18 @@ importers:
'@tanstack/react-router':
specifier: ^1.170.16
version: 1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
i18next:
specifier: ^26.3.1
version: 26.3.1(typescript@6.0.3)
react:
specifier: 19.2.7
version: 19.2.7
react-dom:
specifier: 19.2.7
version: 19.2.7(react@19.2.7)
react-i18next:
specifier: ^17.0.8
version: 17.0.8(i18next@26.3.1(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
zustand:
specifier: ^5.0.14
version: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7))
@@ -165,6 +171,10 @@ importers:
packages:
'@babel/runtime@7.29.7':
resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
engines: {node: '>=6.9.0'}
'@drizzle-team/brocli@0.10.2':
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
@@ -1630,10 +1640,21 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
http-errors@2.0.1:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
i18next@26.3.1:
resolution: {integrity: sha512-txQqd5EULsqEh9OJqRH15aCaOuy/nLJyhw5EHCSKLKJE1aBbb3Zve2+uQIxgWhPm1QqUQoWyQBm2kfmmIrzkcQ==}
peerDependencies:
typescript: ^5 || ^6
peerDependenciesMeta:
typescript:
optional: true
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@@ -1852,6 +1873,22 @@ packages:
peerDependencies:
react: ^19.2.7
react-i18next@17.0.8:
resolution: {integrity: sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==}
peerDependencies:
i18next: '>= 26.2.0'
react: '>= 16.8.0'
react-dom: '*'
react-native: '*'
typescript: ^5 || ^6
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
typescript:
optional: true
react-remove-scroll-bar@2.3.8:
resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
engines: {node: '>=10'}
@@ -2126,6 +2163,10 @@ packages:
yaml:
optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -2165,6 +2206,8 @@ packages:
snapshots:
'@babel/runtime@7.29.7': {}
'@drizzle-team/brocli@0.10.2': {}
'@emnapi/core@1.10.0':
@@ -3347,6 +3390,10 @@ snapshots:
graceful-fs@4.2.11: {}
html-parse-stringify@3.0.1:
dependencies:
void-elements: 3.1.0
http-errors@2.0.1:
dependencies:
depd: 2.0.0
@@ -3355,6 +3402,10 @@ snapshots:
statuses: 2.0.2
toidentifier: 1.0.1
i18next@26.3.1(typescript@6.0.3):
optionalDependencies:
typescript: 6.0.3
ieee754@1.2.1: {}
inherits@2.0.4: {}
@@ -3547,6 +3598,17 @@ snapshots:
react: 19.2.7
scheduler: 0.27.0
react-i18next@17.0.8(i18next@26.3.1(typescript@6.0.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3):
dependencies:
'@babel/runtime': 7.29.7
html-parse-stringify: 3.0.1
i18next: 26.3.1(typescript@6.0.3)
react: 19.2.7
use-sync-external-store: 1.6.0(react@19.2.7)
optionalDependencies:
react-dom: 19.2.7(react@19.2.7)
typescript: 6.0.3
react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7):
dependencies:
react: 19.2.7
@@ -3776,6 +3838,8 @@ snapshots:
jiti: 2.7.0
tsx: 4.22.4
void-elements@3.1.0: {}
wrappy@1.0.2: {}
ws@8.21.0: {}