@micha.bigler/ui-core-micha 3.8.0 → 3.9.1

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 (69) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/WORK_ORDERS.md +2 -0
  3. package/dist/auth/apiClient.js +8 -0
  4. package/dist/components/AccessCodeManager.js +5 -5
  5. package/dist/components/AccessCodeSingleUseToggle.js +3 -2
  6. package/dist/components/AllowedEmailDomainsManager.js +3 -2
  7. package/dist/components/AuthFactorRequirementCard.js +3 -2
  8. package/dist/components/BulkInviteCsvTab.js +3 -2
  9. package/dist/components/MFAComponent.js +9 -8
  10. package/dist/components/MfaLoginComponent.js +7 -6
  11. package/dist/components/PasskeysComponent.js +7 -6
  12. package/dist/components/ProfileComponent.js +4 -3
  13. package/dist/components/QrSignupManager.js +4 -3
  14. package/dist/components/QrSignupValidityManager.js +3 -2
  15. package/dist/components/RegistrationMethodsManager.js +3 -2
  16. package/dist/components/SecurityComponent.js +5 -4
  17. package/dist/components/SupportRecoveryRequestsTab.js +8 -7
  18. package/dist/components/UserInviteComponent.js +3 -2
  19. package/dist/components/UserListComponent.js +14 -7
  20. package/dist/i18n/authTranslations.js +420 -0
  21. package/dist/pages/AccountPage.js +3 -2
  22. package/dist/pages/LoginPage.js +10 -9
  23. package/dist/pages/PasswordChangePage.js +4 -3
  24. package/dist/pages/PasswordInvitePage.js +7 -6
  25. package/dist/pages/PasswordResetRequestPage.js +5 -4
  26. package/dist/pages/SignUpPage.js +7 -6
  27. package/dist/pages/SignupConfirmPage.js +7 -6
  28. package/dist/utils/auth-errors.js +45 -8
  29. package/dist/utils/resolveErrorText.js +24 -0
  30. package/package.json +1 -1
  31. package/src/auth/apiClient.jsx +9 -0
  32. package/src/components/AccessCodeManager.jsx +5 -5
  33. package/src/components/AccessCodeSingleUseToggle.jsx +3 -2
  34. package/src/components/AllowedEmailDomainsManager.jsx +3 -2
  35. package/src/components/AuthFactorRequirementCard.jsx +3 -2
  36. package/src/components/BulkInviteCsvTab.jsx +3 -2
  37. package/src/components/MFAComponent.jsx +9 -8
  38. package/src/components/MfaLoginComponent.jsx +7 -6
  39. package/src/components/PasskeysComponent.jsx +7 -6
  40. package/src/components/ProfileComponent.jsx +4 -3
  41. package/src/components/QrSignupManager.jsx +4 -3
  42. package/src/components/QrSignupValidityManager.jsx +3 -2
  43. package/src/components/RegistrationMethodsManager.jsx +3 -2
  44. package/src/components/SecurityComponent.jsx +5 -4
  45. package/src/components/SupportRecoveryRequestsTab.jsx +9 -8
  46. package/src/components/UserInviteComponent.jsx +3 -2
  47. package/src/components/UserListComponent.jsx +14 -7
  48. package/src/i18n/authTranslations.ts +421 -0
  49. package/src/pages/AccountPage.jsx +3 -4
  50. package/src/pages/LoginPage.jsx +10 -9
  51. package/src/pages/PasswordChangePage.jsx +4 -3
  52. package/src/pages/PasswordInvitePage.jsx +7 -6
  53. package/src/pages/PasswordResetRequestPage.jsx +5 -4
  54. package/src/pages/SignUpPage.jsx +7 -6
  55. package/src/pages/SignupConfirmPage.jsx +7 -6
  56. package/src/utils/auth-errors.js +44 -7
  57. package/src/utils/resolveErrorText.js +28 -0
  58. package/tests/AccountPage.test.jsx +27 -20
  59. package/tests/PasswordInvitePage.test.jsx +28 -21
  60. package/tests/QrSignupManager.registrationContext.test.jsx +5 -1
  61. package/tests/SignUpPage.test.jsx +14 -3
  62. package/tests/UserListComponent.test.jsx +100 -16
  63. package/tests/apiClientLanguage.test.js +33 -0
  64. package/tests/authErrors.test.js +31 -0
  65. package/tests/errorCallSiteGuard.test.js +32 -0
  66. package/tests/loginPageErrorResolution.test.jsx +102 -0
  67. package/tests/resolveErrorText.test.js +72 -0
  68. package/work-orders/UCM-AUTH-10.md +490 -0
  69. package/work-orders/UCM-AUTH-11.md +185 -0
@@ -2084,6 +2084,426 @@ export const authTranslations = {
2084
2084
  "en": "{{count}} successful",
2085
2085
  "sw": "{{count}} zimefaulu"
2086
2086
  },
