mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-04 16:14:07 +00:00
feat: use the plain wording for everyone and drop the plain language switch
The plain-language test asserted that the normal strings show while the switch is off and that changing the switch swaps them live. With no switch left, it now asserts the plain strings show from the first render and through a language change.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { AppLockGate } from "@/components/app-lock/app-lock-gate";
|
||||
import { IntlProvider } from "@/components/providers/intl-provider";
|
||||
import { addPlainLanguage } from "@/i18n/plain-language";
|
||||
import { ThemeProvider } from "@/components/providers/theme-provider";
|
||||
import { CalendarAlertProvider } from "@/components/providers/calendar-alert-provider";
|
||||
import { PushBindingsHost } from "@/components/providers/push-bindings-host";
|
||||
@@ -77,6 +78,7 @@ export default async function LocaleLayout({
|
||||
} catch {
|
||||
notFound();
|
||||
}
|
||||
messages = await addPlainLanguage(locale, messages);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,6 +3,7 @@ import { IntlProvider } from '@/components/providers/intl-provider';
|
||||
import { ThemeProvider } from '@/components/providers/theme-provider';
|
||||
import { TourProvider } from '@/components/tour/tour-provider';
|
||||
import { defaultLocale } from '@/i18n/routing';
|
||||
import { addPlainLanguage } from '@/i18n/plain-language';
|
||||
import { AdminLayoutClient } from './_layout-client';
|
||||
import { WindowMenuBar } from '@/components/layout/window-menu-bar';
|
||||
|
||||
@@ -18,9 +19,9 @@ export default async function AdminLayout({ children }: { children: React.ReactN
|
||||
const locale = await getLocale();
|
||||
let messages;
|
||||
try {
|
||||
messages = (await import(`@/locales/${locale}/common.json`)).default;
|
||||
messages = await addPlainLanguage(locale, (await import(`@/locales/${locale}/common.json`)).default);
|
||||
} catch {
|
||||
messages = (await import(`@/locales/${defaultLocale}/common.json`)).default;
|
||||
messages = await addPlainLanguage(defaultLocale, (await import(`@/locales/${defaultLocale}/common.json`)).default);
|
||||
}
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
|
||||
import { getLocale } from 'next-intl/server';
|
||||
import { IntlProvider } from '@/components/providers/intl-provider';
|
||||
import { defaultLocale } from '@/i18n/routing';
|
||||
import { addPlainLanguage } from '@/i18n/plain-language';
|
||||
|
||||
/**
|
||||
* /setup sits outside the [locale] tree, so it loads the message catalog
|
||||
@@ -13,9 +14,9 @@ export default async function SetupLayout({ children }: { children: ReactNode })
|
||||
const locale = await getLocale();
|
||||
let messages;
|
||||
try {
|
||||
messages = (await import(`@/locales/${locale}/common.json`)).default;
|
||||
messages = await addPlainLanguage(locale, (await import(`@/locales/${locale}/common.json`)).default);
|
||||
} catch {
|
||||
messages = (await import(`@/locales/${defaultLocale}/common.json`)).default;
|
||||
messages = await addPlainLanguage(defaultLocale, (await import(`@/locales/${defaultLocale}/common.json`)).default);
|
||||
}
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
|
||||
@@ -3,16 +3,17 @@ import { act, render, screen } from '@testing-library/react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { IntlProvider } from '../intl-provider';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import enCommon from '@/locales/en/common.json';
|
||||
import deCommon from '@/locales/de/common.json';
|
||||
import frCommon from '@/locales/fr/common.json';
|
||||
import enPlain from '@/locales/en/plain.json';
|
||||
import dePlain from '@/locales/de/plain.json';
|
||||
import { addPlainLanguage } from '@/i18n/plain-language';
|
||||
|
||||
// Plain-language mode lays locales/<en|de>/plain.json over the catalog when the
|
||||
// setting is on. Every useTranslations call has to pick it up from the one
|
||||
// provider, live, and only for English and German.
|
||||
// The plain wording in locales/<en|de|vi>/plain.json is the only wording
|
||||
// (usability pass 2026-11-04, settings-15): it is laid over the catalog for
|
||||
// English, German and Vietnamese with no setting, and other locales keep
|
||||
// their own strings.
|
||||
|
||||
vi.unmock('next-intl');
|
||||
|
||||
@@ -35,74 +36,60 @@ async function settle() {
|
||||
});
|
||||
}
|
||||
|
||||
describe('plain-language mode', () => {
|
||||
describe('plain wording', () => {
|
||||
beforeEach(() => {
|
||||
// The fallback assertions need a key that has no plain version.
|
||||
// The fallback assertions need a key that has no plain version, and the
|
||||
// plain assertions one whose plain version differs.
|
||||
expect((enPlain as { login: Record<string, unknown> }).login.sign_in).toBeUndefined();
|
||||
expect((dePlain as { login: Record<string, unknown> }).login.sign_in).toBeUndefined();
|
||||
expect(enPlain.login.error.invalid_credentials).not.toBe(enCommon.login.error.invalid_credentials);
|
||||
expect(dePlain.login.error.invalid_credentials).not.toBe(deCommon.login.error.invalid_credentials);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
useLocaleStore.setState({ locale: '' });
|
||||
useSettingsStore.setState({ plainLanguage: false });
|
||||
});
|
||||
|
||||
it('keeps the normal strings while the setting is off', async () => {
|
||||
render(<IntlProvider locale="en" messages={enCommon}><Strings /></IntlProvider>);
|
||||
await settle();
|
||||
expect(text('plain')).toBe(enCommon.login.error.invalid_credentials);
|
||||
});
|
||||
|
||||
it('uses the plain English string when the setting is on', async () => {
|
||||
useSettingsStore.setState({ plainLanguage: true });
|
||||
render(<IntlProvider locale="en" messages={enCommon}><Strings /></IntlProvider>);
|
||||
expect(await screen.findByText(enPlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
expect(enPlain.login.error.invalid_credentials).not.toBe(enCommon.login.error.invalid_credentials);
|
||||
it('shows the plain English string from the first render, with no setting', () => {
|
||||
render(<IntlProvider locale="en"><Strings /></IntlProvider>);
|
||||
expect(text('plain')).toBe(enPlain.login.error.invalid_credentials);
|
||||
// A key without a plain version keeps the common.json string.
|
||||
expect(text('normal')).toBe(enCommon.login.sign_in);
|
||||
});
|
||||
|
||||
it('adds the plain strings to a server catalog for German, not French', async () => {
|
||||
const de = (await addPlainLanguage('de', deCommon)) as typeof deCommon;
|
||||
expect(de.login.error.invalid_credentials).toBe(dePlain.login.error.invalid_credentials);
|
||||
expect(await addPlainLanguage('fr', frCommon)).toBe(frCommon);
|
||||
});
|
||||
|
||||
it('uses the plain German string for a German UI', async () => {
|
||||
useSettingsStore.setState({ plainLanguage: true });
|
||||
render(<IntlProvider locale="de" messages={deCommon}><Strings /></IntlProvider>);
|
||||
expect(await screen.findByText(dePlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
const messages = await addPlainLanguage('de', deCommon);
|
||||
render(<IntlProvider locale="de" messages={messages}><Strings /></IntlProvider>);
|
||||
expect(text('plain')).toBe(dePlain.login.error.invalid_credentials);
|
||||
expect(text('normal')).toBe(deCommon.login.sign_in);
|
||||
});
|
||||
|
||||
it('works without server messages, as in the Lite export', async () => {
|
||||
useSettingsStore.setState({ plainLanguage: true });
|
||||
it('loads the plain German strings without server messages, as in the Lite export', async () => {
|
||||
render(<IntlProvider locale="de"><Strings /></IntlProvider>);
|
||||
expect(await screen.findByText(dePlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
// The German catalog is a lazy chunk, slow to import under load.
|
||||
expect(await screen.findByText(dePlain.login.error.invalid_credentials, {}, { timeout: 8000 })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('leaves other locales on their normal strings', async () => {
|
||||
useSettingsStore.setState({ plainLanguage: true });
|
||||
it('leaves other locales on their own strings', async () => {
|
||||
render(<IntlProvider locale="fr" messages={frCommon}><Strings /></IntlProvider>);
|
||||
await settle();
|
||||
expect(text('plain')).toBe(frCommon.login.error.invalid_credentials);
|
||||
});
|
||||
|
||||
it('switches live when the setting changes', async () => {
|
||||
render(<IntlProvider locale="en" messages={enCommon}><Strings /></IntlProvider>);
|
||||
await settle();
|
||||
expect(text('plain')).toBe(enCommon.login.error.invalid_credentials);
|
||||
|
||||
act(() => useSettingsStore.setState({ plainLanguage: true }));
|
||||
expect(await screen.findByText(enPlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
|
||||
act(() => useSettingsStore.setState({ plainLanguage: false }));
|
||||
expect(text('plain')).toBe(enCommon.login.error.invalid_credentials);
|
||||
});
|
||||
|
||||
it('follows a language change while the setting stays on', async () => {
|
||||
useSettingsStore.setState({ plainLanguage: true });
|
||||
render(<IntlProvider locale="en" messages={enCommon}><Strings /></IntlProvider>);
|
||||
expect(await screen.findByText(enPlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
it('keeps the plain wording across a language change', async () => {
|
||||
render(<IntlProvider locale="en"><Strings /></IntlProvider>);
|
||||
expect(text('plain')).toBe(enPlain.login.error.invalid_credentials);
|
||||
|
||||
act(() => useLocaleStore.setState({ locale: 'de' }));
|
||||
expect(await screen.findByText(dePlain.login.error.invalid_credentials)).toBeTruthy();
|
||||
expect(await screen.findByText(dePlain.login.error.invalid_credentials, {}, { timeout: 8000 })).toBeTruthy();
|
||||
|
||||
act(() => useLocaleStore.setState({ locale: 'fr' }));
|
||||
expect(await screen.findByText(frCommon.login.error.invalid_credentials)).toBeTruthy();
|
||||
expect(await screen.findByText(frCommon.login.error.invalid_credentials, {}, { timeout: 8000 })).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,14 +9,19 @@ import { locales } from '@/i18n/routing';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import { getBrowserTimeZone, resolveTimeZone } from '@/lib/timezone';
|
||||
import enMessages from '@/locales/en/common.json';
|
||||
import enCommon from '@/locales/en/common.json';
|
||||
import enPlain from '@/locales/en/plain.json';
|
||||
import { getLocaleDirection } from '@/i18n/direction';
|
||||
import { mergeMessages } from '@/i18n/merge-messages';
|
||||
import { detectBrowserLocale } from '@/i18n/detect-locale';
|
||||
import { PLAIN_LANGUAGE_LOADERS, hasPlainLanguage, withPlainLanguage } from '@/i18n/plain-language';
|
||||
import { addPlainLanguage, withPlainLanguage } from '@/i18n/plain-language';
|
||||
|
||||
type Messages = Record<string, unknown>;
|
||||
|
||||
// English with its plain wording laid over it: the default catalog and the
|
||||
// fallback base. The plain strings are the only wording, with no setting.
|
||||
const enMessages = withPlainLanguage(enCommon as Messages, enPlain as Messages);
|
||||
|
||||
// Per-locale dynamic loaders so each catalog is its own lazy chunk. Importing
|
||||
// them all statically put every locale (~3 MB) in the critical client bundle,
|
||||
// which dominated time-to-mail-list. English stays a static import: it is the
|
||||
@@ -28,8 +33,8 @@ export const LOCALE_LOADERS: Record<string, () => Promise<Messages>> = {
|
||||
ca: () => import('@/locales/ca/common.json').then((m) => m.default),
|
||||
cs: () => import('@/locales/cs/common.json').then((m) => m.default),
|
||||
da: () => import('@/locales/da/common.json').then((m) => m.default),
|
||||
de: () => import('@/locales/de/common.json').then((m) => m.default),
|
||||
en: () => Promise.resolve(enMessages as Messages),
|
||||
de: () => import('@/locales/de/common.json').then((m) => addPlainLanguage('de', m.default)),
|
||||
en: () => Promise.resolve(enMessages),
|
||||
es: () => import('@/locales/es/common.json').then((m) => m.default),
|
||||
he: () => import('@/locales/he/common.json').then((m) => m.default),
|
||||
et: () => import('@/locales/et/common.json').then((m) => m.default),
|
||||
@@ -51,7 +56,7 @@ export const LOCALE_LOADERS: Record<string, () => Promise<Messages>> = {
|
||||
th: () => import('@/locales/th/common.json').then((m) => m.default),
|
||||
tr: () => import('@/locales/tr/common.json').then((m) => m.default),
|
||||
uk: () => import('@/locales/uk/common.json').then((m) => m.default),
|
||||
vi: () => import('@/locales/vi/common.json').then((m) => m.default),
|
||||
vi: () => import('@/locales/vi/common.json').then((m) => addPlainLanguage('vi', m.default)),
|
||||
zh: () => import('@/locales/zh/common.json').then((m) => m.default),
|
||||
'zh-TW': () => import('@/locales/zh-TW/common.json').then((m) => m.default),
|
||||
};
|
||||
@@ -70,7 +75,6 @@ export function IntlProvider({ locale: initialLocale, messages: initialMessages,
|
||||
const [browserTimeZone, setBrowserTimeZone] = useState<string>('UTC');
|
||||
const timeZoneSetting = useSettingsStore((state) => state.timeZone);
|
||||
const timeZone = resolveTimeZone(timeZoneSetting, browserTimeZone);
|
||||
const plainLanguage = useSettingsStore((state) => state.plainLanguage);
|
||||
const pathname = usePathname();
|
||||
|
||||
// The catalog currently in use. Seeded with the server-provided messages for
|
||||
@@ -79,12 +83,12 @@ export function IntlProvider({ locale: initialLocale, messages: initialMessages,
|
||||
// lazily loaded catalog arrives, never out of sync. Without server messages
|
||||
// (Lite) only English is at hand; any other locale renders nothing, on the
|
||||
// server and on the client alike, until its chunk arrives.
|
||||
const seed = initialMessages ?? (initialLocale === 'en' ? (enMessages as Messages) : undefined);
|
||||
const seed = initialMessages ?? (initialLocale === 'en' ? enMessages : undefined);
|
||||
const [catalog, setCatalog] = useState<{ locale: string; messages: Messages } | null>(
|
||||
seed ? { locale: initialLocale, messages: seed } : null,
|
||||
);
|
||||
const loadedRef = useRef<Record<string, Messages>>({
|
||||
en: enMessages as Messages,
|
||||
en: enMessages,
|
||||
...(seed ? { [initialLocale]: seed } : {}),
|
||||
});
|
||||
|
||||
@@ -124,22 +128,6 @@ export function IntlProvider({ locale: initialLocale, messages: initialMessages,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentLocale]);
|
||||
|
||||
// Plain-language strings, loaded the first time the setting is on for an
|
||||
// English or German UI. They arrive after the first render, so hydration
|
||||
// always matches the server's normal strings.
|
||||
const [plainCatalogs, setPlainCatalogs] = useState<Record<string, Messages>>({});
|
||||
const plainLocale = plainLanguage && catalog && hasPlainLanguage(catalog.locale) ? catalog.locale : null;
|
||||
useEffect(() => {
|
||||
if (!plainLocale || plainCatalogs[plainLocale]) return;
|
||||
let stale = false;
|
||||
PLAIN_LANGUAGE_LOADERS[plainLocale]()
|
||||
.catch(() => ({} as Messages))
|
||||
.then((plain) => {
|
||||
if (!stale) setPlainCatalogs((prev) => ({ ...prev, [plainLocale]: plain }));
|
||||
});
|
||||
return () => { stale = true; };
|
||||
}, [plainLocale, plainCatalogs]);
|
||||
|
||||
// Keep <html> lang/dir in sync with the rendered locale (RTL for he/fa).
|
||||
const activeLocale = catalog?.locale;
|
||||
useEffect(() => {
|
||||
@@ -150,19 +138,16 @@ export function IntlProvider({ locale: initialLocale, messages: initialMessages,
|
||||
|
||||
// Fall back to English for any key the active locale has not translated, so
|
||||
// untranslated strings show English text instead of a raw message key.
|
||||
const baseMessages = useMemo(
|
||||
// Server-provided catalogs already carry their plain strings (the layouts
|
||||
// add them), and so do the client loaders, so first render and hydration
|
||||
// show the same wording.
|
||||
const messages = useMemo(
|
||||
() =>
|
||||
!catalog || catalog.locale === 'en'
|
||||
? (enMessages as Messages)
|
||||
: mergeMessages(enMessages as Messages, catalog.messages),
|
||||
? enMessages
|
||||
: mergeMessages(enMessages, catalog.messages),
|
||||
[catalog]
|
||||
);
|
||||
// Plain strings win over the catalog; keys without a plain version keep it.
|
||||
const plainMessages = plainLocale ? plainCatalogs[plainLocale] : undefined;
|
||||
const messages = useMemo(
|
||||
() => withPlainLanguage(baseMessages, plainMessages),
|
||||
[baseMessages, plainMessages]
|
||||
);
|
||||
|
||||
if (!catalog) {
|
||||
// Lite without this locale's catalog yet: no text can be drawn, but the
|
||||
|
||||
@@ -268,9 +268,6 @@ export function AccessibilitySettings() {
|
||||
<SettingItem label={t('reading_mask.label')} description={t('reading_mask.description')}>
|
||||
<ToggleSwitch checked={settings.readingMask} onChange={(checked) => set('readingMask', checked)} />
|
||||
</SettingItem>
|
||||
<SettingItem label={t('plain_language.label')} description={t('plain_language.description')}>
|
||||
<ToggleSwitch checked={settings.plainLanguage} onChange={(checked) => set('plainLanguage', checked)} />
|
||||
</SettingItem>
|
||||
{!isSettingHidden('density') && (
|
||||
<SettingItem label={tAppearance('list_density.label')} description={tAppearance('list_density.description')} locked={isSettingLocked('density')}>
|
||||
<Select
|
||||
|
||||
+16
-4
@@ -3,14 +3,16 @@ import { mergeMessages } from './merge-messages';
|
||||
type Messages = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* Plain-language mode (CO-14): simpler wording for settings and error
|
||||
* messages. English, German and Vietnamese have plain versions; every
|
||||
* other locale keeps its normal strings when the setting is on.
|
||||
* Plain wording (CO-14, made the only wording in the 2026-11-04 usability
|
||||
* pass): simpler versions of settings and error messages. English, German
|
||||
* and Vietnamese have them; every other locale keeps its strings.
|
||||
*
|
||||
* The plain strings live in `locales/<code>/plain.json`, outside common.json,
|
||||
* so the translation parity test doesn't ask every locale for them. Each file
|
||||
* holds only the keys that get a simpler version, under the same key paths as
|
||||
* common.json; anything it leaves out falls back to the normal string.
|
||||
* common.json; anything it leaves out falls back to the normal string. They
|
||||
* are laid over the catalog wherever a catalog is loaded (server layouts,
|
||||
* request config, the client's locale loaders), always, with no setting.
|
||||
*/
|
||||
export const PLAIN_LANGUAGE_LOADERS: Record<string, () => Promise<Messages>> = {
|
||||
en: () => import('@/locales/en/plain.json').then((m) => m.default as Messages),
|
||||
@@ -26,3 +28,13 @@ export function hasPlainLanguage(locale: string): boolean {
|
||||
export function withPlainLanguage(messages: Messages, plain: Messages | undefined): Messages {
|
||||
return plain ? mergeMessages(messages, plain) : messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* The locale's catalog with its plain strings laid over it. A locale without
|
||||
* plain strings, or one whose file fails to load, gets the catalog unchanged.
|
||||
*/
|
||||
export async function addPlainLanguage(locale: string, messages: Messages): Promise<Messages> {
|
||||
if (!hasPlainLanguage(locale)) return messages;
|
||||
const plain = await PLAIN_LANGUAGE_LOADERS[locale]().catch(() => undefined);
|
||||
return withPlainLanguage(messages, plain);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { mergeMessages } from './merge-messages';
|
||||
import { localeFromAcceptLanguage } from './locale-matcher';
|
||||
import { routing, type Locale } from './routing';
|
||||
import { IS_LITE } from '@/lib/lite';
|
||||
import { addPlainLanguage } from './plain-language';
|
||||
|
||||
export default getRequestConfig(async ({ requestLocale }) => {
|
||||
let locale = await requestLocale;
|
||||
@@ -118,6 +119,8 @@ export default getRequestConfig(async ({ requestLocale }) => {
|
||||
messages = mergeMessages(enBase, messages as Record<string, unknown>);
|
||||
}
|
||||
|
||||
messages = await addPlainLanguage(locale, messages as Record<string, unknown>);
|
||||
|
||||
return {
|
||||
locale,
|
||||
messages,
|
||||
|
||||
@@ -65,7 +65,6 @@ export interface AccessibilitySettings {
|
||||
paragraphSpacing: ParagraphSpacing;
|
||||
readingWidth: ReadingWidth;
|
||||
readingMask: boolean;
|
||||
plainLanguage: boolean;
|
||||
// Motion
|
||||
reduceMotion: SystemToggle;
|
||||
pauseAnimatedImages: SystemToggle;
|
||||
@@ -117,7 +116,6 @@ export const ACCESSIBILITY_DEFAULTS: AccessibilitySettings = {
|
||||
paragraphSpacing: 'normal',
|
||||
readingWidth: 'full',
|
||||
readingMask: false,
|
||||
plainLanguage: false,
|
||||
reduceMotion: 'system',
|
||||
pauseAnimatedImages: 'system',
|
||||
focusRing: 'normal',
|
||||
@@ -196,7 +194,7 @@ export function isAllowedAccessibilityValue(key: string, value: unknown): boolea
|
||||
export const UNLOCKABLE_SETTING_KEYS: ReadonlySet<string> = new Set([
|
||||
'fontSize', 'reduceMotion', 'contrast', 'reduceTransparency', 'underlineLinks', 'showColorNames', 'colorBlindPalette',
|
||||
'appFont', 'lineSpacing', 'letterSpacing', 'wordSpacing', 'paragraphSpacing', 'readingWidth', 'readingMask',
|
||||
'plainLanguage', 'pauseAnimatedImages', 'focusRing', 'focusAlwaysVisible', 'largeTargets', 'largeCursor',
|
||||
'pauseAnimatedImages', 'focusRing', 'focusAlwaysVisible', 'largeTargets', 'largeCursor',
|
||||
'openOnHover', 'showRowActionButton', 'nativeScrollbars', 'mailViewMode', 'mailTextScale', 'mailMinFontSize',
|
||||
'mailOverrideStyles', 'mailFitWidth', 'readAloudRate', 'readAloudVoice', 'visualAlerts', 'unreadCountStyle',
|
||||
'doNotDisturb', 'announceNewMail', 'announceRowPreview', 'simpleMode', 'simpleModePagedList', 'showAccessibilityButton',
|
||||
|
||||
@@ -108,7 +108,6 @@ export const ACCESSIBILITY_POLICY_SETTINGS: readonly PresettableSetting[] = [
|
||||
options: [{ value: 'full', label: 'Full width' }, { value: 'comfortable', label: 'About 80 characters' }],
|
||||
},
|
||||
{ key: 'readingMask', label: 'Reading mask', type: 'boolean', labelKey: `${A}.reading_mask.label` },
|
||||
{ key: 'plainLanguage', label: 'Plain language', type: 'boolean', labelKey: `${A}.plain_language.label` },
|
||||
]),
|
||||
...group('Colour and contrast', [
|
||||
{
|
||||
|
||||
@@ -153,7 +153,7 @@ export const SHARED_SETTINGS = [
|
||||
'calendarFreeScroll', 'calendarHoverPreview', 'showTasksOnCalendar',
|
||||
'groupContactsByLetter', 'sortContactsByLastName', 'showContactsDirectory',
|
||||
'showAccessibilityButton', 'lineSpacing', 'letterSpacing', 'wordSpacing', 'paragraphSpacing', 'readingWidth',
|
||||
'readingMask', 'plainLanguage', 'reduceTransparency', 'showColorNames', 'colorBlindPalette', 'pauseAnimatedImages',
|
||||
'readingMask', 'reduceTransparency', 'showColorNames', 'colorBlindPalette', 'pauseAnimatedImages',
|
||||
'focusAlwaysVisible', 'largeCursor', 'openOnHover', 'showRowActionButton', 'nativeScrollbars',
|
||||
'mailViewMode', 'mailTextScale', 'mailMinFontSize', 'mailOverrideStyles', 'mailFitWidth', 'readAloudRate',
|
||||
'composeFontFamily', 'composeFontSize', 'confirmDelete', 'confirmArchive', 'unreadCountStyle',
|
||||
|
||||
@@ -356,7 +356,6 @@ const ENTRIES: SettingSchemaEntry[] = [
|
||||
choice('paragraphSpacing', 'accessibility', `${A}paragraph_spacing.label`, opts(`${A}spacing.`, allowed('paragraphSpacing'))),
|
||||
choice('readingWidth', 'accessibility', `${A}reading_width.label`, opts(`${A}reading_width.`, allowed('readingWidth'))),
|
||||
bool('readingMask', 'accessibility', `${A}reading_mask.label`),
|
||||
bool('plainLanguage', 'accessibility', `${A}plain_language.label`),
|
||||
choice('contrast', 'accessibility', `${A}contrast.label`, [
|
||||
{ value: 'system', label: `${A}system` },
|
||||
{ value: 'more', label: `${A}contrast.more` },
|
||||
|
||||
@@ -125,7 +125,6 @@ export const tabSearchEntries: Record<Tab, SettingsSearchEntry[]> = {
|
||||
{ label: 'settings.accessibility.paragraph_spacing.label' },
|
||||
{ label: 'settings.accessibility.reading_width.label' },
|
||||
{ label: 'settings.accessibility.reading_mask.label' },
|
||||
{ label: 'settings.accessibility.plain_language.label' },
|
||||
{ label: 'settings.appearance.list_density.label' },
|
||||
{ label: 'settings.appearance.toolbar_labels.label' },
|
||||
{ label: 'settings.accessibility.sections.contrast' },
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "قناع القراءة",
|
||||
"description": "يعتّم كل شيء في الرسالة ما عدا بضعة أسطر حول المؤشر، لتحافظ على موضعك في النص."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "لغة مبسطة",
|
||||
"description": "صياغة أبسط للإعدادات ورسائل الخطأ، مع شروحات قصيرة للمصطلحات التقنية. متاحة بالإنجليزية والألمانية."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "التباين",
|
||||
"description": "يجعل التباين الأعلى النص والحدود وإطار التركيز أغمق أو أفتح في أي سمة، ويضع خطًا تحت الروابط. خيار النظام يتبع جهازك.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Màscara de lectura",
|
||||
"description": "Enfosqueix tot el missatge excepte unes quantes línies al voltant del punter, perquè no perdis el lloc."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Llenguatge senzill",
|
||||
"description": "Textos més simples a les opcions i als missatges d'error, i explicacions breus dels termes tècnics. Disponible en anglès i alemany."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contrast",
|
||||
"description": "Més contrast fa que el text, les vores i el contorn de focus siguin més foscos o més clars amb qualsevol tema, i subratlla els enllaços. Sistema segueix el teu dispositiu.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Čtecí maska",
|
||||
"description": "Ve zprávě ztlumí vše kromě několika řádků kolem ukazatele, abyste neztratili místo, kde čtete."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Jednoduchý jazyk",
|
||||
"description": "Jednodušší formulace v nastavení a chybových hlášeních a krátké vysvětlivky odborných výrazů. K dispozici v angličtině a němčině."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Vyšší kontrast zesvětlí nebo ztmaví text, okraje a obrys zaměření v jakémkoli motivu a podtrhne odkazy. Systém se řídí vaším zařízením.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Læsemaske",
|
||||
"description": "Gør alt i en besked mørkt undtagen nogle få linjer omkring markøren, så du ikke mister pladsen."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Letforståeligt sprog",
|
||||
"description": "Enklere formuleringer i indstillinger og fejlmeddelelser og korte forklaringer af tekniske begreber. Findes på engelsk og tysk."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Mere kontrast gør tekst, kanter og fokusramme mørkere eller lysere i ethvert tema og understreger links. System følger din enhed.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Lesemaske",
|
||||
"description": "Blendet in einer Nachricht alles außer ein paar Zeilen um den Zeiger ab, damit Sie die Stelle nicht verlieren."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Einfache Sprache",
|
||||
"description": "Einfachere Formulierungen in Einstellungen und Fehlermeldungen und kurze Erklärungen zu Fachbegriffen. Auf Deutsch und Englisch verfügbar."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Mehr Kontrast macht Text, Rahmen und den Fokusrahmen bei jedem Design dunkler oder heller und unterstreicht Links. System folgt Ihrem Gerät.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Reading mask",
|
||||
"description": "Dims everything in a message except a few lines around the pointer, to help you keep your place."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Plain language",
|
||||
"description": "Simpler wording for settings and error messages, and short explanations of technical terms. Available in English and German."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contrast",
|
||||
"description": "More contrast makes text, borders and the focus outline darker or lighter on any theme, and underlines links. System follows your device.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Máscara de lectura",
|
||||
"description": "Oscurece todo el mensaje salvo unas líneas alrededor del puntero, para que no pierdas el sitio."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Lenguaje sencillo",
|
||||
"description": "Textos más simples en los ajustes y los mensajes de error, y explicaciones breves de los términos técnicos. Disponible en inglés y alemán."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contraste",
|
||||
"description": "Más contraste hace que el texto, los bordes y el contorno de foco sean más oscuros o más claros en cualquier tema, y subraya los enlaces. Sistema sigue tu dispositivo.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Lugemismask",
|
||||
"description": "Tumendab kirjas kõik peale mõne rea osuti ümber, et sa ei kaotaks kohta silmist."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Lihtsas keeles",
|
||||
"description": "Lihtsamad sõnastused seadetes ja veateadetes ning lühikesed selgitused tehnilistele terminitele. Saadaval inglise ja saksa keeles."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Suurem kontrast muudab teksti, äärised ja fookusraami igas teemas tumedamaks või heledamaks ning joonib lingid alla. Süsteem järgib sinu seadet.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "ماسک خواندن",
|
||||
"description": "هر چیز در پیام را بهجز چند خط اطراف نشانگر تیره میکند تا جای خود را گم نکنید."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "زبان ساده",
|
||||
"description": "عبارتهای سادهتر برای تنظیمات و پیامهای خطا، همراه با توضیح کوتاه برای اصطلاحات فنی. به انگلیسی و آلمانی موجود است."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "تضاد",
|
||||
"description": "تضاد بیشتر، متن، حاشیهها و قاب تمرکز را در هر تمی تیرهتر یا روشنتر میکند و زیر پیوندها خط میکشد. گزینهٔ سیستم از دستگاه شما پیروی میکند.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Masque de lecture",
|
||||
"description": "Assombrit tout le message sauf quelques lignes autour du pointeur, pour vous aider à ne pas perdre votre place."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Langage simple",
|
||||
"description": "Formulations plus simples pour les paramètres et les messages d'erreur, avec de courtes explications des termes techniques. Disponible en anglais et en allemand."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contraste",
|
||||
"description": "Plus de contraste rend le texte, les bordures et le contour de focus plus sombres ou plus clairs avec n'importe quel thème, et souligne les liens. Système suit votre appareil.",
|
||||
|
||||
@@ -3114,10 +3114,6 @@
|
||||
"label": "מסכת קריאה",
|
||||
"description": "מחשיך הכול בהודעה מלבד כמה שורות סביב המצביע, כדי שלא תאבדו את המקום."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "שפה פשוטה",
|
||||
"description": "ניסוח פשוט יותר בהגדרות ובהודעות שגיאה, והסברים קצרים למונחים טכניים. זמין באנגלית ובגרמנית."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "ניגודיות",
|
||||
"description": "ניגודיות גבוהה מכהה או מבהיר את הטקסט, הגבולות ומסגרת המיקוד בכל ערכת נושא, ומוסיפה קו תחתון לקישורים. האפשרות מערכת עוקבת אחרי המכשיר שלכם.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Olvasómaszk",
|
||||
"description": "Az üzenetben a mutató körüli néhány sor kivételével mindent elhomályosít, hogy ne veszítse el a helyét."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Egyszerű nyelv",
|
||||
"description": "Egyszerűbb megfogalmazás a beállításokban és a hibaüzenetekben, valamint rövid magyarázatok a szakkifejezésekhez. Angolul és németül érhető el."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontraszt",
|
||||
"description": "A nagyobb kontraszt minden témán sötétebbé vagy világosabbá teszi a szöveget, a kereteket és a fókuszkeretet, és aláhúzza a hivatkozásokat. A Rendszer az eszköze beállítását követi.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Maschera di lettura",
|
||||
"description": "Oscura tutto in un messaggio tranne alcune righe intorno al puntatore, per aiutarti a non perdere il segno."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Linguaggio semplice",
|
||||
"description": "Parole più semplici per impostazioni e messaggi di errore, e brevi spiegazioni dei termini tecnici. Disponibile in inglese e tedesco."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contrasto",
|
||||
"description": "Più contrasto rende testo, bordi e contorno del focus più scuri o più chiari con qualsiasi tema e sottolinea i link. Sistema segue il tuo dispositivo.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "閲覧マスク",
|
||||
"description": "メッセージ内でポインター周辺の数行以外を暗くして、読んでいる位置を見失わないようにします。"
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "やさしい言葉",
|
||||
"description": "設定やエラーメッセージをより簡単な言葉にし、専門用語に短い説明を付けます。英語とドイツ語で利用できます。"
|
||||
},
|
||||
"contrast": {
|
||||
"label": "コントラスト",
|
||||
"description": "コントラストを高めると、どのテーマでも文字、枠線、フォーカス枠がより濃く、または明るくなり、リンクに下線が付きます。「システム」はお使いのデバイスの設定に従います。",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "읽기 마스크",
|
||||
"description": "메시지에서 포인터 주변 몇 줄을 빼고 나머지를 어둡게 해서 읽던 위치를 놓치지 않게 도와줘요."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "쉬운 말",
|
||||
"description": "설정과 오류 메시지를 더 쉬운 말로 바꾸고, 전문 용어에 짧은 설명을 붙여요. 영어와 독일어에서 사용할 수 있어요."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "대비",
|
||||
"description": "대비를 높이면 어떤 테마에서든 글자, 테두리, 포커스 윤곽선이 더 어둡거나 밝아지고 링크에 밑줄이 생겨요. 시스템은 기기 설정을 따라요.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Lasīšanas maska",
|
||||
"description": "Aptumšo visu ziņā, izņemot dažas rindas ap rādītāju, lai nepazaudētu vietu, kur lasāt."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Vienkārša valoda",
|
||||
"description": "Vienkāršāki formulējumi iestatījumos un kļūdu ziņojumos un īsi skaidrojumi tehniskiem terminiem. Pieejama angļu un vācu valodā."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrasts",
|
||||
"description": "Lielāks kontrasts padara tekstu, apmales un fokusa apvadījumu tumšāku vai gaišāku jebkurā motīvā un pasvītro saites. Sistēma seko jūsu ierīcei.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Унших маск",
|
||||
"description": "Мессежийн заагчийн тойрсон хэдэн мөрөөс бусдыг бүдэгрүүлж, уншиж буй байраа алдахгүй байхад тусална."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Энгийн хэл",
|
||||
"description": "Тохиргоо болон алдааны мессежийг илүү энгийн үгээр, мөн техникийн нэр томьёонд товч тайлбар өгнө. Англи, герман хэлээр боломжтой."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Тодосгогч",
|
||||
"description": "Илүү их тодосгогч нь аль ч загвар дээр текст, хүрээ, фокусын хүрээг илүү хар эсвэл цайвар болгож, холбоосыг доогуур зураасаар тэмдэглэнэ. Систем нь таны төхөөрөмжийг дагана.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Lesemaske",
|
||||
"description": "Demper alt i en melding unntatt noen få linjer rundt pekeren, slik at du holder styr på hvor du er."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Enkelt språk",
|
||||
"description": "Enklere ord i innstillinger og feilmeldinger, og korte forklaringer av tekniske uttrykk. Tilgjengelig på engelsk og tysk."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Mer kontrast gjør tekst, kantlinjer og fokusrammen mørkere eller lysere i alle temaer, og understreker lenker. System følger enheten din.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Leesmasker",
|
||||
"description": "Dimt alles in een bericht behalve een paar regels rond de aanwijzer, zodat je je plek niet kwijtraakt."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Makkelijke taal",
|
||||
"description": "Eenvoudigere formuleringen bij instellingen en foutmeldingen, en korte uitleg bij technische termen. Beschikbaar in het Engels en Duits."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contrast",
|
||||
"description": "Meer contrast maakt tekst, randen en de focusrand donkerder of lichter in elk thema en onderstreept links. Systeem volgt je apparaat.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Maska czytania",
|
||||
"description": "Przyciemnia wszystko w wiadomości poza kilkoma wierszami wokół wskaźnika, żeby łatwiej było nie zgubić miejsca."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Prosty język",
|
||||
"description": "Prostsze sformułowania w ustawieniach i komunikatach o błędach oraz krótkie wyjaśnienia terminów technicznych. Dostępne po angielsku i niemiecku."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Większy kontrast przyciemnia lub rozjaśnia tekst, obramowania i ramkę fokusu w każdym motywie oraz podkreśla linki. System korzysta z ustawień urządzenia.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Máscara de leitura",
|
||||
"description": "Escurece tudo em uma mensagem, exceto algumas linhas ao redor do ponteiro, para ajudar a não perder o ponto da leitura."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Linguagem simples",
|
||||
"description": "Textos mais simples nas configurações e nas mensagens de erro, com explicações curtas de termos técnicos. Disponível em inglês e alemão."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contraste",
|
||||
"description": "Mais contraste deixa texto, bordas e o contorno de foco mais escuros ou mais claros em qualquer tema, e sublinha os links. Sistema segue o seu dispositivo.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Mască de citire",
|
||||
"description": "Estompează tot ce este în mesaj, în afară de câteva rânduri din jurul cursorului, ca să nu pierdeți locul."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Limbaj simplu",
|
||||
"description": "Formulări mai simple în setări și în mesajele de eroare și explicații scurte pentru termenii tehnici. Disponibil în engleză și germană."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Contrast",
|
||||
"description": "Mai mult contrast face textul, marginile și conturul de focalizare mai închise sau mai deschise la orice temă și subliniază linkurile. Sistem urmează dispozitivul dvs.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Маска для чтения",
|
||||
"description": "Затемняет всё в письме, кроме нескольких строк возле указателя, чтобы вы не теряли место."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Простой язык",
|
||||
"description": "Более простые формулировки в настройках и сообщениях об ошибках и короткие пояснения технических терминов. Доступно на английском и немецком."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Контраст",
|
||||
"description": "Повышенный контраст делает текст, границы и рамку фокуса темнее или светлее в любой теме и подчёркивает ссылки. «Как в системе» следует настройке устройства.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Maska na čítanie",
|
||||
"description": "V správe zatemní všetko okrem niekoľkých riadkov okolo ukazovateľa, aby ste nestratili miesto."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Jednoduchý jazyk",
|
||||
"description": "Jednoduchšie formulácie v nastaveniach a chybových hláseniach a krátke vysvetlenia odborných pojmov. K dispozícii v angličtine a nemčine."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Kontrast",
|
||||
"description": "Vyšší kontrast zvýrazní text, orámovanie a rámik zamerania tmavšie alebo svetlejšie v každom motíve a podčiarkne odkazy. Systém sleduje vaše zariadenie.",
|
||||
|
||||
@@ -6074,10 +6074,6 @@
|
||||
"label": "แถบบังการอ่าน",
|
||||
"description": "หรี่ทุกอย่างในข้อความ ยกเว้นไม่กี่บรรทัดรอบตัวชี้ เพื่อช่วยให้คุณไม่หลงตำแหน่งที่อ่านอยู่"
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "ภาษาที่เข้าใจง่าย",
|
||||
"description": "ใช้ถ้อยคำที่ง่ายขึ้นในการตั้งค่าและข้อความแสดงข้อผิดพลาด พร้อมคำอธิบายสั้นๆ ของศัพท์เทคนิค ใช้ได้ในภาษาอังกฤษและภาษาเยอรมัน"
|
||||
},
|
||||
"contrast": {
|
||||
"label": "คอนทราสต์",
|
||||
"description": "คอนทราสต์สูงทำให้ข้อความ เส้นขอบ และเส้นกรอบโฟกัสเข้มขึ้นหรืออ่อนลงในทุกธีม และขีดเส้นใต้ลิงก์ ตามระบบจะทำตามอุปกรณ์ของคุณ",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Okuma maskesi",
|
||||
"description": "İletide işaretçinin çevresindeki birkaç satır dışındaki her şeyi karartır, böylece okuduğunuz yeri kaybetmezsiniz."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Sade dil",
|
||||
"description": "Ayarlarda ve hata iletilerinde daha basit ifadeler ve teknik terimler için kısa açıklamalar. İngilizce ve Almanca dillerinde kullanılabilir."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Karşıtlık",
|
||||
"description": "Daha fazla karşıtlık, her temada metni, kenarlıkları ve odak çerçevesini daha koyu ya da daha açık yapar ve bağlantıların altını çizer. Sistem, cihazınızı izler.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "Маска для читання",
|
||||
"description": "Затемнює все в листі, окрім кількох рядків навколо вказівника, щоб ви не втрачали місце."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Проста мова",
|
||||
"description": "Простіші формулювання в налаштуваннях і повідомленнях про помилки та короткі пояснення технічних термінів. Доступно англійською та німецькою."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Контраст",
|
||||
"description": "Вищий контраст робить текст, межі та рамку фокуса темнішими або світлішими в будь-якій темі й підкреслює посилання. «Як у системі» наслідує налаштування пристрою.",
|
||||
|
||||
@@ -3182,10 +3182,6 @@
|
||||
"label": "Vùng tập trung khi đọc",
|
||||
"description": "Làm mờ mọi thứ trong thư ngoại trừ một vài dòng xung quanh con trỏ để giúp bạn giữ nguyên vị trí của mình."
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "Ngôn ngữ đơn giản",
|
||||
"description": "Từ ngữ đơn giản hơn cho các cài đặt và thông báo lỗi cũng như giải thích ngắn gọn về các thuật ngữ kỹ thuật. Có sẵn bằng tiếng Anh và tiếng Đức."
|
||||
},
|
||||
"contrast": {
|
||||
"label": "Độ tương phản",
|
||||
"description": "Độ tương phản cao hơn làm cho văn bản, đường viền và đường viền tiêu điểm tối hơn hoặc sáng hơn trên bất kỳ giao diện nào và gạch chân các liên kết. Hệ thống theo dõi thiết bị của bạn.",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "閱讀遮罩",
|
||||
"description": "將郵件中指標周圍幾行以外的內容調暗,幫助您不會找不到閱讀位置。"
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "白話語言",
|
||||
"description": "設定和錯誤訊息使用更簡單的措辭,並為技術術語提供簡短說明。支援英文和德文。"
|
||||
},
|
||||
"contrast": {
|
||||
"label": "對比",
|
||||
"description": "較高的對比會讓任何主題下的文字、邊框和焦點外框更深或更淺,並為連結加上底線。「跟隨系統」會沿用您裝置的設定。",
|
||||
|
||||
@@ -3170,10 +3170,6 @@
|
||||
"label": "阅读遮罩",
|
||||
"description": "将邮件中指针周围几行以外的内容调暗,帮助您不丢失阅读位置。"
|
||||
},
|
||||
"plain_language": {
|
||||
"label": "通俗语言",
|
||||
"description": "设置和错误提示使用更简单的措辞,并为技术术语提供简短说明。支持英语和德语。"
|
||||
},
|
||||
"contrast": {
|
||||
"label": "对比度",
|
||||
"description": "更高的对比度会让任何主题下的文字、边框和焦点轮廓更深或更浅,并为链接加下划线。“跟随系统”会沿用您设备的设置。",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { migrateSettings, useSettingsStore } from '../settings-store';
|
||||
import { SETTINGS_SCHEMA } from '@/lib/settings-schema';
|
||||
import { ACCESSIBILITY_DEFAULTS } from '@/lib/accessibility-settings';
|
||||
|
||||
// Plain wording is the only wording now (settings-15): the switch, its
|
||||
// default and its stored value are gone, and an old stored value is ignored.
|
||||
|
||||
describe('the old plain-language setting', () => {
|
||||
it('is not a setting any more', () => {
|
||||
expect('plainLanguage' in ACCESSIBILITY_DEFAULTS).toBe(false);
|
||||
expect('plainLanguage' in useSettingsStore.getState()).toBe(false);
|
||||
expect('plainLanguage' in SETTINGS_SCHEMA).toBe(false);
|
||||
});
|
||||
|
||||
it('is dropped from stored settings', () => {
|
||||
const migrated = migrateSettings({ plainLanguage: true, sendDelaySeconds: 0 }, 11) as unknown as Record<string, unknown>;
|
||||
expect('plainLanguage' in migrated).toBe(false);
|
||||
});
|
||||
|
||||
it('is not taken over from an imported settings file', () => {
|
||||
useSettingsStore.getState().importSettings(JSON.stringify({ plainLanguage: true }));
|
||||
expect('plainLanguage' in useSettingsStore.getState()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -2101,6 +2101,8 @@ export function migrateSettings(persisted: unknown, version: number): SettingsSt
|
||||
state.protocolOpenMode = state.protocolMailtoOpenMode;
|
||||
}
|
||||
delete state.protocolMailtoOpenMode;
|
||||
// Plain wording became the only wording: the switch is gone.
|
||||
delete state.plainLanguage;
|
||||
// Never read: drafts save 2 s after the last change.
|
||||
delete state.autoSaveDraftInterval;
|
||||
// v4: `dateFormat` was repurposed from 'regional'|'iso'|'custom' to
|
||||
|
||||
Reference in New Issue
Block a user