fix: ask "discard changes?" with keep editing and discard in settings editors and the admin pages, as in calendar and contacts

This commit is contained in:
Linus Rath
2026-10-28 10:19:10 +01:00
parent cc46573524
commit 62ab48aee4
32 changed files with 126 additions and 99 deletions
@@ -21,27 +21,27 @@ describe('admin unsaved changes guard (#1255)', () => {
expect(screen.queryByRole('alertdialog')).toBeNull();
});
it('asks before leaving with unsaved edits; Stay keeps the admin on the page', () => {
it('asks before leaving with unsaved edits; Keep editing keeps the admin on the page', () => {
render(<><UnsavedChangesGuard /><DirtySection dirty /></>);
const action = vi.fn();
act(() => useAdminUnsavedStore.getState().requestLeave(action));
expect(screen.getByRole('alertdialog')).toBeTruthy();
fireEvent.click(screen.getByRole('button', { name: 'Stay' }));
expect(screen.getByRole('alertdialog', { name: 'Discard changes?' })).toBeTruthy();
fireEvent.click(screen.getByRole('button', { name: 'Keep editing' }));
expect(action).not.toHaveBeenCalled();
expect(screen.queryByRole('alertdialog')).toBeNull();
expect(useAdminUnsavedStore.getState().dirty).toEqual({ settings: true });
});
it('Leave runs the action and drops the unsaved flag', () => {
it('Discard runs the action and drops the unsaved flag', () => {
render(<><UnsavedChangesGuard /><DirtySection dirty /></>);
const action = vi.fn();
act(() => useAdminUnsavedStore.getState().requestLeave(action));
fireEvent.click(screen.getByRole('button', { name: 'Leave' }));
fireEvent.click(screen.getByRole('button', { name: 'Discard' }));
expect(action).toHaveBeenCalledTimes(1);
expect(useAdminUnsavedStore.getState().dirty).toEqual({});
});
it('Escape closes the prompt like Stay', () => {
it('Escape closes the prompt like Keep editing', () => {
render(<><UnsavedChangesGuard /><DirtySection dirty /></>);
const action = vi.fn();
act(() => useAdminUnsavedStore.getState().requestLeave(action));
@@ -58,12 +58,12 @@ describe('admin unsaved changes guard (#1255)', () => {
act(() => useAdminUnsavedStore.getState().setDirty('plugin-config', true));
act(() => useAdminUnsavedStore.getState().requestLeave(back, 'plugin-config'));
fireEvent.click(screen.getByRole('button', { name: 'Leave' }));
fireEvent.click(screen.getByRole('button', { name: 'Discard' }));
expect(back).toHaveBeenCalledTimes(2);
expect(useAdminUnsavedStore.getState().dirty).toEqual({ plugins: true });
});
it('holds a link click until the admin picks Leave', () => {
it('holds a link click until the admin picks Discard', () => {
const onLinkClick = vi.fn((e: React.MouseEvent) => e.preventDefault());
render(
<>
@@ -76,7 +76,7 @@ describe('admin unsaved changes guard (#1255)', () => {
expect(onLinkClick).not.toHaveBeenCalled();
expect(screen.getByRole('alertdialog')).toBeTruthy();
fireEvent.click(screen.getByRole('button', { name: 'Leave' }));
fireEvent.click(screen.getByRole('button', { name: 'Discard' }));
expect(onLinkClick).toHaveBeenCalledTimes(1);
});
@@ -103,7 +103,7 @@ describe('admin unsaved changes guard on Back', () => {
await act(async () => { await done; });
};
it('keeps the page and asks when Back is pressed with unsaved edits; Stay keeps guarding', async () => {
it('keeps the page and asks when Back is pressed with unsaved edits; Keep editing keeps guarding', async () => {
window.history.pushState(null, '', '/admin/policy');
window.history.pushState(null, '', '/admin/telemetry');
render(<><UnsavedChangesGuard /><DirtySection dirty /></>);
@@ -112,7 +112,7 @@ describe('admin unsaved changes guard on Back', () => {
expect(window.location.pathname).toBe('/admin/telemetry');
expect(screen.getByRole('alertdialog')).toBeTruthy();
fireEvent.click(screen.getByRole('button', { name: 'Stay' }));
fireEvent.click(screen.getByRole('button', { name: 'Keep editing' }));
expect(useAdminUnsavedStore.getState().dirty).toEqual({ settings: true });
// Back asks again: the page is still guarded.
@@ -121,14 +121,14 @@ describe('admin unsaved changes guard on Back', () => {
expect(screen.getByRole('alertdialog')).toBeTruthy();
});
it('Leave goes back to the previous page', async () => {
it('Discard goes back to the previous page', async () => {
window.history.pushState(null, '', '/admin/policy');
window.history.pushState(null, '', '/admin/telemetry');
render(<><UnsavedChangesGuard /><DirtySection dirty /></>);
await back();
const done = popped();
fireEvent.click(screen.getByRole('button', { name: 'Leave' }));
fireEvent.click(screen.getByRole('button', { name: 'Discard' }));
await act(async () => { await done; });
expect(window.location.pathname).toBe('/admin/policy');
expect(useAdminUnsavedStore.getState().dirty).toEqual({});
+6 -6
View File
@@ -49,8 +49,8 @@ export function UnsavedChangesGuard() {
// Back and the back gesture are a same-document popstate (the pages switch
// through pushState), which can't be cancelled. So while something is
// unsaved a copy of the page's entry sits on top: Back only takes that
// one off, the page stays, and the prompt asks. Stay puts the copy back;
// Leave goes back past the page for real.
// one off, the page stays, and the prompt asks. Keep editing puts the
// copy back; Discard goes back past the page for real.
// The mark on the page entry the copy was put on top of.
const guard = useRef<string | null>(null);
useEffect(() => {
@@ -124,10 +124,10 @@ export function UnsavedChangesGuard() {
isOpen={isOpen}
onClose={cancelLeave}
onConfirm={confirmLeave}
title="Unsaved changes"
message="You have changes that haven't been saved. If you leave now, they will be lost."
cancelText="Stay"
confirmText="Leave"
title="Discard changes?"
message="Your changes haven't been saved."
cancelText="Keep editing"
confirmText="Discard"
variant="destructive"
/>
);
+27
View File
@@ -1,4 +1,6 @@
import { describe, expect, it } from 'vitest';
import { readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import en from '@/locales/en/common.json';
import { getByPath } from '../settings-search';
@@ -59,6 +61,31 @@ describe('settings wording', () => {
expect(text('notifications.filters_saved')).toBe('Filters saved');
});
// R5: every editor asks the same question with the same buttons, in every
// language: Settings and Contacts say what Calendar says.
it('asks "Discard changes?" with Keep editing / Discard everywhere', () => {
expect(text('calendar.discard.title')).toBe('Discard changes?');
const mismatches: string[] = [];
for (const locale of readdirSync(join(process.cwd(), 'locales'))) {
const messages = JSON.parse(readFileSync(join(process.cwd(), 'locales', locale, 'common.json'), 'utf8'));
const ref = getByPath(messages, 'calendar.discard') as Record<string, string>;
const expected: Record<string, string> = {
'settings.discard_changes': ref.title,
'settings.unsaved_changes': ref.message,
'settings.keep_editing': ref.keep,
'settings.discard': ref.confirm,
'contacts.form.discard_title': ref.title,
'contacts.form.discard_message': ref.message,
'contacts.form.keep_editing': ref.keep,
'contacts.form.discard': ref.confirm,
};
for (const [key, value] of Object.entries(expected)) {
if (getByPath(messages, key) !== value) mismatches.push(`${locale} ${key}`);
}
}
expect(mismatches).toEqual([]);
});
it('does not repeat the debug section title as its only row', () => {
expect(text('settings.advanced.debug_mode.toggle')).not.toBe(text('settings.advanced.debug_mode.label'));
});
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "تم استيراد الإعدادات بنجاح",
"import_error": "فشل استيراد الإعدادات",
"reset_confirm": "هل أنت متأكد أنك تريد إعادة تعيين جميع الإعدادات إلى الافتراضية؟",
"unsaved_changes": "لديك تغييرات غير محفوظة",
"discard_changes": "تجاهل التغييرات غير المحفوظة؟",
"unsaved_changes": "لم يتم حفظ تغييراتك.",
"discard_changes": "تجاهل التغييرات؟",
"discard": "تجاهل",
"keep_editing": "متابعة التعديل",
"search_placeholder": "بحث في الإعدادات",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Configuració importada correctament",
"import_error": "No s'ha pogut importar la configuració",
"reset_confirm": "Segur que voleu restablir tota la configuració als valors per defecte?",
"unsaved_changes": "Teniu canvis sense desar",
"discard_changes": "Voleu descartar els canvis sense desar?",
"unsaved_changes": "Els canvis no s'han desat.",
"discard_changes": "Voleu descartar els canvis?",
"discard": "Descarta",
"keep_editing": "Continua editant",
"search_placeholder": "Cerca a la configuració",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Nastavení bylo importováno",
"import_error": "Import nastavení selhal",
"reset_confirm": "Opravdu chcete obnovit výchozí nastavení?",
"unsaved_changes": "Máte neuložené změny",
"discard_changes": "Zahodit neuložené změny?",
"unsaved_changes": "Vaše změny nebyly uloženy.",
"discard_changes": "Zahodit změny?",
"discard": "Zahodit",
"keep_editing": "Pokračovat v úpravách",
"tabs": {
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Indstillinger importeret succesfuldt",
"import_error": "Kunne ikke importere indstillinger",
"reset_confirm": "Er du sikker på, at du vil nulstille alle indstillinger til standard?",
"unsaved_changes": "Du har ugemte ændringer",
"discard_changes": "Kassér ugemte ændringer?",
"unsaved_changes": "Dine ændringer er ikke gemt.",
"discard_changes": "Kassér ændringer?",
"discard": "Kassér",
"keep_editing": "Fortsæt redigering",
"search_placeholder": "Søg i indstillinger",
+2 -2
View File
@@ -1118,7 +1118,7 @@
"import_success": "Einstellungen erfolgreich importiert",
"import_error": "Import der Einstellungen fehlgeschlagen",
"reset_confirm": "Sind Sie sicher, dass Sie alle Einstellungen auf die Standardwerte zurücksetzen möchten?",
"unsaved_changes": "Sie haben ungespeicherte Änderungen",
"unsaved_changes": "Ihre Änderungen wurden noch nicht gespeichert.",
"discard_changes": "Änderungen verwerfen?",
"discard": "Verwerfen",
"keep_editing": "Weiter bearbeiten",
@@ -3468,7 +3468,7 @@
"save": "Speichern",
"cancel": "Abbrechen",
"discard_title": "Änderungen verwerfen?",
"discard_message": "Ihre Änderungen wurden nicht gespeichert.",
"discard_message": "Ihre Änderungen wurden noch nicht gespeichert.",
"discard": "Verwerfen",
"keep_editing": "Weiter bearbeiten",
"remove_entry": "Entfernen",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Settings imported",
"import_error": "Couldn't import settings",
"reset_confirm": "Are you sure you want to reset all settings to defaults?",
"unsaved_changes": "You have unsaved changes",
"discard_changes": "Discard unsaved changes?",
"unsaved_changes": "Your changes haven't been saved.",
"discard_changes": "Discard changes?",
"discard": "Discard",
"keep_editing": "Keep editing",
"search_placeholder": "Search settings",
+1 -1
View File
@@ -1118,7 +1118,7 @@
"import_success": "Configuración importada exitosamente",
"import_error": "Error al importar la configuración",
"reset_confirm": "¿Está seguro de que desea restablecer toda la configuración a los valores predeterminados?",
"unsaved_changes": "Tienes cambios sin guardar",
"unsaved_changes": "Tus cambios no se han guardado.",
"discard_changes": "¿Descartar los cambios?",
"discard": "Descartar",
"keep_editing": "Seguir editando",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Seaded imporditud",
"import_error": "Seadete importimine ebaõnnestus",
"reset_confirm": "Kas soovid kindlasti lähtestada kõik seaded vaikeväärtustele?",
"unsaved_changes": "Sul on salvestamata muudatusi",
"discard_changes": "Kas loobuda salvestamata muudatustest?",
"unsaved_changes": "Teie muudatusi pole salvestatud.",
"discard_changes": "Kas loobuda muudatustest?",
"discard": "Loobu",
"keep_editing": "Jätka muutmist",
"search_placeholder": "Otsi seadetest",
+3 -3
View File
@@ -1118,8 +1118,8 @@
"import_success": "تنظیمات با موفقیت وارد شد",
"import_error": "وارد کردن تنظیمات ناموفق بود",
"reset_confirm": "آیا از بازنشانی همه تنظیمات اطمینان دارید؟",
"unsaved_changes": "تغییرات ذخیره نشده دارید",
"discard_changes": "دور انداختن تغییرات ذخیره نشده؟",
"unsaved_changes": "تغییرات شما ذخیره نشده است.",
"discard_changes": "تغییرات دور انداخته شود؟",
"discard": "دور انداختن",
"keep_editing": "ادامه ویرایش",
"search_placeholder": "جستجوی تنظیمات",
@@ -3469,7 +3469,7 @@
"add_phone": "افزودن تلفن",
"save": "ذخیره",
"cancel": "انصراف",
"discard_title": "تغییرات دور انداخته شوند؟",
"discard_title": "تغییرات دور انداخته شود؟",
"discard_message": "تغییرات شما ذخیره نشده است.",
"discard": "دور انداختن",
"keep_editing": "ادامه ویرایش",
+1 -1
View File
@@ -1118,7 +1118,7 @@
"import_success": "Paramètres importés avec succès",
"import_error": "Échec de l'importation des paramètres",
"reset_confirm": "Êtes-vous sûr de vouloir réinitialiser tous les paramètres ?",
"unsaved_changes": "Vous avez des modifications non enregistrées",
"unsaved_changes": "Vos modifications n'ont pas été enregistrées.",
"discard_changes": "Abandonner les modifications ?",
"discard": "Abandonner",
"keep_editing": "Continuer l'édition",
+6 -6
View File
@@ -1083,10 +1083,10 @@
"import_success": "ההגדרות יובאו בהצלחה",
"import_error": "ייבוא ההגדרות נכשל",
"reset_confirm": "האם אתה בטוח שברצונך לאפס את כל ההגדרות לברירות מחדל?",
"unsaved_changes": "יש לך שינויים שלא נשמרו",
"discard_changes": "למחוק שינויים שלא נשמרו?",
"discard": "לזרוק",
"keep_editing": "תמשיך לערוך",
"unsaved_changes": "השינויים שלך לא נשמרו.",
"discard_changes": "לבטל את השינויים?",
"discard": "לבטל שינויים",
"keep_editing": "להמשיך לערוך",
"tabs": {
"appearance": "מראה",
"account": "חשבון",
@@ -3373,8 +3373,8 @@
"cancel": "לְבַטֵל",
"discard_title": "לבטל את השינויים?",
"discard_message": "השינויים שלך לא נשמרו.",
"discard": "בטל",
"keep_editing": "המשך לערוך",
"discard": "לבטל שינויים",
"keep_editing": "להמשיך לערוך",
"remove_entry": "הסר",
"close": "סגור",
"remove_category": "הסר את {name}",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Beállítások sikeresen importálva",
"import_error": "Nem sikerült importálni a beállításokat",
"reset_confirm": "Biztosan vissza akarod állítani az összes beállítást az alapértelmezettre?",
"unsaved_changes": "Nem mentett változtatások vannak",
"discard_changes": "Nem mentett változtatások elvetése?",
"unsaved_changes": "A változtatásai nincsenek mentve.",
"discard_changes": "Elveti a változtatásokat?",
"discard": "Elvetés",
"keep_editing": "Szerkesztés folytatása",
"search_placeholder": "Beállítások keresése",
+4 -4
View File
@@ -1118,9 +1118,9 @@
"import_success": "Impostazioni importate con successo",
"import_error": "Impossibile importare le impostazioni",
"reset_confirm": "Sei sicuro di voler ripristinare tutte le impostazioni ai valori predefiniti?",
"unsaved_changes": "Hai modifiche non salvate",
"unsaved_changes": "Le modifiche non sono state salvate.",
"discard_changes": "Annullare le modifiche?",
"discard": "Annulla",
"discard": "Annulla modifiche",
"keep_editing": "Continua a modificare",
"tabs": {
"appearance": "Aspetto",
@@ -3467,9 +3467,9 @@
"add_phone": "Aggiungi telefono",
"save": "Salva",
"cancel": "Annulla",
"discard_title": "Eliminare le modifiche?",
"discard_title": "Annullare le modifiche?",
"discard_message": "Le modifiche non sono state salvate.",
"discard": "Elimina",
"discard": "Annulla modifiche",
"keep_editing": "Continua a modificare",
"remove_entry": "Rimuovi",
"close": "Chiudi",
+2 -2
View File
@@ -1118,7 +1118,7 @@
"import_success": "設定をインポートしました",
"import_error": "設定のインポートに失敗しました",
"reset_confirm": "すべての設定をデフォルトにリセットしてもよろしいですか?",
"unsaved_changes": "保存されていない変更があります",
"unsaved_changes": "変更はまだ保存されていません。",
"discard_changes": "変更を破棄しますか?",
"discard": "破棄",
"keep_editing": "編集を続ける",
@@ -3468,7 +3468,7 @@
"save": "保存",
"cancel": "キャンセル",
"discard_title": "変更を破棄しますか?",
"discard_message": "変更は保存されていません。",
"discard_message": "変更はまだ保存されていません。",
"discard": "破棄",
"keep_editing": "編集を続ける",
"remove_entry": "削除",
+7 -7
View File
@@ -1118,9 +1118,9 @@
"import_success": "설정을 성공적으로 가져왔어요",
"import_error": "설정 가져오기에 실패했어요",
"reset_confirm": "모든 설정을 기본값으로 되돌릴까요?",
"unsaved_changes": "저장되지 않은 변경 사항이 있어요",
"discard_changes": "변경 사항을 취소할까요?",
"discard": "취소하기",
"unsaved_changes": "변경 사항이 아직 저장되지 않았습니다.",
"discard_changes": "변경 사항을 버릴까요?",
"discard": "버리기",
"keep_editing": "계속 수정하기",
"tabs": {
"appearance": "화면 설정",
@@ -3467,10 +3467,10 @@
"add_phone": "전화번호 추가",
"save": "저장",
"cancel": "취소",
"discard_title": "변경 사항을 삭제할까요?",
"discard_message": "변경 사항이 저장되지 않았습니다.",
"discard": "삭제",
"keep_editing": "계속 편집",
"discard_title": "변경 사항을 버릴까요?",
"discard_message": "변경 사항이 아직 저장되지 않았습니다.",
"discard": "버리기",
"keep_editing": "계속 수정하기",
"remove_entry": "제거",
"close": "닫기",
"remove_category": "{name} 제거",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Iestatījumi veiksmīgi importēti",
"import_error": "Neizdevās importēt iestatījumus",
"reset_confirm": "Vai tiešām vēlaties atiestatīt visus iestatījumus uz noklusējuma vērtībām?",
"unsaved_changes": "Jums ir nesaglabātas izmaiņas",
"discard_changes": "Atmest nesaglabātās izmaiņas?",
"unsaved_changes": "Jūsu izmaiņas nav saglabātas.",
"discard_changes": "Atmest izmaiņas?",
"discard": "Atmest",
"keep_editing": "Turpināt rediģēšanu",
"tabs": {
+6 -6
View File
@@ -1118,10 +1118,10 @@
"import_success": "Тохиргоог амжилттай импортоллоо",
"import_error": "Тохиргоог оруулж чадсангүй",
"reset_confirm": "Та бүх тохиргоог өгөгдмөл рүү буцаахдаа итгэлтэй байна уу?",
"unsaved_changes": "Танд хадгалагдаагүй өөрчлөлтүүд байна",
"discard_changes": "Хадгалагдаагүй өөрчлөлтүүдийг устгах уу?",
"discard": "Хасах",
"keep_editing": "Засварлаж байгаарай",
"unsaved_changes": "Таны өөрчлөлтүүд хадгалагдаагүй байна.",
"discard_changes": "Өөрчлөлтүүдийг хаях уу?",
"discard": "Хаях",
"keep_editing": "Үргэлжлүүлэн засах",
"search_placeholder": "Хайлтын тохиргоо",
"search_clear": "Хайлтыг арилгах",
"search_no_results": "Тохирох тохиргоо байхгүй",
@@ -3469,8 +3469,8 @@
"add_phone": "Утас нэмэх",
"save": "Хадгалах",
"cancel": "Цуцлах",
"discard_title": "Өөрчлөлтийг хаях уу?",
"discard_message": "Таны өөрчлөлт хадгалагдаагүй байна.",
"discard_title": "Өөрчлөлтүүдийг хаях уу?",
"discard_message": "Таны өөрчлөлтүүд хадгалагдаагүй байна.",
"discard": "Хаях",
"keep_editing": "Үргэлжлүүлэн засах",
"remove_entry": "Хасах",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Innstillingene er importert",
"import_error": "Kunne ikke importere innstillinger",
"reset_confirm": "Vil du tilbakestille alle innstillingene?",
"unsaved_changes": "Du har ulagrede endringer",
"discard_changes": "Vil du forkaste ulagrede endringer?",
"unsaved_changes": "Endringene dine er ikke lagret.",
"discard_changes": "Vil du forkaste endringene?",
"discard": "Forkast",
"keep_editing": "Fortsett å redigere",
"search_placeholder": "Søk i innstillinger",
+1 -1
View File
@@ -1118,7 +1118,7 @@
"import_success": "Instellingen succesvol geïmporteerd",
"import_error": "Kan instellingen niet importeren",
"reset_confirm": "Weet je zeker dat je alle instellingen wilt resetten naar de standaardwaarden?",
"unsaved_changes": "U heeft niet-opgeslagen wijzigingen",
"unsaved_changes": "Je wijzigingen zijn niet opgeslagen.",
"discard_changes": "Wijzigingen verwerpen?",
"discard": "Verwerpen",
"keep_editing": "Doorgaan met bewerken",
+2 -2
View File
@@ -1118,8 +1118,8 @@
"import_success": "Ustawienia zostały zaimportowane",
"import_error": "Nie udało się zaimportować ustawień",
"reset_confirm": "Czy na pewno chcesz przywrócić domyślne ustawienia?",
"unsaved_changes": "Masz niezapisane zmiany",
"discard_changes": "Odrzucić niezapisane zmiany?",
"unsaved_changes": "Twoje zmiany nie zostały zapisane.",
"discard_changes": "Odrzucić zmiany?",
"discard": "Odrzuć",
"keep_editing": "Kontynuuj edycję",
"tabs": {
+1 -1
View File
@@ -1118,7 +1118,7 @@
"import_success": "Configurações importadas com sucesso",
"import_error": "Falha ao importar configurações",
"reset_confirm": "Tem certeza de que deseja redefinir todas as configurações para os padrões?",
"unsaved_changes": "Você tem alterações não salvas",
"unsaved_changes": "Suas alterações não foram salvas.",
"discard_changes": "Descartar alterações?",
"discard": "Descartar",
"keep_editing": "Continuar editando",
+3 -3
View File
@@ -1118,9 +1118,9 @@
"import_success": "Setările au fost importate cu succes",
"import_error": "Nu s-au putut importa setările",
"reset_confirm": "Sunteți sigur că doriți să resetați toate setările la valorile implicite?",
"unsaved_changes": "Aveți modificări nesalvate",
"discard_changes": "Doriți să renunțați la modificările nesalvate?",
"discard": "Ignorați",
"unsaved_changes": "Modificările dvs. nu au fost salvate.",
"discard_changes": "Renunțați la modificări?",
"discard": "Renunțați",
"keep_editing": "Continuați editarea",
"search_placeholder": "Setări de căutare",
"search_clear": "Șterge căutarea",
+4 -4
View File
@@ -1118,9 +1118,9 @@
"import_success": "Настройки успешно импортированы",
"import_error": "Не удалось импортировать настройки",
"reset_confirm": "Вы уверены, что хотите сбросить все настройки до значений по умолчанию?",
"unsaved_changes": "У вас есть несохранённые изменения",
"discard_changes": "Отменить несохранённые изменения?",
"discard": "Отменить",
"unsaved_changes": "Ваши изменения не сохранены.",
"discard_changes": "Отменить изменения?",
"discard": "Отменить изменения",
"keep_editing": "Продолжить редактирование",
"tabs": {
"appearance": "Внешний вид",
@@ -3469,7 +3469,7 @@
"cancel": "Отмена",
"discard_title": "Отменить изменения?",
"discard_message": "Ваши изменения не сохранены.",
"discard": "Отменить",
"discard": "Отменить изменения",
"keep_editing": "Продолжить редактирование",
"remove_entry": "Убрать",
"close": "Закрыть",
+4 -4
View File
@@ -1118,9 +1118,9 @@
"import_success": "Nastavenia boli úspešne importované",
"import_error": "Import nastavení zlyhal",
"reset_confirm": "Naozaj chcete obnoviť všetky nastavenia na predvolené?",
"unsaved_changes": "Máte neuložené zmeny",
"discard_changes": "Zahoditť neuložené zmeny?",
"discard": "Zahoditť",
"unsaved_changes": "Vaše zmeny neboli uložené.",
"discard_changes": "Zahodiť zmeny?",
"discard": "Zahodiť",
"keep_editing": "Pokračovať v úprave",
"search_placeholder": "Hľadať nastavenia",
"search_clear": "Vymazať hľadanie",
@@ -3472,7 +3472,7 @@
"discard_title": "Zahodiť zmeny?",
"discard_message": "Vaše zmeny neboli uložené.",
"discard": "Zahodiť",
"keep_editing": "Pokračovať v úpravách",
"keep_editing": "Pokračovať v úprave",
"remove_entry": "Odstrániť",
"close": "Zavrieť",
"remove_category": "Odstrániť {name}",
+2 -2
View File
@@ -3297,8 +3297,8 @@
"import_success": "นำเข้าการตั้งค่าเรียบร้อยแล้ว",
"import_error": "นำเข้าการตั้งค่าไม่สำเร็จ",
"reset_confirm": "คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตการตั้งค่าทั้งหมดกลับเป็นค่าเริ่มต้น?",
"unsaved_changes": "คุณมีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก",
"discard_changes": "ละทิ้งการเปลี่ยนแปลงที่ยังไม่ได้บันทึกหรือไม่?",
"unsaved_changes": "การเปลี่ยนแปลงของคุณยังไม่ได้บันทึก",
"discard_changes": "ละทิ้งการเปลี่ยนแปลงหรือไม่?",
"discard": "ละทิ้ง",
"keep_editing": "แก้ไขต่อ",
"search_placeholder": "ค้นหาการตั้งค่า",
+4 -4
View File
@@ -1118,9 +1118,9 @@
"import_success": "Ayarlar başarıyla içe aktarıldı",
"import_error": "Ayarlar içe aktarılamadı",
"reset_confirm": "Tüm ayarları varsayılanlara sıfırlamak istediğinizden emin misiniz?",
"unsaved_changes": "Kaydedilmemiş değişiklikleriniz var",
"discard_changes": "Kaydedilmemiş değişiklikler atılsın mı?",
"discard": "Atla",
"unsaved_changes": "Değişiklikleriniz kaydedilmedi.",
"discard_changes": "Değişiklikler atılsın mı?",
"discard": "Değişiklikleri at",
"keep_editing": "Düzenlemeye devam et",
"tabs": {
"appearance": "Görünüm",
@@ -3469,7 +3469,7 @@
"cancel": "İptal",
"discard_title": "Değişiklikler atılsın mı?",
"discard_message": "Değişiklikleriniz kaydedilmedi.",
"discard": "At",
"discard": "Değişiklikleri at",
"keep_editing": "Düzenlemeye devam et",
"remove_entry": "Kaldır",
"close": "Kapat",
+3 -3
View File
@@ -1118,10 +1118,10 @@
"import_success": "Налаштування успішно імпортовано",
"import_error": "Не вдалося імпортувати налаштування",
"reset_confirm": "Ви впевнені, що бажаєте скинути всі налаштування до стандартних?",
"unsaved_changes": "У вас є незбережені зміни",
"discard_changes": "Скасувати незбережені зміни?",
"unsaved_changes": "Ваші зміни не збережено.",
"discard_changes": "Відкинути зміни?",
"discard": "Відкинути",
"keep_editing": "Продовжуйте редагувати",
"keep_editing": "Продовжити редагування",
"tabs": {
"appearance": "Зовнішній вигляд",
"account": "Обліковий запис",
+3 -3
View File
@@ -1118,8 +1118,8 @@
"import_success": "已成功匯入設定",
"import_error": "無法匯入設定",
"reset_confirm": "您確定要將所有設定重設為預設值嗎?",
"unsaved_changes": "您有尚未儲存的變更",
"discard_changes": "要捨棄尚未儲存的變更嗎?",
"unsaved_changes": "你的變更尚未儲存。",
"discard_changes": "要捨棄變更嗎?",
"discard": "捨棄",
"keep_editing": "繼續編輯",
"search_placeholder": "搜尋設定",
@@ -3470,7 +3470,7 @@
"save": "儲存",
"cancel": "取消",
"discard_title": "要捨棄變更嗎?",
"discard_message": "您的變更尚未儲存。",
"discard_message": "你的變更尚未儲存。",
"discard": "捨棄",
"keep_editing": "繼續編輯",
"remove_entry": "移除",
+3 -3
View File
@@ -1118,8 +1118,8 @@
"import_success": "设置导入成功",
"import_error": "导入设置失败",
"reset_confirm": "您确定要将所有设置重置为默认值吗?",
"unsaved_changes": "您有未保存的更改",
"discard_changes": "放弃未保存的更改?",
"unsaved_changes": "你的更改尚未保存。",
"discard_changes": "放弃更改?",
"discard": "放弃",
"keep_editing": "继续编辑",
"tabs": {
@@ -3468,7 +3468,7 @@
"save": "保存",
"cancel": "取消",
"discard_title": "放弃更改?",
"discard_message": "您的更改尚未保存。",
"discard_message": "你的更改尚未保存。",
"discard": "放弃",
"keep_editing": "继续编辑",
"remove_entry": "移除",