diff --git a/app/(main)/setup/__tests__/setup-i18n.test.tsx b/app/(main)/setup/__tests__/setup-i18n.test.tsx index 49754e19a..44fe1ea44 100644 --- a/app/(main)/setup/__tests__/setup-i18n.test.tsx +++ b/app/(main)/setup/__tests__/setup-i18n.test.tsx @@ -1,5 +1,7 @@ import { render, screen } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { readdirSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; import { NextIntlClientProvider } from 'next-intl'; import de from '@/locales/de/common.json'; import en from '@/locales/en/common.json'; @@ -8,9 +10,10 @@ import en from '@/locales/en/common.json'; // instead of being English only. vi.unmock('next-intl'); +const status = vi.hoisted(() => ({ readOnly: false })); vi.mock('next/navigation', () => ({ useRouter: () => ({ replace: vi.fn(), push: vi.fn() }) })); vi.mock('@/lib/browser-navigation', () => ({ - apiFetch: vi.fn(async () => new Response(JSON.stringify({ state: 'bootstrap', authenticated: false, readOnly: false, partialConfig: null }), { + apiFetch: vi.fn(async () => new Response(JSON.stringify({ state: 'bootstrap', authenticated: false, readOnly: status.readOnly, partialConfig: null }), { status: 200, headers: { 'content-type': 'application/json' }, })), getPathPrefix: () => '', @@ -43,3 +46,35 @@ describe('setup wizard language', () => { expect(screen.getByText('Server')).toBeTruthy(); }); }); + +// Variables, URLs and paths in the texts are shown as code, not as words. +describe('setup wizard literals', () => { + afterEach(() => { status.readOnly = false; }); + + it('shows the read-only variable as code, in every language', async () => { + status.readOnly = true; + const { unmount } = renderIn('en', en); + const variable = await screen.findByText('ADMIN_CONFIG_READONLY'); + expect(variable.tagName).toBe('CODE'); + expect(variable.parentElement!.textContent).toBe( + 'The config volume is mounted read-only or ADMIN_CONFIG_READONLY is set. Remount it read-write or unset that variable, then restart the container.', + ); + unmount(); + + renderIn('de', de); + expect((await screen.findByText('ADMIN_CONFIG_READONLY')).tagName).toBe('CODE'); + }); + + it('marks the literal in each of those texts as code in all languages', () => { + const dir = join(process.cwd(), 'locales'); + const pick = (o: Record, path: string) => + path.split('.').reduce((v, k) => (v as Record)[k], o) as string; + for (const locale of readdirSync(dir)) { + const setup = JSON.parse(readFileSync(join(dir, locale, 'common.json'), 'utf8')).setup; + expect.soft(pick(setup, 'read_only.body'), locale).toContain('{variable}'); + expect.soft(pick(setup, 'server.http_body'), locale).toContain('{https}'); + expect.soft(pick(setup, 'server.local_body'), locale).toContain('{example}'); + expect.soft(pick(setup, 'review.password_hint'), locale).toContain('{path}'); + } + }); +}); diff --git a/app/(main)/setup/page.tsx b/app/(main)/setup/page.tsx index f956fdf08..875c1d124 100644 --- a/app/(main)/setup/page.tsx +++ b/app/(main)/setup/page.tsx @@ -97,6 +97,9 @@ const STEPS = [ type SetupT = ReturnType>; +/** Literal values in the texts (a variable, a URL, a path) as inline code, for t.rich. */ +const code = (chunks: ReactNode) => {chunks}; + export default function SetupWizardPage() { const t = useTranslations('setup'); // For the one-time status load: a language switch must not rerun it. @@ -215,7 +218,7 @@ export default function SetupWizardPage() {

{t('read_only.title')}

- {t('read_only.body', { variable: 'ADMIN_CONFIG_READONLY' })} + {t.rich('read_only.body', { variable: 'ADMIN_CONFIG_READONLY', code })}

); @@ -748,7 +751,7 @@ function ServerStep({ config, setConfig, onNext }: Pick

- {t('server.http_body', { https: 'https://' })} + {t.rich('server.http_body', { https: 'https://', code })}

@@ -763,7 +766,7 @@ function ServerStep({ config, setConfig, onNext }: Pick

- {t('server.local_body', { example: 'https://mail.example.com' })} + {t.rich('server.local_body', { example: 'https://mail.example.com', code })}

@@ -1539,7 +1542,7 @@ function ReviewStep({ config, onBack, onFinish }: { config: WizardConfig; onBack
{t('review.password_title')}

- {t('review.password_hint', { path: '/admin' })} + {t.rich('review.password_hint', { path: '/admin', code })}

diff --git a/components/contacts/__tests__/contact-print.test.ts b/components/contacts/__tests__/contact-print.test.ts index e229e4100..f5f277a9f 100644 --- a/components/contacts/__tests__/contact-print.test.ts +++ b/components/contacts/__tests__/contact-print.test.ts @@ -76,6 +76,32 @@ describe('printContact', () => { expect(printWindow.document.write).not.toHaveBeenCalled(); }); + it('prints from a hidden frame in the page when the browser blocks the print window', async () => { + open.mockReturnValue(null); + await printContact({ ...base, emails: { e: { address: 'ann@example.com' } } } as ContactCard, LABELS); + + const frame = document.querySelector('iframe[data-contact-print-frame]') as HTMLIFrameElement; + expect(frame).not.toBeNull(); + expect(frame.srcdoc).toContain('

Ann Lee

'); + expect(frame.srcdoc).toContain('
ann@example.com
'); + vi.spyOn(frame.contentWindow!, 'focus').mockImplementation(() => {}); + const print = vi.spyOn(frame.contentWindow!, 'print').mockImplementation(() => {}); + + // The empty start page some browsers load first is not printed. + frame.dispatchEvent(new Event('load')); + expect(print).not.toHaveBeenCalled(); + + frame.contentDocument!.body.innerHTML = '

Ann Lee

'; + frame.dispatchEvent(new Event('load')); + expect(print).toHaveBeenCalledOnce(); + + // Gone once the print dialog closes. + vi.useFakeTimers({ toFake: ['setTimeout'] }); + frame.contentWindow!.dispatchEvent(new Event('afterprint')); + vi.runAllTimers(); + expect(document.querySelector('iframe[data-contact-print-frame]')).toBeNull(); + }); + it('prints the headings and dates in the language of the app', async () => { const de = printLabels((key) => ({ 'detail.emails': 'E-Mail-Adressen', 'detail.anniversaries': 'Jahrestage', 'detail.anniversary_birth': 'Geburtstag' } as Record)[key] ?? key, 'de'); await printContact({ diff --git a/components/contacts/contact-print.ts b/components/contacts/contact-print.ts index 24fa9e706..d34a51286 100644 --- a/components/contacts/contact-print.ts +++ b/components/contacts/contact-print.ts @@ -84,15 +84,44 @@ export function printLabels(t: (key: string) => string, locale: string): PrintLa }; } +const PRINT_FRAME_ATTR = "data-contact-print-frame"; + +/** + * Prints the sheet from a hidden frame in this page, for when the browser + * blocked the print window. The frame goes away after printing, or when the + * next sheet is printed. + */ +function printInFrame(html: string): void { + document.querySelectorAll(`iframe[${PRINT_FRAME_ATTR}]`).forEach((f) => f.remove()); + const frame = document.createElement("iframe"); + frame.setAttribute(PRINT_FRAME_ATTR, ""); + frame.setAttribute("aria-hidden", "true"); + frame.tabIndex = -1; + frame.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;visibility:hidden"; + // Printed once the sheet and its photo have loaded. Some browsers report + // the frame's empty start page first; that one is skipped. + let printed = false; + frame.addEventListener("load", () => { + const frameWindow = frame.contentWindow; + if (printed || !frameWindow || !frame.contentDocument?.querySelector("h1")) return; + printed = true; + frameWindow.addEventListener("afterprint", () => setTimeout(() => frame.remove(), 0), { once: true }); + frameWindow.focus(); + frameWindow.print(); + }); + frame.srcdoc = html; + document.body.appendChild(frame); +} + export async function printContact(contact: ContactCard, labels: PrintLabels, displayName?: string): Promise { // Open the window before anything is awaited: browsers allow the popup only - // while the click that asked for it is being handled. + // while the click that asked for it is being handled. When the popup is + // blocked, the sheet is printed from a hidden frame instead. const printWindow = window.open("", "_blank"); - if (!printWindow) return; const name = displayName || getContactDisplayName(contact); const photoUri = await printablePhotoUri(contact); - if (printWindow.closed) return; + if (printWindow?.closed) return; const emails = contact.emails ? Object.values(contact.emails) : []; const phones = contact.phones ? Object.values(contact.phones) : []; const orgs = contact.organizations ? Object.values(contact.organizations) : []; @@ -173,6 +202,10 @@ ${rows.join("")} `; + if (!printWindow) { + printInFrame(html); + return; + } printWindow.document.write(html); printWindow.document.close(); printWindow.focus(); diff --git a/components/contacts/contacts-app.tsx b/components/contacts/contacts-app.tsx index 6d5fe2e17..7fccc9654 100644 --- a/components/contacts/contacts-app.tsx +++ b/components/contacts/contacts-app.tsx @@ -52,6 +52,7 @@ import { useLiteLinkSegments } from "@/hooks/use-lite-link-segments"; import { useDocumentTitle } from "@/hooks/use-document-title"; import { useRegisterCommands } from "@/lib/command-registry"; import { useCloseOnBack } from "@/hooks/use-close-on-back"; +import { useDeleteCategory } from "@/hooks/use-delete-category"; import { MvTopBar } from "@/components/layout/mv-top-bar"; import { useMountainViewShell } from "@/hooks/use-mountain-view-shell"; @@ -119,8 +120,6 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps = shareAddressBook, setDefaultAddressBook, renameKeyword, - removeKeyword, - addKeyword, importContacts, } = useContactStore(); @@ -439,26 +438,13 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps = }, [movingContactIds, contacts]); // Deleting a category only takes a label off contacts: no question, an Undo (R3). + const deleteCategory = useDeleteCategory(); const handleDeleteKeyword = useCallback(async (keyword: string) => { - const jmapClient = supportsSync && client ? client : null; - try { - const ids = await removeKeyword(jmapClient, keyword); - if (typeof activeCategory === "object" && "keyword" in activeCategory && activeCategory.keyword === keyword) { - setActiveCategory("all"); - } - toast.success(t("category_deleted", { name: keyword }), { - action: { - label: t("undo"), - onClick: () => { - void addKeyword(jmapClient, keyword, ids).catch(() => toast.error(t("toast.error_update"))); - }, - }, - }); - } catch (error) { - console.error("Failed to delete category:", error); - toast.error(t("category_delete_failed")); + if (!(await deleteCategory(keyword))) return; + if (typeof activeCategory === "object" && "keyword" in activeCategory && activeCategory.keyword === keyword) { + setActiveCategory("all"); } - }, [supportsSync, client, removeKeyword, addKeyword, activeCategory, t]); + }, [deleteCategory, activeCategory]); const handleDropContactsToCategory = useCallback(async (contactIds: string[], keyword: string) => { if (!client && supportsSync) return; diff --git a/components/settings/address-book-management-settings.tsx b/components/settings/address-book-management-settings.tsx index 41f24489d..5df3e5b18 100644 --- a/components/settings/address-book-management-settings.tsx +++ b/components/settings/address-book-management-settings.tsx @@ -14,6 +14,7 @@ import { ShareCollectionDialog } from "./share-collection-dialog"; import { PromptDialog } from "@/components/ui/prompt-dialog"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; +import { useDeleteCategory } from "@/hooks/use-delete-category"; function AddressBookEditRow({ initial, @@ -76,8 +77,8 @@ export function AddressBookManagementSettings() { const tSettings = useTranslations("settings.contacts"); const { client } = useAuthStore(); const managedAccountId = useManagedAccountStore((s) => s.managedAccountId); - const tNotifications = useTranslations("notifications"); - const { addressBooks, contacts, supportsSync, fetchAddressBooks, createAddressBook, renameAddressBook, shareAddressBook, setDefaultAddressBook, removeAddressBook, renameKeyword, updateContact, updateLocalContact } = useContactStore(); + const { addressBooks, contacts, supportsSync, fetchAddressBooks, createAddressBook, renameAddressBook, shareAddressBook, setDefaultAddressBook, removeAddressBook, renameKeyword } = useContactStore(); + const deleteCategory = useDeleteCategory(); const { dialogProps: confirmProps, confirm } = useConfirmDialog(); const [editingId, setEditingId] = useState(null); const [editingKeyword, setEditingKeyword] = useState(null); @@ -154,41 +155,15 @@ export function AddressBookManagementSettings() { } }; - // Sets a category on or off for each of these contacts. - const setCategory = async (keyword: string, ids: string[], on: boolean) => { - for (const id of ids) { - const contact = useContactStore.getState().contacts.find((c) => c.id === id); - if (!contact) continue; - const { [keyword]: _removed, ...rest } = contact.keywords || {}; - const keywords: Record = on ? { ...rest, [keyword]: true } : rest; - const saved = supportsSync && client - ? await updateContact(client, id, { keywords }) - : await updateLocalContact(id, { keywords }); - if (!saved) throw new Error("not saved"); - } - }; - - // Deleting a category only takes it off the contacts: no confirm, and - // Undo puts it back on the same ones (R3). + // Deleting a category works as in the Contacts sidebar: no confirm, and + // Undo puts it back on the same contacts (R3). const handleDeleteCategory = async (keyword: string) => { - const ids = contacts.filter((c) => c.kind !== "group" && c.keywords?.[keyword]).map((c) => c.id); setIsLoading(true); try { - await setCategory(keyword, ids, false); - } catch { - toast.error(tSettings("category_delete_failed")); - return; + await deleteCategory(keyword); } finally { setIsLoading(false); } - toast.success(tSettings("category_deleted"), { - action: { - label: tNotifications("rule_undo"), - onClick: () => { - setCategory(keyword, ids, true).catch(() => toast.error(tSettings("category_delete_failed"))); - }, - }, - }); }; // Group: personal first, then by shared account @@ -405,8 +380,8 @@ export function AddressBookManagementSettings() { onClick={() => void handleDeleteCategory(keyword)} disabled={isLoading} className="p-1.5 rounded-md hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-50" - title={tSettings("delete_category")} - aria-label={tSettings("delete_category")} + title={tContacts("delete_category")} + aria-label={tContacts("delete_category")} > diff --git a/hooks/__tests__/use-delete-category.test.tsx b/hooks/__tests__/use-delete-category.test.tsx new file mode 100644 index 000000000..3e3b850a6 --- /dev/null +++ b/hooks/__tests__/use-delete-category.test.tsx @@ -0,0 +1,95 @@ +import { act, renderHook, waitFor } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { ContactCard } from '@/lib/jmap/types'; +import { useAuthStore } from '@/stores/auth-store'; +import { useContactStore } from '@/stores/contact-store'; +import { contactHooks, clearAllHooks } from '@/lib/plugin-hooks'; +import { useDeleteCategory } from '../use-delete-category'; + +// One way to delete a contact category, used by the Contacts sidebar and by +// Settings: no question, a toast with Undo, through the normal contact update. + +const toast = vi.hoisted(() => ({ success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn() })); +vi.mock('@/stores/toast-store', () => ({ toast })); + +const contact = (id: string, keywords: Record, extra: Partial = {}) => + ({ id, kind: 'individual', keywords, addressBookIds: { home: true }, ...extra }) as unknown as ContactCard; + +const initial = { auth: useAuthStore.getState(), contacts: useContactStore.getState() }; +let updateContact: ReturnType; + +beforeEach(() => { + clearAllHooks(); + toast.success.mockClear(); + toast.error.mockClear(); + updateContact = vi.fn(async () => undefined); + useAuthStore.setState({ client: { updateContact } } as never); + useContactStore.setState({ + supportsSync: true, + contacts: [ + contact('a', { friends: true, work: true }), + contact('b', { friends: true }), + contact('c', { work: true }), + contact('s', { friends: true }, { isShared: true, accountId: 'other', originalId: 'srv-s' }), + ], + }); +}); +afterEach(() => { + clearAllHooks(); + useAuthStore.setState(initial.auth, true); + useContactStore.setState(initial.contacts, true); +}); + +const keywords = () => Object.fromEntries(useContactStore.getState().contacts.map((c) => [c.id, c.keywords])); +const undo = () => act(async () => { (toast.success.mock.calls[0][1] as { action: { onClick: () => void } }).action.onClick(); }); + +describe('useDeleteCategory', () => { + it('takes the category off its contacts on the server, and Undo puts it back on the same ones', async () => { + const { result } = renderHook(() => useDeleteCategory()); + await act(async () => { expect(await result.current('friends')).toBe(true); }); + + expect(keywords()).toEqual({ a: { work: true }, b: {}, c: { work: true }, s: {} }); + // A shared contact is changed in the account it belongs to. + expect(updateContact).toHaveBeenCalledWith('srv-s', { keywords: {} }, 'other'); + expect(toast.success).toHaveBeenCalledWith('category_deleted', { action: expect.objectContaining({ label: 'undo' }) }); + + await undo(); + await waitFor(() => expect(keywords()).toEqual({ + a: { work: true, friends: true }, b: { friends: true }, c: { work: true }, s: { friends: true }, + })); + }); + + it('leaves the category on a contact a plugin keeps unchanged, and Undo leaves that contact alone', async () => { + const before = vi.fn(({ contactId }: { contactId: string }) => contactId !== 'b'); + contactHooks.onBeforeContactUpdate.register('test', before); + const { result } = renderHook(() => useDeleteCategory()); + await act(async () => { await result.current('friends'); }); + + expect(before).toHaveBeenCalledWith(expect.objectContaining({ contactId: 'b' })); + expect(keywords()).toEqual({ a: { work: true }, b: { friends: true }, c: { work: true }, s: {} }); + + before.mockClear(); + await undo(); + await waitFor(() => expect(keywords().a).toEqual({ work: true, friends: true })); + expect(before.mock.calls.map(([p]) => p.contactId).sort()).toEqual(['a', 's']); + }); + + it('works on contacts kept in the browser when there is no server', async () => { + useContactStore.setState({ supportsSync: false }); + const { result } = renderHook(() => useDeleteCategory()); + await act(async () => { await result.current('work'); }); + + expect(updateContact).not.toHaveBeenCalled(); + expect(keywords()).toEqual({ a: { friends: true }, b: { friends: true }, c: {}, s: { friends: true } }); + }); + + it('says so when the server refuses, without an Undo', async () => { + updateContact.mockRejectedValue(new Error('forbidden')); + vi.spyOn(console, 'error').mockImplementation(() => {}); + const { result } = renderHook(() => useDeleteCategory()); + await act(async () => { expect(await result.current('friends')).toBe(false); }); + + expect(toast.error).toHaveBeenCalledWith('category_delete_failed'); + expect(toast.success).not.toHaveBeenCalled(); + }); +}); diff --git a/hooks/use-delete-category.ts b/hooks/use-delete-category.ts new file mode 100644 index 000000000..29ab9a9ec --- /dev/null +++ b/hooks/use-delete-category.ts @@ -0,0 +1,40 @@ +"use client"; + +import { useCallback } from "react"; +import { useTranslations } from "next-intl"; +import { useAuthStore } from "@/stores/auth-store"; +import { useContactStore } from "@/stores/contact-store"; +import { toast } from "@/stores/toast-store"; + +/** + * Deletes a contact category, the same way from the Contacts sidebar and + * from Settings. It only takes the label off contacts, so there is no + * question: the toast has an Undo that puts it back on the same contacts (R3). + * Resolves true once the category is gone. + */ +export function useDeleteCategory(): (keyword: string) => Promise { + const t = useTranslations("contacts"); + + return useCallback(async (keyword: string) => { + const { client } = useAuthStore.getState(); + const { supportsSync, removeKeyword, addKeyword } = useContactStore.getState(); + const jmapClient = supportsSync && client ? client : null; + let ids: string[]; + try { + ids = await removeKeyword(jmapClient, keyword); + } catch (error) { + console.error("Failed to delete category:", error); + toast.error(t("category_delete_failed")); + return false; + } + toast.success(t("category_deleted", { name: keyword }), { + action: { + label: t("undo"), + onClick: () => { + void addKeyword(jmapClient, keyword, ids).catch(() => toast.error(t("toast.error_update"))); + }, + }, + }); + return true; + }, [t]); +} diff --git a/locales/ar/common.json b/locales/ar/common.json index 02b26a95b..82e0b6734 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "لم يتم العثور على دفاتر عناوين", "categories_title": "الفئات", "categories_description": "إعادة تسمية فئات جهات الاتصال", - "no_categories": "لم يتم العثور على فئات", - "delete_category": "حذف الفئة", - "category_deleted": "تم حذف الفئة", - "category_delete_failed": "تعذّر حذف الفئة" + "no_categories": "لم يتم العثور على فئات" }, "calendar_management": { "delete_title": "حذف التقويم؟", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "الإعدادات للقراءة فقط", - "body": "وحدة تخزين الإعدادات مثبتة للقراءة فقط أو تم تعيين {variable}. أعد تثبيتها مع إذن الكتابة أو أزل هذا المتغير، ثم أعد تشغيل الحاوية." + "body": "وحدة تخزين الإعدادات مثبتة للقراءة فقط أو تم تعيين {variable}. أعد تثبيتها مع إذن الكتابة أو أزل هذا المتغير، ثم أعد تشغيل الحاوية." }, "done": { "title": "كل شيء جاهز", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "قد يحدث هذا عندما يوجّه وكيل عكسي JMAP بشكل منفصل على النطاق نفسه. وإلا فعادةً يكون عنوان URL خاطئًا.", "not_jmap_confirm": "أنا متأكد من أن عنوان URL صحيح، تابع على أي حال.", "http_title": "يستخدم عنوان URL هذا HTTP غير مشفر.", - "http_body": "ستنتقل كلمات المرور ومحتوى الرسائل دون تشفير بين المستخدمين وخادمك. استخدم {https} في بيئة الإنتاج: أنهِ TLS على خادم البريد أو في وكيل عكسي أمامه.", + "http_body": "ستنتقل كلمات المرور ومحتوى الرسائل دون تشفير بين المستخدمين وخادمك. استخدم {https} في بيئة الإنتاج: أنهِ TLS على خادم البريد أو في وكيل عكسي أمامه.", "local_title": "عنوان URL هذا يعمل محليًا فقط.", - "local_body": "يُجلب البريد مباشرةً من متصفح المستخدم، لذا يجب أن يكون عنوان JMAP متاحًا من كل مكان يسجّل منه المستخدمون الدخول، لا من هذا الجهاز أو الشبكة المحلية فقط. استخدم اسم مضيف عامًا (مثل {example}) في بيئة الإنتاج.", + "local_body": "يُجلب البريد مباشرةً من متصفح المستخدم، لذا يجب أن يكون عنوان JMAP متاحًا من كل مكان يسجّل منه المستخدمون الدخول، لا من هذا الجهاز أو الشبكة المحلية فقط. استخدم اسم مضيف عامًا (مثل {example}) في بيئة الإنتاج.", "additional_title": "خوادم JMAP إضافية", "additional_hint": "اختياري. اعرض عدة خوادم في قائمة تسجيل الدخول، وهذا مفيد لمن يشغّل عدة نسخ من Stalwart.", "additional_show": "إظهار ({count})", @@ -2891,7 +2888,7 @@ "defaults": "القيم الافتراضية", "company": "اسم الشركة", "password_title": "اختر كلمة مرور للمسؤول", - "password_hint": "ستستخدمها لتسجيل الدخول عبر {path}. 8 أحرف على الأقل.", + "password_hint": "ستستخدمها لتسجيل الدخول عبر {path}. 8 أحرف على الأقل.", "new_password": "كلمة المرور الجديدة", "confirm": "التأكيد", "too_short": "8 أحرف على الأقل.", diff --git a/locales/ca/common.json b/locales/ca/common.json index 6af811d62..9f91d22cb 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "No s'ha trobat cap llibreta d'adreces", "categories_title": "Categories", "categories_description": "Canvieu el nom de les categories de contactes", - "no_categories": "No s'ha trobat cap categoria", - "delete_category": "Suprimeix la categoria", - "category_deleted": "Categoria suprimida", - "category_delete_failed": "No s'ha pogut suprimir la categoria" + "no_categories": "No s'ha trobat cap categoria" }, "calendar_management": { "delete_title": "Voleu suprimir el calendari?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "La configuració és només de lectura", - "body": "El volum de configuració està muntat només de lectura o la variable {variable} està definida. Torneu-lo a muntar amb escriptura o elimineu la variable i reinicieu el contenidor." + "body": "El volum de configuració està muntat només de lectura o la variable {variable} està definida. Torneu-lo a muntar amb escriptura o elimineu la variable i reinicieu el contenidor." }, "done": { "title": "Tot a punt", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Pot passar quan un servidor intermediari invers encamina JMAP per separat al mateix domini. Si no, normalment l’URL és incorrecte.", "not_jmap_confirm": "Estic segur que l’URL és correcte, continua igualment.", "http_title": "Aquest URL fa servir HTTP sense xifrar.", - "http_body": "Les contrasenyes i el contingut dels correus viatjaran sense xifrar entre els usuaris i el vostre servidor. En producció feu servir {https}: acabeu el TLS al servidor de correu o en un servidor intermediari invers al davant.", + "http_body": "Les contrasenyes i el contingut dels correus viatjaran sense xifrar entre els usuaris i el vostre servidor. En producció feu servir {https}: acabeu el TLS al servidor de correu o en un servidor intermediari invers al davant.", "local_title": "Aquest URL només funciona en local.", - "local_body": "El correu s’obté directament des del navegador de l’usuari, per tant l’URL de JMAP ha de ser accessible des de qualsevol lloc on els usuaris iniciïn la sessió, no només des d’aquest ordinador o xarxa local. En producció feu servir un nom d’amfitrió públic (p. ex. {example}).", + "local_body": "El correu s’obté directament des del navegador de l’usuari, per tant l’URL de JMAP ha de ser accessible des de qualsevol lloc on els usuaris iniciïn la sessió, no només des d’aquest ordinador o xarxa local. En producció feu servir un nom d’amfitrió públic (p. ex. {example}).", "additional_title": "Servidors JMAP addicionals", "additional_hint": "Opcional. Oferiu diversos servidors a la llista d’inici de sessió, útil per a proveïdors amb diverses instàncies de Stalwart.", "additional_show": "Mostra ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valors predeterminats", "company": "Nom de l’empresa", "password_title": "Trieu una contrasenya d’administrador", - "password_hint": "La fareu servir per iniciar la sessió a {path}. Mínim 8 caràcters.", + "password_hint": "La fareu servir per iniciar la sessió a {path}. Mínim 8 caràcters.", "new_password": "Contrasenya nova", "confirm": "Confirma", "too_short": "Almenys 8 caràcters.", diff --git a/locales/cs/common.json b/locales/cs/common.json index af01165f5..e6ffacf4a 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -2336,10 +2336,7 @@ "no_address_books": "Nenalezeny žádné adresáře", "categories_title": "Kategorie", "categories_description": "Přejmenovat kategorie kontaktů", - "no_categories": "Nenalezeny žádné kategorie", - "delete_category": "Odstranit kategorii", - "category_deleted": "Kategorie byla odstraněna", - "category_delete_failed": "Kategorii se nepodařilo odstranit" + "no_categories": "Nenalezeny žádné kategorie" }, "calendar_management": { "delete_title": "Odstranit kalendář?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfigurace je jen pro čtení", - "body": "Svazek s konfigurací je připojen jen pro čtení nebo je nastavena proměnná {variable}. Připojte ho pro zápis nebo proměnnou odstraňte a restartujte kontejner." + "body": "Svazek s konfigurací je připojen jen pro čtení nebo je nastavena proměnná {variable}. Připojte ho pro zápis nebo proměnnou odstraňte a restartujte kontejner." }, "done": { "title": "Vše je připraveno", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "To se stává, když reverzní proxy směruje JMAP na stejné doméně zvlášť. Jinak je URL obvykle chybná.", "not_jmap_confirm": "Jsem si jistý, že URL je správná, přesto pokračovat.", "http_title": "Tato URL používá nešifrované HTTP.", - "http_body": "Hesla a obsah e-mailů se budou mezi uživateli a vaším serverem přenášet nešifrovaně. V provozu použijte {https}: ukončete TLS na poštovním serveru nebo v reverzní proxy před ním.", + "http_body": "Hesla a obsah e-mailů se budou mezi uživateli a vaším serverem přenášet nešifrovaně. V provozu použijte {https}: ukončete TLS na poštovním serveru nebo v reverzní proxy před ním.", "local_title": "Tato URL funguje jen lokálně.", - "local_body": "Pošta se načítá přímo v prohlížeči uživatele, takže URL JMAP musí být dostupná odkudkoli, kde se uživatelé přihlašují, nejen z tohoto počítače nebo místní sítě. V provozu použijte veřejný název hostitele (např. {example}).", + "local_body": "Pošta se načítá přímo v prohlížeči uživatele, takže URL JMAP musí být dostupná odkudkoli, kde se uživatelé přihlašují, nejen z tohoto počítače nebo místní sítě. V provozu použijte veřejný název hostitele (např. {example}).", "additional_title": "Další servery JMAP", "additional_hint": "Volitelné. Nabídněte při přihlášení více serverů, užitečné pro hostingy s několika instancemi Stalwart.", "additional_show": "Zobrazit ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Výchozí hodnoty", "company": "Název firmy", "password_title": "Zvolte heslo správce", - "password_hint": "Budete se jím přihlašovat na {path}. Nejméně 8 znaků.", + "password_hint": "Budete se jím přihlašovat na {path}. Nejméně 8 znaků.", "new_password": "Nové heslo", "confirm": "Potvrdit", "too_short": "Nejméně 8 znaků.", diff --git a/locales/da/common.json b/locales/da/common.json index c5b06f954..2040c9c19 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -2339,10 +2339,7 @@ "no_address_books": "Ingen adressebøger fundet", "categories_title": "Kategorier", "categories_description": "Omdøb kontaktkategorier", - "no_categories": "Ingen kategorier fundet", - "delete_category": "Slet kategori", - "category_deleted": "Kategori slettet", - "category_delete_failed": "Kategorien kunne ikke slettes" + "no_categories": "Ingen kategorier fundet" }, "calendar_management": { "delete_title": "Slet kalenderen?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfigurationen er skrivebeskyttet", - "body": "Konfigurationsvolumen er monteret skrivebeskyttet, eller {variable} er sat. Montér den med skriveadgang eller fjern variablen, og genstart containeren." + "body": "Konfigurationsvolumen er monteret skrivebeskyttet, eller {variable} er sat. Montér den med skriveadgang eller fjern variablen, og genstart containeren." }, "done": { "title": "Alt er klar", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Det kan ske, når en reverse proxy sender JMAP videre separat på samme domæne. Ellers er URL’en som regel forkert.", "not_jmap_confirm": "Jeg er sikker på, at URL’en er rigtig, fortsæt alligevel.", "http_title": "Denne URL bruger ukrypteret HTTP.", - "http_body": "Adgangskoder og mailindhold sendes ukrypteret mellem brugerne og din server. Brug {https} i produktion: afslut TLS på mailserveren eller i en reverse proxy foran den.", + "http_body": "Adgangskoder og mailindhold sendes ukrypteret mellem brugerne og din server. Brug {https} i produktion: afslut TLS på mailserveren eller i en reverse proxy foran den.", "local_title": "Denne URL virker kun lokalt.", - "local_body": "Mail hentes direkte fra brugerens browser, så JMAP-URL’en skal kunne nås alle steder, hvor brugerne logger ind, ikke kun fra denne maskine eller det lokale netværk. Brug et offentligt værtsnavn (f.eks. {example}) i produktion.", + "local_body": "Mail hentes direkte fra brugerens browser, så JMAP-URL’en skal kunne nås alle steder, hvor brugerne logger ind, ikke kun fra denne maskine eller det lokale netværk. Brug et offentligt værtsnavn (f.eks. {example}) i produktion.", "additional_title": "Flere JMAP-servere", "additional_hint": "Valgfrit. Vis flere servere i listen ved login, nyttigt for udbydere med flere Stalwart-instanser.", "additional_show": "Vis ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Standardværdier", "company": "Firmanavn", "password_title": "Vælg en administratoradgangskode", - "password_hint": "Du bruger den til at logge ind på {path}. Mindst 8 tegn.", + "password_hint": "Du bruger den til at logge ind på {path}. Mindst 8 tegn.", "new_password": "Ny adgangskode", "confirm": "Bekræft", "too_short": "Mindst 8 tegn.", diff --git a/locales/de/common.json b/locales/de/common.json index ffda1a3d4..a0ef503b5 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Kategorien", "categories_description": "Kontaktkategorien umbenennen", "no_categories": "Keine Kategorien gefunden", - "delete_category": "Kategorie löschen", - "category_deleted": "Kategorie gelöscht", - "category_delete_failed": "Kategorie konnte nicht gelöscht werden", "group_by_letter_description": "Alphabetische Abschnittsüberschriften in der Kontaktliste anzeigen", "group_by_letter_label": "Nach Anfangsbuchstaben gruppieren", "sort_by_last_name_label": "Nach Nachname sortieren", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Die Konfiguration ist schreibgeschützt", - "body": "Das Konfigurations-Volume ist schreibgeschützt eingebunden oder {variable} ist gesetzt. Binden Sie es beschreibbar ein oder entfernen Sie die Variable und starten Sie den Container neu." + "body": "Das Konfigurations-Volume ist schreibgeschützt eingebunden oder {variable} ist gesetzt. Binden Sie es beschreibbar ein oder entfernen Sie die Variable und starten Sie den Container neu." }, "done": { "title": "Alles bereit", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Das kann vorkommen, wenn ein Reverse Proxy JMAP auf derselben Domain gesondert weiterleitet. Sonst ist die URL meist falsch.", "not_jmap_confirm": "Ich bin sicher, dass die URL stimmt, trotzdem fortfahren.", "http_title": "Diese URL verwendet unverschlüsseltes HTTP.", - "http_body": "Passwörter und E-Mail-Inhalte werden unverschlüsselt zwischen den Benutzern und Ihrem Server übertragen. Verwenden Sie im Betrieb {https}: Terminieren Sie TLS auf dem Mailserver oder in einem vorgeschalteten Reverse Proxy.", + "http_body": "Passwörter und E-Mail-Inhalte werden unverschlüsselt zwischen den Benutzern und Ihrem Server übertragen. Verwenden Sie im Betrieb {https}: Terminieren Sie TLS auf dem Mailserver oder in einem vorgeschalteten Reverse Proxy.", "local_title": "Diese URL ist nur lokal erreichbar.", - "local_body": "E-Mails werden direkt vom Browser der Benutzer abgerufen, daher muss die JMAP-URL von überall erreichbar sein, wo sich Benutzer anmelden, nicht nur von diesem Rechner oder LAN. Verwenden Sie im Betrieb einen öffentlichen Hostnamen (z. B. {example}).", + "local_body": "E-Mails werden direkt vom Browser der Benutzer abgerufen, daher muss die JMAP-URL von überall erreichbar sein, wo sich Benutzer anmelden, nicht nur von diesem Rechner oder LAN. Verwenden Sie im Betrieb einen öffentlichen Hostnamen (z. B. {example}).", "additional_title": "Weitere JMAP-Server", "additional_hint": "Optional. Mehrere Server in der Auswahl bei der Anmeldung anbieten, nützlich für Hosts mit mehreren Stalwart-Instanzen.", "additional_show": "Anzeigen ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Standardwerte", "company": "Name des Unternehmens", "password_title": "Admin-Passwort wählen", - "password_hint": "Damit melden Sie sich unter {path} an. Mindestens 8 Zeichen.", + "password_hint": "Damit melden Sie sich unter {path} an. Mindestens 8 Zeichen.", "new_password": "Neues Passwort", "confirm": "Bestätigen", "too_short": "Mindestens 8 Zeichen.", diff --git a/locales/en/common.json b/locales/en/common.json index fd6ec566e..a3014176a 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "No address books found", "categories_title": "Categories", "categories_description": "Rename contact categories", - "no_categories": "No categories found", - "delete_category": "Delete category", - "category_deleted": "Category deleted", - "category_delete_failed": "Couldn't delete the category" + "no_categories": "No categories found" }, "calendar_management": { "delete_title": "Delete calendar?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Configuration is read-only", - "body": "The config volume is mounted read-only or {variable} is set. Remount it read-write or unset that variable, then restart the container." + "body": "The config volume is mounted read-only or {variable} is set. Remount it read-write or unset that variable, then restart the container." }, "done": { "title": "You're all set", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "This can happen when a reverse proxy routes JMAP separately on the same domain. Otherwise, it usually means the URL is wrong.", "not_jmap_confirm": "I'm sure this is the right URL, continue anyway.", "http_title": "This URL uses plain HTTP.", - "http_body": "Passwords and email contents will travel unencrypted between users and your server. Use {https} in production: terminate TLS on the mail server or a reverse proxy in front of it.", + "http_body": "Passwords and email contents will travel unencrypted between users and your server. Use {https} in production: terminate TLS on the mail server or a reverse proxy in front of it.", "local_title": "This URL only resolves locally.", - "local_body": "Mail is fetched directly from the user's browser, so the JMAP URL must be reachable from anywhere users sign in, not just this machine or LAN. Use a public hostname (e.g. {example}) in production.", + "local_body": "Mail is fetched directly from the user's browser, so the JMAP URL must be reachable from anywhere users sign in, not just this machine or LAN. Use a public hostname (e.g. {example}) in production.", "additional_title": "Additional JMAP servers", "additional_hint": "Optional. Offer several servers in the login dropdown, useful for hosts running several Stalwart instances.", "additional_show": "Show ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Using defaults", "company": "Company name", "password_title": "Choose an admin password", - "password_hint": "You'll use this to sign in at {path}. Minimum 8 characters.", + "password_hint": "You'll use this to sign in at {path}. Minimum 8 characters.", "new_password": "New password", "confirm": "Confirm", "too_short": "At least 8 characters.", diff --git a/locales/es/common.json b/locales/es/common.json index 932cda03a..ee41cecee 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Categorías", "categories_description": "Renombrar categorías de contactos", "no_categories": "No se encontraron categorías", - "delete_category": "Eliminar categoría", - "category_deleted": "Categoría eliminada", - "category_delete_failed": "No se pudo eliminar la categoría", "group_by_letter_description": "Mostrar encabezados alfabéticos en la lista de contactos", "group_by_letter_label": "Agrupar por primera letra", "sort_by_last_name_label": "Ordenar por apellido", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "La configuración es de solo lectura", - "body": "El volumen de configuración está montado como solo lectura o la variable {variable} está definida. Móntalo con escritura o quita esa variable y reinicia el contenedor." + "body": "El volumen de configuración está montado como solo lectura o la variable {variable} está definida. Móntalo con escritura o quita esa variable y reinicia el contenedor." }, "done": { "title": "Todo listo", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Puede ocurrir cuando un proxy inverso enruta JMAP por separado en el mismo dominio. Si no, normalmente la URL es incorrecta.", "not_jmap_confirm": "Estoy seguro de que la URL es correcta, continuar de todos modos.", "http_title": "Esta URL usa HTTP sin cifrar.", - "http_body": "Las contraseñas y el contenido de los correos viajarán sin cifrar entre los usuarios y tu servidor. Usa {https} en producción: termina TLS en el servidor de correo o en un proxy inverso delante de él.", + "http_body": "Las contraseñas y el contenido de los correos viajarán sin cifrar entre los usuarios y tu servidor. Usa {https} en producción: termina TLS en el servidor de correo o en un proxy inverso delante de él.", "local_title": "Esta URL solo funciona en local.", - "local_body": "El correo se obtiene directamente desde el navegador del usuario, así que la URL de JMAP debe ser accesible desde cualquier lugar donde inicien sesión los usuarios, no solo desde este equipo o esta red local. Usa un nombre de host público (p. ej., {example}) en producción.", + "local_body": "El correo se obtiene directamente desde el navegador del usuario, así que la URL de JMAP debe ser accesible desde cualquier lugar donde inicien sesión los usuarios, no solo desde este equipo o esta red local. Usa un nombre de host público (p. ej., {example}) en producción.", "additional_title": "Servidores JMAP adicionales", "additional_hint": "Opcional. Ofrece varios servidores en la lista de inicio de sesión, útil para proveedores con varias instancias de Stalwart.", "additional_show": "Mostrar ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valores predeterminados", "company": "Nombre de la empresa", "password_title": "Elige una contraseña de administrador", - "password_hint": "La usarás para iniciar sesión en {path}. Mínimo 8 caracteres.", + "password_hint": "La usarás para iniciar sesión en {path}. Mínimo 8 caracteres.", "new_password": "Nueva contraseña", "confirm": "Confirmar", "too_short": "Al menos 8 caracteres.", diff --git a/locales/et/common.json b/locales/et/common.json index f0d0c3860..1af2dd1ba 100644 --- a/locales/et/common.json +++ b/locales/et/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "Aadressiraamatuid ei leitud", "categories_title": "Kategooriad", "categories_description": "Nimeta kontaktikategooriad ümber", - "no_categories": "Kategooriaid ei leitud", - "delete_category": "Kustuta kategooria", - "category_deleted": "Kategooria kustutatud", - "category_delete_failed": "Kategooriat ei õnnestunud kustutada" + "no_categories": "Kategooriaid ei leitud" }, "calendar_management": { "delete_title": "Kustutada kalender?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Seadistus on kirjutuskaitstud", - "body": "Seadistuse köide on ühendatud kirjutuskaitstuna või on määratud {variable}. Ühenda see kirjutusõigusega või eemalda muutuja ja käivita konteiner uuesti." + "body": "Seadistuse köide on ühendatud kirjutuskaitstuna või on määratud {variable}. Ühenda see kirjutusõigusega või eemalda muutuja ja käivita konteiner uuesti." }, "done": { "title": "Kõik on valmis", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "See võib juhtuda, kui pöördpuhverserver suunab JMAP-i samal domeenil eraldi. Muidu on URL tavaliselt vale.", "not_jmap_confirm": "Olen kindel, et URL on õige, jätka ikkagi.", "http_title": "See URL kasutab krüpteerimata HTTP-d.", - "http_body": "Paroolid ja kirjade sisu liiguvad kasutajate ja sinu serveri vahel krüpteerimata. Kasuta tootmises {https}: lõpeta TLS meiliserveris või selle ees olevas pöördpuhverserveris.", + "http_body": "Paroolid ja kirjade sisu liiguvad kasutajate ja sinu serveri vahel krüpteerimata. Kasuta tootmises {https}: lõpeta TLS meiliserveris või selle ees olevas pöördpuhverserveris.", "local_title": "See URL töötab ainult kohalikult.", - "local_body": "Post laaditakse otse kasutaja brauserist, seega peab JMAP-i URL olema kättesaadav kõikjal, kus kasutajad sisse logivad, mitte ainult sellest arvutist või kohtvõrgust. Kasuta tootmises avalikku hostinime (nt {example}).", + "local_body": "Post laaditakse otse kasutaja brauserist, seega peab JMAP-i URL olema kättesaadav kõikjal, kus kasutajad sisse logivad, mitte ainult sellest arvutist või kohtvõrgust. Kasuta tootmises avalikku hostinime (nt {example}).", "additional_title": "Täiendavad JMAP-serverid", "additional_hint": "Valikuline. Paku sisselogimisel mitut serverit, kasulik mitme Stalwarti eksemplariga teenusepakkujale.", "additional_show": "Näita ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Vaikeväärtused", "company": "Ettevõtte nimi", "password_title": "Vali administraatori parool", - "password_hint": "Selle abil logid sisse aadressil {path}. Vähemalt 8 märki.", + "password_hint": "Selle abil logid sisse aadressil {path}. Vähemalt 8 märki.", "new_password": "Uus parool", "confirm": "Kinnita", "too_short": "Vähemalt 8 märki.", diff --git a/locales/fa/common.json b/locales/fa/common.json index 0fa77d4b4..58ffba6c9 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "دفترچه آدرسی یافت نشد", "categories_title": "دسته‌بندی‌ها", "categories_description": "تغییر نام دسته‌بندی‌های مخاطبین", - "no_categories": "دسته‌بندی یافت نشد", - "delete_category": "حذف دسته", - "category_deleted": "دسته حذف شد", - "category_delete_failed": "حذف دسته ممکن نشد" + "no_categories": "دسته‌بندی یافت نشد" }, "calendar_management": { "delete_title": "تقویم حذف شود؟", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "پیکربندی فقط‌خواندنی است", - "body": "حجم پیکربندی فقط‌خواندنی متصل شده یا {variable} تنظیم شده است. آن را با اجازهٔ نوشتن متصل کنید یا آن متغیر را بردارید و سپس کانتینر را دوباره راه‌اندازی کنید." + "body": "حجم پیکربندی فقط‌خواندنی متصل شده یا {variable} تنظیم شده است. آن را با اجازهٔ نوشتن متصل کنید یا آن متغیر را بردارید و سپس کانتینر را دوباره راه‌اندازی کنید." }, "done": { "title": "همه‌چیز آماده است", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "این وقتی پیش می‌آید که یک پراکسی معکوس JMAP را روی همان دامنه جداگانه مسیریابی کند. وگرنه معمولاً نشانی اشتباه است.", "not_jmap_confirm": "مطمئنم این نشانی درست است، در هر حال ادامه بده.", "http_title": "این نشانی از HTTP رمزنگاری‌نشده استفاده می‌کند.", - "http_body": "گذرواژه‌ها و محتوای نامه‌ها بدون رمزنگاری بین کاربران و سرور شما جابه‌جا می‌شوند. در محیط تولید از {https} استفاده کنید: TLS را روی سرور نامه یا در یک پراکسی معکوس جلوی آن خاتمه دهید.", + "http_body": "گذرواژه‌ها و محتوای نامه‌ها بدون رمزنگاری بین کاربران و سرور شما جابه‌جا می‌شوند. در محیط تولید از {https} استفاده کنید: TLS را روی سرور نامه یا در یک پراکسی معکوس جلوی آن خاتمه دهید.", "local_title": "این نشانی فقط به‌صورت محلی کار می‌کند.", - "local_body": "نامه‌ها مستقیماً از مرورگر کاربر دریافت می‌شوند، پس نشانی JMAP باید از هر جایی که کاربران وارد می‌شوند در دسترس باشد، نه فقط از این رایانه یا شبکهٔ محلی. در محیط تولید از نام میزبان عمومی (مثلاً {example}) استفاده کنید.", + "local_body": "نامه‌ها مستقیماً از مرورگر کاربر دریافت می‌شوند، پس نشانی JMAP باید از هر جایی که کاربران وارد می‌شوند در دسترس باشد، نه فقط از این رایانه یا شبکهٔ محلی. در محیط تولید از نام میزبان عمومی (مثلاً {example}) استفاده کنید.", "additional_title": "سرورهای JMAP بیشتر", "additional_hint": "اختیاری. چند سرور را در فهرست ورود نشان دهید؛ برای میزبان‌هایی با چند نمونهٔ Stalwart مفید است.", "additional_show": "نمایش ({count})", @@ -2891,7 +2888,7 @@ "defaults": "مقادیر پیش‌فرض", "company": "نام شرکت", "password_title": "گذرواژهٔ مدیر را انتخاب کنید", - "password_hint": "با آن در {path} وارد می‌شوید. دست‌کم ۸ نویسه.", + "password_hint": "با آن در {path} وارد می‌شوید. دست‌کم ۸ نویسه.", "new_password": "گذرواژهٔ جدید", "confirm": "تأیید", "too_short": "دست‌کم ۸ نویسه.", diff --git a/locales/fr/common.json b/locales/fr/common.json index 4c94fc9fb..8e6161cab 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Catégories", "categories_description": "Renommer les catégories de contacts", "no_categories": "Aucune catégorie trouvée", - "delete_category": "Supprimer la catégorie", - "category_deleted": "Catégorie supprimée", - "category_delete_failed": "Impossible de supprimer la catégorie", "group_by_letter_description": "Afficher des en-têtes alphabétiques dans la liste de contacts", "group_by_letter_label": "Grouper par première lettre", "sort_by_last_name_label": "Trier par nom de famille", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "La configuration est en lecture seule", - "body": "Le volume de configuration est monté en lecture seule ou la variable {variable} est définie. Remontez-le en lecture-écriture ou supprimez cette variable, puis redémarrez le conteneur." + "body": "Le volume de configuration est monté en lecture seule ou la variable {variable} est définie. Remontez-le en lecture-écriture ou supprimez cette variable, puis redémarrez le conteneur." }, "done": { "title": "Tout est prêt", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Cela peut arriver quand un proxy inverse achemine JMAP séparément sur le même domaine. Sinon, l’URL est généralement fausse.", "not_jmap_confirm": "Je suis sûr que cette URL est la bonne, continuer quand même.", "http_title": "Cette URL utilise HTTP non chiffré.", - "http_body": "Les mots de passe et le contenu des e-mails circuleront sans chiffrement entre les utilisateurs et votre serveur. Utilisez {https} en production : terminez TLS sur le serveur de messagerie ou sur un proxy inverse placé devant.", + "http_body": "Les mots de passe et le contenu des e-mails circuleront sans chiffrement entre les utilisateurs et votre serveur. Utilisez {https} en production : terminez TLS sur le serveur de messagerie ou sur un proxy inverse placé devant.", "local_title": "Cette URL ne fonctionne qu’en local.", - "local_body": "Les e-mails sont récupérés directement par le navigateur de l’utilisateur : l’URL JMAP doit donc être accessible partout où les utilisateurs se connectent, pas seulement depuis cette machine ou ce réseau local. Utilisez un nom d’hôte public (par ex. {example}) en production.", + "local_body": "Les e-mails sont récupérés directement par le navigateur de l’utilisateur : l’URL JMAP doit donc être accessible partout où les utilisateurs se connectent, pas seulement depuis cette machine ou ce réseau local. Utilisez un nom d’hôte public (par ex. {example}) en production.", "additional_title": "Serveurs JMAP supplémentaires", "additional_hint": "Facultatif. Proposez plusieurs serveurs dans la liste de connexion, utile pour les hébergeurs qui exploitent plusieurs instances Stalwart.", "additional_show": "Afficher ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valeurs par défaut", "company": "Nom de l’entreprise", "password_title": "Choisissez un mot de passe administrateur", - "password_hint": "Vous l’utiliserez pour vous connecter sur {path}. 8 caractères minimum.", + "password_hint": "Vous l’utiliserez pour vous connecter sur {path}. 8 caractères minimum.", "new_password": "Nouveau mot de passe", "confirm": "Confirmer", "too_short": "8 caractères minimum.", diff --git a/locales/he/common.json b/locales/he/common.json index f40e74c15..c4a353163 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -2299,9 +2299,6 @@ "categories_title": "קטגוריות", "categories_description": "שנה שם של קטגוריות אנשי קשר", "no_categories": "לא נמצאו קטגוריות", - "delete_category": "מחיקת קטגוריה", - "category_deleted": "הקטגוריה נמחקה", - "category_delete_failed": "לא ניתן היה למחוק את הקטגוריה", "group_by_letter_label": "קבוצה לפי אות ראשונה", "sort_by_last_name_label": "מיון לפי שם משפחה", "sort_by_last_name_description": "סידור רשימת אנשי הקשר לפי שם משפחה כך שבני אותה משפחה יופיעו יחד", @@ -2684,7 +2681,7 @@ }, "read_only": { "title": "התצורה לקריאה בלבד", - "body": "אמצעי האחסון של התצורה מחובר לקריאה בלבד או שהמשתנה {variable} מוגדר. חברו אותו מחדש עם הרשאת כתיבה או הסירו את המשתנה, ואז הפעילו מחדש את הקונטיינר." + "body": "אמצעי האחסון של התצורה מחובר לקריאה בלבד או שהמשתנה {variable} מוגדר. חברו אותו מחדש עם הרשאת כתיבה או הסירו את המשתנה, ואז הפעילו מחדש את הקונטיינר." }, "done": { "title": "הכול מוכן", @@ -2736,9 +2733,9 @@ "not_jmap_hint": "זה יכול לקרות כששרת proxy הפוך מנתב את JMAP בנפרד באותו דומיין. אחרת, בדרך כלל כתובת ה-URL שגויה.", "not_jmap_confirm": "אני בטוח שכתובת ה-URL נכונה, להמשיך בכל זאת.", "http_title": "כתובת ה-URL הזו משתמשת ב-HTTP לא מוצפן.", - "http_body": "סיסמאות ותוכן הודעות יעברו ללא הצפנה בין המשתמשים לשרת שלכם. בסביבת ייצור השתמשו ב-{https}: סיימו את TLS בשרת הדואר או בשרת proxy הפוך שלפניו.", + "http_body": "סיסמאות ותוכן הודעות יעברו ללא הצפנה בין המשתמשים לשרת שלכם. בסביבת ייצור השתמשו ב-{https}: סיימו את TLS בשרת הדואר או בשרת proxy הפוך שלפניו.", "local_title": "כתובת ה-URL הזו פועלת רק מקומית.", - "local_body": "הדואר נטען ישירות מהדפדפן של המשתמש, ולכן כתובת ה-JMAP חייבת להיות נגישה מכל מקום שבו המשתמשים מתחברים, לא רק מהמחשב הזה או מהרשת המקומית. בסביבת ייצור השתמשו בשם מארח ציבורי (למשל {example}).", + "local_body": "הדואר נטען ישירות מהדפדפן של המשתמש, ולכן כתובת ה-JMAP חייבת להיות נגישה מכל מקום שבו המשתמשים מתחברים, לא רק מהמחשב הזה או מהרשת המקומית. בסביבת ייצור השתמשו בשם מארח ציבורי (למשל {example}).", "additional_title": "שרתי JMAP נוספים", "additional_hint": "אופציונלי. הציעו כמה שרתים ברשימת ההתחברות, שימושי למארחים שמריצים כמה מופעי Stalwart.", "additional_show": "הצגה ({count})", @@ -2857,7 +2854,7 @@ "defaults": "ערכי ברירת מחדל", "company": "שם החברה", "password_title": "בחרו סיסמת מנהל", - "password_hint": "תשתמשו בה כדי להתחבר בכתובת {path}. לפחות 8 תווים.", + "password_hint": "תשתמשו בה כדי להתחבר בכתובת {path}. לפחות 8 תווים.", "new_password": "סיסמה חדשה", "confirm": "אישור", "too_short": "לפחות 8 תווים.", diff --git a/locales/hu/common.json b/locales/hu/common.json index e5fbfcd5c..935a2735a 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -2339,10 +2339,7 @@ "no_address_books": "Nincs címjegyzék", "categories_title": "Kategóriák", "categories_description": "Névjegy kategóriák átnevezése", - "no_categories": "Nincs kategória", - "delete_category": "Kategória törlése", - "category_deleted": "Kategória törölve", - "category_delete_failed": "Nem sikerült törölni a kategóriát" + "no_categories": "Nincs kategória" }, "calendar_management": { "delete_title": "Törli a naptárt?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "A konfiguráció csak olvasható", - "body": "A konfigurációs kötet csak olvasásra van csatolva, vagy be van állítva a(z) {variable}. Csatolja írhatóként vagy törölje a változót, majd indítsa újra a konténert." + "body": "A konfigurációs kötet csak olvasásra van csatolva, vagy be van állítva a(z) {variable}. Csatolja írhatóként vagy törölje a változót, majd indítsa újra a konténert." }, "done": { "title": "Minden kész", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Ez előfordulhat, ha egy fordított proxy ugyanazon a tartományon külön irányítja a JMAP-ot. Egyébként általában rossz az URL.", "not_jmap_confirm": "Biztos vagyok benne, hogy az URL helyes, folytatás így is.", "http_title": "Ez az URL titkosítatlan HTTP-t használ.", - "http_body": "A jelszavak és a levelek tartalma titkosítás nélkül utaznak a felhasználók és a szerver között. Éles környezetben használja a(z) {https} előtagot: a TLS-t a levelezőszerveren vagy egy előtte álló fordított proxyban zárja le.", + "http_body": "A jelszavak és a levelek tartalma titkosítás nélkül utaznak a felhasználók és a szerver között. Éles környezetben használja a(z) {https} előtagot: a TLS-t a levelezőszerveren vagy egy előtte álló fordított proxyban zárja le.", "local_title": "Ez az URL csak helyben érhető el.", - "local_body": "A leveleket közvetlenül a felhasználó böngészője tölti le, ezért a JMAP-URL-nek mindenhonnan elérhetőnek kell lennie, ahol a felhasználók bejelentkeznek, nem csak erről a gépről vagy helyi hálózatból. Éles környezetben használjon nyilvános gépnevet (pl. {example}).", + "local_body": "A leveleket közvetlenül a felhasználó böngészője tölti le, ezért a JMAP-URL-nek mindenhonnan elérhetőnek kell lennie, ahol a felhasználók bejelentkeznek, nem csak erről a gépről vagy helyi hálózatból. Éles környezetben használjon nyilvános gépnevet (pl. {example}).", "additional_title": "További JMAP-szerverek", "additional_hint": "Nem kötelező. Több szervert kínálhat a bejelentkezési listában, hasznos több Stalwart-példányt futtató szolgáltatóknak.", "additional_show": "Megjelenítés ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Alapértelmezések", "company": "A cég neve", "password_title": "Válasszon rendszergazdai jelszót", - "password_hint": "Ezzel jelentkezik be itt: {path}. Legalább 8 karakter.", + "password_hint": "Ezzel jelentkezik be itt: {path}. Legalább 8 karakter.", "new_password": "Új jelszó", "confirm": "Megerősítés", "too_short": "Legalább 8 karakter.", diff --git a/locales/it/common.json b/locales/it/common.json index 568b29361..43a2d65e1 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Categorie", "categories_description": "Rinomina le categorie dei contatti", "no_categories": "Nessuna categoria trovata", - "delete_category": "Elimina categoria", - "category_deleted": "Categoria eliminata", - "category_delete_failed": "Impossibile eliminare la categoria", "group_by_letter_description": "Mostra intestazioni alfabetiche nell'elenco dei contatti", "group_by_letter_label": "Raggruppa per prima lettera", "sort_by_last_name_label": "Ordina per cognome", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "La configurazione è di sola lettura", - "body": "Il volume di configurazione è montato in sola lettura oppure è impostata la variabile {variable}. Rimontalo in lettura e scrittura o rimuovi la variabile, poi riavvia il container." + "body": "Il volume di configurazione è montato in sola lettura oppure è impostata la variabile {variable}. Rimontalo in lettura e scrittura o rimuovi la variabile, poi riavvia il container." }, "done": { "title": "Tutto pronto", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Può succedere quando un reverse proxy instrada JMAP separatamente sullo stesso dominio. Altrimenti di solito l’URL è sbagliato.", "not_jmap_confirm": "Sono sicuro che l’URL sia giusto, continua comunque.", "http_title": "Questo URL usa HTTP non cifrato.", - "http_body": "Password e contenuto delle email viaggeranno senza cifratura tra gli utenti e il tuo server. Usa {https} in produzione: termina TLS sul server di posta o su un reverse proxy davanti.", + "http_body": "Password e contenuto delle email viaggeranno senza cifratura tra gli utenti e il tuo server. Usa {https} in produzione: termina TLS sul server di posta o su un reverse proxy davanti.", "local_title": "Questo URL funziona solo in locale.", - "local_body": "La posta viene recuperata direttamente dal browser dell’utente, quindi l’URL JMAP deve essere raggiungibile ovunque gli utenti accedano, non solo da questo computer o dalla rete locale. In produzione usa un nome host pubblico (ad es. {example}).", + "local_body": "La posta viene recuperata direttamente dal browser dell’utente, quindi l’URL JMAP deve essere raggiungibile ovunque gli utenti accedano, non solo da questo computer o dalla rete locale. In produzione usa un nome host pubblico (ad es. {example}).", "additional_title": "Server JMAP aggiuntivi", "additional_hint": "Facoltativo. Offri più server nell’elenco di accesso, utile per chi gestisce più istanze Stalwart.", "additional_show": "Mostra ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valori predefiniti", "company": "Nome dell’azienda", "password_title": "Scegli una password di amministratore", - "password_hint": "La userai per accedere a {path}. Almeno 8 caratteri.", + "password_hint": "La userai per accedere a {path}. Almeno 8 caratteri.", "new_password": "Nuova password", "confirm": "Conferma", "too_short": "Almeno 8 caratteri.", diff --git a/locales/ja/common.json b/locales/ja/common.json index c2be688d2..d9f082790 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -2333,9 +2333,6 @@ "categories_title": "カテゴリ", "categories_description": "連絡先カテゴリの名前を変更", "no_categories": "カテゴリが見つかりません", - "delete_category": "カテゴリーを削除", - "category_deleted": "カテゴリーを削除しました", - "category_delete_failed": "カテゴリーを削除できませんでした", "group_by_letter_description": "連絡先リストにアルファベット順のセクション見出しを表示", "group_by_letter_label": "頭文字でグループ化", "sort_by_last_name_label": "姓で並べ替え", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "設定は読み取り専用です", - "body": "設定ボリュームが読み取り専用でマウントされているか、{variable} が設定されています。書き込み可能でマウントし直すか変数を削除してから、コンテナーを再起動してください。" + "body": "設定ボリュームが読み取り専用でマウントされているか、{variable} が設定されています。書き込み可能でマウントし直すか変数を削除してから、コンテナーを再起動してください。" }, "done": { "title": "準備ができました", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "リバースプロキシが同じドメインで JMAP を別にルーティングしている場合に起こることがあります。それ以外の場合は、たいてい URL が間違っています。", "not_jmap_confirm": "この URL で正しいので、このまま続ける。", "http_title": "この URL は暗号化されていない HTTP を使用しています。", - "http_body": "パスワードとメールの内容が、ユーザーとサーバーの間を暗号化されずに送信されます。本番環境では {https} を使用してください。TLS はメールサーバーか、その手前のリバースプロキシで終端します。", + "http_body": "パスワードとメールの内容が、ユーザーとサーバーの間を暗号化されずに送信されます。本番環境では {https} を使用してください。TLS はメールサーバーか、その手前のリバースプロキシで終端します。", "local_title": "この URL はローカルでしか解決できません。", - "local_body": "メールはユーザーのブラウザーから直接取得されるため、JMAP の URL はこのマシンや LAN だけでなく、ユーザーがサインインするあらゆる場所から到達できる必要があります。本番環境では公開ホスト名 (例: {example}) を使用してください。", + "local_body": "メールはユーザーのブラウザーから直接取得されるため、JMAP の URL はこのマシンや LAN だけでなく、ユーザーがサインインするあらゆる場所から到達できる必要があります。本番環境では公開ホスト名 (例: {example}) を使用してください。", "additional_title": "追加の JMAP サーバー", "additional_hint": "任意です。ログイン時のリストに複数のサーバーを表示します。複数の Stalwart インスタンスを運用するホストに便利です。", "additional_show": "表示 ({count})", @@ -2891,7 +2888,7 @@ "defaults": "既定値", "company": "会社名", "password_title": "管理者パスワードを決めてください", - "password_hint": "{path} へのサインインに使います。8 文字以上です。", + "password_hint": "{path} へのサインインに使います。8 文字以上です。", "new_password": "新しいパスワード", "confirm": "確認", "too_short": "8 文字以上にしてください。", diff --git a/locales/ko/common.json b/locales/ko/common.json index bfd929c6f..6967a1106 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -2333,9 +2333,6 @@ "categories_title": "카테고리", "categories_description": "연락처 카테고리 이름 변경", "no_categories": "카테고리를 찾을 수 없음", - "delete_category": "카테고리 삭제", - "category_deleted": "카테고리를 삭제했어요", - "category_delete_failed": "카테고리를 삭제하지 못했어요", "group_by_letter_description": "연락처 목록에 알파벳순 섹션 헤더 표시", "group_by_letter_label": "첫 글자로 그룹화", "sort_by_last_name_label": "성으로 정렬", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "구성이 읽기 전용이에요", - "body": "구성 볼륨이 읽기 전용으로 마운트되었거나 {variable}이(가) 설정되어 있어요. 쓰기 가능하게 다시 마운트하거나 변수를 해제한 뒤 컨테이너를 다시 시작하세요." + "body": "구성 볼륨이 읽기 전용으로 마운트되었거나 {variable}이(가) 설정되어 있어요. 쓰기 가능하게 다시 마운트하거나 변수를 해제한 뒤 컨테이너를 다시 시작하세요." }, "done": { "title": "모두 준비되었어요", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "리버스 프록시가 같은 도메인에서 JMAP를 따로 라우팅하면 이럴 수 있어요. 그렇지 않다면 대개 URL이 잘못된 거예요.", "not_jmap_confirm": "이 URL이 맞다고 확신해요. 그래도 계속할게요.", "http_title": "이 URL은 암호화되지 않은 HTTP를 사용해요.", - "http_body": "비밀번호와 메일 내용이 사용자와 서버 사이에서 암호화되지 않은 채 전송돼요. 운영 환경에서는 {https}을(를) 사용하세요. TLS는 메일 서버나 그 앞의 리버스 프록시에서 종료하세요.", + "http_body": "비밀번호와 메일 내용이 사용자와 서버 사이에서 암호화되지 않은 채 전송돼요. 운영 환경에서는 {https}을(를) 사용하세요. TLS는 메일 서버나 그 앞의 리버스 프록시에서 종료하세요.", "local_title": "이 URL은 로컬에서만 접근할 수 있어요.", - "local_body": "메일은 사용자의 브라우저에서 직접 가져오므로, JMAP URL은 이 컴퓨터나 LAN뿐 아니라 사용자가 로그인하는 모든 곳에서 접근할 수 있어야 해요. 운영 환경에서는 공개 호스트 이름(예: {example})을 사용하세요.", + "local_body": "메일은 사용자의 브라우저에서 직접 가져오므로, JMAP URL은 이 컴퓨터나 LAN뿐 아니라 사용자가 로그인하는 모든 곳에서 접근할 수 있어야 해요. 운영 환경에서는 공개 호스트 이름(예: {example})을 사용하세요.", "additional_title": "추가 JMAP 서버", "additional_hint": "선택 사항이에요. 로그인 목록에 여러 서버를 표시해요. Stalwart 인스턴스를 여러 개 운영하는 호스트에 유용해요.", "additional_show": "표시 ({count})", @@ -2891,7 +2888,7 @@ "defaults": "기본값 사용", "company": "회사 이름", "password_title": "관리자 비밀번호 정하기", - "password_hint": "{path}에 로그인할 때 사용해요. 최소 8자예요.", + "password_hint": "{path}에 로그인할 때 사용해요. 최소 8자예요.", "new_password": "새 비밀번호", "confirm": "확인", "too_short": "8자 이상이어야 해요.", diff --git a/locales/lv/common.json b/locales/lv/common.json index 0bb1485dc..ef7085ff6 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Kategorijas", "categories_description": "Pārdēvēt kontaktu kategorijas", "no_categories": "Kategorijas nav atrastas", - "delete_category": "Dzēst kategoriju", - "category_deleted": "Kategorija izdzēsta", - "category_delete_failed": "Neizdevās izdzēst kategoriju", "group_by_letter_description": "Rādīt alfabētiskos sadaļu virsrakstus kontaktu sarakstā", "group_by_letter_label": "Grupēt pēc pirmā burta", "sort_by_last_name_label": "Kārtot pēc uzvārda", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfigurācija ir tikai lasāma", - "body": "Konfigurācijas sējums ir pievienots tikai lasīšanai vai ir iestatīts {variable}. Pievienojiet to ar rakstīšanas tiesībām vai noņemiet mainīgo un restartējiet konteineru." + "body": "Konfigurācijas sējums ir pievienots tikai lasīšanai vai ir iestatīts {variable}. Pievienojiet to ar rakstīšanas tiesībām vai noņemiet mainīgo un restartējiet konteineru." }, "done": { "title": "Viss gatavs", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Tā var notikt, ja reversais starpniekserveris tajā pašā domēnā JMAP maršrutē atsevišķi. Citādi URL parasti ir nepareizs.", "not_jmap_confirm": "Esmu pārliecināts, ka URL ir pareizs, tomēr turpināt.", "http_title": "Šis URL izmanto nešifrētu HTTP.", - "http_body": "Paroles un vēstuļu saturs starp lietotājiem un jūsu serveri tiks pārsūtīts nešifrēti. Ražošanā izmantojiet {https}: pārtrauciet TLS pasta serverī vai tā priekšā esošā reversajā starpniekserverī.", + "http_body": "Paroles un vēstuļu saturs starp lietotājiem un jūsu serveri tiks pārsūtīts nešifrēti. Ražošanā izmantojiet {https}: pārtrauciet TLS pasta serverī vai tā priekšā esošā reversajā starpniekserverī.", "local_title": "Šis URL darbojas tikai lokāli.", - "local_body": "Pasts tiek ielādēts tieši lietotāja pārlūkā, tāpēc JMAP URL jābūt sasniedzamam visur, kur lietotāji piesakās, nevis tikai no šī datora vai lokālā tīkla. Ražošanā izmantojiet publisku resursdatora nosaukumu (piem., {example}).", + "local_body": "Pasts tiek ielādēts tieši lietotāja pārlūkā, tāpēc JMAP URL jābūt sasniedzamam visur, kur lietotāji piesakās, nevis tikai no šī datora vai lokālā tīkla. Ražošanā izmantojiet publisku resursdatora nosaukumu (piem., {example}).", "additional_title": "Papildu JMAP serveri", "additional_hint": "Neobligāti. Piedāvājiet pieteikšanās sarakstā vairākus serverus, noderīgi pakalpojumu sniedzējiem ar vairākām Stalwart instancēm.", "additional_show": "Rādīt ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Noklusējuma vērtības", "company": "Uzņēmuma nosaukums", "password_title": "Izvēlieties administratora paroli", - "password_hint": "Ar to piesakīsieties vietnē {path}. Vismaz 8 rakstzīmes.", + "password_hint": "Ar to piesakīsieties vietnē {path}. Vismaz 8 rakstzīmes.", "new_password": "Jaunā parole", "confirm": "Apstiprināt", "too_short": "Vismaz 8 rakstzīmes.", diff --git a/locales/mn/common.json b/locales/mn/common.json index 93a9c7995..1e2dda79c 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "Хаягийн дэвтэр олдсонгүй", "categories_title": "Ангилал", "categories_description": "Харилцах ангиллын нэрийг өөрчлөх", - "no_categories": "Ангилал олдсонгүй", - "delete_category": "Ангиллыг устгах", - "category_deleted": "Ангиллыг устгасан", - "category_delete_failed": "Ангиллыг устгаж чадсангүй" + "no_categories": "Ангилал олдсонгүй" }, "calendar_management": { "delete_title": "Хуанлийг устгах уу?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Тохиргоо зөвхөн уншигдана", - "body": "Тохиргооны боть зөвхөн уншихаар холбогдсон эсвэл {variable} тохируулагдсан байна. Бичих эрхтэй холбох эсвэл хувьсагчийг устгаад контейнерыг дахин эхлүүлнэ үү." + "body": "Тохиргооны боть зөвхөн уншихаар холбогдсон эсвэл {variable} тохируулагдсан байна. Бичих эрхтэй холбох эсвэл хувьсагчийг устгаад контейнерыг дахин эхлүүлнэ үү." }, "done": { "title": "Бүх зүйл бэлэн", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Урвуу прокси нэг домэйн дээр JMAP-ийг тусад нь чиглүүлж байвал ингэж болно. Үгүй бол URL ихэвчлэн буруу байдаг.", "not_jmap_confirm": "Энэ URL зөв гэдэгт итгэлтэй байна, үргэлжлүүлэх.", "http_title": "Энэ URL шифрлэгдээгүй HTTP ашиглаж байна.", - "http_body": "Нууц үг болон захидлын агуулга хэрэглэгчид болон таны серверийн хооронд шифрлэлтгүй дамжина. Үйлдвэрлэлийн орчинд {https} ашиглана уу: TLS-ийг шуудангийн сервер эсвэл түүний өмнөх урвуу прокси дээр төгсгөнө.", + "http_body": "Нууц үг болон захидлын агуулга хэрэглэгчид болон таны серверийн хооронд шифрлэлтгүй дамжина. Үйлдвэрлэлийн орчинд {https} ашиглана уу: TLS-ийг шуудангийн сервер эсвэл түүний өмнөх урвуу прокси дээр төгсгөнө.", "local_title": "Энэ URL зөвхөн дотоод сүлжээнд ажиллана.", - "local_body": "Шууданг хэрэглэгчийн хөтөч шууд татдаг тул JMAP URL нь зөвхөн энэ компьютер эсвэл дотоод сүлжээнээс бус, хэрэглэгчид нэвтэрдэг бүх газраас хүрэх боломжтой байх ёстой. Үйлдвэрлэлийн орчинд нийтийн хостын нэр (жишээ нь {example}) ашиглана уу.", + "local_body": "Шууданг хэрэглэгчийн хөтөч шууд татдаг тул JMAP URL нь зөвхөн энэ компьютер эсвэл дотоод сүлжээнээс бус, хэрэглэгчид нэвтэрдэг бүх газраас хүрэх боломжтой байх ёстой. Үйлдвэрлэлийн орчинд нийтийн хостын нэр (жишээ нь {example}) ашиглана уу.", "additional_title": "Нэмэлт JMAP серверүүд", "additional_hint": "Заавал биш. Нэвтрэх жагсаалтад хэд хэдэн сервер санал болгоно; олон Stalwart инстанс ажиллуулдаг үйлчилгээ үзүүлэгчдэд тохиромжтой.", "additional_show": "Харуулах ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Анхдагч утга", "company": "Компанийн нэр", "password_title": "Админы нууц үг сонгох", - "password_hint": "Үүгээр {path} хаягт нэвтэрнэ. Хамгийн багадаа 8 тэмдэгт.", + "password_hint": "Үүгээр {path} хаягт нэвтэрнэ. Хамгийн багадаа 8 тэмдэгт.", "new_password": "Шинэ нууц үг", "confirm": "Баталгаажуулах", "too_short": "Хамгийн багадаа 8 тэмдэгт.", diff --git a/locales/nb/common.json b/locales/nb/common.json index 9b781bf62..a837be64d 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "Ingen adressebøker funnet", "categories_title": "Kategorier", "categories_description": "Gi nytt navn til kontaktkategorier", - "no_categories": "Ingen kategorier funnet", - "delete_category": "Slett kategori", - "category_deleted": "Kategori slettet", - "category_delete_failed": "Kunne ikke slette kategorien" + "no_categories": "Ingen kategorier funnet" }, "calendar_management": { "delete_title": "Slette kalenderen?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfigurasjonen er skrivebeskyttet", - "body": "Konfigurasjonsvolumet er montert skrivebeskyttet, eller {variable} er satt. Monter det med skrivetilgang eller fjern variabelen, og start containeren på nytt." + "body": "Konfigurasjonsvolumet er montert skrivebeskyttet, eller {variable} er satt. Monter det med skrivetilgang eller fjern variabelen, og start containeren på nytt." }, "done": { "title": "Alt er klart", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Dette kan skje når en omvendt proxy ruter JMAP separat på samme domene. Ellers er URL-en som regel feil.", "not_jmap_confirm": "Jeg er sikker på at URL-en er riktig, fortsett likevel.", "http_title": "Denne URL-en bruker ukryptert HTTP.", - "http_body": "Passord og e-postinnhold sendes ukryptert mellom brukerne og serveren din. Bruk {https} i produksjon: avslutt TLS på e-postserveren eller i en omvendt proxy foran den.", + "http_body": "Passord og e-postinnhold sendes ukryptert mellom brukerne og serveren din. Bruk {https} i produksjon: avslutt TLS på e-postserveren eller i en omvendt proxy foran den.", "local_title": "Denne URL-en virker bare lokalt.", - "local_body": "E-post hentes direkte fra brukerens nettleser, så JMAP-URL-en må kunne nås overalt der brukerne logger på, ikke bare fra denne maskinen eller det lokale nettverket. Bruk et offentlig vertsnavn (f.eks. {example}) i produksjon.", + "local_body": "E-post hentes direkte fra brukerens nettleser, så JMAP-URL-en må kunne nås overalt der brukerne logger på, ikke bare fra denne maskinen eller det lokale nettverket. Bruk et offentlig vertsnavn (f.eks. {example}) i produksjon.", "additional_title": "Flere JMAP-servere", "additional_hint": "Valgfritt. Vis flere servere i listen ved pålogging, nyttig for leverandører med flere Stalwart-instanser.", "additional_show": "Vis ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Standardverdier", "company": "Firmanavn", "password_title": "Velg et administratorpassord", - "password_hint": "Du bruker det til å logge på {path}. Minst 8 tegn.", + "password_hint": "Du bruker det til å logge på {path}. Minst 8 tegn.", "new_password": "Nytt passord", "confirm": "Bekreft", "too_short": "Minst 8 tegn.", diff --git a/locales/nl/common.json b/locales/nl/common.json index 2d7184897..2ca8fca33 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Categorieën", "categories_description": "Contactcategorieën hernoemen", "no_categories": "Geen categorieën gevonden", - "delete_category": "Categorie verwijderen", - "category_deleted": "Categorie verwijderd", - "category_delete_failed": "Kan categorie niet verwijderen", "group_by_letter_description": "Toon alfabetische sectiekoppen in de contactenlijst", "group_by_letter_label": "Groeperen op eerste letter", "sort_by_last_name_label": "Sorteren op achternaam", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "De configuratie is alleen-lezen", - "body": "Het configuratievolume is alleen-lezen gekoppeld of {variable} is ingesteld. Koppel het met schrijfrechten of verwijder die variabele en start de container opnieuw." + "body": "Het configuratievolume is alleen-lezen gekoppeld of {variable} is ingesteld. Koppel het met schrijfrechten of verwijder die variabele en start de container opnieuw." }, "done": { "title": "Alles is klaar", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Dit kan gebeuren als een reverse proxy JMAP apart routeert op hetzelfde domein. Anders is de URL meestal onjuist.", "not_jmap_confirm": "Ik weet zeker dat dit de juiste URL is, toch doorgaan.", "http_title": "Deze URL gebruikt onversleuteld HTTP.", - "http_body": "Wachtwoorden en e-mailinhoud gaan onversleuteld tussen gebruikers en je server. Gebruik {https} in productie: beëindig TLS op de mailserver of in een reverse proxy ervoor.", + "http_body": "Wachtwoorden en e-mailinhoud gaan onversleuteld tussen gebruikers en je server. Gebruik {https} in productie: beëindig TLS op de mailserver of in een reverse proxy ervoor.", "local_title": "Deze URL werkt alleen lokaal.", - "local_body": "E-mail wordt rechtstreeks door de browser van de gebruiker opgehaald, dus de JMAP-URL moet bereikbaar zijn overal waar gebruikers zich aanmelden, niet alleen vanaf deze computer of dit lokale netwerk. Gebruik in productie een openbare hostnaam (bijv. {example}).", + "local_body": "E-mail wordt rechtstreeks door de browser van de gebruiker opgehaald, dus de JMAP-URL moet bereikbaar zijn overal waar gebruikers zich aanmelden, niet alleen vanaf deze computer of dit lokale netwerk. Gebruik in productie een openbare hostnaam (bijv. {example}).", "additional_title": "Extra JMAP-servers", "additional_hint": "Optioneel. Bied meerdere servers aan in de keuzelijst bij het aanmelden, handig voor hosts met meerdere Stalwart-instanties.", "additional_show": "Tonen ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Standaardwaarden", "company": "Naam van het bedrijf", "password_title": "Kies een beheerderswachtwoord", - "password_hint": "Hiermee meld je je aan op {path}. Minimaal 8 tekens.", + "password_hint": "Hiermee meld je je aan op {path}. Minimaal 8 tekens.", "new_password": "Nieuw wachtwoord", "confirm": "Bevestigen", "too_short": "Minimaal 8 tekens.", diff --git a/locales/pl/common.json b/locales/pl/common.json index 949b6d9e7..7c36a4512 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Kategorie", "categories_description": "Zmień nazwy kategorii kontaktów", "no_categories": "Nie znaleziono kategorii", - "delete_category": "Usuń kategorię", - "category_deleted": "Usunięto kategorię", - "category_delete_failed": "Nie udało się usunąć kategorii", "group_by_letter_description": "Pokaż alfabetyczne nagłówki sekcji na liście kontaktów", "group_by_letter_label": "Grupuj według pierwszej litery", "sort_by_last_name_label": "Sortuj według nazwiska", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfiguracja jest tylko do odczytu", - "body": "Wolumin konfiguracji jest zamontowany tylko do odczytu lub ustawiono zmienną {variable}. Zamontuj go z prawem zapisu lub usuń tę zmienną, a potem uruchom ponownie kontener." + "body": "Wolumin konfiguracji jest zamontowany tylko do odczytu lub ustawiono zmienną {variable}. Zamontuj go z prawem zapisu lub usuń tę zmienną, a potem uruchom ponownie kontener." }, "done": { "title": "Wszystko gotowe", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Tak bywa, gdy odwrotne proxy kieruje JMAP osobno w tej samej domenie. W przeciwnym razie adres URL jest zwykle błędny.", "not_jmap_confirm": "Jestem pewien, że ten adres URL jest prawidłowy, kontynuuj mimo to.", "http_title": "Ten adres URL używa niezaszyfrowanego HTTP.", - "http_body": "Hasła i treść wiadomości będą przesyłane bez szyfrowania między użytkownikami a Twoim serwerem. W środowisku produkcyjnym użyj {https}: zakończ TLS na serwerze poczty lub w odwrotnym proxy przed nim.", + "http_body": "Hasła i treść wiadomości będą przesyłane bez szyfrowania między użytkownikami a Twoim serwerem. W środowisku produkcyjnym użyj {https}: zakończ TLS na serwerze poczty lub w odwrotnym proxy przed nim.", "local_title": "Ten adres URL działa tylko lokalnie.", - "local_body": "Poczta jest pobierana bezpośrednio przez przeglądarkę użytkownika, więc adres URL JMAP musi być osiągalny wszędzie, gdzie użytkownicy się logują, nie tylko z tego komputera czy sieci lokalnej. W środowisku produkcyjnym użyj publicznej nazwy hosta (np. {example}).", + "local_body": "Poczta jest pobierana bezpośrednio przez przeglądarkę użytkownika, więc adres URL JMAP musi być osiągalny wszędzie, gdzie użytkownicy się logują, nie tylko z tego komputera czy sieci lokalnej. W środowisku produkcyjnym użyj publicznej nazwy hosta (np. {example}).", "additional_title": "Dodatkowe serwery JMAP", "additional_hint": "Opcjonalnie. Pokaż kilka serwerów na liście przy logowaniu, przydatne dla dostawców z kilkoma instancjami Stalwart.", "additional_show": "Pokaż ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Wartości domyślne", "company": "Nazwa firmy", "password_title": "Wybierz hasło administratora", - "password_hint": "Użyjesz go do logowania pod adresem {path}. Co najmniej 8 znaków.", + "password_hint": "Użyjesz go do logowania pod adresem {path}. Co najmniej 8 znaków.", "new_password": "Nowe hasło", "confirm": "Potwierdź", "too_short": "Co najmniej 8 znaków.", diff --git a/locales/pt/common.json b/locales/pt/common.json index b8498c9ff..0a62923ec 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Categorias", "categories_description": "Renomear categorias de contatos", "no_categories": "Nenhuma categoria encontrada", - "delete_category": "Eliminar categoria", - "category_deleted": "Categoria eliminada", - "category_delete_failed": "Não foi possível eliminar a categoria", "group_by_letter_description": "Mostrar cabeçalhos de seção alfabéticos na lista de contatos", "group_by_letter_label": "Agrupar pela primeira letra", "sort_by_last_name_label": "Ordenar por sobrenome", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "A configuração é só de leitura", - "body": "O volume de configuração está montado só de leitura ou a variável {variable} está definida. Volte a montá-lo com escrita ou remova essa variável e reinicie o contentor." + "body": "O volume de configuração está montado só de leitura ou a variável {variable} está definida. Volte a montá-lo com escrita ou remova essa variável e reinicie o contentor." }, "done": { "title": "Está tudo pronto", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Pode acontecer quando um proxy inverso encaminha o JMAP à parte no mesmo domínio. Caso contrário, o URL costuma estar errado.", "not_jmap_confirm": "Tenho a certeza de que o URL está certo, continuar mesmo assim.", "http_title": "Este URL usa HTTP sem encriptação.", - "http_body": "As palavras-passe e o conteúdo dos emails vão circular sem encriptação entre os utilizadores e o seu servidor. Use {https} em produção: termine o TLS no servidor de correio ou num proxy inverso à frente dele.", + "http_body": "As palavras-passe e o conteúdo dos emails vão circular sem encriptação entre os utilizadores e o seu servidor. Use {https} em produção: termine o TLS no servidor de correio ou num proxy inverso à frente dele.", "local_title": "Este URL só funciona localmente.", - "local_body": "O correio é obtido diretamente pelo navegador do utilizador, por isso o URL JMAP tem de estar acessível em qualquer lugar onde os utilizadores iniciem sessão, não só a partir desta máquina ou rede local. Em produção, use um nome de anfitrião público (por ex. {example}).", + "local_body": "O correio é obtido diretamente pelo navegador do utilizador, por isso o URL JMAP tem de estar acessível em qualquer lugar onde os utilizadores iniciem sessão, não só a partir desta máquina ou rede local. Em produção, use um nome de anfitrião público (por ex. {example}).", "additional_title": "Servidores JMAP adicionais", "additional_hint": "Opcional. Ofereça vários servidores na lista de início de sessão, útil para quem tem várias instâncias Stalwart.", "additional_show": "Mostrar ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valores predefinidos", "company": "Nome da empresa", "password_title": "Escolha uma palavra-passe de administrador", - "password_hint": "Vai usá-la para iniciar sessão em {path}. Mínimo de 8 caracteres.", + "password_hint": "Vai usá-la para iniciar sessão em {path}. Mínimo de 8 caracteres.", "new_password": "Nova palavra-passe", "confirm": "Confirmar", "too_short": "Pelo menos 8 caracteres.", diff --git a/locales/ro/common.json b/locales/ro/common.json index 429fa4dfa..9805a1708 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "Nu s-au găsit agende de adrese", "categories_title": "Categorii", "categories_description": "Redenumiți categoriile de contacte", - "no_categories": "Nu s-au găsit categorii", - "delete_category": "Șterge categoria", - "category_deleted": "Categorie ștearsă", - "category_delete_failed": "Categoria nu a putut fi ștearsă" + "no_categories": "Nu s-au găsit categorii" }, "calendar_management": { "delete_title": "Ștergeți calendarul?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Configurația este doar în citire", - "body": "Volumul de configurare este montat doar în citire sau este setată variabila {variable}. Montați-l cu drept de scriere sau eliminați variabila, apoi reporniți containerul." + "body": "Volumul de configurare este montat doar în citire sau este setată variabila {variable}. Montați-l cu drept de scriere sau eliminați variabila, apoi reporniți containerul." }, "done": { "title": "Totul este gata", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Se poate întâmpla când un proxy invers direcționează separat JMAP pe același domeniu. Altfel, de obicei URL-ul este greșit.", "not_jmap_confirm": "Sunt sigur că URL-ul este corect, continuă oricum.", "http_title": "Acest URL folosește HTTP necriptat.", - "http_body": "Parolele și conținutul e-mailurilor vor circula necriptat între utilizatori și serverul dvs. În producție folosiți {https}: terminați TLS pe serverul de e-mail sau într-un proxy invers aflat în fața lui.", + "http_body": "Parolele și conținutul e-mailurilor vor circula necriptat între utilizatori și serverul dvs. În producție folosiți {https}: terminați TLS pe serverul de e-mail sau într-un proxy invers aflat în fața lui.", "local_title": "Acest URL funcționează doar local.", - "local_body": "E-mailul este preluat direct din browserul utilizatorului, așa că URL-ul JMAP trebuie să fie accesibil de oriunde se conectează utilizatorii, nu doar de pe acest calculator sau din rețeaua locală. În producție folosiți un nume de gazdă public (de ex. {example}).", + "local_body": "E-mailul este preluat direct din browserul utilizatorului, așa că URL-ul JMAP trebuie să fie accesibil de oriunde se conectează utilizatorii, nu doar de pe acest calculator sau din rețeaua locală. În producție folosiți un nume de gazdă public (de ex. {example}).", "additional_title": "Servere JMAP suplimentare", "additional_hint": "Opțional. Oferiți mai multe servere în lista de autentificare, util pentru furnizorii cu mai multe instanțe Stalwart.", "additional_show": "Afișează ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Valori implicite", "company": "Numele companiei", "password_title": "Alegeți o parolă de administrator", - "password_hint": "O veți folosi pentru a vă conecta la {path}. Minimum 8 caractere.", + "password_hint": "O veți folosi pentru a vă conecta la {path}. Minimum 8 caractere.", "new_password": "Parolă nouă", "confirm": "Confirmați", "too_short": "Cel puțin 8 caractere.", diff --git a/locales/ru/common.json b/locales/ru/common.json index 82f6008b3..489bb9abc 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Категории", "categories_description": "Переименование категорий контактов", "no_categories": "Категории не найдены", - "delete_category": "Удалить категорию", - "category_deleted": "Категория удалена", - "category_delete_failed": "Не удалось удалить категорию", "group_by_letter_description": "Показывать алфавитные заголовки разделов в списке контактов", "group_by_letter_label": "Группировать по первой букве", "sort_by_last_name_label": "Сортировать по фамилии", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Конфигурация доступна только для чтения", - "body": "Том с конфигурацией смонтирован только для чтения или задана переменная {variable}. Смонтируйте его с правом записи или удалите переменную, затем перезапустите контейнер." + "body": "Том с конфигурацией смонтирован только для чтения или задана переменная {variable}. Смонтируйте его с правом записи или удалите переменную, затем перезапустите контейнер." }, "done": { "title": "Всё готово", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Так бывает, если обратный прокси отдельно маршрутизирует JMAP в том же домене. Иначе URL, скорее всего, неверный.", "not_jmap_confirm": "Я уверен, что URL правильный, продолжить всё равно.", "http_title": "Этот URL использует незашифрованный HTTP.", - "http_body": "Пароли и содержимое писем будут передаваться между пользователями и вашим сервером без шифрования. В рабочей среде используйте {https}: завершайте TLS на почтовом сервере или на обратном прокси перед ним.", + "http_body": "Пароли и содержимое писем будут передаваться между пользователями и вашим сервером без шифрования. В рабочей среде используйте {https}: завершайте TLS на почтовом сервере или на обратном прокси перед ним.", "local_title": "Этот URL работает только локально.", - "local_body": "Почта загружается прямо в браузере пользователя, поэтому URL JMAP должен быть доступен отовсюду, где входят пользователи, а не только с этого компьютера или из локальной сети. В рабочей среде используйте публичное имя хоста (например, {example}).", + "local_body": "Почта загружается прямо в браузере пользователя, поэтому URL JMAP должен быть доступен отовсюду, где входят пользователи, а не только с этого компьютера или из локальной сети. В рабочей среде используйте публичное имя хоста (например, {example}).", "additional_title": "Дополнительные серверы JMAP", "additional_hint": "Необязательно. Предложите несколько серверов в списке при входе; удобно для хостингов с несколькими экземплярами Stalwart.", "additional_show": "Показать ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Значения по умолчанию", "company": "Название компании", "password_title": "Выберите пароль администратора", - "password_hint": "Он нужен для входа на {path}. Не менее 8 символов.", + "password_hint": "Он нужен для входа на {path}. Не менее 8 символов.", "new_password": "Новый пароль", "confirm": "Подтверждение", "too_short": "Не менее 8 символов.", diff --git a/locales/sk/common.json b/locales/sk/common.json index fd5533096..5f25c3f8f 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "Neboli nájdené žiadne adresáre", "categories_title": "Kategórie", "categories_description": "Premenovať kategórie kontaktov", - "no_categories": "Neboli nájdené žiadne kategórie", - "delete_category": "Odstrániť kategóriu", - "category_deleted": "Kategória bola odstránená", - "category_delete_failed": "Kategóriu sa nepodarilo odstrániť" + "no_categories": "Neboli nájdené žiadne kategórie" }, "calendar_management": { "delete_title": "Odstrániť kalendár?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Konfigurácia je len na čítanie", - "body": "Zväzok s konfiguráciou je pripojený len na čítanie alebo je nastavená premenná {variable}. Pripojte ho na zápis alebo premennú odstráňte a reštartujte kontajner." + "body": "Zväzok s konfiguráciou je pripojený len na čítanie alebo je nastavená premenná {variable}. Pripojte ho na zápis alebo premennú odstráňte a reštartujte kontajner." }, "done": { "title": "Všetko je pripravené", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Stáva sa to, keď reverzná proxy smeruje JMAP na tej istej doméne zvlášť. Inak je URL zvyčajne nesprávna.", "not_jmap_confirm": "Som si istý, že URL je správna, aj tak pokračovať.", "http_title": "Táto URL používa nešifrované HTTP.", - "http_body": "Heslá a obsah e-mailov sa budú medzi používateľmi a vaším serverom prenášať nešifrovane. V prevádzke použite {https}: ukončite TLS na poštovom serveri alebo v reverznej proxy pred ním.", + "http_body": "Heslá a obsah e-mailov sa budú medzi používateľmi a vaším serverom prenášať nešifrovane. V prevádzke použite {https}: ukončite TLS na poštovom serveri alebo v reverznej proxy pred ním.", "local_title": "Táto URL funguje len lokálne.", - "local_body": "Pošta sa načítava priamo v prehliadači používateľa, takže URL JMAP musí byť dostupná odkiaľkoľvek, kde sa používatelia prihlasujú, nielen z tohto počítača alebo lokálnej siete. V prevádzke použite verejný názov hostiteľa (napr. {example}).", + "local_body": "Pošta sa načítava priamo v prehliadači používateľa, takže URL JMAP musí byť dostupná odkiaľkoľvek, kde sa používatelia prihlasujú, nielen z tohto počítača alebo lokálnej siete. V prevádzke použite verejný názov hostiteľa (napr. {example}).", "additional_title": "Ďalšie servery JMAP", "additional_hint": "Voliteľné. Ponúknite pri prihlásení viac serverov, užitočné pre hostingy s viacerými inštanciami Stalwart.", "additional_show": "Zobraziť ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Predvolené hodnoty", "company": "Názov firmy", "password_title": "Zvoľte heslo správcu", - "password_hint": "Budete sa ním prihlasovať na {path}. Aspoň 8 znakov.", + "password_hint": "Budete sa ním prihlasovať na {path}. Aspoň 8 znakov.", "new_password": "Nové heslo", "confirm": "Potvrdiť", "too_short": "Aspoň 8 znakov.", diff --git a/locales/th/common.json b/locales/th/common.json index e6181e420..8ed377e11 100644 --- a/locales/th/common.json +++ b/locales/th/common.json @@ -4507,10 +4507,7 @@ "no_address_books": "ไม่พบสมุดที่อยู่", "categories_title": "หมวดหมู่", "categories_description": "เปลี่ยนชื่อหมวดหมู่ผู้ติดต่อ", - "no_categories": "ไม่พบหมวดหมู่", - "delete_category": "ลบหมวดหมู่", - "category_deleted": "ลบหมวดหมู่แล้ว", - "category_delete_failed": "ลบหมวดหมู่ไม่ได้" + "no_categories": "ไม่พบหมวดหมู่" }, "calendar_management": { "delete_title": "ลบปฏิทินไหม", @@ -4882,7 +4879,7 @@ }, "read_only": { "title": "การกำหนดค่าเป็นแบบอ่านอย่างเดียว", - "body": "โวลุ่มการกำหนดค่าถูกเมานต์แบบอ่านอย่างเดียว หรือมีการตั้งค่า {variable} ไว้ เมานต์ใหม่แบบเขียนได้หรือยกเลิกตัวแปรนั้น แล้วรีสตาร์ตคอนเทนเนอร์" + "body": "โวลุ่มการกำหนดค่าถูกเมานต์แบบอ่านอย่างเดียว หรือมีการตั้งค่า {variable} ไว้ เมานต์ใหม่แบบเขียนได้หรือยกเลิกตัวแปรนั้น แล้วรีสตาร์ตคอนเทนเนอร์" }, "done": { "title": "พร้อมแล้ว", @@ -4934,9 +4931,9 @@ "not_jmap_hint": "อาจเกิดขึ้นเมื่อรีเวิร์สพร็อกซีส่งต่อ JMAP แยกต่างหากบนโดเมนเดียวกัน มิฉะนั้นมักแปลว่า URL ผิด", "not_jmap_confirm": "ฉันมั่นใจว่า URL นี้ถูกต้อง ดำเนินการต่อเลย", "http_title": "URL นี้ใช้ HTTP ที่ไม่เข้ารหัส", - "http_body": "รหัสผ่านและเนื้อหาอีเมลจะถูกส่งระหว่างผู้ใช้กับเซิร์ฟเวอร์ของคุณโดยไม่เข้ารหัส ในการใช้งานจริงให้ใช้ {https}: สิ้นสุด TLS ที่เซิร์ฟเวอร์อีเมลหรือที่รีเวิร์สพร็อกซีด้านหน้า", + "http_body": "รหัสผ่านและเนื้อหาอีเมลจะถูกส่งระหว่างผู้ใช้กับเซิร์ฟเวอร์ของคุณโดยไม่เข้ารหัส ในการใช้งานจริงให้ใช้ {https}: สิ้นสุด TLS ที่เซิร์ฟเวอร์อีเมลหรือที่รีเวิร์สพร็อกซีด้านหน้า", "local_title": "URL นี้ใช้ได้เฉพาะในเครื่อง", - "local_body": "อีเมลถูกดึงโดยตรงจากเบราว์เซอร์ของผู้ใช้ ดังนั้น URL ของ JMAP ต้องเข้าถึงได้จากทุกที่ที่ผู้ใช้ลงชื่อเข้าใช้ ไม่ใช่แค่จากเครื่องนี้หรือ LAN ในการใช้งานจริงให้ใช้ชื่อโฮสต์สาธารณะ (เช่น {example})", + "local_body": "อีเมลถูกดึงโดยตรงจากเบราว์เซอร์ของผู้ใช้ ดังนั้น URL ของ JMAP ต้องเข้าถึงได้จากทุกที่ที่ผู้ใช้ลงชื่อเข้าใช้ ไม่ใช่แค่จากเครื่องนี้หรือ LAN ในการใช้งานจริงให้ใช้ชื่อโฮสต์สาธารณะ (เช่น {example})", "additional_title": "เซิร์ฟเวอร์ JMAP เพิ่มเติม", "additional_hint": "ไม่บังคับ แสดงหลายเซิร์ฟเวอร์ในรายการตอนลงชื่อเข้าใช้ เหมาะกับผู้ให้บริการที่มี Stalwart หลายอินสแตนซ์", "additional_show": "แสดง ({count})", @@ -5055,7 +5052,7 @@ "defaults": "ใช้ค่าเริ่มต้น", "company": "ชื่อบริษัท", "password_title": "เลือกรหัสผ่านผู้ดูแล", - "password_hint": "ใช้รหัสนี้ลงชื่อเข้าใช้ที่ {path} อย่างน้อย 8 ตัวอักษร", + "password_hint": "ใช้รหัสนี้ลงชื่อเข้าใช้ที่ {path} อย่างน้อย 8 ตัวอักษร", "new_password": "รหัสผ่านใหม่", "confirm": "ยืนยัน", "too_short": "อย่างน้อย 8 ตัวอักษร", diff --git a/locales/tr/common.json b/locales/tr/common.json index 166856d55..b39dc5357 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -2336,10 +2336,7 @@ "no_address_books": "Adres defteri bulunamadı", "categories_title": "Kategoriler", "categories_description": "Kişi kategorilerini yeniden adlandırın", - "no_categories": "Kategori bulunamadı", - "delete_category": "Kategoriyi sil", - "category_deleted": "Kategori silindi", - "category_delete_failed": "Kategori silinemedi" + "no_categories": "Kategori bulunamadı" }, "calendar_management": { "delete_title": "Takvim silinsin mi?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Yapılandırma salt okunur", - "body": "Yapılandırma birimi salt okunur bağlanmış ya da {variable} ayarlanmış. Birimi yazılabilir olarak bağlayın veya değişkeni kaldırın, ardından kapsayıcıyı yeniden başlatın." + "body": "Yapılandırma birimi salt okunur bağlanmış ya da {variable} ayarlanmış. Birimi yazılabilir olarak bağlayın veya değişkeni kaldırın, ardından kapsayıcıyı yeniden başlatın." }, "done": { "title": "Her şey hazır", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Bu, bir ters vekil sunucu JMAP’i aynı alan adında ayrı yönlendirdiğinde olabilir. Aksi halde URL genellikle yanlıştır.", "not_jmap_confirm": "URL’nin doğru olduğundan eminim, yine de devam et.", "http_title": "Bu URL şifrelenmemiş HTTP kullanıyor.", - "http_body": "Parolalar ve e-posta içerikleri kullanıcılarla sunucunuz arasında şifrelenmeden iletilecek. Üretimde {https} kullanın: TLS’yi posta sunucusunda veya önündeki bir ters vekil sunucuda sonlandırın.", + "http_body": "Parolalar ve e-posta içerikleri kullanıcılarla sunucunuz arasında şifrelenmeden iletilecek. Üretimde {https} kullanın: TLS’yi posta sunucusunda veya önündeki bir ters vekil sunucuda sonlandırın.", "local_title": "Bu URL yalnızca yerelde çalışıyor.", - "local_body": "Postalar doğrudan kullanıcının tarayıcısından alınır; bu yüzden JMAP URL’si yalnızca bu makineden veya yerel ağdan değil, kullanıcıların oturum açtığı her yerden erişilebilir olmalıdır. Üretimde herkese açık bir ana bilgisayar adı (ör. {example}) kullanın.", + "local_body": "Postalar doğrudan kullanıcının tarayıcısından alınır; bu yüzden JMAP URL’si yalnızca bu makineden veya yerel ağdan değil, kullanıcıların oturum açtığı her yerden erişilebilir olmalıdır. Üretimde herkese açık bir ana bilgisayar adı (ör. {example}) kullanın.", "additional_title": "Ek JMAP sunucuları", "additional_hint": "İsteğe bağlı. Oturum açma listesinde birden çok sunucu sunun; birden fazla Stalwart örneği çalıştıran sağlayıcılar için kullanışlıdır.", "additional_show": "Göster ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Varsayılanlar", "company": "Şirket adı", "password_title": "Bir yönetici parolası seçin", - "password_hint": "{path} adresinde oturum açmak için bunu kullanacaksınız. En az 8 karakter.", + "password_hint": "{path} adresinde oturum açmak için bunu kullanacaksınız. En az 8 karakter.", "new_password": "Yeni parola", "confirm": "Onayla", "too_short": "En az 8 karakter.", diff --git a/locales/uk/common.json b/locales/uk/common.json index 957bb13e6..9b078c7db 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -2333,9 +2333,6 @@ "categories_title": "Категорії", "categories_description": "Перейменувати категорії контактів", "no_categories": "Категорії не знайдено", - "delete_category": "Видалити категорію", - "category_deleted": "Категорію видалено", - "category_delete_failed": "Не вдалося видалити категорію", "group_by_letter_description": "Показувати алфавітні заголовки розділів у списку контактів", "group_by_letter_label": "Групувати за першою літерою", "sort_by_last_name_label": "Сортувати за прізвищем", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "Конфігурація доступна лише для читання", - "body": "Том із конфігурацією змонтовано лише для читання або задано змінну {variable}. Змонтуйте його з правом запису або приберіть змінну, а потім перезапустіть контейнер." + "body": "Том із конфігурацією змонтовано лише для читання або задано змінну {variable}. Змонтуйте його з правом запису або приберіть змінну, а потім перезапустіть контейнер." }, "done": { "title": "Усе готово", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "Таке буває, коли зворотний проксі окремо маршрутизує JMAP у тому самому домені. Інакше URL, найімовірніше, неправильний.", "not_jmap_confirm": "Я впевнений, що URL правильний, однаково продовжити.", "http_title": "Цей URL використовує незашифрований HTTP.", - "http_body": "Паролі та вміст листів передаватимуться між користувачами й вашим сервером без шифрування. У робочому середовищі використовуйте {https}: завершуйте TLS на поштовому сервері або на зворотному проксі перед ним.", + "http_body": "Паролі та вміст листів передаватимуться між користувачами й вашим сервером без шифрування. У робочому середовищі використовуйте {https}: завершуйте TLS на поштовому сервері або на зворотному проксі перед ним.", "local_title": "Цей URL працює лише локально.", - "local_body": "Пошта завантажується просто в браузері користувача, тому URL JMAP має бути доступним звідусіль, де входять користувачі, а не лише з цього комп’ютера чи локальної мережі. У робочому середовищі використовуйте публічне ім’я хоста (наприклад, {example}).", + "local_body": "Пошта завантажується просто в браузері користувача, тому URL JMAP має бути доступним звідусіль, де входять користувачі, а не лише з цього комп’ютера чи локальної мережі. У робочому середовищі використовуйте публічне ім’я хоста (наприклад, {example}).", "additional_title": "Додаткові сервери JMAP", "additional_hint": "Необов’язково. Запропонуйте кілька серверів у списку під час входу; зручно для хостингів із кількома екземплярами Stalwart.", "additional_show": "Показати ({count})", @@ -2891,7 +2888,7 @@ "defaults": "Типові значення", "company": "Назва компанії", "password_title": "Виберіть пароль адміністратора", - "password_hint": "Він потрібен для входу на {path}. Щонайменше 8 символів.", + "password_hint": "Він потрібен для входу на {path}. Щонайменше 8 символів.", "new_password": "Новий пароль", "confirm": "Підтвердження", "too_short": "Щонайменше 8 символів.", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index 1c3d6eba5..c8a7a8c01 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -2343,10 +2343,7 @@ "no_address_books": "找不到通訊錄", "categories_title": "類別", "categories_description": "重新命名聯絡人類別", - "no_categories": "找不到類別", - "delete_category": "刪除類別", - "category_deleted": "類別已刪除", - "category_delete_failed": "無法刪除類別" + "no_categories": "找不到類別" }, "calendar_management": { "delete_title": "刪除行事曆?", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "設定為唯讀", - "body": "設定磁碟區以唯讀方式掛載,或設定了 {variable}。請以可寫入方式重新掛載或取消該變數,然後重新啟動容器。" + "body": "設定磁碟區以唯讀方式掛載,或設定了 {variable}。請以可寫入方式重新掛載或取消該變數,然後重新啟動容器。" }, "done": { "title": "一切就緒", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "當反向代理伺服器在同一網域下另外路由 JMAP 時可能發生這種情況。否則通常是 URL 有誤。", "not_jmap_confirm": "我確定此 URL 正確,仍要繼續。", "http_title": "此 URL 使用未加密的 HTTP。", - "http_body": "密碼和郵件內容將在使用者與伺服器之間以未加密方式傳送。正式環境請使用 {https}:在郵件伺服器或其前方的反向代理伺服器上終止 TLS。", + "http_body": "密碼和郵件內容將在使用者與伺服器之間以未加密方式傳送。正式環境請使用 {https}:在郵件伺服器或其前方的反向代理伺服器上終止 TLS。", "local_title": "此 URL 只能在本機存取。", - "local_body": "郵件直接由使用者的瀏覽器擷取,因此 JMAP URL 必須能從使用者登入的任何地方存取,而不僅是本機或區域網路。正式環境請使用公開的主機名稱(例如 {example})。", + "local_body": "郵件直接由使用者的瀏覽器擷取,因此 JMAP URL 必須能從使用者登入的任何地方存取,而不僅是本機或區域網路。正式環境請使用公開的主機名稱(例如 {example})。", "additional_title": "其他 JMAP 伺服器", "additional_hint": "選用。在登入清單中提供多台伺服器,適合執行多個 Stalwart 執行個體的託管業者。", "additional_show": "顯示 ({count})", @@ -2891,7 +2888,7 @@ "defaults": "使用預設值", "company": "公司名稱", "password_title": "選擇管理員密碼", - "password_hint": "你將用它在 {path} 登入。至少 8 個字元。", + "password_hint": "你將用它在 {path} 登入。至少 8 個字元。", "new_password": "新密碼", "confirm": "確認", "too_short": "至少 8 個字元。", diff --git a/locales/zh/common.json b/locales/zh/common.json index 11734ff85..04221e390 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -2333,9 +2333,6 @@ "categories_title": "类别", "categories_description": "重命名联系人类别", "no_categories": "未找到类别", - "delete_category": "删除类别", - "category_deleted": "类别已删除", - "category_delete_failed": "无法删除类别", "group_by_letter_description": "在联系人列表中显示按字母顺序排列的分节标题", "group_by_letter_label": "按首字母分组", "sort_by_last_name_label": "按姓氏排序", @@ -2718,7 +2715,7 @@ }, "read_only": { "title": "配置为只读", - "body": "配置卷以只读方式挂载,或设置了 {variable}。请以可写方式重新挂载或取消该变量,然后重启容器。" + "body": "配置卷以只读方式挂载,或设置了 {variable}。请以可写方式重新挂载或取消该变量,然后重启容器。" }, "done": { "title": "一切就绪", @@ -2770,9 +2767,9 @@ "not_jmap_hint": "当反向代理在同一域名下单独路由 JMAP 时可能出现这种情况。否则通常是 URL 有误。", "not_jmap_confirm": "我确定这个 URL 正确,仍然继续。", "http_title": "此 URL 使用未加密的 HTTP。", - "http_body": "密码和邮件内容将在用户与服务器之间以未加密方式传输。生产环境请使用 {https}:在邮件服务器或其前方的反向代理上终止 TLS。", + "http_body": "密码和邮件内容将在用户与服务器之间以未加密方式传输。生产环境请使用 {https}:在邮件服务器或其前方的反向代理上终止 TLS。", "local_title": "此 URL 只能在本地访问。", - "local_body": "邮件直接由用户的浏览器获取,因此 JMAP URL 必须能从用户登录的任何地方访问,而不仅是本机或局域网。生产环境请使用公共主机名(例如 {example})。", + "local_body": "邮件直接由用户的浏览器获取,因此 JMAP URL 必须能从用户登录的任何地方访问,而不仅是本机或局域网。生产环境请使用公共主机名(例如 {example})。", "additional_title": "其他 JMAP 服务器", "additional_hint": "可选。在登录列表中提供多个服务器,适合运行多个 Stalwart 实例的托管方。", "additional_show": "显示 ({count})", @@ -2891,7 +2888,7 @@ "defaults": "使用默认值", "company": "公司名称", "password_title": "选择管理员密码", - "password_hint": "你将用它在 {path} 登录。至少 8 个字符。", + "password_hint": "你将用它在 {path} 登录。至少 8 个字符。", "new_password": "新密码", "confirm": "确认", "too_short": "至少 8 个字符。", diff --git a/stores/contact-store.ts b/stores/contact-store.ts index 9cb62dea7..f6c8d84ab 100644 --- a/stores/contact-store.ts +++ b/stores/contact-store.ts @@ -527,6 +527,15 @@ export const useContactStore = create()( persist( (set, get) => { + // A contact's categories, saved on the server when there is one; + // false when a plugin stopped the change. + function saveContactKeywords(client: IJMAPClient | null, id: string, keywords: Record): Promise { + const { supportsSync, updateContact, updateLocalContact } = get(); + return supportsSync && client + ? updateContact(client, id, { keywords }) + : updateLocalContact(id, { keywords }); + } + // Clean group member references when contacts are removed function cleanGroupMembers(contacts: ContactCard[], removedIds: Set): ContactCard[] { // Collect uid/id variants of removed contacts for matching @@ -1413,22 +1422,14 @@ export const useContactStore = create()( removeKeyword: async (client, keyword) => { set({ error: null }); const kw = keyword.trim(); - const { contacts, supportsSync } = get(); - const affected = contacts.filter(c => c.keywords?.[kw]); + const affected = get().contacts.filter(c => c.keywords?.[kw]); const done: string[] = []; for (const contact of affected) { - const { [kw]: _gone, ...rest } = contact.keywords || {}; + const { [kw]: _gone, ...keywords } = contact.keywords || {}; void _gone; - if (supportsSync && client) { - const originalId = contact.originalId || contact.id; - const accountId = contact.isShared ? contact.accountId : undefined; - // JMAP patch: only this keyword goes; the card's others stay. - await client.updateContact(originalId, { keywords: rest }, accountId); - } - set((state) => ({ - contacts: state.contacts.map(c => (c.id === contact.id ? { ...c, keywords: rest } : c)), - })); - done.push(contact.id); + // Through the normal update, so plugins see it and each contact + // goes to its own account; one a plugin stops keeps the category. + if (await saveContactKeywords(client, contact.id, keywords)) done.push(contact.id); } return done; }, @@ -1436,19 +1437,10 @@ export const useContactStore = create()( addKeyword: async (client, keyword, contactIds) => { set({ error: null }); const kw = keyword.trim(); - const { contacts, supportsSync } = get(); for (const id of contactIds) { - const contact = contacts.find(c => c.id === id); + const contact = get().contacts.find(c => c.id === id); if (!contact || contact.keywords?.[kw]) continue; - const keywords = { ...(contact.keywords || {}), [kw]: true }; - if (supportsSync && client) { - const originalId = contact.originalId || contact.id; - const accountId = contact.isShared ? contact.accountId : undefined; - await client.updateContact(originalId, { keywords }, accountId); - } - set((state) => ({ - contacts: state.contacts.map(c => (c.id === id ? { ...c, keywords } : c)), - })); + await saveContactKeywords(client, id, { ...(contact.keywords || {}), [kw]: true }); } },