mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
feat(web): add an option to change the date formats (#7174)
* feat: add an option to change the date formats * pr feedback * fix: change title * fix: show list supported by the browser * fix: tests * fix: dates * fix: check only if locale is set * fix: better fallback value * fix: fallback * fix: fallback * feat: add default locale option * refactor: shared components * refactor: shared components * prepare for svelte 5 * don't use relative paths * refactor: fallback value Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * fix: parsing store * fix: lint * refactor: locales --------- Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
parent
a224bb23d0
commit
01d6707b59
45 changed files with 383 additions and 80 deletions
|
|
@ -1,11 +1,62 @@
|
|||
<script lang="ts">
|
||||
import type { ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
||||
import SettingCombobox from '$lib/components/shared-components/settings/setting-combobox.svelte';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
import { fallbackLocale, locales } from '$lib/constants';
|
||||
import { colorTheme, locale } from '$lib/stores/preferences.store';
|
||||
import { findLocale } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { colorTheme } from '../../stores/preferences.store';
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
|
||||
export const handleToggle = () => {
|
||||
let time = new Date();
|
||||
|
||||
$: formattedDate = time.toLocaleString(editedLocale, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
});
|
||||
$: timePortion = time.toLocaleString(editedLocale, {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
});
|
||||
$: selectedDate = `${formattedDate} ${timePortion}`;
|
||||
$: editedLocale = findLocale($locale).code;
|
||||
$: selectedOption = {
|
||||
value: findLocale(editedLocale).code || fallbackLocale.code,
|
||||
label: findLocale(editedLocale).name || fallbackLocale.name,
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
time = new Date();
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
|
||||
const getAllLanguages = (): ComboBoxOption[] => {
|
||||
return locales
|
||||
.filter(({ code }) => Intl.NumberFormat.supportedLocalesOf(code).length > 0)
|
||||
.map((locale) => ({
|
||||
label: locale.name,
|
||||
value: locale.code,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleToggleColorTheme = () => {
|
||||
$colorTheme.system = !$colorTheme.system;
|
||||
};
|
||||
|
||||
const handleToggleLocaleBrowser = () => {
|
||||
$locale = $locale ? undefined : fallbackLocale.code;
|
||||
};
|
||||
|
||||
const handleLocaleChange = (newLocale: string | undefined) => {
|
||||
$locale = newLocale;
|
||||
};
|
||||
</script>
|
||||
|
||||
<section class="my-4">
|
||||
|
|
@ -16,9 +67,31 @@
|
|||
title="Theme selection"
|
||||
subtitle="Automatically set the theme to light or dark based on your browser's system preference"
|
||||
bind:checked={$colorTheme.system}
|
||||
on:toggle={handleToggle}
|
||||
on:toggle={handleToggleColorTheme}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<SettingSwitch
|
||||
title="Default Locale"
|
||||
subtitle="Format dates and numbers based on your browser locale"
|
||||
checked={$locale == undefined}
|
||||
on:toggle={handleToggleLocaleBrowser}
|
||||
>
|
||||
<p class="mt-2">{selectedDate}</p>
|
||||
</SettingSwitch>
|
||||
</div>
|
||||
{#if $locale !== undefined}
|
||||
<div class="ml-4">
|
||||
<SettingCombobox
|
||||
comboboxPlaceholder="Searching locales..."
|
||||
{selectedOption}
|
||||
options={getAllLanguages()}
|
||||
title="Custom Locale"
|
||||
subtitle="Format dates and numbers based on the language and the region"
|
||||
onSelect={(combobox) => handleLocaleChange(combobox?.value)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@
|
|||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { changePassword } from '@immich/sdk';
|
||||
import { fade } from 'svelte/transition';
|
||||
import SettingInputField, { SettingInputFieldType } from '../admin-page/settings/setting-input-field.svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import type { HttpError } from '@sveltejs/kit';
|
||||
import SettingInputField, {
|
||||
SettingInputFieldType,
|
||||
} from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
||||
|
||||
let password = '';
|
||||
let newPassword = '';
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
</span>
|
||||
<div class="text-sm">
|
||||
<span class="">Last seen</span>
|
||||
<span>{DateTime.fromISO(device.updatedAt).toRelativeCalendar(options)}</span>
|
||||
<span>{DateTime.fromISO(device.updatedAt, { locale: $locale }).toRelativeCalendar(options)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{#if !device.current}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
import { updateUser, type UserResponseDto } from '@immich/sdk';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@
|
|||
import { mdiCheck, mdiClose } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||
import Icon from '../elements/icon.svelte';
|
||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||
import PartnerSelectionModal from './partner-selection-modal.svelte';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
|
||||
interface PartnerSharing {
|
||||
user: UserResponseDto;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
import { alwaysLoadOriginalFile } from '../../stores/preferences.store';
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
|
||||
const handleToggle = () => {
|
||||
$alwaysLoadOriginalFile = !$alwaysLoadOriginalFile;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
import { sidebarSettings } from '../../stores/preferences.store';
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
</script>
|
||||
|
||||
<section class="my-4">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import SettingSwitch from '../admin-page/settings/setting-switch.svelte';
|
||||
import { showDeleteModal } from '$lib/stores/preferences.store';
|
||||
import { fade } from 'svelte/transition';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
</script>
|
||||
|
||||
<section class="my-4">
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
import SettingInputField, { SettingInputFieldType } from '../admin-page/settings/setting-input-field.svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { updateUser } from '@immich/sdk';
|
||||
import SettingInputField, {
|
||||
SettingInputFieldType,
|
||||
} from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
||||
|
||||
let editedUser = cloneDeep($user);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { user } from '$lib/stores/user.store';
|
||||
import { oauth } from '$lib/utils';
|
||||
import { type ApiKeyResponseDto, type AuthDeviceResponseDto } from '@immich/sdk';
|
||||
import SettingAccordion from '../admin-page/settings/setting-accordion.svelte';
|
||||
import SettingAccordion from '../shared-components/settings/setting-accordion.svelte';
|
||||
import AppearanceSettings from './appearance-settings.svelte';
|
||||
import ChangePasswordSettings from './change-password-settings.svelte';
|
||||
import DeviceList from './device-list.svelte';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue