feat: add settings template for multi-email .zip filename
This commit is contained in:
@@ -8,9 +8,12 @@ import { RotateCcw } from "lucide-react";
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ATTACHMENT_TEMPLATE,
|
DEFAULT_ATTACHMENT_TEMPLATE,
|
||||||
|
DEFAULT_BUNDLE_TEMPLATE,
|
||||||
DEFAULT_EMAIL_TEMPLATE,
|
DEFAULT_EMAIL_TEMPLATE,
|
||||||
EMAIL_TOKENS,
|
EMAIL_TOKENS,
|
||||||
ATTACHMENT_TOKENS,
|
ATTACHMENT_TOKENS,
|
||||||
|
BUNDLE_TOKENS,
|
||||||
|
bundleExportFilename,
|
||||||
emailExportFilename,
|
emailExportFilename,
|
||||||
attachmentDownloadFilename,
|
attachmentDownloadFilename,
|
||||||
buildSampleEmail,
|
buildSampleEmail,
|
||||||
@@ -130,6 +133,7 @@ export function DownloadsSettings() {
|
|||||||
const {
|
const {
|
||||||
emailDownloadTemplate,
|
emailDownloadTemplate,
|
||||||
attachmentDownloadTemplate,
|
attachmentDownloadTemplate,
|
||||||
|
bundleDownloadTemplate,
|
||||||
filenameSpaceReplacement,
|
filenameSpaceReplacement,
|
||||||
filenameLowercase,
|
filenameLowercase,
|
||||||
filenameStripDiacritics,
|
filenameStripDiacritics,
|
||||||
@@ -158,6 +162,10 @@ export function DownloadsSettings() {
|
|||||||
() => ({ ...transform, template: attachmentDownloadTemplate || DEFAULT_ATTACHMENT_TEMPLATE }),
|
() => ({ ...transform, template: attachmentDownloadTemplate || DEFAULT_ATTACHMENT_TEMPLATE }),
|
||||||
[transform, attachmentDownloadTemplate],
|
[transform, attachmentDownloadTemplate],
|
||||||
);
|
);
|
||||||
|
const bundleOptions: EmailFilenameOptions = useMemo(
|
||||||
|
() => ({ ...transform, template: bundleDownloadTemplate || DEFAULT_BUNDLE_TEMPLATE }),
|
||||||
|
[transform, bundleDownloadTemplate],
|
||||||
|
);
|
||||||
|
|
||||||
const emlPreview = useMemo(
|
const emlPreview = useMemo(
|
||||||
() => emailExportFilename(sampleEmail, emailOptions),
|
() => emailExportFilename(sampleEmail, emailOptions),
|
||||||
@@ -167,6 +175,12 @@ export function DownloadsSettings() {
|
|||||||
() => attachmentDownloadFilename(sampleEmail, sampleAttachment, attachmentOptions),
|
() => attachmentDownloadFilename(sampleEmail, sampleAttachment, attachmentOptions),
|
||||||
[sampleEmail, sampleAttachment, attachmentOptions],
|
[sampleEmail, sampleAttachment, attachmentOptions],
|
||||||
);
|
);
|
||||||
|
const bundlePreview = useMemo(
|
||||||
|
// Render with the email's fixed sample date so the preview is stable as the
|
||||||
|
// user types in the template field.
|
||||||
|
() => bundleExportFilename(3, bundleOptions, sampleEmail.receivedAt ?? undefined),
|
||||||
|
[bundleOptions, sampleEmail],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection title={t("title")} description={t("description")}>
|
<SettingsSection title={t("title")} description={t("description")}>
|
||||||
@@ -194,6 +208,18 @@ export function DownloadsSettings() {
|
|||||||
previewLabel={t("preview")}
|
previewLabel={t("preview")}
|
||||||
placeholder={DEFAULT_ATTACHMENT_TEMPLATE}
|
placeholder={DEFAULT_ATTACHMENT_TEMPLATE}
|
||||||
/>
|
/>
|
||||||
|
<TemplateEditor
|
||||||
|
label={t("bundle_template.label")}
|
||||||
|
description={t("bundle_template.description")}
|
||||||
|
value={bundleDownloadTemplate}
|
||||||
|
defaultValue={DEFAULT_BUNDLE_TEMPLATE}
|
||||||
|
tokens={BUNDLE_TOKENS}
|
||||||
|
preview={bundlePreview}
|
||||||
|
onChange={(next) => updateSetting("bundleDownloadTemplate", next)}
|
||||||
|
resetLabel={t("reset")}
|
||||||
|
previewLabel={t("preview")}
|
||||||
|
placeholder={DEFAULT_BUNDLE_TEMPLATE}
|
||||||
|
/>
|
||||||
<SettingItem label={t("spaces.label")} description={t("spaces.description")}>
|
<SettingItem label={t("spaces.label")} description={t("spaces.description")}>
|
||||||
<Select
|
<Select
|
||||||
value={filenameSpaceReplacement}
|
value={filenameSpaceReplacement}
|
||||||
|
|||||||
+26
-10
@@ -8,7 +8,13 @@ import { useAuthStore } from "@/stores/auth-store";
|
|||||||
import { useDragDropContext } from "@/contexts/drag-drop-context";
|
import { useDragDropContext } from "@/contexts/drag-drop-context";
|
||||||
import { useUIStore } from "@/stores/ui-store";
|
import { useUIStore } from "@/stores/ui-store";
|
||||||
import { isDragOutSupported } from "@/hooks/use-attachment-drag";
|
import { isDragOutSupported } from "@/hooks/use-attachment-drag";
|
||||||
import { emailExportFilename, DEFAULT_EMAIL_TEMPLATE, type EmailFilenameOptions } from "@/lib/download-filename";
|
import {
|
||||||
|
bundleExportFilename,
|
||||||
|
DEFAULT_BUNDLE_TEMPLATE,
|
||||||
|
DEFAULT_EMAIL_TEMPLATE,
|
||||||
|
emailExportFilename,
|
||||||
|
type EmailFilenameOptions,
|
||||||
|
} from "@/lib/download-filename";
|
||||||
import { useSettingsStore } from "@/stores/settings-store";
|
import { useSettingsStore } from "@/stores/settings-store";
|
||||||
|
|
||||||
interface UseEmailDragOptions {
|
interface UseEmailDragOptions {
|
||||||
@@ -50,8 +56,8 @@ function createDragPreview(count: number): HTMLElement {
|
|||||||
return preview;
|
return preview;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleFilename(count: number): string {
|
function bundleFilename(count: number, options: EmailFilenameOptions): string {
|
||||||
return `emails-${count}.zip`;
|
return bundleExportFilename(count, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shared bundle cache. The .zip is keyed by the sorted list of email IDs in
|
// Shared bundle cache. The .zip is keyed by the sorted list of email IDs in
|
||||||
@@ -95,7 +101,12 @@ async function buildEmailZip(client: IJMAPClient, emails: Email[], options: Emai
|
|||||||
return URL.createObjectURL(zipBlob);
|
return URL.createObjectURL(zipBlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
function prefetchEmailBundle(client: IJMAPClient, emails: Email[], options: EmailFilenameOptions): void {
|
function prefetchEmailBundle(
|
||||||
|
client: IJMAPClient,
|
||||||
|
emails: Email[],
|
||||||
|
emailOptions: EmailFilenameOptions,
|
||||||
|
bundleOptions: EmailFilenameOptions,
|
||||||
|
): void {
|
||||||
const key = selectionKey(emails.map((e) => e.id));
|
const key = selectionKey(emails.map((e) => e.id));
|
||||||
if (currentBundle && currentBundle.key === key) return;
|
if (currentBundle && currentBundle.key === key) return;
|
||||||
if (currentBundle?.url) {
|
if (currentBundle?.url) {
|
||||||
@@ -104,11 +115,11 @@ function prefetchEmailBundle(client: IJMAPClient, emails: Email[], options: Emai
|
|||||||
}
|
}
|
||||||
const entry: BundleEntry = {
|
const entry: BundleEntry = {
|
||||||
key,
|
key,
|
||||||
name: bundleFilename(emails.length),
|
name: bundleFilename(emails.length, bundleOptions),
|
||||||
url: null,
|
url: null,
|
||||||
promise: null,
|
promise: null,
|
||||||
};
|
};
|
||||||
entry.promise = buildEmailZip(client, emails, options)
|
entry.promise = buildEmailZip(client, emails, emailOptions)
|
||||||
.then((url) => {
|
.then((url) => {
|
||||||
if (url && currentBundle === entry) entry.url = url;
|
if (url && currentBundle === entry) entry.url = url;
|
||||||
return url;
|
return url;
|
||||||
@@ -131,6 +142,7 @@ export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailD
|
|||||||
const isMobile = useUIStore((state) => state.isMobile);
|
const isMobile = useUIStore((state) => state.isMobile);
|
||||||
const client = useAuthStore((state) => state.client);
|
const client = useAuthStore((state) => state.client);
|
||||||
const template = useSettingsStore((s) => s.emailDownloadTemplate) || DEFAULT_EMAIL_TEMPLATE;
|
const template = useSettingsStore((s) => s.emailDownloadTemplate) || DEFAULT_EMAIL_TEMPLATE;
|
||||||
|
const bundleTemplate = useSettingsStore((s) => s.bundleDownloadTemplate) || DEFAULT_BUNDLE_TEMPLATE;
|
||||||
const spaceReplacement = useSettingsStore((s) => s.filenameSpaceReplacement);
|
const spaceReplacement = useSettingsStore((s) => s.filenameSpaceReplacement);
|
||||||
const lowercase = useSettingsStore((s) => s.filenameLowercase);
|
const lowercase = useSettingsStore((s) => s.filenameLowercase);
|
||||||
const stripDiacritics = useSettingsStore((s) => s.filenameStripDiacritics);
|
const stripDiacritics = useSettingsStore((s) => s.filenameStripDiacritics);
|
||||||
@@ -139,6 +151,10 @@ export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailD
|
|||||||
() => ({ template, spaceReplacement, lowercase, stripDiacritics, collapseSeparators }),
|
() => ({ template, spaceReplacement, lowercase, stripDiacritics, collapseSeparators }),
|
||||||
[template, spaceReplacement, lowercase, stripDiacritics, collapseSeparators],
|
[template, spaceReplacement, lowercase, stripDiacritics, collapseSeparators],
|
||||||
);
|
);
|
||||||
|
const bundleOptions: EmailFilenameOptions = useMemo(
|
||||||
|
() => ({ template: bundleTemplate, spaceReplacement, lowercase, stripDiacritics, collapseSeparators }),
|
||||||
|
[bundleTemplate, spaceReplacement, lowercase, stripDiacritics, collapseSeparators],
|
||||||
|
);
|
||||||
|
|
||||||
const dragOutEnabled = !isMobile && isDragOutSupported() && !!client;
|
const dragOutEnabled = !isMobile && isDragOutSupported() && !!client;
|
||||||
const singleBlobUrlRef = useRef<string | null>(null);
|
const singleBlobUrlRef = useRef<string | null>(null);
|
||||||
@@ -181,12 +197,12 @@ export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailD
|
|||||||
const selected = emails.filter((em) => selectedEmailIds.has(em.id));
|
const selected = emails.filter((em) => selectedEmailIds.has(em.id));
|
||||||
// Only worth bundling when at least one selected email has a blobId.
|
// Only worth bundling when at least one selected email has a blobId.
|
||||||
if (selected.some((em) => em.blobId)) {
|
if (selected.some((em) => em.blobId)) {
|
||||||
prefetchEmailBundle(client, selected, filenameOptions);
|
prefetchEmailBundle(client, selected, filenameOptions, bundleOptions);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prefetchSingle();
|
prefetchSingle();
|
||||||
}
|
}
|
||||||
}, [dragOutEnabled, client, selectedEmailIds, email.id, emails, prefetchSingle, filenameOptions]);
|
}, [dragOutEnabled, client, selectedEmailIds, email.id, emails, prefetchSingle, filenameOptions, bundleOptions]);
|
||||||
|
|
||||||
const handleDragStart = useCallback((e: DragEvent<HTMLDivElement>) => {
|
const handleDragStart = useCallback((e: DragEvent<HTMLDivElement>) => {
|
||||||
// Determine which emails to drag:
|
// Determine which emails to drag:
|
||||||
@@ -237,7 +253,7 @@ export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailD
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Kick off the bundle build for the next attempt.
|
// Kick off the bundle build for the next attempt.
|
||||||
prefetchEmailBundle(client, emailsToDrag, filenameOptions);
|
prefetchEmailBundle(client, emailsToDrag, filenameOptions, bundleOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +268,7 @@ export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailD
|
|||||||
});
|
});
|
||||||
|
|
||||||
startDrag(emailsToDrag, sourceMailboxId);
|
startDrag(emailsToDrag, sourceMailboxId);
|
||||||
}, [email, selectedEmailIds, emails, sourceMailboxId, startDrag, threadEmails, dragOutEnabled, client, prefetchSingle, filenameOptions]);
|
}, [email, selectedEmailIds, emails, sourceMailboxId, startDrag, threadEmails, dragOutEnabled, client, prefetchSingle, filenameOptions, bundleOptions]);
|
||||||
|
|
||||||
const handleDragEnd = useCallback(() => {
|
const handleDragEnd = useCallback(() => {
|
||||||
endDrag();
|
endDrag();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const DEFAULT_TRANSFORM: Required<FilenameTransformOptions> = {
|
|||||||
|
|
||||||
export const DEFAULT_EMAIL_TEMPLATE = "{date} ({from}-{to}) {subject}";
|
export const DEFAULT_EMAIL_TEMPLATE = "{date} ({from}-{to}) {subject}";
|
||||||
export const DEFAULT_ATTACHMENT_TEMPLATE = "{filename}";
|
export const DEFAULT_ATTACHMENT_TEMPLATE = "{filename}";
|
||||||
|
export const DEFAULT_BUNDLE_TEMPLATE = "emails-{count}";
|
||||||
|
|
||||||
export const EMAIL_TOKENS: { token: string; description: string }[] = [
|
export const EMAIL_TOKENS: { token: string; description: string }[] = [
|
||||||
{ token: "date", description: "Full date and time, e.g. 2026-05-22 14.05.33" },
|
{ token: "date", description: "Full date and time, e.g. 2026-05-22 14.05.33" },
|
||||||
@@ -53,6 +54,16 @@ export const ATTACHMENT_TOKENS: { token: string; description: string }[] = [
|
|||||||
{ token: "ext", description: "Attachment file extension without leading dot" },
|
{ token: "ext", description: "Attachment file extension without leading dot" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const BUNDLE_TOKENS: { token: string; description: string }[] = [
|
||||||
|
{ token: "count", description: "Number of emails in the bundle" },
|
||||||
|
{ token: "date", description: "Current date and time, e.g. 2026-05-22 14.05.33" },
|
||||||
|
{ token: "date_short", description: "Current date, e.g. 2026-05-22" },
|
||||||
|
{ token: "time", description: "Current time, e.g. 14.05.33" },
|
||||||
|
{ token: "year", description: "4-digit year" },
|
||||||
|
{ token: "month", description: "2-digit month" },
|
||||||
|
{ token: "day", description: "2-digit day" },
|
||||||
|
];
|
||||||
|
|
||||||
function sanitizePart(input: string, maxLen = 80): string {
|
function sanitizePart(input: string, maxLen = 80): string {
|
||||||
const cleaned = input
|
const cleaned = input
|
||||||
.replace(SAFE_CHARS, "_")
|
.replace(SAFE_CHARS, "_")
|
||||||
@@ -211,6 +222,25 @@ export function attachmentDownloadFilename(
|
|||||||
return `${transformedStem}.${transformedExt}`;
|
return `${transformedStem}.${transformedExt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function bundleVars(count: number, iso?: string): Record<string, string> {
|
||||||
|
const dp = dateParts(iso ?? new Date().toISOString());
|
||||||
|
return { ...dp, count: String(count) };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bundleExportFilename(
|
||||||
|
count: number,
|
||||||
|
options: EmailFilenameOptions | string = {},
|
||||||
|
iso?: string,
|
||||||
|
): string {
|
||||||
|
const opts = typeof options === "string" ? { template: options } : options;
|
||||||
|
const template = opts.template ?? DEFAULT_BUNDLE_TEMPLATE;
|
||||||
|
const rendered = renderRaw(template, bundleVars(count, iso));
|
||||||
|
const cleaned = sanitizePart(rendered, 200);
|
||||||
|
const transformed = applyTransforms(cleaned, opts);
|
||||||
|
const stem = transformed.slice(0, 200) || "emails";
|
||||||
|
return `${stem}.zip`;
|
||||||
|
}
|
||||||
|
|
||||||
// Build a synthetic email for previewing templates in the settings UI.
|
// Build a synthetic email for previewing templates in the settings UI.
|
||||||
export function buildSampleEmail(): Email {
|
export function buildSampleEmail(): Email {
|
||||||
// Use a fixed date so the preview doesn't churn as the user types.
|
// Use a fixed date so the preview doesn't churn as the user types.
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Název souboru přílohy",
|
"label": "Název souboru přílohy",
|
||||||
"description": "Šablona použitá při stahování nebo přetahování přílohy. Pokud vynecháte {filename} a {ext}, původní přípona se zachová."
|
"description": "Šablona použitá při stahování nebo přetahování přílohy. Pokud vynecháte {filename} a {ext}, původní přípona se zachová."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Název .zip souboru s více e-maily",
|
||||||
|
"description": "Šablona použitá při přetažení nebo stažení několika vybraných e-mailů jako jediného .zip archivu. Přípona .zip se přidává automaticky."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Mezery",
|
"label": "Mezery",
|
||||||
"description": "Nahradit mezery ve výsledném názvu souboru jiným znakem.",
|
"description": "Nahradit mezery ve výsledném názvu souboru jiným znakem.",
|
||||||
|
|||||||
@@ -1512,6 +1512,10 @@
|
|||||||
"label": "Filnavn på vedhæftet fil",
|
"label": "Filnavn på vedhæftet fil",
|
||||||
"description": "Skabelon som bruges når du downloader eller trækker en vedhæftet fil ud. Hvis du udelader {filename} og {ext}, bevares den oprindelige endelse."
|
"description": "Skabelon som bruges når du downloader eller trækker en vedhæftet fil ud. Hvis du udelader {filename} og {ext}, bevares den oprindelige endelse."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Filnavn for .zip med flere e-mails",
|
||||||
|
"description": "Skabelon som bruges når du trækker ud eller downloader flere valgte e-mails som ét .zip-arkiv. Endelsen .zip tilføjes automatisk."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Mellemrum",
|
"label": "Mellemrum",
|
||||||
"description": "Erstat mellemrum i det endelige filnavn med et andet tegn.",
|
"description": "Erstat mellemrum i det endelige filnavn med et andet tegn.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Anhang-Dateiname",
|
"label": "Anhang-Dateiname",
|
||||||
"description": "Vorlage zum Herunterladen oder Herausziehen eines Anhangs. Wenn {filename} und {ext} fehlen, bleibt die ursprüngliche Endung erhalten."
|
"description": "Vorlage zum Herunterladen oder Herausziehen eines Anhangs. Wenn {filename} und {ext} fehlen, bleibt die ursprüngliche Endung erhalten."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Mehrere E-Mails als .zip",
|
||||||
|
"description": "Vorlage, die beim Herausziehen oder Herunterladen mehrerer ausgewählter E-Mails als einzelnes .zip-Archiv verwendet wird. Die Endung .zip wird automatisch ergänzt."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Leerzeichen",
|
"label": "Leerzeichen",
|
||||||
"description": "Ersetze Leerzeichen im Dateinamen durch ein anderes Zeichen.",
|
"description": "Ersetze Leerzeichen im Dateinamen durch ein anderes Zeichen.",
|
||||||
|
|||||||
@@ -1512,6 +1512,10 @@
|
|||||||
"label": "Attachment filename",
|
"label": "Attachment filename",
|
||||||
"description": "Template used when downloading or dragging out an attachment. If you omit {filename} and {ext}, the original extension is preserved."
|
"description": "Template used when downloading or dragging out an attachment. If you omit {filename} and {ext}, the original extension is preserved."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Multi-email .zip filename",
|
||||||
|
"description": "Template used when you drag out or download several selected emails as a single .zip archive. The .zip extension is added automatically."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Spaces",
|
"label": "Spaces",
|
||||||
"description": "Replace spaces in the resulting filename with another character.",
|
"description": "Replace spaces in the resulting filename with another character.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Nombre del archivo adjunto",
|
"label": "Nombre del archivo adjunto",
|
||||||
"description": "Plantilla usada al descargar o arrastrar un adjunto. Si omites {filename} y {ext}, se conserva la extensión original."
|
"description": "Plantilla usada al descargar o arrastrar un adjunto. Si omites {filename} y {ext}, se conserva la extensión original."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Nombre de archivo .zip multi-correo",
|
||||||
|
"description": "Plantilla utilizada al arrastrar o descargar varios correos seleccionados como un único archivo .zip. La extensión .zip se añade automáticamente."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Espacios",
|
"label": "Espacios",
|
||||||
"description": "Reemplaza los espacios del nombre de archivo resultante por otro carácter.",
|
"description": "Reemplaza los espacios del nombre de archivo resultante por otro carácter.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Nom du fichier de pièce jointe",
|
"label": "Nom du fichier de pièce jointe",
|
||||||
"description": "Modèle utilisé lors du téléchargement ou du glisser-déposer d'une pièce jointe. Si vous omettez {filename} et {ext}, l'extension d'origine est conservée."
|
"description": "Modèle utilisé lors du téléchargement ou du glisser-déposer d'une pièce jointe. Si vous omettez {filename} et {ext}, l'extension d'origine est conservée."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Nom du fichier .zip multi-e-mails",
|
||||||
|
"description": "Modèle utilisé lorsque vous faites glisser ou téléchargez plusieurs e-mails sélectionnés sous forme d'archive .zip unique. L'extension .zip est ajoutée automatiquement."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Espaces",
|
"label": "Espaces",
|
||||||
"description": "Remplacer les espaces dans le nom de fichier final par un autre caractère.",
|
"description": "Remplacer les espaces dans le nom de fichier final par un autre caractère.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Nome file dell’allegato",
|
"label": "Nome file dell’allegato",
|
||||||
"description": "Modello usato quando scarichi o trascini un allegato. Se ometti {filename} e {ext}, l'estensione originale viene mantenuta."
|
"description": "Modello usato quando scarichi o trascini un allegato. Se ometti {filename} e {ext}, l'estensione originale viene mantenuta."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Nome del file .zip multi-email",
|
||||||
|
"description": "Modello usato quando trascini o scarichi più email selezionate come un singolo archivio .zip. L'estensione .zip viene aggiunta automaticamente."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Spazi",
|
"label": "Spazi",
|
||||||
"description": "Sostituisci gli spazi nel nome file risultante con un altro carattere.",
|
"description": "Sostituisci gli spazi nel nome file risultante con un altro carattere.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "添付ファイルのファイル名",
|
"label": "添付ファイルのファイル名",
|
||||||
"description": "添付ファイルをダウンロードまたはドラッグするときに使用するテンプレートです。{filename} と {ext} を省略すると、元の拡張子が保持されます。"
|
"description": "添付ファイルをダウンロードまたはドラッグするときに使用するテンプレートです。{filename} と {ext} を省略すると、元の拡張子が保持されます。"
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "複数メールの .zip ファイル名",
|
||||||
|
"description": "複数の選択したメールを 1 つの .zip としてドラッグまたはダウンロードするときに使用するテンプレートです。拡張子 .zip は自動的に付加されます。"
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "スペース",
|
"label": "スペース",
|
||||||
"description": "最終的なファイル名のスペースを別の文字に置き換えます。",
|
"description": "最終的なファイル名のスペースを別の文字に置き換えます。",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "첨부 파일 이름",
|
"label": "첨부 파일 이름",
|
||||||
"description": "첨부 파일을 다운로드하거나 드래그할 때 사용하는 템플릿입니다. {filename}과 {ext}를 생략하면 원래 확장자가 유지됩니다."
|
"description": "첨부 파일을 다운로드하거나 드래그할 때 사용하는 템플릿입니다. {filename}과 {ext}를 생략하면 원래 확장자가 유지됩니다."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "다중 이메일 .zip 파일 이름",
|
||||||
|
"description": "여러 선택한 이메일을 하나의 .zip 아카이브로 드래그하거나 다운로드할 때 사용하는 템플릿입니다. .zip 확장자는 자동으로 추가됩니다."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "공백",
|
"label": "공백",
|
||||||
"description": "결과 파일 이름의 공백을 다른 문자로 바꿉니다.",
|
"description": "결과 파일 이름의 공백을 다른 문자로 바꿉니다.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Pielikuma faila nosaukums",
|
"label": "Pielikuma faila nosaukums",
|
||||||
"description": "Veidne, ko izmanto, lejupielādējot vai velkot pielikumu. Ja izlaižat {filename} un {ext}, sākotnējais paplašinājums tiek saglabāts."
|
"description": "Veidne, ko izmanto, lejupielādējot vai velkot pielikumu. Ja izlaižat {filename} un {ext}, sākotnējais paplašinājums tiek saglabāts."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Vairāku e-pastu .zip faila nosaukums",
|
||||||
|
"description": "Veidne, ko izmanto, kad velkat vai lejupielādējat vairākus atlasītos e-pastus kā vienu .zip arhīvu. Paplašinājums .zip tiek pievienots automātiski."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Atstarpes",
|
"label": "Atstarpes",
|
||||||
"description": "Aizstāt atstarpes izvades faila nosaukumā ar citu rakstzīmi.",
|
"description": "Aizstāt atstarpes izvades faila nosaukumā ar citu rakstzīmi.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Bestandsnaam van bijlage",
|
"label": "Bestandsnaam van bijlage",
|
||||||
"description": "Sjabloon bij het downloaden of slepen van een bijlage. Als je {filename} en {ext} weglaat, blijft de oorspronkelijke extensie behouden."
|
"description": "Sjabloon bij het downloaden of slepen van een bijlage. Als je {filename} en {ext} weglaat, blijft de oorspronkelijke extensie behouden."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Bestandsnaam .zip met meerdere e-mails",
|
||||||
|
"description": "Sjabloon dat wordt gebruikt wanneer je meerdere geselecteerde e-mails als één .zip-archief sleept of downloadt. De extensie .zip wordt automatisch toegevoegd."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Spaties",
|
"label": "Spaties",
|
||||||
"description": "Vervang spaties in de uiteindelijke bestandsnaam door een ander teken.",
|
"description": "Vervang spaties in de uiteindelijke bestandsnaam door een ander teken.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Nazwa pliku załącznika",
|
"label": "Nazwa pliku załącznika",
|
||||||
"description": "Szablon używany przy pobieraniu lub przeciąganiu załącznika. Jeśli pominiesz {filename} i {ext}, oryginalne rozszerzenie zostanie zachowane."
|
"description": "Szablon używany przy pobieraniu lub przeciąganiu załącznika. Jeśli pominiesz {filename} i {ext}, oryginalne rozszerzenie zostanie zachowane."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Nazwa pliku .zip wielu wiadomości",
|
||||||
|
"description": "Szablon używany przy przeciąganiu lub pobieraniu kilku wybranych wiadomości jako jednego archiwum .zip. Rozszerzenie .zip jest dodawane automatycznie."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Spacje",
|
"label": "Spacje",
|
||||||
"description": "Zastąp spacje w nazwie pliku innym znakiem.",
|
"description": "Zastąp spacje w nazwie pliku innym znakiem.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Nome do arquivo do anexo",
|
"label": "Nome do arquivo do anexo",
|
||||||
"description": "Modelo usado ao baixar ou arrastar um anexo. Se você omitir {filename} e {ext}, a extensão original é preservada."
|
"description": "Modelo usado ao baixar ou arrastar um anexo. Se você omitir {filename} e {ext}, a extensão original é preservada."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Nome do arquivo .zip multi-e-mails",
|
||||||
|
"description": "Modelo usado ao arrastar ou baixar vários e-mails selecionados como um único arquivo .zip. A extensão .zip é adicionada automaticamente."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Espaços",
|
"label": "Espaços",
|
||||||
"description": "Substitui espaços no nome de arquivo resultante por outro caractere.",
|
"description": "Substitui espaços no nome de arquivo resultante por outro caractere.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Имя файла вложения",
|
"label": "Имя файла вложения",
|
||||||
"description": "Шаблон, используемый при загрузке или перетаскивании вложения. Если опустить {filename} и {ext}, исходное расширение сохраняется."
|
"description": "Шаблон, используемый при загрузке или перетаскивании вложения. Если опустить {filename} и {ext}, исходное расширение сохраняется."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Имя файла .zip с несколькими письмами",
|
||||||
|
"description": "Шаблон, используемый при перетаскивании или загрузке нескольких выбранных писем одним .zip-архивом. Расширение .zip добавляется автоматически."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Пробелы",
|
"label": "Пробелы",
|
||||||
"description": "Заменять пробелы в итоговом имени файла другим символом.",
|
"description": "Заменять пробелы в итоговом имени файла другим символом.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Ek dosyası adı",
|
"label": "Ek dosyası adı",
|
||||||
"description": "Bir eki indirirken veya sürüklerken kullanılan şablon. {filename} ve {ext} yazılmazsa orijinal uzantı korunur."
|
"description": "Bir eki indirirken veya sürüklerken kullanılan şablon. {filename} ve {ext} yazılmazsa orijinal uzantı korunur."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Çoklu e-posta .zip dosya adı",
|
||||||
|
"description": "Birden çok seçili e-postayı tek bir .zip arşivi olarak sürüklediğinizde veya indirdiğinizde kullanılan şablon. .zip uzantısı otomatik olarak eklenir."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Boşluklar",
|
"label": "Boşluklar",
|
||||||
"description": "Sonuçtaki dosya adındaki boşlukları başka bir karakterle değiştirin.",
|
"description": "Sonuçtaki dosya adındaki boşlukları başka bir karakterle değiştirin.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "Ім'я файлу вкладення",
|
"label": "Ім'я файлу вкладення",
|
||||||
"description": "Шаблон, що використовується при завантаженні або перетягуванні вкладення. Якщо пропустити {filename} та {ext}, оригінальне розширення зберігається."
|
"description": "Шаблон, що використовується при завантаженні або перетягуванні вкладення. Якщо пропустити {filename} та {ext}, оригінальне розширення зберігається."
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "Ім'я файлу .zip з кількома листами",
|
||||||
|
"description": "Шаблон, що використовується при перетягуванні або завантаженні кількох вибраних листів одним .zip-архівом. Розширення .zip додається автоматично."
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "Пробіли",
|
"label": "Пробіли",
|
||||||
"description": "Замінити пробіли в підсумковому імені файлу іншим символом.",
|
"description": "Замінити пробіли в підсумковому імені файлу іншим символом.",
|
||||||
|
|||||||
@@ -1509,6 +1509,10 @@
|
|||||||
"label": "附件文件名",
|
"label": "附件文件名",
|
||||||
"description": "下载或拖出附件时使用的模板。如果省略 {filename} 和 {ext},将保留原始扩展名。"
|
"description": "下载或拖出附件时使用的模板。如果省略 {filename} 和 {ext},将保留原始扩展名。"
|
||||||
},
|
},
|
||||||
|
"bundle_template": {
|
||||||
|
"label": "多邮件 .zip 文件名",
|
||||||
|
"description": "将多个选中的邮件作为单个 .zip 拖出或下载时使用的模板。扩展名 .zip 会自动添加。"
|
||||||
|
},
|
||||||
"spaces": {
|
"spaces": {
|
||||||
"label": "空格",
|
"label": "空格",
|
||||||
"description": "用其他字符替换最终文件名中的空格。",
|
"description": "用其他字符替换最终文件名中的空格。",
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ interface SettingsState {
|
|||||||
// Downloads
|
// Downloads
|
||||||
emailDownloadTemplate: string;
|
emailDownloadTemplate: string;
|
||||||
attachmentDownloadTemplate: string;
|
attachmentDownloadTemplate: string;
|
||||||
|
bundleDownloadTemplate: string;
|
||||||
filenameSpaceReplacement: 'keep' | 'underscore' | 'dash';
|
filenameSpaceReplacement: 'keep' | 'underscore' | 'dash';
|
||||||
filenameLowercase: boolean;
|
filenameLowercase: boolean;
|
||||||
filenameStripDiacritics: boolean;
|
filenameStripDiacritics: boolean;
|
||||||
@@ -435,6 +436,7 @@ const DEFAULT_SETTINGS = {
|
|||||||
// Downloads
|
// Downloads
|
||||||
emailDownloadTemplate: '{date} ({from}-{to}) {subject}',
|
emailDownloadTemplate: '{date} ({from}-{to}) {subject}',
|
||||||
attachmentDownloadTemplate: '{filename}',
|
attachmentDownloadTemplate: '{filename}',
|
||||||
|
bundleDownloadTemplate: 'emails-{count}',
|
||||||
filenameSpaceReplacement: 'keep' as 'keep' | 'underscore' | 'dash',
|
filenameSpaceReplacement: 'keep' as 'keep' | 'underscore' | 'dash',
|
||||||
filenameLowercase: false,
|
filenameLowercase: false,
|
||||||
filenameStripDiacritics: false,
|
filenameStripDiacritics: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user