fix: show every attachment in the composer, with type icons and a total, failed and uploading files first

The attachment list test now expects every chip and a bounded, scrolling row instead of three chips and a +N counter.
This commit is contained in:
Linus Rath
2026-11-04 09:01:04 +01:00
parent 69ec26fe33
commit 2b2b7b8298
34 changed files with 309 additions and 82 deletions
@@ -218,21 +218,20 @@ const DRAFT = {
attachments: ATTACHMENTS,
};
/** The wrapping flex row that holds every chip and the expand button. */
/** The wrapping flex row that holds every chip. */
function chipRow() {
return screen.getByText('invoice-0.pdf').closest('[class*="flex-wrap"]') as HTMLElement;
return screen.getByTestId('composer-attachments');
}
/**
* The attachment row is a shrink-0 sibling of the body's scroll container,
* so whatever height it takes is taken from the composer and from nothing
* else. Collapsed that is three chips. Expanded it is one row per two
* attachments, and with a few dozen files it grew past the bottom of the
* composer: the send toolbar was pushed off-screen and no ancestor
* scrolled, so neither the rest of the list nor Send could be reached.
* Expanding therefore has to bound the row and scroll it itself.
* else. With a few dozen files it grew past the bottom of the composer: the
* send toolbar was pushed off-screen and no ancestor scrolled. It used to
* show three chips and "+N", which hid the fourth file's upload. Now every
* chip shows, wrapping, and the row is bounded and scrolls itself.
*/
describe('expanded attachment list', () => {
describe('attachment list', () => {
beforeEach(() => {
observers.length = 0;
vi.stubGlobal('ResizeObserver', ResizeObserverStub);
@@ -242,39 +241,27 @@ describe('expanded attachment list', () => {
vi.unstubAllGlobals();
});
it('does not scroll while collapsed', () => {
it('shows every attachment, with no counter to expand', () => {
render(<EmailComposer initialData={DRAFT} />);
expect(chipRow().className).not.toContain('overflow-y-auto');
expect(screen.getByText('invoice-3.pdf')).toBeInTheDocument();
expect(screen.getByText('invoice-11.pdf')).toBeInTheDocument();
expect(screen.queryByText(`+${ATTACHMENTS.length - 3}`)).toBeNull();
});
it('shows only the first three attachments and a counter for the rest', () => {
it('caps its height and scrolls itself', () => {
render(<EmailComposer initialData={DRAFT} />);
expect(screen.getByText('invoice-2.pdf')).toBeInTheDocument();
expect(screen.queryByText('invoice-3.pdf')).not.toBeInTheDocument();
expect(screen.getByText(`+${ATTACHMENTS.length - 3}`)).toBeInTheDocument();
});
it('caps its height and scrolls once expanded', () => {
render(<EmailComposer initialData={DRAFT} />);
fireEvent.click(screen.getByText(`+${ATTACHMENTS.length - 3}`));
const row = chipRow();
expect(screen.getByText('invoice-11.pdf')).toBeInTheDocument();
expect(row.className).toContain('overflow-y-auto');
// Bounded, or the row grows with the attachment count again and takes
// the send toolbar off the bottom of the composer with it.
expect(row.className).toContain('max-h-[');
});
it('stops scrolling again when collapsed back', () => {
it('says how many files and how much they weigh', () => {
render(<EmailComposer initialData={DRAFT} />);
fireEvent.click(screen.getByText(`+${ATTACHMENTS.length - 3}`));
fireEvent.click(screen.getByText('show_less'));
expect(chipRow().className).not.toContain('overflow-y-auto');
expect(screen.getByTestId('composer-attachments-summary')).toHaveTextContent('attachments_summary');
});
});
+23 -25
View File
@@ -68,6 +68,8 @@ import { isFilePreviewable } from "@/lib/file-preview";
import { isEditableEventTarget } from "@/lib/keyboard";
import { isSingleKeyShortcutOff } from "@/lib/single-key-shortcuts";
import { markReplyQuoteHeader } from "@/components/email/reply-quote-collapse";
import { attachmentIcon } from "@/components/email/attachment-chips";
import { attachmentsForDisplay } from "@/lib/compose/attachment-order";
import { showDraftSavedToast } from "@/lib/compose/draft-close-toast";
import { buildQuotedHtmlBlock, serializeEditorContent } from "@/components/email/quoted-html";
import { containsEmbeddedSignature } from "@/components/email/signature-block";
@@ -1244,7 +1246,6 @@ export function EmailComposer({
const [closeDialogKind, setCloseDialogKind] = useState<'close' | 'discard'>('close');
// Closing saves without asking; the question comes only when that save failed.
const [closeSaveFailed, setCloseSaveFailed] = useState(false);
const [showAllAttachments, setShowAllAttachments] = useState(false);
const [previewAttachment, setPreviewAttachment] = useState<ComposerAttachment | null>(null);
// What the checks before sending found (no subject, no text, placeholders,
// a missing attachment, open proofreading issues), asked about in one dialog.
@@ -5538,21 +5539,24 @@ export function EmailComposer({
{/* Attachments */}
{attachments.length > 0 && (
<div className="px-4 py-2 border-t shrink-0">
{attachments.length > 1 && (
<p className="mb-1.5 text-xs text-muted-foreground tabular-nums" data-testid="composer-attachments-summary">
{tUx('attachments_summary', {
count: attachments.length,
size: formatFileSize(attachments.reduce((sum, att) => sum + (att.size || 0), 0)),
})}
</p>
)}
<div
className={cn(
"flex flex-wrap gap-2",
// Collapsed this is three chips and a counter, so it stays
// small. Expanded it is as tall as the attachment count
// makes it, and it sits outside the body's scroll container
// and cannot shrink - so a few dozen files grew it past the
// composer, pushed the send toolbar off the bottom and left
// nothing that scrolled: the list was stuck with its last
// rows and the Send button both unreachable. Cap the
// expanded list and give it a scroller of its own.
showAllAttachments && "max-h-[30vh] overflow-y-auto overscroll-contain",
)}
// Every file shows, wrapping. Past about two rows the list
// scrolls by itself: it sits outside the body's scroller and
// can't shrink, and a few dozen files pushed Send off the
// bottom. Files still uploading or failed come first, so their
// progress and errors are never out of sight.
className="flex flex-wrap gap-2 max-h-[5.25rem] overflow-y-auto overscroll-contain"
data-testid="composer-attachments"
>
{(showAllAttachments ? attachments : attachments.slice(0, 3)).map((att, index) => {
{attachmentsForDisplay(attachments).map(({ att, index }) => {
// Clickable to preview only once it has content (local File or an
// uploaded blob) and the type is previewable; never mid-upload.
const canPreview = !att.uploading && !att.error
@@ -5612,9 +5616,11 @@ export function EmailComposer({
<Loader2 className="w-3 h-3 animate-spin flex-shrink-0" />
) : att.error ? (
<AlertCircle className="w-3 h-3 flex-shrink-0" />
) : (
<Paperclip className="w-3 h-3 flex-shrink-0" />
)}
) : (() => {
// The file's type, as the reader shows it.
const { icon: TypeIcon, className: typeIconClass } = attachmentIcon(att.type, att.name);
return <TypeIcon className={cn("w-3.5 h-3.5 flex-shrink-0", typeIconClass)} aria-hidden />;
})()}
{canPreview ? (
<button
type="button"
@@ -5661,14 +5667,6 @@ export function EmailComposer({
</div>
);
})}
{attachments.length > 3 && (
<button
onClick={() => setShowAllAttachments(prev => !prev)}
className="flex items-center gap-1 px-3 py-1.5 rounded-md text-sm bg-muted text-muted-foreground hover:text-foreground transition-colors"
>
{showAllAttachments ? t('show_less') : `+${attachments.length - 3}`}
</button>
)}
</div>
</div>
)}
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { attachmentsForDisplay } from '../attachment-order';
describe('the order of the composer attachment chips', () => {
it('puts failed, then uploading files first, and keeps the rest in the order added', () => {
const files = [
{ name: 'a.pdf' },
{ name: 'b.pdf', uploading: true },
{ name: 'c.pdf' },
{ name: 'big.zip', uploading: true },
{ name: 'broken.png', error: 'failed' },
];
const shown = attachmentsForDisplay(files);
expect(shown.map(({ att }) => att.name)).toEqual(['broken.png', 'b.pdf', 'big.zip', 'a.pdf', 'c.pdf']);
// Each keeps its place in the composer's list, for Remove.
expect(shown.map(({ index }) => index)).toEqual([4, 1, 3, 0, 2]);
});
});
+14
View File
@@ -0,0 +1,14 @@
/**
* The composer's attachment chips in the order they're shown: failed first,
* then still uploading, then the rest, each group in the order added. The
* list scrolls past about two rows, so the files that need an eye on them
* are the ones always in view. `index` is the place in the composer's list.
*/
export function attachmentsForDisplay<T extends { error?: unknown; uploading?: boolean }>(
attachments: readonly T[],
): Array<{ att: T; index: number }> {
const rank = (att: T) => (att.error ? 0 : att.uploading ? 1 : 2);
return attachments
.map((att, index) => ({ att, index }))
.sort((a, b) => rank(a.att) - rank(b.att) || a.index - b.index);
}
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "تجاهل المسودة",
"save_failed_close": "تعذّر حفظ المسودة. حاول مرة أخرى أو تجاهلها.",
"try_again": "حاول مرة أخرى",
"add_description": "إضافة وصف"
"add_description": "إضافة وصف",
"attachments_summary": "المرفقات: {count}، {size}",
"from_sub_address": "استخدام عنوان فرعي…",
"from_edit_sender": "تعديل المرسل…",
"shortcut_insert_link": "إدراج رابط",
"shortcut_save_draft": "حفظ المسودة",
"shortcut_show_cc": "إظهار نسخة",
"shortcut_show_bcc": "إظهار نسخة مخفية"
},
"confirm_dialog": {
"confirm": "تأكيد",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Descarta l'esborrany",
"save_failed_close": "No s'ha pogut desar l'esborrany. Torneu-ho a provar o descarteu-lo.",
"try_again": "Torna-ho a provar",
"add_description": "Afegeix una descripció"
"add_description": "Afegeix una descripció",
"attachments_summary": "Adjunts: {count}, {size}",
"from_sub_address": "Fes servir una subadreça…",
"from_edit_sender": "Edita el remitent…",
"shortcut_insert_link": "Insereix un enllaç",
"shortcut_save_draft": "Desa l'esborrany",
"shortcut_show_cc": "Mostra Cc",
"shortcut_show_bcc": "Mostra Cco"
},
"confirm_dialog": {
"confirm": "Confirma",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Zahodit koncept",
"save_failed_close": "Koncept se nepodařilo uložit. Zkuste to znovu, nebo ho zahoďte.",
"try_again": "Zkusit znovu",
"add_description": "Přidat popis"
"add_description": "Přidat popis",
"attachments_summary": "Přílohy: {count}, {size}",
"from_sub_address": "Použít podadresu…",
"from_edit_sender": "Upravit odesílatele…",
"shortcut_insert_link": "Vložit odkaz",
"shortcut_save_draft": "Uložit koncept",
"shortcut_show_cc": "Zobrazit kopii",
"shortcut_show_bcc": "Zobrazit skrytou kopii"
},
"confirm_dialog": {
"confirm": "Potvrdit",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Kassér kladde",
"save_failed_close": "Kladden kunne ikke gemmes. Prøv igen, eller kassér den.",
"try_again": "Prøv igen",
"add_description": "Tilføj beskrivelse"
"add_description": "Tilføj beskrivelse",
"attachments_summary": "Vedhæftede filer: {count}, {size}",
"from_sub_address": "Brug en underadresse…",
"from_edit_sender": "Rediger afsender…",
"shortcut_insert_link": "Indsæt link",
"shortcut_save_draft": "Gem kladde",
"shortcut_show_cc": "Vis Cc",
"shortcut_show_bcc": "Vis Bcc"
},
"confirm_dialog": {
"confirm": "Bekræft",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Entwurf verwerfen",
"save_failed_close": "Der Entwurf konnte nicht gespeichert werden. Versuchen Sie es erneut oder verwerfen Sie ihn.",
"try_again": "Erneut versuchen",
"add_description": "Beschreibung hinzufügen"
"add_description": "Beschreibung hinzufügen",
"attachments_summary": "Anhänge: {count}, {size}",
"from_sub_address": "Unteradresse verwenden…",
"from_edit_sender": "Absender bearbeiten…",
"shortcut_insert_link": "Link einfügen",
"shortcut_save_draft": "Entwurf speichern",
"shortcut_show_cc": "Cc anzeigen",
"shortcut_show_bcc": "Bcc anzeigen"
},
"confirm_dialog": {
"confirm": "Bestätigen",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Discard draft",
"save_failed_close": "The draft could not be saved. Try again, or discard it.",
"try_again": "Try again",
"add_description": "Add description"
"add_description": "Add description",
"attachments_summary": "Attachments: {count}, {size}",
"from_sub_address": "Use a sub-address…",
"from_edit_sender": "Edit sender…",
"shortcut_insert_link": "Insert link",
"shortcut_save_draft": "Save draft",
"shortcut_show_cc": "Show Cc",
"shortcut_show_bcc": "Show Bcc"
},
"confirm_dialog": {
"confirm": "Confirm",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Descartar borrador",
"save_failed_close": "No se pudo guardar el borrador. Inténtelo de nuevo o descártelo.",
"try_again": "Reintentar",
"add_description": "Añadir descripción"
"add_description": "Añadir descripción",
"attachments_summary": "Adjuntos: {count}, {size}",
"from_sub_address": "Usar una subdirección…",
"from_edit_sender": "Editar remitente…",
"shortcut_insert_link": "Insertar enlace",
"shortcut_save_draft": "Guardar borrador",
"shortcut_show_cc": "Mostrar CC",
"shortcut_show_bcc": "Mostrar CCO"
},
"confirm_dialog": {
"confirm": "Confirmar",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Loobu mustandist",
"save_failed_close": "Mustandit ei saanud salvestada. Proovige uuesti või loobuge sellest.",
"try_again": "Proovi uuesti",
"add_description": "Lisa kirjeldus"
"add_description": "Lisa kirjeldus",
"attachments_summary": "Manused: {count}, {size}",
"from_sub_address": "Kasuta alamaadressi…",
"from_edit_sender": "Muuda saatjat…",
"shortcut_insert_link": "Lisa link",
"shortcut_save_draft": "Salvesta mustand",
"shortcut_show_cc": "Näita koopiat",
"shortcut_show_bcc": "Näita pimekoopiat"
},
"confirm_dialog": {
"confirm": "Kinnita",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "دور انداختن پیش‌نویس",
"save_failed_close": "پیش‌نویس ذخیره نشد. دوباره تلاش کنید یا آن را دور بیندازید.",
"try_again": "تلاش دوباره",
"add_description": "افزودن توضیح"
"add_description": "افزودن توضیح",
"attachments_summary": "پیوست‌ها: {count}، {size}",
"from_sub_address": "استفاده از زیرنشانی…",
"from_edit_sender": "ویرایش فرستنده…",
"shortcut_insert_link": "درج پیوند",
"shortcut_save_draft": "ذخیرهٔ پیش‌نویس",
"shortcut_show_cc": "نمایش رونوشت",
"shortcut_show_bcc": "نمایش رونوشت پنهان"
},
"confirm_dialog": {
"confirm": "تأیید",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Supprimer le brouillon",
"save_failed_close": "Le brouillon n'a pas pu être enregistré. Réessayez ou supprimez-le.",
"try_again": "Réessayer",
"add_description": "Ajouter une description"
"add_description": "Ajouter une description",
"attachments_summary": "Pièces jointes : {count}, {size}",
"from_sub_address": "Utiliser une sous-adresse…",
"from_edit_sender": "Modifier l'expéditeur…",
"shortcut_insert_link": "Insérer un lien",
"shortcut_save_draft": "Enregistrer le brouillon",
"shortcut_show_cc": "Afficher Cc",
"shortcut_show_bcc": "Afficher Cci"
},
"confirm_dialog": {
"confirm": "Confirmer",
+8 -1
View File
@@ -1161,7 +1161,14 @@
"discard_draft": "מחיקת הטיוטה",
"save_failed_close": "לא ניתן היה לשמור את הטיוטה. נסו שוב או מחקו אותה.",
"try_again": "ניסיון נוסף",
"add_description": "הוספת תיאור"
"add_description": "הוספת תיאור",
"attachments_summary": "קבצים מצורפים: {count}, {size}",
"from_sub_address": "שימוש בכתובת משנה…",
"from_edit_sender": "עריכת השולח…",
"shortcut_insert_link": "הוספת קישור",
"shortcut_save_draft": "שמירת טיוטה",
"shortcut_show_cc": "הצגת עותק",
"shortcut_show_bcc": "הצגת עותק מוסתר"
},
"confirm_dialog": {
"confirm": "אשר",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Piszkozat elvetése",
"save_failed_close": "A piszkozatot nem sikerült menteni. Próbálja újra, vagy vesse el.",
"try_again": "Újra",
"add_description": "Leírás hozzáadása"
"add_description": "Leírás hozzáadása",
"attachments_summary": "Mellékletek: {count}, {size}",
"from_sub_address": "Alcím használata…",
"from_edit_sender": "Feladó szerkesztése…",
"shortcut_insert_link": "Hivatkozás beszúrása",
"shortcut_save_draft": "Piszkozat mentése",
"shortcut_show_cc": "Másolat megjelenítése",
"shortcut_show_bcc": "Titkos másolat megjelenítése"
},
"confirm_dialog": {
"confirm": "Megerősítés",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Elimina bozza",
"save_failed_close": "Impossibile salvare la bozza. Riprova o eliminala.",
"try_again": "Riprova",
"add_description": "Aggiungi descrizione"
"add_description": "Aggiungi descrizione",
"attachments_summary": "Allegati: {count}, {size}",
"from_sub_address": "Usa un sottoindirizzo…",
"from_edit_sender": "Modifica mittente…",
"shortcut_insert_link": "Inserisci link",
"shortcut_save_draft": "Salva bozza",
"shortcut_show_cc": "Mostra Cc",
"shortcut_show_bcc": "Mostra Ccn"
},
"confirm_dialog": {
"confirm": "Conferma",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "下書きを破棄",
"save_failed_close": "下書きを保存できませんでした。もう一度試すか、破棄してください。",
"try_again": "再試行",
"add_description": "説明を追加"
"add_description": "説明を追加",
"attachments_summary": "添付ファイル: {count} 件、{size}",
"from_sub_address": "サブアドレスを使用…",
"from_edit_sender": "差出人を編集…",
"shortcut_insert_link": "リンクを挿入",
"shortcut_save_draft": "下書きを保存",
"shortcut_show_cc": "Cc を表示",
"shortcut_show_bcc": "Bcc を表示"
},
"confirm_dialog": {
"confirm": "確認",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "임시 보관 메일 삭제",
"save_failed_close": "임시 보관 메일을 저장하지 못했습니다. 다시 시도하거나 삭제하세요.",
"try_again": "다시 시도",
"add_description": "설명 추가"
"add_description": "설명 추가",
"attachments_summary": "첨부 파일: {count}개, {size}",
"from_sub_address": "하위 주소 사용…",
"from_edit_sender": "보낸 사람 편집…",
"shortcut_insert_link": "링크 삽입",
"shortcut_save_draft": "임시 저장",
"shortcut_show_cc": "참조 표시",
"shortcut_show_bcc": "숨은 참조 표시"
},
"confirm_dialog": {
"confirm": "확인",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Atmest melnrakstu",
"save_failed_close": "Melnrakstu neizdevās saglabāt. Mēģiniet vēlreiz vai atmetiet to.",
"try_again": "Mēģināt vēlreiz",
"add_description": "Pievienot aprakstu"
"add_description": "Pievienot aprakstu",
"attachments_summary": "Pielikumi: {count}, {size}",
"from_sub_address": "Izmantot apakšadresi…",
"from_edit_sender": "Rediģēt sūtītāju…",
"shortcut_insert_link": "Ievietot saiti",
"shortcut_save_draft": "Saglabāt melnrakstu",
"shortcut_show_cc": "Rādīt kopiju",
"shortcut_show_bcc": "Rādīt diskrēto kopiju"
},
"confirm_dialog": {
"confirm": "Apstiprināt",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Ноорог устгах",
"save_failed_close": "Ноорогийг хадгалж чадсангүй. Дахин оролдох эсвэл устгана уу.",
"try_again": "Дахин оролдох",
"add_description": "Тайлбар нэмэх"
"add_description": "Тайлбар нэмэх",
"attachments_summary": "Хавсралт: {count}, {size}",
"from_sub_address": "Дэд хаяг ашиглах…",
"from_edit_sender": "Илгээгчийг засах…",
"shortcut_insert_link": "Холбоос оруулах",
"shortcut_save_draft": "Ноорог хадгалах",
"shortcut_show_cc": "Хуулбар харуулах",
"shortcut_show_bcc": "Нууц хуулбар харуулах"
},
"confirm_dialog": {
"confirm": "Баталгаажуулах",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Forkast utkast",
"save_failed_close": "Utkastet kunne ikke lagres. Prøv igjen, eller forkast det.",
"try_again": "Prøv igjen",
"add_description": "Legg til beskrivelse"
"add_description": "Legg til beskrivelse",
"attachments_summary": "Vedlegg: {count}, {size}",
"from_sub_address": "Bruk en underadresse…",
"from_edit_sender": "Rediger avsender…",
"shortcut_insert_link": "Sett inn lenke",
"shortcut_save_draft": "Lagre utkast",
"shortcut_show_cc": "Vis kopi",
"shortcut_show_bcc": "Vis blindkopi"
},
"confirm_dialog": {
"confirm": "Bekreft",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Concept verwijderen",
"save_failed_close": "Het concept kon niet worden opgeslagen. Probeer het opnieuw of verwijder het.",
"try_again": "Opnieuw proberen",
"add_description": "Beschrijving toevoegen"
"add_description": "Beschrijving toevoegen",
"attachments_summary": "Bijlagen: {count}, {size}",
"from_sub_address": "Subadres gebruiken…",
"from_edit_sender": "Afzender bewerken…",
"shortcut_insert_link": "Link invoegen",
"shortcut_save_draft": "Concept opslaan",
"shortcut_show_cc": "Cc tonen",
"shortcut_show_bcc": "Bcc tonen"
},
"confirm_dialog": {
"confirm": "Bevestigen",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Odrzuć wersję roboczą",
"save_failed_close": "Nie udało się zapisać wersji roboczej. Spróbuj ponownie lub ją odrzuć.",
"try_again": "Spróbuj ponownie",
"add_description": "Dodaj opis"
"add_description": "Dodaj opis",
"attachments_summary": "Załączniki: {count}, {size}",
"from_sub_address": "Użyj podadresu…",
"from_edit_sender": "Edytuj nadawcę…",
"shortcut_insert_link": "Wstaw link",
"shortcut_save_draft": "Zapisz wersję roboczą",
"shortcut_show_cc": "Pokaż DW",
"shortcut_show_bcc": "Pokaż UDW"
},
"confirm_dialog": {
"confirm": "Potwierdź",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Descartar rascunho",
"save_failed_close": "Não foi possível guardar o rascunho. Tente novamente ou descarte-o.",
"try_again": "Tentar novamente",
"add_description": "Adicionar descrição"
"add_description": "Adicionar descrição",
"attachments_summary": "Anexos: {count}, {size}",
"from_sub_address": "Usar um subendereço…",
"from_edit_sender": "Editar remetente…",
"shortcut_insert_link": "Inserir ligação",
"shortcut_save_draft": "Guardar rascunho",
"shortcut_show_cc": "Mostrar Cc",
"shortcut_show_bcc": "Mostrar Bcc"
},
"confirm_dialog": {
"confirm": "Confirmar",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Renunță la ciornă",
"save_failed_close": "Ciorna nu a putut fi salvată. Încercați din nou sau renunțați la ea.",
"try_again": "Încearcă din nou",
"add_description": "Adaugă o descriere"
"add_description": "Adaugă o descriere",
"attachments_summary": "Atașamente: {count}, {size}",
"from_sub_address": "Folosește o subadresă…",
"from_edit_sender": "Editează expeditorul…",
"shortcut_insert_link": "Inserează un link",
"shortcut_save_draft": "Salvează ciorna",
"shortcut_show_cc": "Afișează Cc",
"shortcut_show_bcc": "Afișează Bcc"
},
"confirm_dialog": {
"confirm": "Confirmare",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Удалить черновик",
"save_failed_close": "Не удалось сохранить черновик. Попробуйте ещё раз или удалите его.",
"try_again": "Повторить",
"add_description": "Добавить описание"
"add_description": "Добавить описание",
"attachments_summary": "Вложения: {count}, {size}",
"from_sub_address": "Использовать подадрес…",
"from_edit_sender": "Изменить отправителя…",
"shortcut_insert_link": "Вставить ссылку",
"shortcut_save_draft": "Сохранить черновик",
"shortcut_show_cc": "Показать копию",
"shortcut_show_bcc": "Показать скрытую копию"
},
"confirm_dialog": {
"confirm": "Подтвердить",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Zahodiť koncept",
"save_failed_close": "Koncept sa nepodarilo uložiť. Skúste to znova alebo ho zahoďte.",
"try_again": "Skúsiť znova",
"add_description": "Pridať popis"
"add_description": "Pridať popis",
"attachments_summary": "Prílohy: {count}, {size}",
"from_sub_address": "Použiť podadresu…",
"from_edit_sender": "Upraviť odosielateľa…",
"shortcut_insert_link": "Vložiť odkaz",
"shortcut_save_draft": "Uložiť koncept",
"shortcut_show_cc": "Zobraziť kópiu",
"shortcut_show_bcc": "Zobraziť skrytú kópiu"
},
"confirm_dialog": {
"confirm": "Potvrdiť",
+8 -1
View File
@@ -1566,7 +1566,14 @@
"discard_draft": "ทิ้งฉบับร่าง",
"save_failed_close": "บันทึกฉบับร่างไม่ได้ ลองอีกครั้งหรือทิ้งไป",
"try_again": "ลองอีกครั้ง",
"add_description": "เพิ่มคำอธิบาย"
"add_description": "เพิ่มคำอธิบาย",
"attachments_summary": "ไฟล์แนบ: {count} ไฟล์, {size}",
"from_sub_address": "ใช้ที่อยู่ย่อย…",
"from_edit_sender": "แก้ไขผู้ส่ง…",
"shortcut_insert_link": "แทรกลิงก์",
"shortcut_save_draft": "บันทึกฉบับร่าง",
"shortcut_show_cc": "แสดงสำเนา",
"shortcut_show_bcc": "แสดงสำเนาลับ"
},
"email_viewer": {
"read_receipt": {
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Taslağı sil",
"save_failed_close": "Taslak kaydedilemedi. Yeniden deneyin ya da silin.",
"try_again": "Yeniden dene",
"add_description": "Açıklama ekle"
"add_description": "Açıklama ekle",
"attachments_summary": "Ekler: {count}, {size}",
"from_sub_address": "Alt adres kullan…",
"from_edit_sender": "Göndereni düzenle…",
"shortcut_insert_link": "Bağlantı ekle",
"shortcut_save_draft": "Taslağı kaydet",
"shortcut_show_cc": "Bilgiyi göster",
"shortcut_show_bcc": "Gizli bilgiyi göster"
},
"confirm_dialog": {
"confirm": "Onayla",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "Видалити чернетку",
"save_failed_close": "Не вдалося зберегти чернетку. Спробуйте ще раз або видаліть її.",
"try_again": "Спробувати ще раз",
"add_description": "Додати опис"
"add_description": "Додати опис",
"attachments_summary": "Вкладення: {count}, {size}",
"from_sub_address": "Використати підадресу…",
"from_edit_sender": "Змінити відправника…",
"shortcut_insert_link": "Вставити посилання",
"shortcut_save_draft": "Зберегти чернетку",
"shortcut_show_cc": "Показати копію",
"shortcut_show_bcc": "Показати приховану копію"
},
"confirm_dialog": {
"confirm": "Підтвердити",
+8 -1
View File
@@ -1230,7 +1230,14 @@
"discard_draft": "Hủy bản nháp",
"save_failed_close": "Không lưu được bản nháp. Hãy thử lại hoặc hủy bản nháp.",
"try_again": "Thử lại",
"add_description": "Thêm mô tả"
"add_description": "Thêm mô tả",
"attachments_summary": "Tệp đính kèm: {count}, {size}",
"from_sub_address": "Dùng địa chỉ phụ…",
"from_edit_sender": "Sửa người gửi…",
"shortcut_insert_link": "Chèn liên kết",
"shortcut_save_draft": "Lưu bản nháp",
"shortcut_show_cc": "Hiện Cc",
"shortcut_show_bcc": "Hiện Bcc"
},
"confirm_dialog": {
"confirm": "Xác nhận",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "捨棄草稿",
"save_failed_close": "無法儲存草稿。請再試一次或捨棄草稿。",
"try_again": "再試一次",
"add_description": "新增描述"
"add_description": "新增描述",
"attachments_summary": "附件:{count} 個,{size}",
"from_sub_address": "使用子地址…",
"from_edit_sender": "編輯寄件者…",
"shortcut_insert_link": "插入連結",
"shortcut_save_draft": "儲存草稿",
"shortcut_show_cc": "顯示副本",
"shortcut_show_bcc": "顯示密件副本"
},
"confirm_dialog": {
"confirm": "確認",
+8 -1
View File
@@ -1218,7 +1218,14 @@
"discard_draft": "舍弃草稿",
"save_failed_close": "无法保存草稿。请重试或舍弃草稿。",
"try_again": "重试",
"add_description": "添加描述"
"add_description": "添加描述",
"attachments_summary": "附件:{count} 个,{size}",
"from_sub_address": "使用子地址…",
"from_edit_sender": "编辑发件人…",
"shortcut_insert_link": "插入链接",
"shortcut_save_draft": "保存草稿",
"shortcut_show_cc": "显示抄送",
"shortcut_show_bcc": "显示密送"
},
"confirm_dialog": {
"confirm": "确认",