mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 16:15:39 +00:00
fix: show attachment upload progress and failures in words for screen readers
This commit is contained in:
@@ -68,9 +68,10 @@ vi.mock('@/stores/settings-store', () => {
|
||||
return { useSettingsStore: hook };
|
||||
});
|
||||
|
||||
const auth = vi.hoisted(() => ({ client: null as unknown }));
|
||||
vi.mock('@/stores/auth-store', () => {
|
||||
const state = {
|
||||
client: null,
|
||||
get client() { return auth.client; },
|
||||
identities: [],
|
||||
primaryIdentity: null,
|
||||
isAuthenticated: false,
|
||||
@@ -151,6 +152,9 @@ vi.mock('@/lib/plugin-hooks', () => ({
|
||||
onTemplateApply: { size: 0, emit: async () => {} },
|
||||
},
|
||||
emailHooks: {
|
||||
onBeforeAttachmentUpload: { intercept: async () => true },
|
||||
onBeforeBlobUpload: { transform: async (id: unknown) => id },
|
||||
onAfterAttachmentUpload: { emit: () => {} },
|
||||
onComposerOpen: { call: async () => [] },
|
||||
onRecipientChange: { call: async () => [] },
|
||||
getRecipientSuggestions: { call: async () => [] },
|
||||
@@ -165,6 +169,7 @@ vi.mock('@/lib/plugin-hooks', () => ({
|
||||
search: { call: async () => [] },
|
||||
onProvideRecipientSuggestions: { transform: async (initial: unknown) => initial },
|
||||
},
|
||||
isExternalAttachmentResult: () => false,
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/email-sanitization', () => ({
|
||||
@@ -175,6 +180,16 @@ vi.mock('@/lib/email-sanitization', () => ({
|
||||
escapeHtml: (v: string) => v,
|
||||
parseHtmlSafely: (html: string) => new DOMParser().parseFromString(html, 'text/html'),
|
||||
}));
|
||||
const progress = vi.hoisted(() => ({ report: null as null | ((loaded: number, total: number) => void) }));
|
||||
vi.mock('@/lib/upload-progress', () => ({
|
||||
onUploadProgress: (_id: string, report: (loaded: number, total: number) => void) => {
|
||||
progress.report = report;
|
||||
return () => {};
|
||||
},
|
||||
}));
|
||||
vi.mock('@/lib/plugin-storage', () => ({
|
||||
fileStorage: { saveFile: async () => {}, getFile: async () => null, deleteFile: async () => {} },
|
||||
}));
|
||||
vi.mock('@/lib/email-threading', () => ({
|
||||
computeReplyThreadingHeaders: () => ({ inReplyTo: [], references: [] }),
|
||||
}));
|
||||
@@ -205,8 +220,27 @@ const toInput = () => screen.getByPlaceholderText('to_placeholder') as HTMLInput
|
||||
|
||||
beforeEach(() => {
|
||||
Object.assign(settings, DEFAULT_SETTINGS);
|
||||
auth.client = null;
|
||||
});
|
||||
|
||||
/** A client whose upload is held: report progress, then fail or never finish. */
|
||||
function uploadClient(upload: () => Promise<{ blobId: string }>) {
|
||||
auth.client = {
|
||||
uploadBlob: vi.fn(upload),
|
||||
hasDelayedSend: () => false,
|
||||
getMaxDelayedSend: () => 0,
|
||||
};
|
||||
}
|
||||
|
||||
async function attach(file: File) {
|
||||
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
await act(async () => {
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
await Promise.resolve();
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
});
|
||||
}
|
||||
|
||||
describe('recipient fields (SR-06, CV-02)', () => {
|
||||
it('names the To input by its visible label, also once it holds chips', () => {
|
||||
render(<EmailComposer initialData={{ ...DRAFT, to: 'Anna Berg <anna@example.com>' }} />);
|
||||
@@ -346,3 +380,27 @@ describe('message body (SR-07)', () => {
|
||||
expect(error).toHaveTextContent('validation.body_required');
|
||||
});
|
||||
});
|
||||
|
||||
describe('attachment uploads (SR-16)', () => {
|
||||
it('shows upload progress as a named progress bar with a text value', async () => {
|
||||
uploadClient(() => new Promise(() => {}));
|
||||
render(<EmailComposer initialData={DRAFT} />);
|
||||
await attach(new File(['%PDF'], 'report.pdf', { type: 'application/pdf' }));
|
||||
|
||||
const bar = screen.getByRole('progressbar', { name: 'report.pdf' });
|
||||
expect(bar).toHaveAttribute('aria-valuetext', 'attachment_uploading');
|
||||
act(() => progress.report?.(45, 100));
|
||||
expect(bar).toHaveAttribute('aria-valuenow', '45');
|
||||
expect(bar).toHaveAttribute('aria-valuetext', 'attachment_progress:45');
|
||||
});
|
||||
|
||||
it('says in words that an upload failed and announces it', async () => {
|
||||
uploadClient(() => Promise.reject(new Error('boom')));
|
||||
render(<EmailComposer initialData={DRAFT} />);
|
||||
await attach(new File(['%PDF'], 'report.pdf', { type: 'application/pdf' }));
|
||||
|
||||
await waitFor(() => expect(screen.getByText('attachment_upload_failed')).toBeInTheDocument());
|
||||
expect(screen.queryByRole('progressbar')).toBeNull();
|
||||
expect(liveRegion()).toHaveTextContent('upload_failed:report.pdf');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2267,6 +2267,7 @@ export function EmailComposer({
|
||||
if (controller?.signal.aborted) continue;
|
||||
debug.error(`Failed to upload ${file.name}:`, error);
|
||||
toast.error(t('upload_failed', { filename: file.name }));
|
||||
announce(t('upload_failed', { filename: file.name }));
|
||||
|
||||
setAttachments(prev =>
|
||||
prev.map(att =>
|
||||
@@ -2277,7 +2278,7 @@ export function EmailComposer({
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [client, t, plainTextMode]);
|
||||
}, [client, t, plainTextMode, announce]);
|
||||
|
||||
const handleImageUpload = useCallback(async (
|
||||
file: File,
|
||||
@@ -4499,6 +4500,14 @@ export function EmailComposer({
|
||||
<span className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
({formatFileSize(att.size)})
|
||||
</span>
|
||||
{/* State in words, not only a tint or a bar. */}
|
||||
{att.error ? (
|
||||
<span className="text-xs font-medium whitespace-nowrap">{t('attachment_upload_failed')}</span>
|
||||
) : att.uploading ? (
|
||||
<span className="text-xs text-muted-foreground whitespace-nowrap tabular-nums" aria-hidden>
|
||||
{typeof att.progress === 'number' ? `${att.progress}%` : t('attachment_uploading')}
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
return (
|
||||
@@ -4510,7 +4519,17 @@ export function EmailComposer({
|
||||
)}
|
||||
>
|
||||
{att.uploading && (
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<div
|
||||
className="absolute inset-0 pointer-events-none"
|
||||
role="progressbar"
|
||||
aria-label={att.name}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={typeof att.progress === 'number' ? att.progress : undefined}
|
||||
aria-valuetext={typeof att.progress === 'number'
|
||||
? t('attachment_progress', { percent: att.progress })
|
||||
: t('attachment_uploading')}
|
||||
>
|
||||
<div className="h-full bg-primary/10 animate-pulse" />
|
||||
{typeof att.progress === 'number' ? (
|
||||
// Real byte progress from the transport; see
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, zero {لم تتم إضافة أي مستلم} one {تمت إضافة مستلم واحد} two {تمت إضافة مستلمَين} few {تمت إضافة # مستلمين} many {تمت إضافة # مستلمًا} other {تمت إضافة # مستلم}} إلى {field}",
|
||||
"recipients_removed_count": "{count, plural, zero {لم تتم إزالة أي مستلم} one {تمت إزالة مستلم واحد} two {تمت إزالة مستلمَين} few {تمت إزالة # مستلمين} many {تمت إزالة # مستلمًا} other {تمت إزالة # مستلم}} من {field}",
|
||||
"recipients_moved_count": "{count, plural, zero {لم يتم نقل أي مستلم} one {تم نقل مستلم واحد} two {تم نقل مستلمَين} few {تم نقل # مستلمين} many {تم نقل # مستلمًا} other {تم نقل # مستلم}} إلى {field}",
|
||||
"body_label": "الرسالة"
|
||||
"body_label": "الرسالة",
|
||||
"attachment_uploading": "جارٍ الرفع",
|
||||
"attachment_upload_failed": "فشل الرفع",
|
||||
"attachment_progress": "تم رفع {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "تأكيد",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {S'ha afegit # destinatari} other {S'han afegit # destinataris}} a {field}",
|
||||
"recipients_removed_count": "{count, plural, one {S'ha tret # destinatari} other {S'han tret # destinataris}} de {field}",
|
||||
"recipients_moved_count": "{count, plural, one {S'ha mogut # destinatari} other {S'han mogut # destinataris}} a {field}",
|
||||
"body_label": "Missatge"
|
||||
"body_label": "Missatge",
|
||||
"attachment_uploading": "S'està pujant",
|
||||
"attachment_upload_failed": "No s'ha pogut pujar",
|
||||
"attachment_progress": "{percent}% pujat"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirma",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Do {field} {count, plural, one {přidán # příjemce} few {přidáni # příjemci} many {přidáno # příjemce} other {přidáno # příjemců}}",
|
||||
"recipients_removed_count": "Z {field} {count, plural, one {odebrán # příjemce} few {odebráni # příjemci} many {odebráno # příjemce} other {odebráno # příjemců}}",
|
||||
"recipients_moved_count": "Do {field} {count, plural, one {přesunut # příjemce} few {přesunuti # příjemci} many {přesunuto # příjemce} other {přesunuto # příjemců}}",
|
||||
"body_label": "Zpráva"
|
||||
"body_label": "Zpráva",
|
||||
"attachment_uploading": "Nahrává se",
|
||||
"attachment_upload_failed": "Nahrání se nezdařilo",
|
||||
"attachment_progress": "Nahráno {percent} %"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Potvrdit",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# modtager} other {# modtagere}} tilføjet til {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# modtager} other {# modtagere}} fjernet fra {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# modtager} other {# modtagere}} flyttet til {field}",
|
||||
"body_label": "Besked"
|
||||
"body_label": "Besked",
|
||||
"attachment_uploading": "Uploader",
|
||||
"attachment_upload_failed": "Upload mislykkedes",
|
||||
"attachment_progress": "{percent} % uploadet"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bekræft",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# Empfänger} other {# Empfänger}} zu {field} hinzugefügt",
|
||||
"recipients_removed_count": "{count, plural, one {# Empfänger} other {# Empfänger}} aus {field} entfernt",
|
||||
"recipients_moved_count": "{count, plural, one {# Empfänger} other {# Empfänger}} nach {field} verschoben",
|
||||
"body_label": "Nachricht"
|
||||
"body_label": "Nachricht",
|
||||
"attachment_uploading": "Wird hochgeladen",
|
||||
"attachment_upload_failed": "Hochladen fehlgeschlagen",
|
||||
"attachment_progress": "{percent} % hochgeladen"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bestätigen",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Added {count, plural, one {# recipient} other {# recipients}} to {field}",
|
||||
"recipients_removed_count": "Removed {count, plural, one {# recipient} other {# recipients}} from {field}",
|
||||
"recipients_moved_count": "Moved {count, plural, one {# recipient} other {# recipients}} to {field}",
|
||||
"body_label": "Message"
|
||||
"body_label": "Message",
|
||||
"attachment_uploading": "Uploading",
|
||||
"attachment_upload_failed": "Upload failed",
|
||||
"attachment_progress": "{percent}% uploaded"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirm",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {Se añadió # destinatario} other {Se añadieron # destinatarios}} en {field}",
|
||||
"recipients_removed_count": "{count, plural, one {Se quitó # destinatario} other {Se quitaron # destinatarios}} de {field}",
|
||||
"recipients_moved_count": "{count, plural, one {Se movió # destinatario} other {Se movieron # destinatarios}} a {field}",
|
||||
"body_label": "Mensaje"
|
||||
"body_label": "Mensaje",
|
||||
"attachment_uploading": "Subiendo",
|
||||
"attachment_upload_failed": "Error al subir",
|
||||
"attachment_progress": "{percent} % subido"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmar",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Väljale {field} lisati {count, plural, one {# saaja} other {# saajat}}",
|
||||
"recipients_removed_count": "Väljalt {field} eemaldati {count, plural, one {# saaja} other {# saajat}}",
|
||||
"recipients_moved_count": "Väljale {field} teisaldati {count, plural, one {# saaja} other {# saajat}}",
|
||||
"body_label": "Sõnum"
|
||||
"body_label": "Sõnum",
|
||||
"attachment_uploading": "Üleslaadimine",
|
||||
"attachment_upload_failed": "Üleslaadimine ebaõnnestus",
|
||||
"attachment_progress": "{percent}% üles laaditud"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Kinnita",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# گیرنده} other {# گیرنده}} به {field} افزوده شد",
|
||||
"recipients_removed_count": "{count, plural, one {# گیرنده} other {# گیرنده}} از {field} حذف شد",
|
||||
"recipients_moved_count": "{count, plural, one {# گیرنده} other {# گیرنده}} به {field} منتقل شد",
|
||||
"body_label": "پیام"
|
||||
"body_label": "پیام",
|
||||
"attachment_uploading": "در حال بارگذاری",
|
||||
"attachment_upload_failed": "بارگذاری ناموفق بود",
|
||||
"attachment_progress": "{percent}٪ بارگذاری شد"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "تأیید",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# destinataire ajouté} other {# destinataires ajoutés}} à {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# destinataire retiré} other {# destinataires retirés}} de {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# destinataire déplacé} other {# destinataires déplacés}} vers {field}",
|
||||
"body_label": "Message"
|
||||
"body_label": "Message",
|
||||
"attachment_uploading": "Téléversement",
|
||||
"attachment_upload_failed": "Échec du téléversement",
|
||||
"attachment_progress": "{percent} % téléversé"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmer",
|
||||
|
||||
@@ -994,7 +994,10 @@
|
||||
"recipients_added_count": "{count, plural, one {נמען אחד נוסף} two {שני נמענים נוספו} other {# נמענים נוספו}} אל {field}",
|
||||
"recipients_removed_count": "{count, plural, one {נמען אחד הוסר} two {שני נמענים הוסרו} other {# נמענים הוסרו}} מ{field}",
|
||||
"recipients_moved_count": "{count, plural, one {נמען אחד הועבר} two {שני נמענים הועברו} other {# נמענים הועברו}} אל {field}",
|
||||
"body_label": "הודעה"
|
||||
"body_label": "הודעה",
|
||||
"attachment_uploading": "מעלה",
|
||||
"attachment_upload_failed": "ההעלאה נכשלה",
|
||||
"attachment_progress": "{percent}% הועלו"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "אשר",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# címzett} other {# címzett}} hozzáadva ide: {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# címzett} other {# címzett}} eltávolítva innen: {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# címzett} other {# címzett}} áthelyezve ide: {field}",
|
||||
"body_label": "Üzenet"
|
||||
"body_label": "Üzenet",
|
||||
"attachment_uploading": "Feltöltés",
|
||||
"attachment_upload_failed": "A feltöltés nem sikerült",
|
||||
"attachment_progress": "{percent}% feltöltve"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Megerősítés",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# destinatario aggiunto} other {# destinatari aggiunti}} a {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# destinatario rimosso} other {# destinatari rimossi}} da {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# destinatario spostato} other {# destinatari spostati}} in {field}",
|
||||
"body_label": "Messaggio"
|
||||
"body_label": "Messaggio",
|
||||
"attachment_uploading": "Caricamento",
|
||||
"attachment_upload_failed": "Caricamento non riuscito",
|
||||
"attachment_progress": "{percent}% caricato"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Conferma",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, other {# 件の宛先}}を {field} に追加しました",
|
||||
"recipients_removed_count": "{count, plural, other {# 件の宛先}}を {field} から削除しました",
|
||||
"recipients_moved_count": "{count, plural, other {# 件の宛先}}を {field} に移動しました",
|
||||
"body_label": "メッセージ"
|
||||
"body_label": "メッセージ",
|
||||
"attachment_uploading": "アップロード中",
|
||||
"attachment_upload_failed": "アップロードに失敗しました",
|
||||
"attachment_progress": "{percent}% アップロード済み"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "確認",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{field}에 {count, plural, other {받는 사람 #명}}을 추가했어요",
|
||||
"recipients_removed_count": "{field}에서 {count, plural, other {받는 사람 #명}}을 제거했어요",
|
||||
"recipients_moved_count": "{field}(으)로 {count, plural, other {받는 사람 #명}}을 옮겼어요",
|
||||
"body_label": "메시지"
|
||||
"body_label": "메시지",
|
||||
"attachment_uploading": "업로드 중",
|
||||
"attachment_upload_failed": "업로드 실패",
|
||||
"attachment_progress": "{percent}% 업로드됨"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "확인",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Laukam {field} {count, plural, zero {pievienoti # adresāti} one {pievienots # adresāts} other {pievienoti # adresāti}}",
|
||||
"recipients_removed_count": "No lauka {field} {count, plural, zero {noņemti # adresāti} one {noņemts # adresāts} other {noņemti # adresāti}}",
|
||||
"recipients_moved_count": "Uz {field} {count, plural, zero {pārvietoti # adresāti} one {pārvietots # adresāts} other {pārvietoti # adresāti}}",
|
||||
"body_label": "Ziņojums"
|
||||
"body_label": "Ziņojums",
|
||||
"attachment_uploading": "Augšupielādē",
|
||||
"attachment_upload_failed": "Augšupielāde neizdevās",
|
||||
"attachment_progress": "Augšupielādēti {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Apstiprināt",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{field}-д {count, plural, one {# хүлээн авагч} other {# хүлээн авагч}} нэмлээ",
|
||||
"recipients_removed_count": "{field}-ээс {count, plural, one {# хүлээн авагч} other {# хүлээн авагч}} хаслаа",
|
||||
"recipients_moved_count": "{field} руу {count, plural, one {# хүлээн авагч} other {# хүлээн авагч}} зөөлөө",
|
||||
"body_label": "Мессеж"
|
||||
"body_label": "Мессеж",
|
||||
"attachment_uploading": "Байршуулж байна",
|
||||
"attachment_upload_failed": "Байршуулж чадсангүй",
|
||||
"attachment_progress": "{percent}% байршуулсан"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Баталгаажуулах",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# mottaker} other {# mottakere}} lagt til i {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# mottaker} other {# mottakere}} fjernet fra {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# mottaker} other {# mottakere}} flyttet til {field}",
|
||||
"body_label": "Melding"
|
||||
"body_label": "Melding",
|
||||
"attachment_uploading": "Laster opp",
|
||||
"attachment_upload_failed": "Opplastingen mislyktes",
|
||||
"attachment_progress": "{percent} % lastet opp"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bekreft",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# ontvanger} other {# ontvangers}} toegevoegd aan {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# ontvanger} other {# ontvangers}} verwijderd uit {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# ontvanger} other {# ontvangers}} verplaatst naar {field}",
|
||||
"body_label": "Bericht"
|
||||
"body_label": "Bericht",
|
||||
"attachment_uploading": "Uploaden",
|
||||
"attachment_upload_failed": "Uploaden mislukt",
|
||||
"attachment_progress": "{percent}% geüpload"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bevestigen",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Dodano {count, plural, one {# odbiorcę} few {# odbiorców} many {# odbiorców} other {# odbiorcy}} do {field}",
|
||||
"recipients_removed_count": "Usunięto {count, plural, one {# odbiorcę} few {# odbiorców} many {# odbiorców} other {# odbiorcy}} z {field}",
|
||||
"recipients_moved_count": "Przeniesiono {count, plural, one {# odbiorcę} few {# odbiorców} many {# odbiorców} other {# odbiorcy}} do {field}",
|
||||
"body_label": "Wiadomość"
|
||||
"body_label": "Wiadomość",
|
||||
"attachment_uploading": "Przesyłanie",
|
||||
"attachment_upload_failed": "Przesyłanie nie powiodło się",
|
||||
"attachment_progress": "Przesłano {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Potwierdź",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {# destinatário adicionado} other {# destinatários adicionados}} a {field}",
|
||||
"recipients_removed_count": "{count, plural, one {# destinatário removido} other {# destinatários removidos}} de {field}",
|
||||
"recipients_moved_count": "{count, plural, one {# destinatário movido} other {# destinatários movidos}} para {field}",
|
||||
"body_label": "Mensagem"
|
||||
"body_label": "Mensagem",
|
||||
"attachment_uploading": "Enviando",
|
||||
"attachment_upload_failed": "Falha no envio",
|
||||
"attachment_progress": "{percent}% enviado"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmar",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{count, plural, one {A fost adăugat # destinatar} few {Au fost adăugați # destinatari} other {Au fost adăugați # de destinatari}} la {field}",
|
||||
"recipients_removed_count": "{count, plural, one {A fost eliminat # destinatar} few {Au fost eliminați # destinatari} other {Au fost eliminați # de destinatari}} din {field}",
|
||||
"recipients_moved_count": "{count, plural, one {A fost mutat # destinatar} few {Au fost mutați # destinatari} other {Au fost mutați # de destinatari}} la {field}",
|
||||
"body_label": "Mesaj"
|
||||
"body_label": "Mesaj",
|
||||
"attachment_uploading": "Se încarcă",
|
||||
"attachment_upload_failed": "Încărcarea a eșuat",
|
||||
"attachment_progress": "{percent}% încărcat"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmare",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "В «{field}» {count, plural, one {добавлен # получатель} few {добавлено # получателя} many {добавлено # получателей} other {добавлено # получателя}}",
|
||||
"recipients_removed_count": "Из «{field}» {count, plural, one {убран # получатель} few {убрано # получателя} many {убрано # получателей} other {убрано # получателя}}",
|
||||
"recipients_moved_count": "В «{field}» {count, plural, one {перемещён # получатель} few {перемещено # получателя} many {перемещено # получателей} other {перемещено # получателя}}",
|
||||
"body_label": "Сообщение"
|
||||
"body_label": "Сообщение",
|
||||
"attachment_uploading": "Загрузка",
|
||||
"attachment_upload_failed": "Не удалось загрузить",
|
||||
"attachment_progress": "Загружено {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Подтвердить",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "Do {field} {count, plural, one {pridaný # príjemca} few {pridaní # príjemcovia} many {pridaných # príjemcov} other {pridaných # príjemcov}}",
|
||||
"recipients_removed_count": "Z {field} {count, plural, one {odstránený # príjemca} few {odstránení # príjemcovia} many {odstránených # príjemcov} other {odstránených # príjemcov}}",
|
||||
"recipients_moved_count": "Do {field} {count, plural, one {presunutý # príjemca} few {presunutí # príjemcovia} many {presunutých # príjemcov} other {presunutých # príjemcov}}",
|
||||
"body_label": "Správa"
|
||||
"body_label": "Správa",
|
||||
"attachment_uploading": "Nahráva sa",
|
||||
"attachment_upload_failed": "Nahrávanie zlyhalo",
|
||||
"attachment_progress": "Nahraté {percent} %"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Potvrdiť",
|
||||
|
||||
@@ -1277,7 +1277,10 @@
|
||||
"recipients_added_count": "เพิ่มผู้รับ {count, plural, other {# คน}} ใน {field} แล้ว",
|
||||
"recipients_removed_count": "นำผู้รับ {count, plural, other {# คน}} ออกจาก {field} แล้ว",
|
||||
"recipients_moved_count": "ย้ายผู้รับ {count, plural, other {# คน}} ไปที่ {field} แล้ว",
|
||||
"body_label": "ข้อความ"
|
||||
"body_label": "ข้อความ",
|
||||
"attachment_uploading": "กำลังอัปโหลด",
|
||||
"attachment_upload_failed": "อัปโหลดไม่สำเร็จ",
|
||||
"attachment_progress": "อัปโหลดแล้ว {percent}%"
|
||||
},
|
||||
"email_viewer": {
|
||||
"read_receipt": {
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "{field} alanına {count, plural, one {# alıcı} other {# alıcı}} eklendi",
|
||||
"recipients_removed_count": "{field} alanından {count, plural, one {# alıcı} other {# alıcı}} kaldırıldı",
|
||||
"recipients_moved_count": "{field} alanına {count, plural, one {# alıcı} other {# alıcı}} taşındı",
|
||||
"body_label": "İleti"
|
||||
"body_label": "İleti",
|
||||
"attachment_uploading": "Yükleniyor",
|
||||
"attachment_upload_failed": "Yükleme başarısız",
|
||||
"attachment_progress": "%{percent} yüklendi"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Onayla",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "У «{field}» {count, plural, one {додано # одержувача} few {додано # одержувачі} many {додано # одержувачів} other {додано # одержувача}}",
|
||||
"recipients_removed_count": "З «{field}» {count, plural, one {прибрано # одержувача} few {прибрано # одержувачі} many {прибрано # одержувачів} other {прибрано # одержувача}}",
|
||||
"recipients_moved_count": "У «{field}» {count, plural, one {переміщено # одержувача} few {переміщено # одержувачі} many {переміщено # одержувачів} other {переміщено # одержувача}}",
|
||||
"body_label": "Повідомлення"
|
||||
"body_label": "Повідомлення",
|
||||
"attachment_uploading": "Завантаження",
|
||||
"attachment_upload_failed": "Не вдалося завантажити",
|
||||
"attachment_progress": "Завантажено {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Підтвердити",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "已將 {count, plural, other {# 位收件者}}新增到{field}",
|
||||
"recipients_removed_count": "已將 {count, plural, other {# 位收件者}}從{field}移除",
|
||||
"recipients_moved_count": "已將 {count, plural, other {# 位收件者}}移到{field}",
|
||||
"body_label": "郵件內容"
|
||||
"body_label": "郵件內容",
|
||||
"attachment_uploading": "正在上傳",
|
||||
"attachment_upload_failed": "上傳失敗",
|
||||
"attachment_progress": "已上傳 {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "確認",
|
||||
|
||||
@@ -1029,7 +1029,10 @@
|
||||
"recipients_added_count": "已将 {count, plural, other {# 位收件人}}添加到{field}",
|
||||
"recipients_removed_count": "已将 {count, plural, other {# 位收件人}}从{field}移除",
|
||||
"recipients_moved_count": "已将 {count, plural, other {# 位收件人}}移到{field}",
|
||||
"body_label": "邮件正文"
|
||||
"body_label": "邮件正文",
|
||||
"attachment_uploading": "正在上传",
|
||||
"attachment_upload_failed": "上传失败",
|
||||
"attachment_progress": "已上传 {percent}%"
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "确认",
|
||||
|
||||
Reference in New Issue
Block a user