2087
+ "Auth.field.email.invalid": {
2088
+ "de": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
2089
+ "de_informal": "Bitte gib eine gültige E-Mail-Adresse ein.",
2090
+ "fr": "Saisissez une adresse e-mail valide.",
2091
+ "en": "Enter a valid email address.",
2092
+ "sw": "Weka anwani sahihi ya barua pepe."
2093
+ },
2094
+ "Auth.field.email.required": {
2095
+ "de": "Bitte geben Sie eine E-Mail-Adresse ein.",
2096
+ "de_informal": "Bitte gib eine E-Mail-Adresse ein.",
2097
+ "fr": "Saisissez une adresse e-mail.",
2098
+ "en": "Enter an email address.",
2099
+ "sw": "Weka anwani ya barua pepe."
2100
+ },
2101
+ "Auth.field.password.invalid": {
2102
+ "de": "Bitte geben Sie ein gültiges Passwort ein.",
2103
+ "de_informal": "Bitte gib ein gültiges Passwort ein.",
2104
+ "fr": "Saisissez un mot de passe valide.",
2105
+ "en": "Enter a valid password.",
2106
+ "sw": "Weka nenosiri sahihi."
2107
+ },
2108
+ "Auth.field.password.required": {
2109
+ "de": "Bitte geben Sie ein Passwort ein.",
2110
+ "de_informal": "Bitte gib ein Passwort ein.",
2111
+ "fr": "Saisissez un mot de passe.",
2112
+ "en": "Enter a password.",
2113
+ "sw": "Weka nenosiri."
2114
+ },
2115
+ "Auth.field.new_password.invalid": {
2116
+ "de": "Bitte geben Sie ein gültiges neues Passwort ein.",
2117
+ "de_informal": "Bitte gib ein gültiges neues Passwort ein.",
2118
+ "fr": "Saisissez un nouveau mot de passe valide.",
2119
+ "en": "Enter a valid new password.",
2120
+ "sw": "Weka nenosiri jipya sahihi."
2121
+ },
2122
+ "Auth.field.new_password.required": {
2123
+ "de": "Bitte geben Sie ein neues Passwort ein.",
2124
+ "de_informal": "Bitte gib ein neues Passwort ein.",
2125
+ "fr": "Saisissez un nouveau mot de passe.",
2126
+ "en": "Enter a new password.",
2127
+ "sw": "Weka nenosiri jipya."
2128
+ },
2129
+ "Auth.field.current_password.invalid": {
2130
+ "de": "Bitte geben Sie Ihr aktuelles Passwort korrekt ein.",
2131
+ "de_informal": "Bitte gib dein aktuelles Passwort korrekt ein.",
2132
+ "fr": "Saisissez correctement votre mot de passe actuel.",
2133
+ "en": "Enter your current password correctly.",
2134
+ "sw": "Weka nenosiri lako la sasa kwa usahihi."
2135
+ },
2136
+ "Auth.field.current_password.required": {
2137
+ "de": "Bitte geben Sie Ihr aktuelles Passwort ein.",
2138
+ "de_informal": "Bitte gib dein aktuelles Passwort ein.",
2139
+ "fr": "Saisissez votre mot de passe actuel.",
2140
+ "en": "Enter your current password.",
2141
+ "sw": "Weka nenosiri lako la sasa."
2142
+ },
2143
+ "Auth.field.key.invalid": {
2144
+ "de": "Bitte geben Sie einen gültigen Schlüssel ein.",
2145
+ "de_informal": "Bitte gib einen gültigen Schlüssel ein.",
2146
+ "fr": "Saisissez une clé valide.",
2147
+ "en": "Enter a valid key.",
2148
+ "sw": "Weka ufunguo sahihi."
2149
+ },
2150
+ "Auth.field.key.required": {
2151
+ "de": "Bitte geben Sie einen Schlüssel ein.",
2152
+ "de_informal": "Bitte gib einen Schlüssel ein.",
2153
+ "fr": "Saisissez une clé.",
2154
+ "en": "Enter a key.",
2155
+ "sw": "Weka ufunguo."
2156
+ },
2157
+ "Auth.field.code.invalid": {
2158
+ "de": "Bitte geben Sie einen gültigen Code ein.",
2159
+ "de_informal": "Bitte gib einen gültigen Code ein.",
2160
+ "fr": "Saisissez un code valide.",
2161
+ "en": "Enter a valid code.",
2162
+ "sw": "Weka msimbo sahihi."
2163
+ },
2164
+ "Auth.field.code.required": {
2165
+ "de": "Bitte geben Sie einen Code ein.",
2166
+ "de_informal": "Bitte gib einen Code ein.",
2167
+ "fr": "Saisissez un code.",
2168
+ "en": "Enter a code.",
2169
+ "sw": "Weka msimbo."
2170
+ },
2171
+ "Auth.field.credential.invalid": {
2172
+ "de": "Bitte verwenden Sie eine gültige Sicherheitsmethode.",
2173
+ "de_informal": "Bitte verwende eine gültige Sicherheitsmethode.",
2174
+ "fr": "Utilisez une méthode de sécurité valide.",
2175
+ "en": "Use a valid security method.",
2176
+ "sw": "Tumia njia sahihi ya usalama."
2177
+ },
2178
+ "Auth.field.credential.required": {
2179
+ "de": "Bitte verwenden Sie eine Sicherheitsmethode.",
2180
+ "de_informal": "Bitte verwende eine Sicherheitsmethode.",
2181
+ "fr": "Utilisez une méthode de sécurité.",
2182
+ "en": "Use a security method.",
2183
+ "sw": "Tumia njia ya usalama."
2184
+ },
2185
+ "Auth.field.name.invalid": {
2186
+ "de": "Bitte geben Sie einen gültigen Namen ein.",
2187
+ "de_informal": "Bitte gib einen gültigen Namen ein.",
2188
+ "fr": "Saisissez un nom valide.",
2189
+ "en": "Enter a valid name.",
2190
+ "sw": "Weka jina sahihi."
2191
+ },
2192
+ "Auth.field.name.required": {
2193
+ "de": "Bitte geben Sie einen Namen ein.",
2194
+ "de_informal": "Bitte gib einen Namen ein.",
2195
+ "fr": "Saisissez un nom.",
2196
+ "en": "Enter a name.",
2197
+ "sw": "Weka jina."
2198
+ },
2199
+ "Auth.field.mode.invalid": {
2200
+ "de": "Bitte wählen Sie eine gültige Anmeldemethode.",
2201
+ "de_informal": "Bitte wähle eine gültige Anmeldemethode.",
2202
+ "fr": "Sélectionnez un mode d'inscription valide.",
2203
+ "en": "Choose a valid sign-up method.",
2204
+ "sw": "Chagua njia sahihi ya kujisajili."
2205
+ },
2206
+ "Auth.field.mode.required": {
2207
+ "de": "Bitte wählen Sie eine Anmeldemethode.",
2208
+ "de_informal": "Bitte wähle eine Anmeldemethode.",
2209
+ "fr": "Sélectionnez un mode d'inscription.",
2210
+ "en": "Choose a sign-up method.",
2211
+ "sw": "Chagua njia ya kujisajili."
2212
+ },
2213
+ "Auth.field.access_code.invalid": {
2214
+ "de": "Bitte geben Sie einen gültigen Zugangscode ein.",
2215
+ "de_informal": "Bitte gib einen gültigen Zugangscode ein.",
2216
+ "fr": "Saisissez un code d'accès valide.",
2217
+ "en": "Enter a valid access code.",
2218
+ "sw": "Weka msimbo sahihi wa ufikiaji."
2219
+ },
2220
+ "Auth.field.access_code.required": {
2221
+ "de": "Bitte geben Sie einen Zugangscode ein.",
2222
+ "de_informal": "Bitte gib einen Zugangscode ein.",
2223
+ "fr": "Saisissez un code d'accès.",
2224
+ "en": "Enter an access code.",
2225
+ "sw": "Weka msimbo wa ufikiaji."
2226
+ },
2227
+ "Auth.field.registration_context_token.invalid": {
2228
+ "de": "Bitte verwenden Sie einen gültigen Registrierungslink.",
2229
+ "de_informal": "Bitte verwende einen gültigen Registrierungslink.",
2230
+ "fr": "Utilisez un lien d'inscription valide.",
2231
+ "en": "Use a valid registration link.",
2232
+ "sw": "Tumia kiungo sahihi cha usajili."
2233
+ },
2234
+ "Auth.field.registration_context_token.required": {
2235
+ "de": "Bitte verwenden Sie einen Registrierungslink.",
2236
+ "de_informal": "Bitte verwende einen Registrierungslink.",
2237
+ "fr": "Utilisez un lien d'inscription.",
2238
+ "en": "Use a registration link.",
2239
+ "sw": "Tumia kiungo cha usajili."
2240
+ },
2241
+ "Auth.field.registration_context.invalid": {
2242
+ "de": "Die Registrierungsdaten sind ungültig.",
2243
+ "de_informal": "Die Registrierungsdaten sind ungültig.",
2244
+ "fr": "Les données d'inscription sont invalides.",
2245
+ "en": "The registration data is invalid.",
2246
+ "sw": "Data ya usajili si sahihi."
2247
+ },
2248
+ "Auth.field.registration_context.required": {
2249
+ "de": "Bitte geben Sie die Registrierungsdaten an.",
2250
+ "de_informal": "Bitte gib die Registrierungsdaten an.",
2251
+ "fr": "Indiquez les données d'inscription.",
2252
+ "en": "Provide the registration data.",
2253
+ "sw": "Weka data ya usajili."
2254
+ },
2255
+ "Auth.field.turnstile_token.invalid": {
2256
+ "de": "Bitte bestätigen Sie die Sicherheitsprüfung erneut.",
2257
+ "de_informal": "Bitte bestätige die Sicherheitsprüfung erneut.",
2258
+ "fr": "Recommencez la vérification de sécurité.",
2259
+ "en": "Complete the security check again.",
2260
+ "sw": "Kamilisha ukaguzi wa usalama tena."
2261
+ },
2262
+ "Auth.field.turnstile_token.required": {
2263
+ "de": "Bitte bestätigen Sie die Sicherheitsprüfung.",
2264
+ "de_informal": "Bitte bestätige die Sicherheitsprüfung.",
2265
+ "fr": "Confirmez la vérification de sécurité.",
2266
+ "en": "Complete the security check.",
2267
+ "sw": "Kamilisha ukaguzi wa usalama."
2268
+ },
2269
+ "Auth.field.token.invalid": {
2270
+ "de": "Bitte verwenden Sie einen gültigen Bestätigungstoken.",
2271
+ "de_informal": "Bitte verwende einen gültigen Bestätigungstoken.",
2272
+ "fr": "Utilisez un jeton de confirmation valide.",
2273
+ "en": "Use a valid confirmation token.",
2274
+ "sw": "Tumia tokeni sahihi ya uthibitishaji."
2275
+ },
2276
+ "Auth.field.token.required": {
2277
+ "de": "Bitte geben Sie den Bestätigungstoken an.",
2278
+ "de_informal": "Bitte gib den Bestätigungstoken an.",
2279
+ "fr": "Indiquez le jeton de confirmation.",
2280
+ "en": "Provide the confirmation token.",
2281
+ "sw": "Weka tokeni ya uthibitishaji."
2282
+ },
2283
+ "Auth.field.first_name.invalid": {
2284
+ "de": "Bitte geben Sie einen gültigen Vornamen ein.",
2285
+ "de_informal": "Bitte gib einen gültigen Vornamen ein.",
2286
+ "fr": "Saisissez un prénom valide.",
2287
+ "en": "Enter a valid first name.",
2288
+ "sw": "Weka jina la kwanza sahihi."
2289
+ },
2290
+ "Auth.field.first_name.required": {
2291
+ "de": "Bitte geben Sie Ihren Vornamen ein.",
2292
+ "de_informal": "Bitte gib deinen Vornamen ein.",
2293
+ "fr": "Saisissez votre prénom.",
2294
+ "en": "Enter your first name.",
2295
+ "sw": "Weka jina lako la kwanza."
2296
+ },
2297
+ "Auth.field.last_name.invalid": {
2298
+ "de": "Bitte geben Sie einen gültigen Nachnamen ein.",
2299
+ "de_informal": "Bitte gib einen gültigen Nachnamen ein.",
2300
+ "fr": "Saisissez un nom de famille valide.",
2301
+ "en": "Enter a valid last name.",
2302
+ "sw": "Weka jina la mwisho sahihi."
2303
+ },
2304
+ "Auth.field.last_name.required": {
2305
+ "de": "Bitte geben Sie Ihren Nachnamen ein.",
2306
+ "de_informal": "Bitte gib deinen Nachnamen ein.",
2307
+ "fr": "Saisissez votre nom de famille.",
2308
+ "en": "Enter your last name.",
2309
+ "sw": "Weka jina lako la mwisho."
2310
+ },
2311
+ "Auth.field.accepted_privacy_statement.invalid": {
2312
+ "de": "Bitte bestätigen Sie die Datenschutzerklärung.",
2313
+ "de_informal": "Bitte bestätige die Datenschutzerklärung.",
2314
+ "fr": "Confirmez la déclaration de confidentialité.",
2315
+ "en": "Confirm the privacy statement.",
2316
+ "sw": "Thibitisha taarifa ya faragha."
2317
+ },
2318
+ "Auth.field.accepted_privacy_statement.required": {
2319
+ "de": "Bitte bestätigen Sie die Datenschutzerklärung.",
2320
+ "de_informal": "Bitte bestätige die Datenschutzerklärung.",
2321
+ "fr": "Confirmez la déclaration de confidentialité.",
2322
+ "en": "Confirm the privacy statement.",
2323
+ "sw": "Thibitisha taarifa ya faragha."
2324
+ },
2325
+ "Auth.field.accepted_convenience_cookies.invalid": {
2326
+ "de": "Die Cookie-Einstellung ist ungültig.",
2327
+ "de_informal": "Die Cookie-Einstellung ist ungültig.",
2328
+ "fr": "Le choix des cookies est invalide.",
2329
+ "en": "The cookie preference is invalid.",
2330
+ "sw": "Chaguo la vidakuzi si sahihi."
2331
+ },
2332
+ "Auth.field.accepted_convenience_cookies.required": {
2333
+ "de": "Bitte geben Sie Ihre Cookie-Einstellung an.",
2334
+ "de_informal": "Bitte gib deine Cookie-Einstellung an.",
2335
+ "fr": "Indiquez votre choix de cookies.",
2336
+ "en": "Provide your cookie preference.",
2337
+ "sw": "Weka chaguo lako la vidakuzi."
2338
+ },
2339
+ "Auth.field.expires_minutes.invalid": {
2340
+ "de": "Bitte geben Sie eine gültige Ablaufzeit ein.",
2341
+ "de_informal": "Bitte gib eine gültige Ablaufzeit ein.",
2342
+ "fr": "Saisissez une durée de validité valide.",
2343
+ "en": "Enter a valid expiry period.",
2344
+ "sw": "Weka muda sahihi wa kuisha."
2345
+ },
2346
+ "Auth.field.expires_minutes.required": {
2347
+ "de": "Bitte geben Sie eine Ablaufzeit an.",
2348
+ "de_informal": "Bitte gib eine Ablaufzeit an.",
2349
+ "fr": "Indiquez une durée de validité.",
2350
+ "en": "Provide an expiry period.",
2351
+ "sw": "Weka muda wa kuisha."
2352
+ },
2353
+ "Auth.field.max_redemptions.invalid": {
2354
+ "de": "Bitte geben Sie eine gültige Anzahl von Einlösungen ein.",
2355
+ "de_informal": "Bitte gib eine gültige Anzahl von Einlösungen ein.",
2356
+ "fr": "Saisissez un nombre de validations valide.",
2357
+ "en": "Enter a valid redemption count.",
2358
+ "sw": "Weka idadi sahihi ya matumizi."
2359
+ },
2360
+ "Auth.field.max_redemptions.required": {
2361
+ "de": "Bitte geben Sie die maximale Anzahl von Einlösungen an.",
2362
+ "de_informal": "Bitte gib die maximale Anzahl von Einlösungen an.",
2363
+ "fr": "Indiquez le nombre maximal de validations.",
2364
+ "en": "Provide the maximum redemption count.",
2365
+ "sw": "Weka idadi ya juu ya matumizi."
2366
+ },
2367
+ "Auth.field.signup_qr_expiry_days.invalid": {
2368
+ "de": "Bitte geben Sie eine gültige QR-Gültigkeitsdauer ein.",
2369
+ "de_informal": "Bitte gib eine gültige QR-Gültigkeitsdauer ein.",
2370
+ "fr": "Saisissez une durée de validité QR valide.",
2371
+ "en": "Enter a valid QR validity period.",
2372
+ "sw": "Weka muda sahihi wa QR."
2373
+ },
2374
+ "Auth.field.signup_qr_expiry_days.required": {
2375
+ "de": "Bitte geben Sie die QR-Gültigkeitsdauer an.",
2376
+ "de_informal": "Bitte gib die QR-Gültigkeitsdauer an.",
2377
+ "fr": "Indiquez la durée de validité QR.",
2378
+ "en": "Provide the QR validity period.",
2379
+ "sw": "Weka muda wa QR."
2380
+ },
2381
+ "Auth.field.allowed_email_domains.invalid": {
2382
+ "de": "Bitte geben Sie gültige E-Mail-Domains ein.",
2383
+ "de_informal": "Bitte gib gültige E-Mail-Domains ein.",
2384
+ "fr": "Saisissez des domaines e-mail valides.",
2385
+ "en": "Enter valid email domains.",
2386
+ "sw": "Weka vikoa sahihi vya barua pepe."
2387
+ },
2388
+ "Auth.field.allowed_email_domains.required": {
2389
+ "de": "Bitte geben Sie die erlaubten E-Mail-Domains an.",
2390
+ "de_informal": "Bitte gib die erlaubten E-Mail-Domains an.",
2391
+ "fr": "Indiquez les domaines e-mail autorisés.",
2392
+ "en": "Provide the allowed email domains.",
2393
+ "sw": "Weka vikoa vinavyoruhusiwa vya barua pepe."
2394
+ },
2395
+ "Auth.field.required_auth_factor_count.invalid": {
2396
+ "de": "Bitte wählen Sie eine gültige Anzahl von Sicherheitsfaktoren.",
2397
+ "de_informal": "Bitte wähle eine gültige Anzahl von Sicherheitsfaktoren.",
2398
+ "fr": "Sélectionnez un nombre de facteurs de sécurité valide.",
2399
+ "en": "Choose a valid number of security factors.",
2400
+ "sw": "Chagua idadi sahihi ya vipengele vya usalama."
2401
+ },
2402
+ "Auth.field.required_auth_factor_count.required": {
2403
+ "de": "Bitte wählen Sie die Anzahl der Sicherheitsfaktoren.",
2404
+ "de_informal": "Bitte wähle die Anzahl der Sicherheitsfaktoren.",
2405
+ "fr": "Sélectionnez le nombre de facteurs de sécurité.",
2406
+ "en": "Choose the number of security factors.",
2407
+ "sw": "Chagua idadi ya vipengele vya usalama."
2408
+ },
2409
+ "Auth.field.allow_admin_invite.invalid": {
2410
+ "de": "Diese Einstellung für Admin-Einladungen ist ungültig.",
2411
+ "de_informal": "Diese Einstellung für Admin-Einladungen ist ungültig.",
2412
+ "fr": "Ce paramètre d'invitation administrateur est invalide.",
2413
+ "en": "This admin-invite setting is invalid.",
2414
+ "sw": "Mpangilio huu wa mialiko ya msimamizi si sahihi."
2415
+ },
2416
+ "Auth.field.allow_admin_invite.required": {
2417
+ "de": "Bitte geben Sie die Einstellung für Admin-Einladungen an.",
2418
+ "de_informal": "Bitte gib die Einstellung für Admin-Einladungen an.",
2419
+ "fr": "Indiquez le paramètre d'invitation administrateur.",
2420
+ "en": "Provide the admin-invite setting.",
2421
+ "sw": "Toa mpangilio wa mialiko ya msimamizi."
2422
+ },
2423
+ "Auth.field.allow_self_signup_access_code.invalid": {
2424
+ "de": "Diese Einstellung für die Registrierung per Zugangscode ist ungültig.",
2425
+ "de_informal": "Diese Einstellung für die Registrierung per Zugangscode ist ungültig.",
2426
+ "fr": "Ce paramètre d'inscription par code d'accès est invalide.",
2427
+ "en": "This access-code sign-up setting is invalid.",
2428
+ "sw": "Mpangilio huu wa kujisajili kwa msimbo wa ufikiaji si sahihi."
2429
+ },
2430
+ "Auth.field.allow_self_signup_access_code.required": {
2431
+ "de": "Bitte geben Sie die Einstellung für die Registrierung per Zugangscode an.",
2432
+ "de_informal": "Bitte gib die Einstellung für die Registrierung per Zugangscode an.",
2433
+ "fr": "Indiquez le paramètre d'inscription par code d'accès.",
2434
+ "en": "Provide the access-code sign-up setting.",
2435
+ "sw": "Toa mpangilio wa kujisajili kwa msimbo wa ufikiaji."
2436
+ },
2437
+ "Auth.field.allow_self_signup_open.invalid": {
2438
+ "de": "Diese Einstellung für die offene Registrierung ist ungültig.",
2439
+ "de_informal": "Diese Einstellung für die offene Registrierung ist ungültig.",
2440
+ "fr": "Ce paramètre d'inscription ouverte est invalide.",
2441
+ "en": "This open sign-up setting is invalid.",
2442
+ "sw": "Mpangilio huu wa kujisajili wazi si sahihi."
2443
+ },
2444
+ "Auth.field.allow_self_signup_open.required": {
2445
+ "de": "Bitte geben Sie die Einstellung für die offene Registrierung an.",
2446
+ "de_informal": "Bitte gib die Einstellung für die offene Registrierung an.",
2447
+ "fr": "Indiquez le paramètre d'inscription ouverte.",
2448
+ "en": "Provide the open sign-up setting.",
2449
+ "sw": "Toa mpangilio wa kujisajili wazi."
2450
+ },
2451
+ "Auth.field.allow_self_signup_email_domain.invalid": {
2452
+ "de": "Diese Einstellung für die Registrierung per E-Mail-Domain ist ungültig.",
2453
+ "de_informal": "Diese Einstellung für die Registrierung per E-Mail-Domain ist ungültig.",
2454
+ "fr": "Ce paramètre d'inscription par domaine e-mail est invalide.",
2455
+ "en": "This email-domain sign-up setting is invalid.",
2456
+ "sw": "Mpangilio huu wa kujisajili kwa domeni ya barua pepe si sahihi."
2457
+ },
2458
+ "Auth.field.allow_self_signup_email_domain.required": {
2459
+ "de": "Bitte geben Sie die Einstellung für die Registrierung per E-Mail-Domain an.",
2460
+ "de_informal": "Bitte gib die Einstellung für die Registrierung per E-Mail-Domain an.",
2461
+ "fr": "Indiquez le paramètre d'inscription par domaine e-mail.",
2462
+ "en": "Provide the email-domain sign-up setting.",
2463
+ "sw": "Toa mpangilio wa kujisajili kwa domeni ya barua pepe."
2464
+ },
2465
+ "Auth.field.allow_self_signup_qr.invalid": {
2466
+ "de": "Diese Einstellung für die QR-Registrierung ist ungültig.",
2467
+ "de_informal": "Diese Einstellung für die QR-Registrierung ist ungültig.",
2468
+ "fr": "Ce paramètre d'inscription par QR est invalide.",
2469
+ "en": "This QR sign-up setting is invalid.",
2470
+ "sw": "Mpangilio huu wa kujisajili kwa QR si sahihi."
2471
+ },
2472
+ "Auth.field.allow_self_signup_qr.required": {
2473
+ "de": "Bitte geben Sie die Einstellung für die QR-Registrierung an.",
2474
+ "de_informal": "Bitte gib die Einstellung für die QR-Registrierung an.",
2475
+ "fr": "Indiquez le paramètre d'inscription par QR.",
2476
+ "en": "Provide the QR sign-up setting.",
2477
+ "sw": "Toa mpangilio wa kujisajili kwa QR."
2478
+ },
2479
+ "Auth.field.message.invalid": {
2480
+ "de": "Bitte geben Sie eine gültige Nachricht ein.",
2481
+ "de_informal": "Bitte gib eine gültige Nachricht ein.",
2482
+ "fr": "Saisissez un message valide.",
2483
+ "en": "Enter a valid message.",
2484
+ "sw": "Weka ujumbe sahihi."
2485
+ },
2486
+ "Auth.field.message.required": {
2487
+ "de": "Bitte geben Sie eine Nachricht ein.",
2488
+ "de_informal": "Bitte gib eine Nachricht ein.",
2489
+ "fr": "Saisissez un message.",
2490
+ "en": "Enter a message.",
2491
+ "sw": "Weka ujumbe."
2492
+ },
2493
+ "Auth.field.support_note.invalid": {
2494
+ "de": "Bitte geben Sie eine gültige Supportnotiz ein.",
2495
+ "de_informal": "Bitte gib eine gültige Supportnotiz ein.",
2496
+ "fr": "Saisissez une note de support valide.",
2497
+ "en": "Enter a valid support note.",
2498
+ "sw": "Weka dokezo sahihi la usaidizi."
2499
+ },
2500
+ "Auth.field.support_note.required": {
2501
+ "de": "Bitte geben Sie eine Supportnotiz ein.",
2502
+ "de_informal": "Bitte gib eine Supportnotiz ein.",
2503
+ "fr": "Saisissez une note de support.",
2504
+ "en": "Enter a support note.",
2505
+ "sw": "Weka dokezo la usaidizi."
2506
+ },
2087
2507
  // Raw backend auth error codes (allauth-headless + Django password validators).
