feat: locale-aware date format in email list with preset picker #331
This commit is contained in:
@@ -4,17 +4,14 @@ import { useTranslations } from 'next-intl';
|
||||
import { useCalendarStore, CalendarViewMode } from '@/stores/calendar-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import { usePolicyStore } from '@/stores/policy-store';
|
||||
import { SettingsSection, SettingItem, Select, RadioGroup, ToggleSwitch } from './settings-section';
|
||||
import { SettingsSection, SettingItem, Select, ToggleSwitch } from './settings-section';
|
||||
|
||||
export function CalendarSettings() {
|
||||
const t = useTranslations('calendar.settings');
|
||||
const tViews = useTranslations('calendar.views');
|
||||
const tDays = useTranslations('calendar.days');
|
||||
|
||||
const { viewMode, setViewMode } = useCalendarStore();
|
||||
const {
|
||||
timeFormat,
|
||||
firstDayOfWeek,
|
||||
showTimeInMonthView,
|
||||
showWeekNumbers,
|
||||
enableCalendarTasks,
|
||||
@@ -40,28 +37,6 @@ export function CalendarSettings() {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('week_starts_on')}>
|
||||
<Select
|
||||
value={firstDayOfWeek.toString()}
|
||||
onChange={(value) => updateSetting('firstDayOfWeek', parseInt(value) as 0 | 1)}
|
||||
options={[
|
||||
{ value: '1', label: tDays('monday') },
|
||||
{ value: '0', label: tDays('sunday') },
|
||||
]}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('time_format')}>
|
||||
<RadioGroup
|
||||
value={timeFormat}
|
||||
onChange={(value) => updateSetting('timeFormat', value as '12h' | '24h')}
|
||||
options={[
|
||||
{ value: '12h', label: t('time_format_12h') },
|
||||
{ value: '24h', label: t('time_format_24h') },
|
||||
]}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t('show_time_in_month_view')}
|
||||
description={t('show_time_in_month_view_desc')}
|
||||
|
||||
@@ -1,17 +1,100 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { LanguageSwitcher } from '@/components/ui/language-switcher';
|
||||
import { SettingsSection, SettingItem } from './settings-section';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import type { DateFormat, TimeFormat, FirstDayOfWeek } from '@/stores/settings-store';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
import { SettingsSection, SettingItem, Select, RadioGroup } from './settings-section';
|
||||
|
||||
export function LanguageSettings() {
|
||||
const t = useTranslations('settings.appearance');
|
||||
const t = useTranslations('settings.language_region');
|
||||
const tDays = useTranslations('calendar.days');
|
||||
|
||||
const { dateFormat, timeFormat, firstDayOfWeek, updateSetting } = useSettingsStore();
|
||||
|
||||
// Subscribe to locale changes so the preview re-renders on language switch
|
||||
// (formatDate reads it via getState() and would otherwise stay stale).
|
||||
const locale = useLocaleStore((s) => s.locale);
|
||||
|
||||
const preview = useMemo(() => {
|
||||
// Build sample timestamps for each bucket so users see what their pick
|
||||
// will look like in practice. Use offsets relative to "now" so the
|
||||
// bucketing is stable even though the wall-clock keeps moving.
|
||||
void locale; void dateFormat; void timeFormat;
|
||||
const now = new Date();
|
||||
const today = new Date(now);
|
||||
today.setHours(15, 31, 0, 0);
|
||||
const thisWeek = new Date(now);
|
||||
thisWeek.setDate(now.getDate() - 2);
|
||||
thisWeek.setHours(15, 31, 0, 0);
|
||||
const older = new Date(now);
|
||||
older.setMonth(now.getMonth() - 2);
|
||||
older.setHours(15, 31, 0, 0);
|
||||
return {
|
||||
today: formatDate(today),
|
||||
thisWeek: formatDate(thisWeek),
|
||||
older: formatDate(older),
|
||||
};
|
||||
}, [locale, dateFormat, timeFormat]);
|
||||
|
||||
return (
|
||||
<SettingsSection title={t('language.label')} description={t('language.description')}>
|
||||
<SettingsSection title={t('title')} description={t('description')}>
|
||||
<SettingItem label={t('language.label')} description={t('language.description')}>
|
||||
<LanguageSwitcher />
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('date_format.label')} description={t('date_format.description')}>
|
||||
<div className="flex flex-col items-end gap-2">
|
||||
<Select
|
||||
value={dateFormat}
|
||||
onChange={(value) => updateSetting('dateFormat', value as DateFormat)}
|
||||
options={[
|
||||
{ value: 'smart', label: t('date_format.smart') },
|
||||
{ value: 'relative', label: t('date_format.relative') },
|
||||
{ value: 'full', label: t('date_format.full') },
|
||||
]}
|
||||
/>
|
||||
<div className="text-xs text-muted-foreground text-right space-y-0.5 font-mono">
|
||||
<div>
|
||||
<span className="opacity-70">{t('date_format.preview_today')} </span>
|
||||
<span className="text-foreground/90">{preview.today}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="opacity-70">{t('date_format.preview_this_week')} </span>
|
||||
<span className="text-foreground/90">{preview.thisWeek}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="opacity-70">{t('date_format.preview_older')} </span>
|
||||
<span className="text-foreground/90">{preview.older}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('time_format.label')} description={t('time_format.description')}>
|
||||
<RadioGroup
|
||||
value={timeFormat}
|
||||
onChange={(value) => updateSetting('timeFormat', value as TimeFormat)}
|
||||
options={[
|
||||
{ value: '12h', label: t('time_format.12h') },
|
||||
{ value: '24h', label: t('time_format.24h') },
|
||||
]}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('first_day.label')} description={t('first_day.description')}>
|
||||
<Select
|
||||
value={firstDayOfWeek.toString()}
|
||||
onChange={(value) => updateSetting('firstDayOfWeek', parseInt(value) as FirstDayOfWeek)}
|
||||
options={[
|
||||
{ value: '1', label: tDays('monday') },
|
||||
{ value: '0', label: tDays('sunday') },
|
||||
]}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
);
|
||||
}
|
||||
|
||||
+76
-12
@@ -3,6 +3,8 @@ import { twMerge } from "tailwind-merge";
|
||||
import { Mailbox, UNIFIED_MAILBOX_IDS } from "./jmap/types";
|
||||
import type { UnifiedMailboxRole } from "./jmap/types";
|
||||
import { debug } from "./debug";
|
||||
import { useLocaleStore } from "@/stores/locale-store";
|
||||
import { useSettingsStore } from "@/stores/settings-store";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
@@ -40,24 +42,86 @@ export function generateUUID(): string {
|
||||
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a received-at date for the email list. The output style is
|
||||
* controlled by the `dateFormat` user setting:
|
||||
*
|
||||
* - `smart` (default) — locale-aware, age-bucketed:
|
||||
* today → time only ("15:31" or "3:31 PM")
|
||||
* last 7 days → short weekday+time ("Fr 15:31", "Fri 3:31 PM")
|
||||
* older → full locale date ("28.04.2026", "04/28/2026")
|
||||
* - `relative` — legacy en-US relative format ("1h ago", "2d ago").
|
||||
* - `full` — always the full locale date+time.
|
||||
*
|
||||
* Both the locale (from the language picker) and 12h/24h preference are
|
||||
* read via `getState()` so this stays SSR-safe.
|
||||
*/
|
||||
export function formatDate(date: Date | string): string {
|
||||
const d = typeof date === "string" ? new Date(date) : date;
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - d.getTime();
|
||||
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
const hours = Math.floor(diff / 3600000);
|
||||
const days = Math.floor(diff / 86400000);
|
||||
const localeRaw = useLocaleStore.getState().locale;
|
||||
const locale = localeRaw && localeRaw.length > 0 ? localeRaw : "en";
|
||||
// `en` alone resolves to en-US in Intl; everything else uses the language
|
||||
// subtag as-is and lets the runtime pick a sensible default region.
|
||||
const intlLocale = locale === "en" ? "en-US" : locale;
|
||||
const { dateFormat, timeFormat } = useSettingsStore.getState();
|
||||
const hour12 = timeFormat === "12h";
|
||||
|
||||
if (minutes < 1) return "Just now";
|
||||
if (minutes < 60) return `${minutes}m ago`;
|
||||
if (hours < 24) return `${hours}h ago`;
|
||||
if (days < 7) return `${days}d ago`;
|
||||
if (dateFormat === "relative") {
|
||||
const diff = now.getTime() - d.getTime();
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
const hours = Math.floor(diff / 3600000);
|
||||
const days = Math.floor(diff / 86400000);
|
||||
if (minutes < 1) return "Just now";
|
||||
if (minutes < 60) return `${minutes}m ago`;
|
||||
if (hours < 24) return `${hours}h ago`;
|
||||
if (days < 7) return `${days}d ago`;
|
||||
return d.toLocaleDateString(intlLocale, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: d.getFullYear() !== now.getFullYear() ? "numeric" : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return d.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: d.getFullYear() !== now.getFullYear() ? "numeric" : undefined,
|
||||
if (dateFormat === "full") {
|
||||
return d.toLocaleString(intlLocale, {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12,
|
||||
});
|
||||
}
|
||||
|
||||
// 'smart' (default)
|
||||
const timeStr = d.toLocaleTimeString(intlLocale, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12,
|
||||
});
|
||||
|
||||
const isSameDay =
|
||||
d.getFullYear() === now.getFullYear() &&
|
||||
d.getMonth() === now.getMonth() &&
|
||||
d.getDate() === now.getDate();
|
||||
if (isSameDay) return timeStr;
|
||||
|
||||
const daysAgo = Math.floor((now.getTime() - d.getTime()) / 86400000);
|
||||
if (daysAgo < 7) {
|
||||
// German Intl outputs "Fr." with a trailing dot for `weekday: 'short'`;
|
||||
// strip it so the result reads cleanly next to the time.
|
||||
const weekday = d
|
||||
.toLocaleDateString(intlLocale, { weekday: "short" })
|
||||
.replace(/\.$/, "");
|
||||
return `${weekday} ${timeStr}`;
|
||||
}
|
||||
|
||||
return d.toLocaleDateString(intlLocale, {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Pokračovat v úpravách",
|
||||
"tabs": {
|
||||
"appearance": "Vzhled",
|
||||
"language": "Jazyk a region",
|
||||
"language": "Jazyk, region a čas",
|
||||
"email": "Chování e-mailu",
|
||||
"composer": "Psaní zpráv",
|
||||
"privacy": "Soukromí a bezpečnost",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Jazyk a region",
|
||||
"description": "Nakonfigurujte jazykové a místní předvolby",
|
||||
"title": "Jazyk, region a čas",
|
||||
"description": "Jazyk, formát data, formát času a další regionální předvolby",
|
||||
"language": {
|
||||
"label": "Jazyk",
|
||||
"description": "Vyberte preferovaný jazyk",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Formát data",
|
||||
"description": "Jak se mají zobrazovat data",
|
||||
"regional": "Místní",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Vlastní"
|
||||
"description": "Jak se zobrazují data v seznamu e-mailů",
|
||||
"smart": "Chytrý (regionální)",
|
||||
"relative": "Relativní (před 1 h, před 2 d)",
|
||||
"full": "Vždy úplné datum",
|
||||
"preview_today": "Dnes:",
|
||||
"preview_this_week": "Tento týden:",
|
||||
"preview_older": "Starší:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Formát času",
|
||||
|
||||
+10
-7
@@ -755,7 +755,7 @@
|
||||
"search_no_results": "Ingen match i indstillinger",
|
||||
"tabs": {
|
||||
"appearance": "Udseende",
|
||||
"language": "Sprog & region",
|
||||
"language": "Sprog, region & tid",
|
||||
"email": "E-mail-adfærd",
|
||||
"composer": "Komponist",
|
||||
"privacy": "Privatliv & sikkerhed",
|
||||
@@ -935,8 +935,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Sprog & region",
|
||||
"description": "Konfigurér sprog og regionale præferencer",
|
||||
"title": "Sprog, region & tid",
|
||||
"description": "Sprog, datoformat, tidsformat og andre regionale indstillinger",
|
||||
"language": {
|
||||
"label": "Sprog",
|
||||
"description": "Vælg dit foretrukne sprog",
|
||||
@@ -945,10 +945,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Datoformat",
|
||||
"description": "Hvordan datoer skal vises",
|
||||
"regional": "Regionalt",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Brugerdefineret"
|
||||
"description": "Sådan vises datoer på e-mail-listen",
|
||||
"smart": "Smart (regionalt)",
|
||||
"relative": "Relativ (for 1 t siden, for 2 d siden)",
|
||||
"full": "Altid fuld dato",
|
||||
"preview_today": "I dag:",
|
||||
"preview_this_week": "Denne uge:",
|
||||
"preview_older": "Ældre:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Tidsformat",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Weiter bearbeiten",
|
||||
"tabs": {
|
||||
"appearance": "Darstellung",
|
||||
"language": "Sprache & Region",
|
||||
"language": "Sprache, Region & Zeit",
|
||||
"email": "E-Mail-Verhalten",
|
||||
"composer": "Editor",
|
||||
"privacy": "Datenschutz & Sicherheit",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Sprache & Region",
|
||||
"description": "Konfigurieren Sie Sprach- und Regionaleinstellungen",
|
||||
"title": "Sprache, Region & Zeit",
|
||||
"description": "Sprache, Datums- und Zeitformat sowie weitere regionale Einstellungen",
|
||||
"language": {
|
||||
"label": "Sprache",
|
||||
"description": "Wählen Sie Ihre bevorzugte Sprache",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Datumsformat",
|
||||
"description": "Wie Daten angezeigt werden sollen",
|
||||
"regional": "Regional",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Benutzerdefiniert"
|
||||
"description": "Wie Daten in der E-Mail-Liste angezeigt werden",
|
||||
"smart": "Intelligent (gebietsschemaabhängig)",
|
||||
"relative": "Relativ (vor 1 Std., vor 2 Tagen)",
|
||||
"full": "Immer vollständiges Datum",
|
||||
"preview_today": "Heute:",
|
||||
"preview_this_week": "Diese Woche:",
|
||||
"preview_older": "Älter:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Zeitformat",
|
||||
|
||||
+10
-7
@@ -755,7 +755,7 @@
|
||||
"search_no_results": "No matching settings",
|
||||
"tabs": {
|
||||
"appearance": "Appearance",
|
||||
"language": "Language & Region",
|
||||
"language": "Language, Region & Time",
|
||||
"email": "Email Behavior",
|
||||
"composer": "Composer",
|
||||
"privacy": "Privacy & Security",
|
||||
@@ -935,8 +935,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Language & Region",
|
||||
"description": "Configure language and regional preferences",
|
||||
"title": "Language, Region & Time",
|
||||
"description": "Language, date format, time format, and other regional preferences",
|
||||
"language": {
|
||||
"label": "Language",
|
||||
"description": "Choose your preferred language",
|
||||
@@ -945,10 +945,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Date Format",
|
||||
"description": "How dates should be displayed",
|
||||
"regional": "Regional",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Custom"
|
||||
"description": "How dates are shown in the email list",
|
||||
"smart": "Smart (locale-aware)",
|
||||
"relative": "Relative (1h ago, 2d ago)",
|
||||
"full": "Always full date",
|
||||
"preview_today": "Today:",
|
||||
"preview_this_week": "This week:",
|
||||
"preview_older": "Older:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Time Format",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Seguir editando",
|
||||
"tabs": {
|
||||
"appearance": "Apariencia",
|
||||
"language": "Idioma y Región",
|
||||
"language": "Idioma, Región y Hora",
|
||||
"email": "Comportamiento del Correo",
|
||||
"composer": "Editor",
|
||||
"privacy": "Privacidad y Seguridad",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Idioma y Región",
|
||||
"description": "Configure las preferencias de idioma y región",
|
||||
"title": "Idioma, Región y Hora",
|
||||
"description": "Idioma, formato de fecha, formato de hora y otras preferencias regionales",
|
||||
"language": {
|
||||
"label": "Idioma",
|
||||
"description": "Elija su idioma preferido",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Formato de Fecha",
|
||||
"description": "Cómo se deben mostrar las fechas",
|
||||
"regional": "Regional",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Personalizado"
|
||||
"description": "Cómo se muestran las fechas en la lista de correos",
|
||||
"smart": "Inteligente (según región)",
|
||||
"relative": "Relativo (hace 1 h, hace 2 d)",
|
||||
"full": "Fecha completa siempre",
|
||||
"preview_today": "Hoy:",
|
||||
"preview_this_week": "Esta semana:",
|
||||
"preview_older": "Más antiguo:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Formato de Hora",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Continuer l'édition",
|
||||
"tabs": {
|
||||
"appearance": "Apparence",
|
||||
"language": "Langue et région",
|
||||
"language": "Langue, région et heure",
|
||||
"email": "Comportement email",
|
||||
"composer": "Compositeur",
|
||||
"privacy": "Confidentialité et sécurité",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Langue et région",
|
||||
"description": "Configurez vos préférences linguistiques et régionales",
|
||||
"title": "Langue, région et heure",
|
||||
"description": "Langue, format de date, format d'heure et autres préférences régionales",
|
||||
"language": {
|
||||
"label": "Langue",
|
||||
"description": "Choisissez votre langue préférée",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Format de date",
|
||||
"description": "Comment les dates doivent être affichées",
|
||||
"regional": "Régional",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Personnalisé"
|
||||
"description": "Comment les dates apparaissent dans la liste des e-mails",
|
||||
"smart": "Intelligent (adapté à la région)",
|
||||
"relative": "Relatif (il y a 1 h, il y a 2 j)",
|
||||
"full": "Toujours la date complète",
|
||||
"preview_today": "Aujourd'hui :",
|
||||
"preview_this_week": "Cette semaine :",
|
||||
"preview_older": "Plus ancien :"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Format d'heure",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Continua a modificare",
|
||||
"tabs": {
|
||||
"appearance": "Aspetto",
|
||||
"language": "Lingua e regione",
|
||||
"language": "Lingua, regione e ora",
|
||||
"email": "Comportamento email",
|
||||
"composer": "Editor",
|
||||
"privacy": "Privacy e sicurezza",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Lingua e regione",
|
||||
"description": "Configura le preferenze di lingua e regionali",
|
||||
"title": "Lingua, regione e ora",
|
||||
"description": "Lingua, formato data, formato ora e altre preferenze regionali",
|
||||
"language": {
|
||||
"label": "Lingua",
|
||||
"description": "Scegli la tua lingua preferita",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Formato data",
|
||||
"description": "Come devono essere visualizzate le date",
|
||||
"regional": "Regionale",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Personalizzato"
|
||||
"description": "Come vengono visualizzate le date nell'elenco delle e-mail",
|
||||
"smart": "Intelligente (in base alla regione)",
|
||||
"relative": "Relativo (1 h fa, 2 g fa)",
|
||||
"full": "Sempre data completa",
|
||||
"preview_today": "Oggi:",
|
||||
"preview_this_week": "Questa settimana:",
|
||||
"preview_older": "Più vecchio:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Formato ora",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "編集を続ける",
|
||||
"tabs": {
|
||||
"appearance": "外観",
|
||||
"language": "言語と地域",
|
||||
"language": "言語、地域、時刻",
|
||||
"email": "メール動作",
|
||||
"composer": "作成",
|
||||
"privacy": "プライバシーとセキュリティ",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "言語と地域",
|
||||
"description": "言語と地域の設定を構成",
|
||||
"title": "言語、地域、時刻",
|
||||
"description": "言語、日付形式、時刻形式、その他の地域設定",
|
||||
"language": {
|
||||
"label": "言語",
|
||||
"description": "お好みの言語を選択",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "日付形式",
|
||||
"description": "日付の表示形式",
|
||||
"regional": "地域設定",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "カスタム"
|
||||
"description": "メール一覧での日付の表示方法",
|
||||
"smart": "スマート(地域に合わせる)",
|
||||
"relative": "相対表示(1時間前、2日前)",
|
||||
"full": "常に完全な日付",
|
||||
"preview_today": "今日:",
|
||||
"preview_this_week": "今週:",
|
||||
"preview_older": "それ以前:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "時刻形式",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "계속 수정하기",
|
||||
"tabs": {
|
||||
"appearance": "화면 설정",
|
||||
"language": "언어 및 지역",
|
||||
"language": "언어, 지역 및 시간",
|
||||
"email": "메일 동작",
|
||||
"composer": "메일 쓰기",
|
||||
"privacy": "개인정보 및 보안",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "언어 및 지역",
|
||||
"description": "언어와 지역 형식을 설정해 주세요",
|
||||
"title": "언어, 지역 및 시간",
|
||||
"description": "언어, 날짜 형식, 시간 형식 및 기타 지역 환경설정",
|
||||
"language": {
|
||||
"label": "언어",
|
||||
"description": "사용할 언어를 선택해 주세요",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "날짜 형식",
|
||||
"description": "날짜가 표시되는 방식을 설정해요",
|
||||
"regional": "지역 설정",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "사용자 지정"
|
||||
"description": "이메일 목록에 날짜가 표시되는 방식",
|
||||
"smart": "스마트 (지역에 맞춤)",
|
||||
"relative": "상대 시간 (1시간 전, 2일 전)",
|
||||
"full": "항상 전체 날짜",
|
||||
"preview_today": "오늘:",
|
||||
"preview_this_week": "이번 주:",
|
||||
"preview_older": "이전:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "시간 형식",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Turpināt rediģēšanu",
|
||||
"tabs": {
|
||||
"appearance": "Izskats",
|
||||
"language": "Valoda un reģions",
|
||||
"language": "Valoda, reģions un laiks",
|
||||
"email": "Pasta darbība",
|
||||
"composer": "Redaktors",
|
||||
"privacy": "Privātums un drošība",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Valoda un reģions",
|
||||
"description": "Iestatiet valodas un reģionālās preferences",
|
||||
"title": "Valoda, reģions un laiks",
|
||||
"description": "Valoda, datuma formāts, laika formāts un citas reģionālās preferences",
|
||||
"language": {
|
||||
"label": "Valoda",
|
||||
"description": "Izvēlieties vēlamo valodu",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Datuma formāts",
|
||||
"description": "Kā attēlot datumus",
|
||||
"regional": "Reģionālais",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Pielāgots"
|
||||
"description": "Kā datumi tiek attēloti e-pasta sarakstā",
|
||||
"smart": "Gudrs (atbilstoši reģionam)",
|
||||
"relative": "Relatīvs (pirms 1 st., pirms 2 d.)",
|
||||
"full": "Vienmēr pilns datums",
|
||||
"preview_today": "Šodien:",
|
||||
"preview_this_week": "Šajā nedēļā:",
|
||||
"preview_older": "Vecāks:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Laika formāts",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Doorgaan met bewerken",
|
||||
"tabs": {
|
||||
"appearance": "Uiterlijk",
|
||||
"language": "Taal & Regio",
|
||||
"language": "Taal, Regio & Tijd",
|
||||
"email": "E-mailgedrag",
|
||||
"composer": "Opstellen",
|
||||
"privacy": "Privacy & Beveiliging",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Taal & Regio",
|
||||
"description": "Configureer taal- en regiovoorkeuren",
|
||||
"title": "Taal, Regio & Tijd",
|
||||
"description": "Taal, datumnotatie, tijdnotatie en andere regionale voorkeuren",
|
||||
"language": {
|
||||
"label": "Taal",
|
||||
"description": "Kies je voorkeurstaal",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Datumnotatie",
|
||||
"description": "Hoe datums moeten worden weergegeven",
|
||||
"regional": "Regionaal",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Aangepast"
|
||||
"description": "Hoe datums worden weergegeven in de e-maillijst",
|
||||
"smart": "Slim (regionaal)",
|
||||
"relative": "Relatief (1 u geleden, 2 d geleden)",
|
||||
"full": "Altijd volledige datum",
|
||||
"preview_today": "Vandaag:",
|
||||
"preview_this_week": "Deze week:",
|
||||
"preview_older": "Ouder:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Tijdnotatie",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Kontynuuj edycję",
|
||||
"tabs": {
|
||||
"appearance": "Wygląd",
|
||||
"language": "Język i region",
|
||||
"language": "Język, region i czas",
|
||||
"email": "Zachowanie poczty e-mail",
|
||||
"composer": "Redagowanie",
|
||||
"privacy": "Prywatność i bezpieczeństwo",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Język i region",
|
||||
"description": "Skonfiguruj preferencje językowe i regionalne",
|
||||
"title": "Język, region i czas",
|
||||
"description": "Język, format daty, format godziny i inne preferencje regionalne",
|
||||
"language": {
|
||||
"label": "Język",
|
||||
"description": "Wybierz preferowany język",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Format daty",
|
||||
"description": "Jak mają być wyświetlane daty",
|
||||
"regional": "Regionalny",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Niestandardowy"
|
||||
"description": "Jak daty są wyświetlane na liście e-maili",
|
||||
"smart": "Inteligentny (regionalny)",
|
||||
"relative": "Względny (1 g temu, 2 d temu)",
|
||||
"full": "Zawsze pełna data",
|
||||
"preview_today": "Dzisiaj:",
|
||||
"preview_this_week": "W tym tygodniu:",
|
||||
"preview_older": "Starsze:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Format czasu",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Continuar editando",
|
||||
"tabs": {
|
||||
"appearance": "Aparência",
|
||||
"language": "Idioma e Região",
|
||||
"language": "Idioma, Região e Hora",
|
||||
"email": "Comportamento de E-mail",
|
||||
"composer": "Editor",
|
||||
"privacy": "Privacidade e Segurança",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Idioma e Região",
|
||||
"description": "Configure preferências de idioma e região",
|
||||
"title": "Idioma, Região e Hora",
|
||||
"description": "Idioma, formato de data, formato de hora e outras preferências regionais",
|
||||
"language": {
|
||||
"label": "Idioma",
|
||||
"description": "Escolha seu idioma preferido",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Formato de Data",
|
||||
"description": "Como as datas devem ser exibidas",
|
||||
"regional": "Regional",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Personalizado"
|
||||
"description": "Como as datas são mostradas na lista de e-mails",
|
||||
"smart": "Inteligente (regional)",
|
||||
"relative": "Relativo (há 1 h, há 2 d)",
|
||||
"full": "Sempre data completa",
|
||||
"preview_today": "Hoje:",
|
||||
"preview_this_week": "Esta semana:",
|
||||
"preview_older": "Mais antigo:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Formato de Hora",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Продолжить редактирование",
|
||||
"tabs": {
|
||||
"appearance": "Внешний вид",
|
||||
"language": "Язык и регион",
|
||||
"language": "Язык, регион и время",
|
||||
"email": "Поведение почты",
|
||||
"composer": "Редактор",
|
||||
"privacy": "Конфиденциальность и безопасность",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Язык и регион",
|
||||
"description": "Настройте языковые и региональные предпочтения",
|
||||
"title": "Язык, регион и время",
|
||||
"description": "Язык, формат даты, формат времени и другие региональные настройки",
|
||||
"language": {
|
||||
"label": "Язык",
|
||||
"description": "Выберите предпочтительный язык",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Формат даты",
|
||||
"description": "Как отображать даты",
|
||||
"regional": "Региональный",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Пользовательский"
|
||||
"description": "Как отображаются даты в списке писем",
|
||||
"smart": "Умный (по региону)",
|
||||
"relative": "Относительный (1 ч назад, 2 д назад)",
|
||||
"full": "Всегда полная дата",
|
||||
"preview_today": "Сегодня:",
|
||||
"preview_this_week": "На этой неделе:",
|
||||
"preview_older": "Старее:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Формат времени",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Düzenlemeye devam et",
|
||||
"tabs": {
|
||||
"appearance": "Görünüm",
|
||||
"language": "Dil ve Bölge",
|
||||
"language": "Dil, Bölge ve Saat",
|
||||
"email": "E-posta Davranışı",
|
||||
"composer": "Yazıcı",
|
||||
"privacy": "Gizlilik ve Güvenlik",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Dil ve Bölge",
|
||||
"description": "Dil ve bölgesel tercihleri yapılandırın",
|
||||
"title": "Dil, Bölge ve Saat",
|
||||
"description": "Dil, tarih biçimi, saat biçimi ve diğer bölgesel tercihler",
|
||||
"language": {
|
||||
"label": "Dil",
|
||||
"description": "Tercih ettiğiniz dili seçin",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Tarih Biçimi",
|
||||
"description": "Tarihlerin nasıl görüntüleneceği",
|
||||
"regional": "Bölgesel",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Özel"
|
||||
"description": "Tarihlerin e-posta listesinde nasıl gösterileceği",
|
||||
"smart": "Akıllı (bölgeye duyarlı)",
|
||||
"relative": "Göreceli (1 sa önce, 2 g önce)",
|
||||
"full": "Her zaman tam tarih",
|
||||
"preview_today": "Bugün:",
|
||||
"preview_this_week": "Bu hafta:",
|
||||
"preview_older": "Daha eski:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Saat Biçimi",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "Продовжуйте редагувати",
|
||||
"tabs": {
|
||||
"appearance": "Зовнішній вигляд",
|
||||
"language": "Мова та регіон",
|
||||
"language": "Мова, регіон і час",
|
||||
"email": "Поведінка електронної пошти",
|
||||
"composer": "Композитор",
|
||||
"privacy": "Конфіденційність і безпека",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "Мова та регіон",
|
||||
"description": "Налаштуйте мовні та регіональні параметри",
|
||||
"title": "Мова, регіон і час",
|
||||
"description": "Мова, формат дати, формат часу та інші регіональні налаштування",
|
||||
"language": {
|
||||
"label": "Мова",
|
||||
"description": "Виберіть бажану мову",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "Формат дати",
|
||||
"description": "Як мають відображатися дати",
|
||||
"regional": "Регіональний",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Довільний"
|
||||
"description": "Як відображаються дати у списку листів",
|
||||
"smart": "Розумний (за регіоном)",
|
||||
"relative": "Відносний (1 год тому, 2 дн тому)",
|
||||
"full": "Завжди повна дата",
|
||||
"preview_today": "Сьогодні:",
|
||||
"preview_this_week": "Цього тижня:",
|
||||
"preview_older": "Старіше:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "Формат часу",
|
||||
|
||||
+10
-7
@@ -752,7 +752,7 @@
|
||||
"keep_editing": "继续编辑",
|
||||
"tabs": {
|
||||
"appearance": "外观",
|
||||
"language": "语言及地区",
|
||||
"language": "语言、地区与时间",
|
||||
"email": "邮件行为",
|
||||
"composer": "邮件撰写",
|
||||
"privacy": "隐私与安全",
|
||||
@@ -932,8 +932,8 @@
|
||||
}
|
||||
},
|
||||
"language_region": {
|
||||
"title": "语言及地区",
|
||||
"description": "配置语言和区域首选项",
|
||||
"title": "语言、地区与时间",
|
||||
"description": "语言、日期格式、时间格式以及其他区域设置",
|
||||
"language": {
|
||||
"label": "语言",
|
||||
"description": "选择您的首选语言",
|
||||
@@ -942,10 +942,13 @@
|
||||
},
|
||||
"date_format": {
|
||||
"label": "日期格式",
|
||||
"description": "日期应如何显示",
|
||||
"regional": "区域格式",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "自定义"
|
||||
"description": "电子邮件列表中日期的显示方式",
|
||||
"smart": "智能(按地区)",
|
||||
"relative": "相对时间(1 小时前、2 天前)",
|
||||
"full": "始终完整日期",
|
||||
"preview_today": "今天:",
|
||||
"preview_this_week": "本周:",
|
||||
"preview_older": "更早:"
|
||||
},
|
||||
"time_format": {
|
||||
"label": "时间格式",
|
||||
|
||||
@@ -31,7 +31,7 @@ export type ListDensity = Density;
|
||||
export type DeleteAction = 'trash' | 'trash-and-read' | 'permanent';
|
||||
export type ReplyMode = 'reply' | 'replyAll';
|
||||
export type SignaturePosition = 'above_quote' | 'below_quote';
|
||||
export type DateFormat = 'regional' | 'iso' | 'custom';
|
||||
export type DateFormat = 'smart' | 'relative' | 'full';
|
||||
export type TimeFormat = '12h' | '24h';
|
||||
export type FirstDayOfWeek = 0 | 1; // 0 = Sunday, 1 = Monday
|
||||
export type ExternalContentPolicy = 'ask' | 'block' | 'allow';
|
||||
@@ -300,7 +300,7 @@ const DEFAULT_SETTINGS = {
|
||||
animationsEnabled: true,
|
||||
|
||||
// Language & Region
|
||||
dateFormat: 'regional' as DateFormat,
|
||||
dateFormat: 'smart' as DateFormat,
|
||||
timeFormat: '24h' as TimeFormat,
|
||||
firstDayOfWeek: 1 as FirstDayOfWeek, // Monday
|
||||
|
||||
@@ -760,7 +760,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
}),
|
||||
{
|
||||
name: 'settings-storage',
|
||||
version: 3,
|
||||
version: 4,
|
||||
migrate: (persisted, version) => {
|
||||
const state = persisted as Record<string, unknown>;
|
||||
if (version < 2 && state.listDensity) {
|
||||
@@ -771,6 +771,12 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
state.protocolOpenMode = state.protocolMailtoOpenMode;
|
||||
}
|
||||
delete state.protocolMailtoOpenMode;
|
||||
// v4: `dateFormat` was repurposed from 'regional'|'iso'|'custom' to
|
||||
// 'smart'|'relative'|'full'. The old setting was never read anywhere,
|
||||
// so every persisted value maps to the new default.
|
||||
if (version < 4) {
|
||||
state.dateFormat = 'smart';
|
||||
}
|
||||
return state as unknown as SettingsState;
|
||||
},
|
||||
onRehydrateStorage: () => {
|
||||
|
||||
Reference in New Issue
Block a user