@micha.bigler/ui-core-micha 3.5.1 → 3.7.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/CHANGELOG.md +18 -0
- package/DESIGN.md +1 -1
- package/README.md +2 -0
- package/WORK_ORDERS.md +8 -1
- package/dist/auth/UserMenu.js +23 -1
- package/dist/components/EmptyState.js +17 -0
- package/dist/components/UserListComponent.js +2 -1
- package/dist/i18n/authTranslations.js +238 -0
- package/dist/i18n/uiCoreTranslations.js +19 -0
- package/dist/index.js +2 -1
- package/dist/messaging/Composer.js +4 -2
- package/dist/messaging/MessageBubble.js +2 -1
- package/dist/messaging/ReadTicks.js +5 -3
- package/dist/messaging/linkifyText.js +39 -0
- package/dist/pages/PasswordInvitePage.js +23 -8
- package/dist/pages/SignUpPage.js +4 -4
- package/dist/theme/kitSxRegistry.js +5 -1
- package/dist/utils/auth-errors.js +1 -1
- package/package.json +1 -1
- package/src/auth/UserMenu.jsx +26 -1
- package/src/components/EmptyState.jsx +38 -0
- package/src/components/UserListComponent.jsx +2 -0
- package/src/i18n/authTranslations.ts +243 -0
- package/src/i18n/uiCoreTranslations.js +10 -0
- package/src/index.js +2 -1
- package/src/messaging/Composer.jsx +7 -3
- package/src/messaging/MessageBubble.jsx +2 -1
- package/src/messaging/ReadTicks.jsx +4 -3
- package/src/messaging/linkifyText.jsx +37 -0
- package/src/pages/PasswordInvitePage.jsx +36 -7
- package/src/pages/SignUpPage.jsx +79 -68
- package/src/theme/kitSxRegistry.js +9 -1
- package/src/utils/auth-errors.js +2 -2
- package/tests/EmptyState.test.jsx +62 -0
- package/tests/PasswordInvitePage.test.jsx +135 -0
- package/tests/SignUpPage.test.jsx +15 -2
- package/tests/UserListComponent.test.jsx +85 -0
- package/tests/UserMenu.test.jsx +40 -4
- package/tests/authErrors.test.js +43 -0
- package/tests/i18nGermanVariant.test.js +65 -0
- package/tests/messagingComposer.test.jsx +25 -0
- package/tests/messagingLinkify.test.jsx +51 -0
- package/tests/messagingReadTicksTooltip.test.jsx +36 -0
- package/tests/userScreenTranslations.test.jsx +165 -0
- package/work-orders/AUTH-8.md +184 -0
- package/work-orders/UCM-AUTH-9.md +207 -0
- package/work-orders/UCM-I18N-4.md +226 -0
- package/work-orders/UCM-MSG-20.md +192 -0
- package/work-orders/UCM-PRIM-2.md +114 -0
- package/work-orders/UCM-SHELL-7.md +134 -0
- package/work-orders/UCM-THEME-13.md +69 -0
- package/work-orders/UCM-THEME-14.md +140 -0
|
@@ -59,6 +59,7 @@ export const authTranslations = {
|
|
|
59
59
|
|
|
60
60
|
"Auth.INVITE_PERMISSION_DENIED": {
|
|
61
61
|
"de": "Sie haben keine Berechtigung, Einladungen zu versenden.",
|
|
62
|
+
"de_informal": "Du hast keine Berechtigung, Einladungen zu versenden.",
|
|
62
63
|
"fr": "Vous n'avez pas l'autorisation d'envoyer des invitations.",
|
|
63
64
|
"en": "You do not have permission to send invitations.",
|
|
64
65
|
"sw": "Huna ruhusa ya kutuma mialiko."
|
|
@@ -115,6 +116,7 @@ export const authTranslations = {
|
|
|
115
116
|
|
|
116
117
|
"Auth.RESET_LINK_VALID": {
|
|
117
118
|
"de": "Der Link ist gültig. Sie können ein neues Passwort setzen.",
|
|
119
|
+
"de_informal": "Der Link ist gültig. Du kannst ein neues Passwort setzen.",
|
|
118
120
|
"fr": "Le lien est valide. Vous pouvez définir un nouveau mot de passe.",
|
|
119
121
|
"en": "The link is valid. You can set a new password.",
|
|
120
122
|
"sw": "Viungo ni sahihi. Unaweza kuweka nenosiri jipya."
|
|
@@ -129,6 +131,7 @@ export const authTranslations = {
|
|
|
129
131
|
|
|
130
132
|
"Auth.RESET_PASSWORD_REQUIRED": {
|
|
131
133
|
"de": "Bitte geben Sie ein neues Passwort ein.",
|
|
134
|
+
"de_informal": "Bitte gib ein neues Passwort ein.",
|
|
132
135
|
"fr": "Veuillez saisir un nouveau mot de passe.",
|
|
133
136
|
"en": "Please enter a new password.",
|
|
134
137
|
"sw": "Tafadhali ingiza nenosiri jipya."
|
|
@@ -149,6 +152,7 @@ export const authTranslations = {
|
|
|
149
152
|
},
|
|
150
153
|
"Auth.GENERIC_ERROR": {
|
|
151
154
|
"de": "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
|
|
155
|
+
"de_informal": "Es ist ein Fehler aufgetreten. Bitte versuche es erneut.",
|
|
152
156
|
"fr": "Une erreur s'est produite. Veuillez réessayer.",
|
|
153
157
|
"en": "An error occurred. Please try again.",
|
|
154
158
|
"sw": "Hitilafu imetokea. Tafadhali jaribu tena."
|
|
@@ -231,6 +235,13 @@ export const authTranslations = {
|
|
|
231
235
|
"sw": "Uthibitishaji wa Passkey umeghairiwa."
|
|
232
236
|
},
|
|
233
237
|
|
|
238
|
+
"Auth.PASSKEY_CANCELLED": {
|
|
239
|
+
"de": "Der Passkey-Vorgang wurde abgebrochen.",
|
|
240
|
+
"fr": "L'opération avec le passkey a été annulée.",
|
|
241
|
+
"en": "The passkey operation was cancelled.",
|
|
242
|
+
"sw": "Operesheni ya Passkey imeghairiwa."
|
|
243
|
+
},
|
|
244
|
+
|
|
234
245
|
"Auth.PASSKEY_LIST_FAILED": {
|
|
235
246
|
"de": "Die gespeicherten Passkeys konnten nicht geladen werden.",
|
|
236
247
|
"fr": "Les passkeys enregistrés n'ont pas pu être chargés.",
|
|
@@ -259,6 +270,13 @@ export const authTranslations = {
|
|
|
259
270
|
"sw": "Uthibitishaji wa hatua mbili umeshindwa."
|
|
260
271
|
},
|
|
261
272
|
|
|
273
|
+
"Auth.MFA_CHALLENGE_FAILED": {
|
|
274
|
+
"de": "Die Zwei-Faktor-Challenge konnte nicht angefordert werden.",
|
|
275
|
+
"fr": "Le défi d'authentification à deux facteurs n'a pas pu être demandé.",
|
|
276
|
+
"en": "The two-factor challenge could not be requested.",
|
|
277
|
+
"sw": "Changamoto ya uthibitishaji wa hatua mbili haikuweza kuombwa."
|
|
278
|
+
},
|
|
279
|
+
|
|
262
280
|
"Auth.TOTP_REQUEST_FAILED": {
|
|
263
281
|
"de": "Die TOTP-Einrichtung konnte nicht gestartet werden.",
|
|
264
282
|
"fr": "La configuration TOTP n'a pas pu être démarrée.",
|
|
@@ -293,8 +311,16 @@ export const authTranslations = {
|
|
|
293
311
|
"en": "Recovery codes could not be regenerated.",
|
|
294
312
|
"sw": "Misimbo ya urejesho haikuweza kuundwa upya."
|
|
295
313
|
},
|
|
314
|
+
|
|
315
|
+
"Auth.RECOVERY_LOGIN_FAILED": {
|
|
316
|
+
"de": "Die Anmeldung über den Wiederherstellungslink ist fehlgeschlagen.",
|
|
317
|
+
"fr": "La connexion via le lien de récupération a échoué.",
|
|
318
|
+
"en": "Recovery login failed.",
|
|
319
|
+
"sw": "Kuingia kwa njia ya urejeshaji kumeshindwa."
|
|
320
|
+
},
|
|
296
321
|
"Auth.PAGE_CHANGE_PASSWORD_SUBTITLE": {
|
|
297
322
|
"de": "Geben Sie Ihr aktuelles und ein neues Passwort ein.",
|
|
323
|
+
"de_informal": "Gib dein aktuelles und ein neues Passwort ein.",
|
|
298
324
|
"fr": "Saisissez votre mot de passe actuel et un nouveau mot de passe.",
|
|
299
325
|
"en": "Enter your current password and a new password.",
|
|
300
326
|
"sw": "Ingiza nenosiri lako la sasa na nenosiri jipya."
|
|
@@ -307,6 +333,7 @@ export const authTranslations = {
|
|
|
307
333
|
},
|
|
308
334
|
"Auth.PAGE_CHECKING_LINK_TEXT": {
|
|
309
335
|
"de": "Wir prüfen gerade die Gültigkeit Ihres Links.",
|
|
336
|
+
"de_informal": "Wir prüfen gerade die Gültigkeit deines Links.",
|
|
310
337
|
"fr": "Nous vérifions la validité de votre lien.",
|
|
311
338
|
"en": "We are validating your link.",
|
|
312
339
|
"sw": "Tunathibitisha uhalali wa kiungo chako."
|
|
@@ -320,6 +347,7 @@ export const authTranslations = {
|
|
|
320
347
|
},
|
|
321
348
|
"Auth.PAGE_INVITE_SUBTITLE": {
|
|
322
349
|
"de": "Bitte wählen Sie ein Passwort, um auf Ihr Konto zuzugreifen.",
|
|
350
|
+
"de_informal": "Bitte wähle ein Passwort, um auf dein Konto zuzugreifen.",
|
|
323
351
|
"fr": "Veuillez choisir un mot de passe pour accéder à votre compte.",
|
|
324
352
|
"en": "Please choose a password to access your account.",
|
|
325
353
|
"sw": "Tafadhali chagua nenosiri ili kufikia akaunti yako."
|
|
@@ -333,6 +361,7 @@ export const authTranslations = {
|
|
|
333
361
|
},
|
|
334
362
|
"Auth.PAGE_RESET_PASSWORD_SUBTITLE": {
|
|
335
363
|
"de": "Bitte wählen Sie ein neues Passwort.",
|
|
364
|
+
"de_informal": "Bitte wähle ein neues Passwort.",
|
|
336
365
|
"fr": "Veuillez choisir un nouveau mot de passe.",
|
|
337
366
|
"en": "Please choose a new password.",
|
|
338
367
|
"sw": "Tafadhali chagua nenosiri jipya."
|
|
@@ -340,60 +369,70 @@ export const authTranslations = {
|
|
|
340
369
|
|
|
341
370
|
"Auth.RESET_PASSWORD_SUCCESS_INVITE": {
|
|
342
371
|
"de": "Das Passwort wurde gesetzt. Sie können sich nun anmelden.",
|
|
372
|
+
"de_informal": "Das Passwort wurde gesetzt. Du kannst dich nun anmelden.",
|
|
343
373
|
"fr": "Le mot de passe a été défini. Vous pouvez maintenant vous connecter.",
|
|
344
374
|
"en": "Password set successfully. You can now log in.",
|
|
345
375
|
"sw": "Nenosiri limewekwa. Sasa unaweza kuingia."
|
|
346
376
|
},
|
|
347
377
|
"Auth.RESET_PASSWORD_SUCCESS_RESET": {
|
|
348
378
|
"de": "Das Passwort wurde geändert. Sie können sich nun anmelden.",
|
|
379
|
+
"de_informal": "Das Passwort wurde geändert. Du kannst dich nun anmelden.",
|
|
349
380
|
"fr": "Le mot de passe a été modifié. Vous pouvez maintenant vous connecter.",
|
|
350
381
|
"en": "Password changed successfully. You can now log in.",
|
|
351
382
|
"sw": "Nenosiri limebadilishwa. Sasa unaweza kuingia."
|
|
352
383
|
},
|
|
353
384
|
"Auth.PAGE_RESET_REQUEST_SUBTITLE": {
|
|
354
385
|
"de": "Geben Sie Ihre E-Mail-Adresse ein, um den Link zum Zurücksetzen zu erhalten.",
|
|
386
|
+
"de_informal": "Gib deine E-Mail-Adresse ein, um den Link zum Zurücksetzen zu erhalten.",
|
|
355
387
|
"fr": "Saisissez votre adresse e-mail pour recevoir le lien de réinitialisation.",
|
|
356
388
|
"en": "Enter your email address to receive the reset link.",
|
|
357
389
|
"sw": "Ingiza anwani yako ya barua pepe ili kupokea kiungo cha kuweka upya."
|
|
358
390
|
},
|
|
359
391
|
"Auth.EMAIL_REQUIRED": {
|
|
360
392
|
"de": "Bitte geben Sie eine E-Mail-Adresse ein.",
|
|
393
|
+
"de_informal": "Bitte gib eine E-Mail-Adresse ein.",
|
|
361
394
|
"fr": "Veuillez saisir une adresse e-mail.",
|
|
362
395
|
"en": "Please enter an email address.",
|
|
363
396
|
"sw": "Tafadhali ingiza anwani ya barua pepe."
|
|
364
397
|
},
|
|
365
398
|
"Auth.PAGE_SIGNUP_SUBTITLE": {
|
|
366
399
|
"de": "Wählen Sie eine Registrierungsart und geben Sie die benötigten Angaben ein.",
|
|
400
|
+
"de_informal": "Wähle eine Registrierungsart und gib die benötigten Angaben ein.",
|
|
367
401
|
"fr": "Choisissez une méthode d'inscription et saisissez les informations requises.",
|
|
368
402
|
"en": "Choose a sign-up method and enter the required details.",
|
|
369
403
|
"sw": "Chagua njia ya kujisajili na uingize taarifa zinazohitajika."
|
|
370
404
|
},
|
|
371
405
|
"Auth.PAGE_SIGNUP_SUBTITLE_ACCESS_CODE": {
|
|
372
406
|
"de": "Geben Sie Ihre E-Mail-Adresse und den erhaltenen Zugangscode ein.",
|
|
407
|
+
"de_informal": "Gib deine E-Mail-Adresse und den erhaltenen Zugangscode ein.",
|
|
373
408
|
"fr": "Saisissez votre adresse e-mail et le code d'accès reçu.",
|
|
374
409
|
"en": "Enter your email address and the access code you received.",
|
|
375
410
|
"sw": "Ingiza anwani yako ya barua pepe na msimbo wa ufikiaji uliopokea."
|
|
376
411
|
},
|
|
377
412
|
"Auth.PAGE_SIGNUP_SUBTITLE_OPEN": {
|
|
378
413
|
"de": "Geben Sie Ihre E-Mail-Adresse ein, um sich direkt zu registrieren.",
|
|
414
|
+
"de_informal": "Gib deine E-Mail-Adresse ein, um dich direkt zu registrieren.",
|
|
379
415
|
"fr": "Saisissez votre adresse e-mail pour vous inscrire directement.",
|
|
380
416
|
"en": "Enter your email address to sign up directly.",
|
|
381
417
|
"sw": "Ingiza anwani yako ya barua pepe ili kujisajili moja kwa moja."
|
|
382
418
|
},
|
|
383
419
|
"Auth.PAGE_SIGNUP_SUBTITLE_EMAIL_DOMAIN": {
|
|
384
420
|
"de": "Verwenden Sie eine E-Mail-Adresse aus einer freigegebenen Domain.",
|
|
421
|
+
"de_informal": "Verwende eine E-Mail-Adresse aus einer freigegebenen Domain.",
|
|
385
422
|
"fr": "Utilisez une adresse e-mail provenant d'un domaine autorisé.",
|
|
386
423
|
"en": "Use an email address from an approved domain.",
|
|
387
424
|
"sw": "Tumia anwani ya barua pepe kutoka kwenye domeni iliyoidhinishwa."
|
|
388
425
|
},
|
|
389
426
|
"Auth.PAGE_SIGNUP_SUBTITLE_QR": {
|
|
390
427
|
"de": "Öffnen Sie diese Seite über einen gültigen QR-Link und geben Sie dann Ihre E-Mail-Adresse ein.",
|
|
428
|
+
"de_informal": "Öffne diese Seite über einen gültigen QR-Link und gib dann deine E-Mail-Adresse ein.",
|
|
391
429
|
"fr": "Ouvrez cette page via un lien QR valide, puis saisissez votre adresse e-mail.",
|
|
392
430
|
"en": "Open this page from a valid QR link, then enter your email address.",
|
|
393
431
|
"sw": "Fungua ukurasa huu kupitia kiungo halali cha QR, kisha ingiza anwani yako ya barua pepe."
|
|
394
432
|
},
|
|
395
433
|
"Auth.PAGE_SIGNUP_SUBTITLE_QR_READY": {
|
|
396
434
|
"de": "Geben Sie Ihre E-Mail-Adresse ein, um die Registrierung mit diesem QR-Link abzuschließen.",
|
|
435
|
+
"de_informal": "Gib deine E-Mail-Adresse ein, um die Registrierung mit diesem QR-Link abzuschließen.",
|
|
397
436
|
"fr": "Saisissez votre adresse e-mail pour terminer l'inscription avec ce lien QR.",
|
|
398
437
|
"en": "Enter your email address to complete sign-up with this QR link.",
|
|
399
438
|
"sw": "Ingiza anwani yako ya barua pepe ili kukamilisha kujisajili kwa kutumia kiungo hiki cha QR."
|
|
@@ -456,6 +495,7 @@ export const authTranslations = {
|
|
|
456
495
|
|
|
457
496
|
"Auth.SIGNUP_ALREADY_HAVE_ACCOUNT": {
|
|
458
497
|
"de": "Sie haben bereits ein Konto?",
|
|
498
|
+
"de_informal": "Du hast bereits ein Konto?",
|
|
459
499
|
"fr": "Vous avez déjà un compte ?",
|
|
460
500
|
"en": "Already have an account?",
|
|
461
501
|
"sw": "Je, tayari una akaunti?"
|
|
@@ -468,6 +508,7 @@ export const authTranslations = {
|
|
|
468
508
|
},
|
|
469
509
|
"Auth.SIGNUP_ACCESS_CODE_REQUIRED": {
|
|
470
510
|
"de": "Bitte geben Sie einen Zugangscode ein.",
|
|
511
|
+
"de_informal": "Bitte gib einen Zugangscode ein.",
|
|
471
512
|
"fr": "Veuillez saisir un code d'accès.",
|
|
472
513
|
"en": "Please enter an access code.",
|
|
473
514
|
"sw": "Tafadhali ingiza msimbo wa ufikiaji."
|
|
@@ -487,6 +528,7 @@ export const authTranslations = {
|
|
|
487
528
|
},
|
|
488
529
|
"Auth.PAGE_LOGIN_SUBTITLE": {
|
|
489
530
|
"de": "Melden Sie sich mit Ihrem Konto an.",
|
|
531
|
+
"de_informal": "Melde dich mit deinem Konto an.",
|
|
490
532
|
"fr": "Connectez-vous avec votre compte.",
|
|
491
533
|
"en": "Sign in with your account.",
|
|
492
534
|
"sw": "Ingia na akaunti yako."
|
|
@@ -1139,6 +1181,7 @@ export const authTranslations = {
|
|
|
1139
1181
|
},
|
|
1140
1182
|
"Support.RECOVERY_APPROVE_CONFIRM_QUESTION": {
|
|
1141
1183
|
"de": "Sind Sie sicher, dass Sie diese Wiederherstellungsanfrage bewilligen möchten?",
|
|
1184
|
+
"de_informal": "Bist du sicher, dass du diese Wiederherstellungsanfrage bewilligen möchtest?",
|
|
1142
1185
|
"fr": "Êtes-vous sûr de vouloir approuver cette demande de récupération ?",
|
|
1143
1186
|
"en": "Are you sure you want to approve this recovery request?",
|
|
1144
1187
|
"sw": "Una uhakika unataka kuidhinisha ombi hili la urejesho?"
|
|
@@ -1151,6 +1194,7 @@ export const authTranslations = {
|
|
|
1151
1194
|
},
|
|
1152
1195
|
"Support.RECOVERY_APPROVE_NOTE_HELP": {
|
|
1153
1196
|
"de": "Beschreiben Sie kurz, warum Sie diese Anfrage bewilligen.",
|
|
1197
|
+
"de_informal": "Beschreibe kurz, warum du diese Anfrage bewilligst.",
|
|
1154
1198
|
"fr": "Décrivez brièvement pourquoi vous approuvez cette demande.",
|
|
1155
1199
|
"en": "Briefly describe why you are approving this request.",
|
|
1156
1200
|
"sw": "Eleza kwa ufupi kwa nini unaidhinisha ombi hili."
|
|
@@ -1163,12 +1207,14 @@ export const authTranslations = {
|
|
|
1163
1207
|
},
|
|
1164
1208
|
"Auth.MFA_HELP_DIALOG_DESCRIPTION": {
|
|
1165
1209
|
"de": "Beschreiben Sie kurz, warum Sie keine der verfügbaren Methoden verwenden können. Eine Supportperson wird Ihre Anfrage prüfen.",
|
|
1210
|
+
"de_informal": "Beschreibe kurz, warum du keine der verfügbaren Methoden verwenden kannst. Eine Supportperson wird deine Anfrage prüfen.",
|
|
1166
1211
|
"fr": "Décrivez brièvement pourquoi vous ne pouvez utiliser aucune des méthodes disponibles. Un membre du support examinera votre demande.",
|
|
1167
1212
|
"en": "Briefly describe why you cannot use any of the available methods. A support person will review your request.",
|
|
1168
1213
|
"sw": "Eleza kwa ufupi kwa nini huwezi kutumia yoyote ya mbinu zinazopatikana. Mtu wa usaidizi atakagua ombi lako."
|
|
1169
1214
|
},
|
|
1170
1215
|
"Auth.MFA_HELP_MESSAGE_LABEL": {
|
|
1171
1216
|
"de": "Ihre Nachricht an den Support",
|
|
1217
|
+
"de_informal": "Deine Nachricht an den Support",
|
|
1172
1218
|
"fr": "Votre message au support",
|
|
1173
1219
|
"en": "Your message to support",
|
|
1174
1220
|
"sw": "Ujumbe wako kwa usaidizi"
|
|
@@ -1188,6 +1234,7 @@ export const authTranslations = {
|
|
|
1188
1234
|
},
|
|
1189
1235
|
"Support.RECOVERY_NOTE_HELP": {
|
|
1190
1236
|
"de": "Beschreiben Sie kurz, warum Sie diese Anfrage genehmigen oder ablehnen.",
|
|
1237
|
+
"de_informal": "Beschreibe kurz, warum du diese Anfrage genehmigst oder ablehnst.",
|
|
1191
1238
|
"fr": "Décrivez brièvement pourquoi vous approuvez ou rejetez cette demande.",
|
|
1192
1239
|
"en": "Briefly describe why you are approving or rejecting this request.",
|
|
1193
1240
|
"sw": "Eleza kwa ufupi kwa nini unaidhinisha au kukataa ombi hili."
|
|
@@ -1218,6 +1265,7 @@ export const authTranslations = {
|
|
|
1218
1265
|
},
|
|
1219
1266
|
"Support.RECOVERY_REQUESTS_DESCRIPTION": {
|
|
1220
1267
|
"de": "Benutzer, die die MFA nicht abschliessen können, können hier eine Anfrage stellen. Sie können die Anfrage prüfen und anschliessend akzeptieren oder ablehnen.",
|
|
1268
|
+
"de_informal": "Benutzer, die die MFA nicht abschliessen können, können hier eine Anfrage stellen. Du kannst die Anfrage prüfen und anschliessend akzeptieren oder ablehnen.",
|
|
1221
1269
|
"fr": "Les utilisateurs qui ne peuvent pas terminer la MFA peuvent envoyer ici une demande. Vous pouvez examiner la demande puis l’accepter ou la refuser.",
|
|
1222
1270
|
"en": "Users who cannot complete MFA can submit a request here. You can review the request and then approve or reject it.",
|
|
1223
1271
|
"sw": "Watumiaji ambao hawawezi kukamilisha MFA wanaweza kutuma ombi hapa. Unaweza kukagua ombi na kisha kulikubali au kulikataa."
|
|
@@ -1327,12 +1375,14 @@ export const authTranslations = {
|
|
|
1327
1375
|
},
|
|
1328
1376
|
"Auth.MFA_IDENTIFIER_REQUIRED": {
|
|
1329
1377
|
"de": "Bitte geben Sie eine E-Mail-Adresse an.",
|
|
1378
|
+
"de_informal": "Bitte gib eine E-Mail-Adresse an.",
|
|
1330
1379
|
"fr": "Veuillez indiquer une adresse e-mail.",
|
|
1331
1380
|
"en": "Please provide an email address.",
|
|
1332
1381
|
"sw": "Tafadhali toa anwani ya barua pepe."
|
|
1333
1382
|
},
|
|
1334
1383
|
"Auth.MFA_HELP_REQUESTED": {
|
|
1335
1384
|
"de": "Falls ein Konto mit dieser E-Mail existiert, wurde Ihre Anfrage an den Support weitergeleitet.",
|
|
1385
|
+
"de_informal": "Falls ein Konto mit dieser E-Mail existiert, wurde deine Anfrage an den Support weitergeleitet.",
|
|
1336
1386
|
"fr": "Si un compte existe avec cette adresse e-mail, votre demande a été transmise au support.",
|
|
1337
1387
|
"en": "If an account with this email exists, your request has been forwarded to support.",
|
|
1338
1388
|
"sw": "Ikiwa akaunti iliyo na barua pepe hii ipo, ombi lako limetumwa kwa usaidizi."
|
|
@@ -1393,6 +1443,7 @@ export const authTranslations = {
|
|
|
1393
1443
|
},
|
|
1394
1444
|
"Auth.AUTH_FACTOR_HINT": {
|
|
1395
1445
|
"de": "Legen Sie fest, wie viele Authentifizierungsfaktoren mindestens für die Anmeldung erforderlich sind.",
|
|
1446
|
+
"de_informal": "Lege fest, wie viele Authentifizierungsfaktoren mindestens für die Anmeldung erforderlich sind.",
|
|
1396
1447
|
"fr": "Définissez le nombre minimal de facteurs d'authentification requis pour la connexion.",
|
|
1397
1448
|
"en": "Define the minimum number of authentication factors required for sign-in.",
|
|
1398
1449
|
"sw": "Weka idadi ya chini ya vipengele vya uthibitishaji vinavyohitajika ili kuingia."
|
|
@@ -1423,6 +1474,7 @@ export const authTranslations = {
|
|
|
1423
1474
|
},
|
|
1424
1475
|
"Auth.REGISTRATION_METHODS_HINT": {
|
|
1425
1476
|
"de": "Wählen Sie aus, welche Registrierungs- und Einladungswege für diese App aktiv sind.",
|
|
1477
|
+
"de_informal": "Wähle aus, welche Registrierungs- und Einladungswege für diese App aktiv sind.",
|
|
1426
1478
|
"fr": "Choisissez quels flux d'inscription et d'invitation sont actifs pour cette application.",
|
|
1427
1479
|
"en": "Choose which signup and invite flows are active for this app.",
|
|
1428
1480
|
"sw": "Chagua njia zipi za kujisajili na za mwaliko zimewashwa kwa programu hii."
|
|
@@ -1483,6 +1535,7 @@ export const authTranslations = {
|
|
|
1483
1535
|
},
|
|
1484
1536
|
"Auth.ALLOWED_EMAIL_DOMAINS_HINT": {
|
|
1485
1537
|
"de": "Eine Domain pro Zeile, z. B. example.org. Sie können das Feld vorübergehend leer lassen.",
|
|
1538
|
+
"de_informal": "Eine Domain pro Zeile, z. B. example.org. Du kannst das Feld vorübergehend leer lassen.",
|
|
1486
1539
|
"fr": "Un domaine par ligne, p. ex. example.org. Vous pouvez laisser ce champ vide temporairement.",
|
|
1487
1540
|
"en": "One domain per line, e.g. example.org. You can leave this empty temporarily.",
|
|
1488
1541
|
"sw": "Domeni moja kwa kila mstari, kwa mfano example.org. Unaweza kuiacha tupu kwa muda."
|
|
@@ -1495,6 +1548,7 @@ export const authTranslations = {
|
|
|
1495
1548
|
},
|
|
1496
1549
|
"Auth.SIGNUP_QR_MANAGER_HINT": {
|
|
1497
1550
|
"de": "Erzeugen und teilen Sie hier QR-Registrierungslinks.",
|
|
1551
|
+
"de_informal": "Erzeuge und teile hier QR-Registrierungslinks.",
|
|
1498
1552
|
"fr": "Générez et partagez ici des liens d'inscription QR.",
|
|
1499
1553
|
"en": "Generate and share QR signup links below.",
|
|
1500
1554
|
"sw": "Tengeneza na ushiriki viungo vya usajili wa QR hapa chini."
|
|
@@ -1507,6 +1561,7 @@ export const authTranslations = {
|
|
|
1507
1561
|
},
|
|
1508
1562
|
"Auth.SIGNUP_QR_VALIDITY_HINT": {
|
|
1509
1563
|
"de": "Legen Sie die Standard-Gültigkeit für neu erzeugte QR-Registrierungslinks fest.",
|
|
1564
|
+
"de_informal": "Lege die Standard-Gültigkeit für neu erzeugte QR-Registrierungslinks fest.",
|
|
1510
1565
|
"fr": "Définissez la validité par défaut des nouveaux liens d'inscription QR générés.",
|
|
1511
1566
|
"en": "Set the default validity for newly generated QR signup links.",
|
|
1512
1567
|
"sw": "Weka muda wa kawaida wa uhalali wa viungo vipya vya usajili wa QR."
|
|
@@ -1585,12 +1640,14 @@ export const authTranslations = {
|
|
|
1585
1640
|
},
|
|
1586
1641
|
"Auth.SIGNUP_QR_PDF_NOT_READY": {
|
|
1587
1642
|
"de": "Das QR-Bild ist noch nicht bereit. Bitte versuchen Sie es erneut.",
|
|
1643
|
+
"de_informal": "Das QR-Bild ist noch nicht bereit. Bitte versuche es erneut.",
|
|
1588
1644
|
"fr": "L'image QR n'est pas encore prête. Veuillez réessayer.",
|
|
1589
1645
|
"en": "The QR image is not ready yet. Please try again.",
|
|
1590
1646
|
"sw": "Picha ya QR bado haijawa tayari. Tafadhali jaribu tena."
|
|
1591
1647
|
},
|
|
1592
1648
|
"Auth.SIGNUP_QR_PDF_BLOCKED": {
|
|
1593
1649
|
"de": "Popup blockiert. Bitte erlauben Sie Popups, um die QR-Karte als PDF zu speichern.",
|
|
1650
|
+
"de_informal": "Popup blockiert. Bitte erlaube Popups, um die QR-Karte als PDF zu speichern.",
|
|
1594
1651
|
"fr": "Fenêtre contextuelle bloquée. Veuillez autoriser les popups pour enregistrer la carte QR en PDF.",
|
|
1595
1652
|
"en": "Popup blocked. Please allow popups to save the QR card as PDF.",
|
|
1596
1653
|
"sw": "Dirisha ibukizi limezuiwa. Tafadhali ruhusu madirisha ibukizi ili kuhifadhi kadi ya QR kama PDF."
|
|
@@ -1693,6 +1750,7 @@ export const authTranslations = {
|
|
|
1693
1750
|
},
|
|
1694
1751
|
"Account.ACCESS_CODES_HINT": {
|
|
1695
1752
|
"de": "Verwalten Sie Zugangscodes für die Selbstregistrierung.",
|
|
1753
|
+
"de_informal": "Verwalte Zugangscodes für die Selbstregistrierung.",
|
|
1696
1754
|
"fr": "Gérer les codes d'accès pour l'auto-inscription.",
|
|
1697
1755
|
"en": "Manage access codes for self-registration.",
|
|
1698
1756
|
"sw": "Dhibiti misimbo ya ufikiaji kwa kujisajili mwenyewe."
|
|
@@ -1842,6 +1900,37 @@ export const authTranslations = {
|
|
|
1842
1900
|
"en": "An account already exists for this email address. Please log in.",
|
|
1843
1901
|
"sw": "Akaunti tayari ipo kwa anwani hii ya barua pepe. Tafadhali ingia."
|
|
1844
1902
|
},
|
|
1903
|
+
|
|
1904
|
+
"Auth.USER_LIST_FAILED": {
|
|
1905
|
+
"de": "Die Benutzerliste konnte nicht geladen werden.",
|
|
1906
|
+
"fr": "La liste des utilisateurs n'a pas pu être chargée.",
|
|
1907
|
+
"en": "The user list could not be loaded.",
|
|
1908
|
+
"sw": "Orodha ya watumiaji haikuweza kupakiwa."
|
|
1909
|
+
},
|
|
1910
|
+
"Auth.USER_DELETE_FAILED": {
|
|
1911
|
+
"de": "Der Benutzer konnte nicht gelöscht werden.",
|
|
1912
|
+
"fr": "L'utilisateur n'a pas pu être supprimé.",
|
|
1913
|
+
"en": "The user could not be deleted.",
|
|
1914
|
+
"sw": "Mtumiaji hakuweza kufutwa."
|
|
1915
|
+
},
|
|
1916
|
+
"Auth.USER_ROLE_UPDATE_FAILED": {
|
|
1917
|
+
"de": "Die Rolle des Benutzers konnte nicht aktualisiert werden.",
|
|
1918
|
+
"fr": "Le rôle de l'utilisateur n'a pas pu être mis à jour.",
|
|
1919
|
+
"en": "The user's role could not be updated.",
|
|
1920
|
+
"sw": "Jukumu la mtumiaji halikuweza kusasishwa."
|
|
1921
|
+
},
|
|
1922
|
+
"UserList.ROLE_UPDATE_SUCCESS": {
|
|
1923
|
+
"de": "Die Rolle wurde aktualisiert.",
|
|
1924
|
+
"fr": "Le rôle a été mis à jour.",
|
|
1925
|
+
"en": "Role updated.",
|
|
1926
|
+
"sw": "Jukumu limesasishwa."
|
|
1927
|
+
},
|
|
1928
|
+
"Auth.USER_SUPPORT_UPDATE_FAILED": {
|
|
1929
|
+
"de": "Der Support-Status des Benutzers konnte nicht aktualisiert werden.",
|
|
1930
|
+
"fr": "Le statut de support de l'utilisateur n'a pas pu être mis à jour.",
|
|
1931
|
+
"en": "The user's support status could not be updated.",
|
|
1932
|
+
"sw": "Hali ya usaidizi ya mtumiaji haikuweza kusasishwa."
|
|
1933
|
+
},
|
|
1845
1934
|
"Auth.SIGNUP_QR_MAX_REDEMPTIONS_LABEL": {
|
|
1846
1935
|
"de": "Max. Verwendungen",
|
|
1847
1936
|
"fr": "Utilisations max.",
|
|
@@ -1897,6 +1986,158 @@ export const authTranslations = {
|
|
|
1897
1986
|
"sw": "Nenosiri si sahihi."
|
|
1898
1987
|
},
|
|
1899
1988
|
|
|
1989
|
+
"UserList.DELETE_CONFIRM": {
|
|
1990
|
+
"de": "Möchten Sie diesen Benutzer wirklich löschen?",
|
|
1991
|
+
"de_informal": "Möchtest du diesen Benutzer wirklich löschen?",
|
|
1992
|
+
"fr": "Voulez-vous vraiment supprimer cet utilisateur ?",
|
|
1993
|
+
"en": "Are you sure you want to delete this user?",
|
|
1994
|
+
"sw": "Je, una uhakika unataka kumfuta mtumiaji huyu?"
|
|
1995
|
+
},
|
|
1996
|
+
"Common.OPERATION_FAILED": {
|
|
1997
|
+
"de": "Vorgang fehlgeschlagen.",
|
|
1998
|
+
"fr": "L’opération a échoué.",
|
|
1999
|
+
"en": "Operation failed.",
|
|
2000
|
+
"sw": "Uendeshaji umeshindwa."
|
|
2001
|
+
},
|
|
2002
|
+
"UserList.NEW": {
|
|
2003
|
+
"de": "Neu",
|
|
2004
|
+
"fr": "Nouveau",
|
|
2005
|
+
"en": "New",
|
|
2006
|
+
"sw": "Mpya"
|
|
2007
|
+
},
|
|
2008
|
+
"UserList.SUCCESSFUL_LOGIN": {
|
|
2009
|
+
"de": "Erfolgreiche Anmeldung",
|
|
2010
|
+
"fr": "Connexion réussie",
|
|
2011
|
+
"en": "Successful Login",
|
|
2012
|
+
"sw": "Kuingia kwa mafanikio"
|
|
2013
|
+
},
|
|
2014
|
+
"UserList.ROLE": {
|
|
2015
|
+
"de": "Rolle",
|
|
2016
|
+
"fr": "Rôle",
|
|
2017
|
+
"en": "Role",
|
|
2018
|
+
"sw": "Jukumu"
|
|
2019
|
+
},
|
|
2020
|
+
"Common.ACTIONS": {
|
|
2021
|
+
"de": "Aktionen",
|
|
2022
|
+
"fr": "Actions",
|
|
2023
|
+
"en": "Actions",
|
|
2024
|
+
"sw": "Vitendo"
|
|
2025
|
+
},
|
|
2026
|
+
"UserList.TITLE": {
|
|
2027
|
+
"de": "Alle Benutzer",
|
|
2028
|
+
"fr": "Tous les utilisateurs",
|
|
2029
|
+
"en": "All Users",
|
|
2030
|
+
"sw": "Watumiaji wote"
|
|
2031
|
+
},
|
|
2032
|
+
"Common.SEARCH": {
|
|
2033
|
+
"de": "Suche",
|
|
2034
|
+
"fr": "Rechercher",
|
|
2035
|
+
"en": "Search",
|
|
2036
|
+
"sw": "Tafuta"
|
|
2037
|
+
},
|
|
2038
|
+
"UserList.SEARCH_PLACEHOLDER": {
|
|
2039
|
+
"de": "Benutzer suchen...",
|
|
2040
|
+
"fr": "Rechercher des utilisateurs...",
|
|
2041
|
+
"en": "Search users...",
|
|
2042
|
+
"sw": "Tafuta watumiaji..."
|
|
2043
|
+
},
|
|
2044
|
+
"UserList.NO_USERS": {
|
|
2045
|
+
"de": "Keine Benutzer gefunden.",
|
|
2046
|
+
"fr": "Aucun utilisateur trouvé.",
|
|
2047
|
+
"en": "No users found.",
|
|
2048
|
+
"sw": "Hakuna watumiaji waliopatikana."
|
|
2049
|
+
},
|
|
2050
|
+
"UserList.ROWS_PER_PAGE": {
|
|
2051
|
+
"de": "Zeilen pro Seite:",
|
|
2052
|
+
"fr": "Lignes par page :",
|
|
2053
|
+
"en": "Rows per page:",
|
|
2054
|
+
"sw": "Safu kwa ukurasa:"
|
|
2055
|
+
},
|
|
2056
|
+
"Auth.INVITE_SENT_SUCCESS": {
|
|
2057
|
+
"de": "Einladung gesendet.",
|
|
2058
|
+
"fr": "Invitation envoyée.",
|
|
2059
|
+
"en": "Invitation sent.",
|
|
2060
|
+
"sw": "Mwaliko umetumwa."
|
|
2061
|
+
},
|
|
2062
|
+
"Auth.INVITE_TITLE": {
|
|
2063
|
+
"de": "Neuen Benutzer einladen",
|
|
2064
|
+
"fr": "Inviter un nouvel utilisateur",
|
|
2065
|
+
"en": "Invite a new user",
|
|
2066
|
+
"sw": "Mwalike mtumiaji mpya"
|
|
2067
|
+
},
|
|
2068
|
+
"Account.BULK_INVITE_NO_EMAILS": {
|
|
2069
|
+
"de": "Keine gültigen E-Mail-Adressen in der CSV-Datei gefunden.",
|
|
2070
|
+
"fr": "Aucune adresse e-mail valide trouvée dans le fichier CSV.",
|
|
2071
|
+
"en": "No valid email addresses found in CSV.",
|
|
2072
|
+
"sw": "Hakuna anwani halali za barua pepe zilizopatikana kwenye CSV."
|
|
2073
|
+
},
|
|
2074
|
+
"Account.BULK_INVITE_PARSE_FAILED": {
|
|
2075
|
+
"de": "CSV-Datei konnte nicht gelesen werden.",
|
|
2076
|
+
"fr": "Impossible de lire le fichier CSV.",
|
|
2077
|
+
"en": "Could not read CSV file.",
|
|
2078
|
+
"sw": "Imeshindikana kusoma faili ya CSV."
|
|
2079
|
+
},
|
|
2080
|
+
"Account.BULK_INVITE_DONE": {
|
|
2081
|
+
"de": "{{ok}} / {{total}} Einladungen gesendet.",
|
|
2082
|
+
"fr": "{{ok}} / {{total}} invitations envoyées.",
|
|
2083
|
+
"en": "{{ok}} / {{total}} invites sent.",
|
|
2084
|
+
"sw": "Mialiko {{ok}} / {{total}} imetumwa."
|
|
2085
|
+
},
|
|
2086
|
+
"Account.BULK_INVITE_TITLE": {
|
|
2087
|
+
"de": "Masseneinladung per CSV",
|
|
2088
|
+
"fr": "Invitations groupées par CSV",
|
|
2089
|
+
"en": "Bulk Invite via CSV",
|
|
2090
|
+
"sw": "Mialiko ya wingi kupitia CSV"
|
|
2091
|
+
},
|
|
2092
|
+
"Account.BULK_INVITE_HINT": {
|
|
2093
|
+
"de": "CSV-Datei mit E-Mail-Adressen hochladen. Header \"email\" wird unterstützt.",
|
|
2094
|
+
"fr": "Téléversez un fichier CSV contenant des adresses e-mail. L’en-tête \"email\" est pris en charge.",
|
|
2095
|
+
"en": "Upload a CSV file containing email addresses. Header \"email\" is supported.",
|
|
2096
|
+
"sw": "Pakia faili ya CSV yenye anwani za barua pepe. Kichwa \"email\" kinatumika."
|
|
2097
|
+
},
|
|
2098
|
+
"Account.BULK_INVITE_UPLOAD": {
|
|
2099
|
+
"de": "CSV hochladen",
|
|
2100
|
+
"fr": "Téléverser un CSV",
|
|
2101
|
+
"en": "Upload CSV",
|
|
2102
|
+
"sw": "Pakia CSV"
|
|
2103
|
+
},
|
|
2104
|
+
"Account.BULK_INVITE_SEND": {
|
|
2105
|
+
"de": "Einladungen senden",
|
|
2106
|
+
"fr": "Envoyer les invitations",
|
|
2107
|
+
"en": "Send Invites",
|
|
2108
|
+
"sw": "Tuma mialiko"
|
|
2109
|
+
},
|
|
2110
|
+
"Account.BULK_INVITE_COUNT": {
|
|
2111
|
+
"de": "{{count}} E-Mail-Adressen geladen",
|
|
2112
|
+
"fr": "{{count}} adresses e-mail chargées",
|
|
2113
|
+
"en": "{{count}} emails loaded",
|
|
2114
|
+
"sw": "Anwani {{count}} za barua pepe zimepakiwa"
|
|
2115
|
+
},
|
|
2116
|
+
"Common.STATUS": {
|
|
2117
|
+
"de": "Status",
|
|
2118
|
+
"fr": "Statut",
|
|
2119
|
+
"en": "Status",
|
|
2120
|
+
"sw": "Hali"
|
|
2121
|
+
},
|
|
2122
|
+
"Common.DETAILS": {
|
|
2123
|
+
"de": "Details",
|
|
2124
|
+
"fr": "Détails",
|
|
2125
|
+
"en": "Details",
|
|
2126
|
+
"sw": "Maelezo"
|
|
2127
|
+
},
|
|
2128
|
+
"Account.BULK_INVITE_PROGRESS": {
|
|
2129
|
+
"de": "{{done}} / {{total}} verarbeitet",
|
|
2130
|
+
"fr": "{{done}} / {{total}} traitées",
|
|
2131
|
+
"en": "{{done}} / {{total}} processed",
|
|
2132
|
+
"sw": "{{done}} / {{total}} zimechakatwa"
|
|
2133
|
+
},
|
|
2134
|
+
"Account.BULK_INVITE_SUCCESS_COUNT": {
|
|
2135
|
+
"de": "{{count}} erfolgreich",
|
|
2136
|
+
"fr": "{{count}} réussies",
|
|
2137
|
+
"en": "{{count}} successful",
|
|
2138
|
+
"sw": "{{count}} zimefaulu"
|
|
2139
|
+
},
|
|
2140
|
+
|
|
1900
2141
|
// Raw backend auth error codes (allauth-headless + Django password validators).
|
|
1901
2142
|
// Keyed by the exact code string so the existing `t(err.code)` call sites resolve
|
|
1902
2143
|
// as a drop-in, without any component change. See AUTH-2.
|
|
@@ -1920,6 +2161,7 @@ export const authTranslations = {
|
|
|
1920
2161
|
},
|
|
1921
2162
|
"too_many_login_attempts": {
|
|
1922
2163
|
"de": "Zu viele fehlgeschlagene Anmeldeversuche. Bitte versuchen Sie es später erneut.",
|
|
2164
|
+
"de_informal": "Zu viele fehlgeschlagene Anmeldeversuche. Bitte versuche es später erneut.",
|
|
1923
2165
|
"fr": "Trop de tentatives de connexion échouées. Veuillez réessayer plus tard.",
|
|
1924
2166
|
"en": "Too many failed login attempts. Please try again later.",
|
|
1925
2167
|
"sw": "Majaribio mengi ya kuingia yameshindwa. Tafadhali jaribu tena baadaye."
|
|
@@ -1962,6 +2204,7 @@ export const authTranslations = {
|
|
|
1962
2204
|
},
|
|
1963
2205
|
"password_too_similar": {
|
|
1964
2206
|
"de": "Das Passwort ist Ihren persönlichen Daten zu ähnlich.",
|
|
2207
|
+
"de_informal": "Das Passwort ist deinen persönlichen Daten zu ähnlich.",
|
|
1965
2208
|
"fr": "Le mot de passe est trop similaire à vos informations personnelles.",
|
|
1966
2209
|
"en": "The password is too similar to your personal information.",
|
|
1967
2210
|
"sw": "Nenosiri linafanana sana na taarifa zako binafsi."
|
|
@@ -15,3 +15,13 @@ export const uiCoreTranslations = {
|
|
|
15
15
|
...sectionNavTranslations,
|
|
16
16
|
...userMenuTranslations,
|
|
17
17
|
};
|
|
18
|
+
|
|
19
|
+
export function createUiCoreTranslations({ germanVariant = 'formal' } = {}) {
|
|
20
|
+
return Object.fromEntries(
|
|
21
|
+
Object.entries(uiCoreTranslations).map(([key, value]) => {
|
|
22
|
+
const { de_informal, ...rest } = value;
|
|
23
|
+
if (germanVariant === 'informal' && de_informal) return [key, { ...rest, de: de_informal }];
|
|
24
|
+
return [key, rest];
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
}
|
package/src/index.js
CHANGED
|
@@ -63,6 +63,7 @@ export { QrSignupManager } from './components/QrSignupManager';
|
|
|
63
63
|
export { MobileBottomNav } from './components/MobileBottomNav';
|
|
64
64
|
export { default as StatTile } from './components/StatTile';
|
|
65
65
|
export { default as SoftChip } from './components/SoftChip';
|
|
66
|
+
export { default as EmptyState } from './components/EmptyState';
|
|
66
67
|
|
|
67
68
|
// --- 6. Charts ---
|
|
68
69
|
export { ChartFrame } from './components/charts/ChartFrame';
|
|
@@ -140,4 +141,4 @@ export { notificationsTranslations } from './i18n/notificationsTranslations';
|
|
|
140
141
|
export { onboardingTranslations } from './i18n/onboardingTranslations';
|
|
141
142
|
export { chartsTranslations } from './i18n/chartsTranslations';
|
|
142
143
|
export { messagingTranslations } from './i18n/messagingTranslations';
|
|
143
|
-
export { uiCoreTranslations } from './i18n/uiCoreTranslations';
|
|
144
|
+
export { createUiCoreTranslations, uiCoreTranslations } from './i18n/uiCoreTranslations';
|
|
@@ -11,6 +11,8 @@ import { compressImageForUpload } from './composerImageCompression';
|
|
|
11
11
|
import { extractApiErrorMessage, useMessaging } from './MessagingProvider';
|
|
12
12
|
|
|
13
13
|
export const COMPOSER_EMOJI_BUTTON_SX = { fontSize: '1.15rem' };
|
|
14
|
+
export const COMPOSER_MESSAGE_FIELD_SX = { flex: 1, minWidth: 120 };
|
|
15
|
+
export const COMPOSER_SEND_BUTTON_SX = { flexShrink: 0 };
|
|
14
16
|
|
|
15
17
|
// A wider, Composer-only set (MSG-6i) -- deliberately separate from
|
|
16
18
|
// ReactionBar's own QUICK_EMOJIS (5, curated for fast reactions). Mobile
|
|
@@ -136,14 +138,16 @@ export function Composer({ conversationId, conversation, replyTarget = null, onR
|
|
|
136
138
|
</Stack>)}
|
|
137
139
|
</Stack>}
|
|
138
140
|
{files.length > 0 && <Typography variant="caption">{t('MessagingComposer.FILES_SELECTED', { count: files.length })}</Typography>}
|
|
139
|
-
<Stack direction="row" spacing={1}
|
|
141
|
+
<Stack direction="row" spacing={1}>
|
|
140
142
|
<input ref={inputRef} hidden type="file" multiple onChange={(event) => setFiles(Array.from(event.target.files || []))} />
|
|
141
143
|
<IconButton type="button" aria-label={t('MessagingComposer.ADD_ATTACHMENT')} onClick={() => inputRef.current?.click()}><AttachFileIcon /></IconButton>
|
|
142
144
|
<IconButton type="button" aria-label={t('MessagingComposer.ADD_EMOJI')} onClick={(event) => setEmojiAnchor(event.currentTarget)}><EmojiEmotionsOutlinedIcon /></IconButton>
|
|
143
145
|
<IconButton type="button" aria-label={t('MessagingPoll.CREATE')} disabled={pollOpen || files.some(isImage)} onClick={() => setPollOpen(true)}><PollOutlinedIcon /></IconButton>
|
|
144
146
|
{canAnnounce && <IconButton type="button" aria-label={t('MessagingAnnouncement.CREATE')} onClick={() => setAnnouncementOpen(true)}><CampaignOutlinedIcon /></IconButton>}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
</Stack>
|
|
148
|
+
<Stack direction="row" spacing={1} alignItems="flex-end">
|
|
149
|
+
<TextField inputRef={messageInputRef} fullWidth multiline minRows={2} value={body} onChange={(event) => setBody(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) { event.preventDefault(); submit(); } }} label={t('MessagingComposer.MESSAGE')} disabled={sending} sx={COMPOSER_MESSAGE_FIELD_SX} />
|
|
150
|
+
<Button type="submit" variant="contained" disabled={sending || (!body.trim() && !files.length)} sx={COMPOSER_SEND_BUTTON_SX}>{t('MessagingComposer.SEND')}</Button>
|
|
147
151
|
</Stack>
|
|
148
152
|
{sending && files.length > 0 && <Stack spacing={0.5} role="status">
|
|
149
153
|
<Stack direction="row" spacing={1} alignItems="center">
|
|
@@ -7,6 +7,7 @@ import { AttachmentList } from './AttachmentList';
|
|
|
7
7
|
import { extractApiErrorMessage, useOptionalMessaging } from './MessagingProvider';
|
|
8
8
|
import { ReactionBar } from './ReactionBar';
|
|
9
9
|
import { PollCard } from './PollCard';
|
|
10
|
+
import { linkifyText } from './linkifyText';
|
|
10
11
|
|
|
11
12
|
export const MESSAGE_BUBBLE_ROOT_SX = {
|
|
12
13
|
position: 'relative',
|
|
@@ -146,7 +147,7 @@ export function MessageBubble({ message, replyTo, conversation, onReply, onJumpT
|
|
|
146
147
|
{!deleted && message.kind === 'announcement' && message.title && <Typography variant="subtitle1" fontWeight={700}>{message.title}</Typography>}
|
|
147
148
|
{!deleted && message.kind === 'announcement' && message.link_target && onAnnouncementLink && <Button type="button" size="small" onClick={() => onAnnouncementLink(message.link_target)}>{t('MessagingAnnouncement.OPEN_LINK')}</Button>}
|
|
148
149
|
{error && <Alert severity="error" role="alert">{error}</Alert>}
|
|
149
|
-
{editing ? <Stack spacing={0.75}><TextField label={t('MessagingActions.EDIT')} value={draft} onChange={(event) => setDraft(event.target.value)} multiline minRows={2} autoFocus disabled={saving} /><Stack direction="row" spacing={1}><Button type="button" onClick={saveEdit} disabled={saving}>{t('MessagingActions.SAVE')}</Button><Button type="button" onClick={() => setEditing(false)} disabled={saving}>{t('MessagingActions.CANCEL')}</Button></Stack></Stack> : <Typography sx={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>{deleted ? t('MessagingThread.DELETED') : (message.kind === 'announcement' ? message.body : (message.body || message.title)) || ''}</Typography>}
|
|
150
|
+
{editing ? <Stack spacing={0.75}><TextField label={t('MessagingActions.EDIT')} value={draft} onChange={(event) => setDraft(event.target.value)} multiline minRows={2} autoFocus disabled={saving} /><Stack direction="row" spacing={1}><Button type="button" onClick={saveEdit} disabled={saving}>{t('MessagingActions.SAVE')}</Button><Button type="button" onClick={() => setEditing(false)} disabled={saving}>{t('MessagingActions.CANCEL')}</Button></Stack></Stack> : <Typography sx={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>{deleted ? t('MessagingThread.DELETED') : linkifyText((message.kind === 'announcement' ? message.body : (message.body || message.title)) || '')}</Typography>}
|
|
150
151
|
{!deleted && <Stack spacing={0.75}>
|
|
151
152
|
{attachments.length > 0 && <AttachmentList attachments={attachments} />}
|
|
152
153
|
{message.poll && <PollCard message={message} />}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DoneAllOutlinedIcon from '@mui/icons-material/DoneAllOutlined';
|
|
2
2
|
import DoneOutlinedIcon from '@mui/icons-material/DoneOutlined';
|
|
3
|
-
import { ButtonBase, List, ListItem, Popover, Typography } from '@mui/material';
|
|
3
|
+
import { ButtonBase, List, ListItem, Popover, Tooltip, Typography } from '@mui/material';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
@@ -48,6 +48,7 @@ export function ReadTicks({ messageId, conversation }) {
|
|
|
48
48
|
const hasCounts = typeof status.read_count === 'number' && typeof status.recipient_count === 'number';
|
|
49
49
|
|
|
50
50
|
if (!hasCounts && conversation?.kind !== 'direct') return null;
|
|
51
|
+
if (hasCounts && status.recipient_count === 0) return null;
|
|
51
52
|
|
|
52
53
|
// The server never returns DM detail; enforce the same carve-out defensively.
|
|
53
54
|
const detail = conversation?.kind === 'direct' ? null : recipientDetail;
|
|
@@ -71,8 +72,8 @@ export function ReadTicks({ messageId, conversation }) {
|
|
|
71
72
|
// next read-status fetch, not live from a read_state frame.
|
|
72
73
|
const label = t('MessagingReadTicks.READ_RATIO', { read: status.read_count, total: status.recipient_count });
|
|
73
74
|
const ratio = <Typography component="span" variant="caption" color="inherit">{status.read_count}/{status.recipient_count}</Typography>;
|
|
74
|
-
if (!recipients.length) return <span role="img" aria-label={label}>{ratio}</span>;
|
|
75
|
-
return <><ButtonBase aria-label={label} aria-haspopup="dialog" aria-expanded={Boolean(anchorEl)} onClick={(event) => setAnchorEl(event.currentTarget)} sx={{ display: 'inline-flex' }}>{ratio}</ButtonBase><Popover open={Boolean(anchorEl)} anchorEl={anchorEl} onClose={() => setAnchorEl(null)}><List aria-label={t('MessagingReadTicks.RECIPIENTS')}>{recipients.map((recipient) => <ListItem key={recipient}>{recipient}</ListItem>)}</List></Popover></>;
|
|
75
|
+
if (!recipients.length) return <Tooltip title={label} describeChild><span role="img" aria-label={label}>{ratio}</span></Tooltip>;
|
|
76
|
+
return <><Tooltip title={label} describeChild><ButtonBase aria-label={label} aria-haspopup="dialog" aria-expanded={Boolean(anchorEl)} onClick={(event) => setAnchorEl(event.currentTarget)} sx={{ display: 'inline-flex' }}>{ratio}</ButtonBase></Tooltip><Popover open={Boolean(anchorEl)} anchorEl={anchorEl} onClose={() => setAnchorEl(null)}><List aria-label={t('MessagingReadTicks.RECIPIENTS')}>{recipients.map((recipient) => <ListItem key={recipient}>{recipient}</ListItem>)}</List></Popover></>;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
const label = allRead ? t('MessagingReadTicks.ALL_READ') : t('MessagingReadTicks.SENT');
|