2088
2508
  // Keyed by the exact code string so the existing `t(err.code)` call sites resolve
2089
2509
  // as a drop-in, without any component change. See AUTH-2.
@@ -5,6 +5,7 @@ import { useSearchParams } from 'react-router-dom';
5
5
  import { Box, Typography, Alert, CircularProgress, Paper, Stack, useMediaQuery, } from '@mui/material';
6
6
  import { useTheme } from '@mui/material/styles';
7
7
  import { useTranslation } from 'react-i18next';
8
+ import { resolveErrorText } from '../utils/resolveErrorText';
8
9
  // Internal context
9
10
  import { AuthContext } from '../auth/AuthContext';
10
11
  export const ACCOUNT_PAGE_SECTION_PAPER_SX = { p: 2.5 };
@@ -27,7 +28,7 @@ import { BulkInviteCsvTab } from '../components/BulkInviteCsvTab';
27
28
  import { fetchAuthPolicy, updateUserProfile } from '../auth/authApi'; // Ggf. Pfad anpassen
28
29
  export function AccountPage({ userListExtraColumns = [], userListExtraRowActions = [], userListExtraContext = null, userListRefreshTrigger = 0, userListCanEditUser = null, userListShowNewColumn = true, userListShowSuccessfulLoginColumn = true, userListShowRoleColumn = true, userListOnChangeRole = null, userListShowDeleteAction = true, userListCanDeleteUser = null, userListOnDeleteUser = null, showBulkInviteCsvTab = false, bulkInviteCsvProps = {}, extraTabs = [], }) {
29
30
  var _a;
30
- const { t } = useTranslation();
31
+ const { t, i18n } = useTranslation();
31
32
  const { user, login, loading } = useContext(AuthContext);
32
33
  const [searchParams, setSearchParams] = useSearchParams();
33
34
  const [authPolicy, setAuthPolicy] = useState(null);
@@ -80,7 +81,7 @@ export function AccountPage({ userListExtraColumns = [], userListExtraRowActions
80
81
  if (!active)
81
82
  return;
82
83
  setAuthPolicy(null);
83
- setAuthPolicyError(t((err === null || err === void 0 ? void 0 : err.code) || 'Auth.AUTH_POLICY_FETCH_FAILED', 'Could not load authentication policy.'));
84
+ setAuthPolicyError(resolveErrorText(i18n, err, 'Auth.AUTH_POLICY_FETCH_FAILED'));
84
85
  }
85
86
  };
86
87
  loadPolicy();
@@ -13,12 +13,13 @@ import { loginWithPasskey, startSocialLogin } from '../utils/authService';
13
13
  // Components
14
14
  import { LoginForm } from '../components/LoginForm';
15
15
  import { MfaLoginComponent } from '../components/MfaLoginComponent';
16
+ import { resolveErrorText } from '../utils/resolveErrorText';
16
17
  export const LOGIN_PAGE_ALERT_SX = { mb: 2 };
17
18
  export function LoginPage() {
18
19
  const navigate = useNavigate();
19
20
  const location = useLocation();
20
21
  const { user, loading, login, authMethods } = useContext(AuthContext);
21
- const { t } = useTranslation();
22
+ const { t, i18n } = useTranslation();
22
23
  // State
23
24
  const [step, setStep] = useState('credentials'); // 'credentials' | 'mfa'
24
25
  const [submitting, setSubmitting] = useState(false);
@@ -77,7 +78,7 @@ export function LoginPage() {
77
78
  useEffect(() => {
78
79
  const socialError = params.get('error') || params.get('social');
79
80
  if (socialError) {
80
- setErrorKey('Auth.SOCIAL_LOGIN_FAILED');
81
+ setErrorKey(t('Auth.SOCIAL_LOGIN_FAILED'));
81
82
  }
82
83
  }, [location.search]);
83
84
  // S164 handoff: on `#recovery=ok`, pull the plaintext token out of the
@@ -112,14 +113,14 @@ export function LoginPage() {
112
113
  window.history.replaceState(null, '', cleanUrl);
113
114
  }
114
115
  if (recoveryStatus === 'expired') {
115
- setErrorKey('Auth.RECOVERY_TOKEN_EXPIRED');
116
+ setErrorKey(t('Auth.RECOVERY_TOKEN_EXPIRED'));
116
117
  setRecoveryToken(null);
117
118
  return;
118
119
  }
119
120
  if (recoveryStatus !== 'ok') {
120
121
  // Catches `invalid` and any unknown value (including legacy email
121
122
  // links that carried the plaintext token before S164).
122
- setErrorKey('Auth.RECOVERY_TOKEN_INVALID');
123
+ setErrorKey(t('Auth.RECOVERY_TOKEN_INVALID'));
123
124
  setRecoveryToken(null);
124
125
  return;
125
126
  }
@@ -131,7 +132,7 @@ export function LoginPage() {
131
132
  return;
132
133
  if (!token) {
133
134
  // Session entry missing or already consumed — treat as invalid.
134
- setErrorKey('Auth.RECOVERY_TOKEN_INVALID');
135
+ setErrorKey(t('Auth.RECOVERY_TOKEN_INVALID'));
135
136
  setRecoveryToken(null);
136
137
  return;
137
138
  }
@@ -140,7 +141,7 @@ export function LoginPage() {
140
141
  .catch((err) => {
141
142
  if (cancelled)
142
143
  return;
143
- setErrorKey((err === null || err === void 0 ? void 0 : err.code) || 'Auth.RECOVERY_TOKEN_INVALID');
144
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.RECOVERY_TOKEN_INVALID'));
144
145
  setRecoveryToken(null);
145
146
  })
146
147
  .finally(() => {
@@ -190,7 +191,7 @@ export function LoginPage() {
190
191
  }
191
192
  }
192
193
  catch (err) {
193
- setErrorKey(err.code || 'Auth.LOGIN_FAILED');
194
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.LOGIN_FAILED'));
194
195
  }
195
196
  finally {
196
197
  setSubmitting(false);
@@ -207,7 +208,7 @@ export function LoginPage() {
207
208
  catch (err) {
208
209
  // 'Auth.PASSKEY_CANCELLED' is generic, maybe ignore visually or show specific hint
209
210
  if (err.code !== 'Auth.PASSKEY_CANCELLED') {
210
- setErrorKey(err.code || 'Auth.PASSKEY_FAILED');
211
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.PASSKEY_FAILED'));
211
212
  }
212
213
  }
213
214
  finally {
@@ -245,7 +246,7 @@ export function LoginPage() {
245
246
  const twoFactorRequired = Boolean(authMethods === null || authMethods === void 0 ? void 0 : authMethods.two_factor_required)
246
247
  || Number((authMethods === null || authMethods === void 0 ? void 0 : authMethods.required_auth_factor_count) || 1) >= 2;
247
248
  // --- Render ---
248
- return (_jsxs(NarrowPage, { title: t('Auth.PAGE_LOGIN_TITLE'), subtitle: t('Auth.PAGE_LOGIN_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.PAGE_LOGIN_TITLE')] }) }), errorKey && (_jsx(Alert, { severity: "error", sx: LOGIN_PAGE_ALERT_SX, children: t(errorKey) })), recoveryFetching && !errorKey && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.RECOVERY_LINK_VALIDATING', 'Validating recovery link…') })), recoveryToken && !errorKey && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.RECOVERY_LOGIN_WARNING', 'Recovery link validated. Please enter your password.') })), twoFactorRequired && !recoveryToken && !recoveryFetching && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.TWO_FACTOR_REQUIRED_HINT', 'This app requires two authentication factors for full access.') })), step === 'credentials' && (_jsx(LoginForm, { onSubmit: passwordLoginEnabled ? handleSubmitCredentials : null, onForgotPassword: passwordResetEnabled ? () => navigate('/reset-request-password') : null, onSocialLogin: socialLoginEnabled ? (provider) => startSocialLogin(provider) : null, socialProviders: socialProviders, onPasskeyLogin: passkeyLoginEnabled ? handlePasskeyLoginInitial : null, onSignUp: signupEnabled ? () => navigate('/signup') : null,
249
+ return (_jsxs(NarrowPage, { title: t('Auth.PAGE_LOGIN_TITLE'), subtitle: t('Auth.PAGE_LOGIN_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.PAGE_LOGIN_TITLE')] }) }), errorKey && (_jsx(Alert, { severity: "error", sx: LOGIN_PAGE_ALERT_SX, children: errorKey })), recoveryFetching && !errorKey && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.RECOVERY_LINK_VALIDATING', 'Validating recovery link…') })), recoveryToken && !errorKey && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.RECOVERY_LOGIN_WARNING', 'Recovery link validated. Please enter your password.') })), twoFactorRequired && !recoveryToken && !recoveryFetching && (_jsx(Alert, { severity: "info", sx: LOGIN_PAGE_ALERT_SX, children: t('Auth.TWO_FACTOR_REQUIRED_HINT', 'This app requires two authentication factors for full access.') })), step === 'credentials' && (_jsx(LoginForm, { onSubmit: passwordLoginEnabled ? handleSubmitCredentials : null, onForgotPassword: passwordResetEnabled ? () => navigate('/reset-request-password') : null, onSocialLogin: socialLoginEnabled ? (provider) => startSocialLogin(provider) : null, socialProviders: socialProviders, onPasskeyLogin: passkeyLoginEnabled ? handlePasskeyLoginInitial : null, onSignUp: signupEnabled ? () => navigate('/signup') : null,
249
250
  // Block submit while the handoff is in flight so the user does not
250
251
  // race the recovery-token fetch with a normal password POST.
251
252
  disabled: submitting || recoveryFetching, initialIdentifier: recoveryEmail })), step === 'mfa' && mfaState && (_jsx(Box, { children: _jsx(MfaLoginComponent, { availableTypes: mfaState.availableTypes, identifier: mfaState.identifier, onSuccess: handleMfaSuccess, onCancel: handleMfaCancel }) }))] }));
@@ -7,8 +7,9 @@ import { useTranslation } from 'react-i18next';
7
7
  import { NarrowPage } from '../layout/PageLayout';
8
8
  import { PasswordChangeForm } from '../components/PasswordChangeForm';
9
9
  import { changePassword } from '../auth/authApi';
10
+ import { resolveErrorText } from '../utils/resolveErrorText';
10
11
  export function PasswordChangePage() {
11
- const { t } = useTranslation();
12
+ const { t, i18n } = useTranslation();
12
13
  const [submitting, setSubmitting] = useState(false);
13
14
  const [successKey, setSuccessKey] = useState(null);
14
15
  const [errorKey, setErrorKey] = useState(null);
@@ -21,11 +22,11 @@ export function PasswordChangePage() {
21
22
  setSuccessKey('Auth.RESET_PASSWORD_SUCCESS');
22
23
  }
23
24
  catch (err) {
24
- setErrorKey(err.code || 'Auth.PASSWORD_CHANGE_FAILED');
25
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.PASSWORD_CHANGE_FAILED'));
25
26
  }
26
27
  finally {
27
28
  setSubmitting(false);
28
29
  }
29
30
  };
30
- return (_jsxs(NarrowPage, { title: t('Auth.CHANGE_PASSWORD_BUTTON'), subtitle: t('Auth.PAGE_CHANGE_PASSWORD_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.CHANGE_PASSWORD_BUTTON')] }) }), successKey && (_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) })), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: t(errorKey) })), _jsx(PasswordChangeForm, { onSubmit: handleSubmit, submitting: submitting })] }));
31
+ return (_jsxs(NarrowPage, { title: t('Auth.CHANGE_PASSWORD_BUTTON'), subtitle: t('Auth.PAGE_CHANGE_PASSWORD_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.CHANGE_PASSWORD_BUTTON')] }) }), successKey && (_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) })), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: errorKey })), _jsx(PasswordChangeForm, { onSubmit: handleSubmit, submitting: submitting })] }));
31
32
  }
@@ -8,11 +8,12 @@ import { useTranslation } from 'react-i18next';
8
8
  import { NarrowPage } from '../layout/PageLayout';
9
9
  import { PasswordSetForm } from '../components/PasswordSetForm';
10
10
  import { verifyResetToken, setNewPassword } from '../auth/authApi';
11
+ import { resolveErrorText } from '../utils/resolveErrorText';
11
12
  export function PasswordInvitePage() {
12
13
  const { uid, token } = useParams();
13
14
  const location = useLocation();
14
15
  const navigate = useNavigate();
15
- const { t } = useTranslation();
16
+ const { t, i18n } = useTranslation();
16
17
  const searchParams = new URLSearchParams(location.search);
17
18
  const nextPath = searchParams.get('next');
18
19
  const [submitting, setSubmitting] = useState(false);
@@ -32,7 +33,7 @@ export function PasswordInvitePage() {
32
33
  : 'Auth.PAGE_RESET_PASSWORD_SUBTITLE';
33
34
  useEffect(() => {
34
35
  if (!uid || !token) {
35
- setErrorKey('Auth.RESET_LINK_INVALID');
36
+ setErrorKey(t('Auth.RESET_LINK_INVALID'));
36
37
  setChecked(true);
37
38
  return;
38
39
  }
@@ -42,7 +43,7 @@ export function PasswordInvitePage() {
42
43
  setChecked(true);
43
44
  }
44
45
  catch (err) {
45
- setErrorKey(err.code || 'Auth.RESET_LINK_INVALID');
46
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.RESET_LINK_INVALID'));
46
47
  setChecked(true);
47
48
  }
48
49
  };
@@ -98,13 +99,13 @@ export function PasswordInvitePage() {
98
99
  // only a password rejection keeps the form; a link problem must still
99
100
  // end in the same invalid-link state the initial check produces.
100
101
  if (err.code === 'Auth.RESET_LINK_INVALID') {
101
- setErrorKey(err.code);
102
+ setErrorKey(resolveErrorText(i18n, err, 'Auth.RESET_LINK_INVALID'));
102
103
  }
103
104
  else {
104
105
  const responseMessages = ((_a = err.raw) === null || _a === void 0 ? void 0 : _a.messages) || ((_c = (_b = err.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.messages);
105
106
  setSubmitErrorKey(Array.isArray(responseMessages) && responseMessages.length > 0
106
107
  ? responseMessages.join(' ')
107
- : t(err.code || 'Auth.RESET_PASSWORD_FAILED'));
108
+ : resolveErrorText(i18n, err, 'Auth.RESET_PASSWORD_FAILED'));
108
109
  }
109
110
  }
110
111
  finally {
@@ -115,5 +116,5 @@ export function PasswordInvitePage() {
115
116
  if (!checked && !errorKey) {
116
117
  return (_jsx(NarrowPage, { title: t('Auth.PAGE_CHECKING_LINK_TITLE'), children: _jsx(Typography, { children: t('Auth.PAGE_CHECKING_LINK_TEXT') }) }));
117
118
  }
118
- return (_jsxs(NarrowPage, { title: t(pageTitleKey), subtitle: t(pageSubtitleKey), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t(pageTitleKey)] }) }), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: t(errorKey) })), successKey && (_jsxs(_Fragment, { children: [_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) }), _jsx(Button, { variant: "contained", onClick: () => navigate(continueTarget), children: t('Auth.SIGNUP_GO_TO_LOGIN') })] })), submitErrorKey && !successKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: submitErrorKey })), !successKey && !errorKey && (_jsx(PasswordSetForm, { onSubmit: handleSubmit, submitting: submitting }))] }));
119
+ return (_jsxs(NarrowPage, { title: t(pageTitleKey), subtitle: t(pageSubtitleKey), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t(pageTitleKey)] }) }), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: errorKey })), successKey && (_jsxs(_Fragment, { children: [_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) }), _jsx(Button, { variant: "contained", onClick: () => navigate(continueTarget), children: t('Auth.SIGNUP_GO_TO_LOGIN') })] })), submitErrorKey && !successKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: submitErrorKey })), !successKey && !errorKey && (_jsx(PasswordSetForm, { onSubmit: handleSubmit, submitting: submitting }))] }));
119
120
  }