diff --git a/web/__mocks__/$app/environment.js b/web/__mocks__/$app/environment.js new file mode 100644 index 0000000000..357e6533cd --- /dev/null +++ b/web/__mocks__/$app/environment.js @@ -0,0 +1,3 @@ +module.exports = { + browser: false +}; diff --git a/web/package-lock.json b/web/package-lock.json index a4e929b3d6..3615d5c318 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -16,6 +16,7 @@ "luxon": "^3.1.1", "rxjs": "^7.8.0", "socket.io-client": "^4.5.1", + "svelte-local-storage-store": "^0.4.0", "svelte-material-icons": "^2.0.2" }, "devDependencies": { @@ -10584,6 +10585,17 @@ "svelte": ">= 3" } }, + "node_modules/svelte-local-storage-store": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/svelte-local-storage-store/-/svelte-local-storage-store-0.4.0.tgz", + "integrity": "sha512-ctPykTt4S3BE5bF0mfV0jKiUR1qlmqLvnAkQvYHLeb9wRyO1MdIFDVI23X+TZEFleATHkTaOpYZswIvf3b2tWA==", + "engines": { + "node": ">=0.14" + }, + "peerDependencies": { + "svelte": "^3.48.0" + } + }, "node_modules/svelte-material-icons": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz", @@ -19014,6 +19026,12 @@ "dev": true, "requires": {} }, + "svelte-local-storage-store": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/svelte-local-storage-store/-/svelte-local-storage-store-0.4.0.tgz", + "integrity": "sha512-ctPykTt4S3BE5bF0mfV0jKiUR1qlmqLvnAkQvYHLeb9wRyO1MdIFDVI23X+TZEFleATHkTaOpYZswIvf3b2tWA==", + "requires": {} + }, "svelte-material-icons": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz", diff --git a/web/package.json b/web/package.json index 31b5f5ab0b..28fd337963 100644 --- a/web/package.json +++ b/web/package.json @@ -68,6 +68,7 @@ "luxon": "^3.1.1", "rxjs": "^7.8.0", "socket.io-client": "^4.5.1", + "svelte-local-storage-store": "^0.4.0", "svelte-material-icons": "^2.0.2" } } diff --git a/web/src/app.html b/web/src/app.html index 3838f41f2d..8aed10653b 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -4,6 +4,15 @@ %sveltekit.head% + diff --git a/web/src/lib/components/admin-page/jobs/job-tile.svelte b/web/src/lib/components/admin-page/jobs/job-tile.svelte index 9c92c8491b..f7b23c8ad7 100644 --- a/web/src/lib/components/admin-page/jobs/job-tile.svelte +++ b/web/src/lib/components/admin-page/jobs/job-tile.svelte @@ -3,7 +3,7 @@ import SelectionSearch from 'svelte-material-icons/SelectionSearch.svelte'; import Play from 'svelte-material-icons/Play.svelte'; import AllInclusive from 'svelte-material-icons/AllInclusive.svelte'; - + import { locale } from '$lib/stores/preferences.store'; import { createEventDispatcher } from 'svelte'; import { JobCounts } from '@api'; @@ -22,8 +22,6 @@ const run = (includeAllAssets: boolean) => { dispatch('click', { includeAllAssets }); }; - - const locale = navigator.language;
@@ -45,7 +43,7 @@

Active

{#if jobCounts.active !== undefined} - {jobCounts.active.toLocaleString(locale)} + {jobCounts.active.toLocaleString($locale)} {:else} {/if} @@ -57,7 +55,7 @@ >

{#if jobCounts.waiting !== undefined} - {jobCounts.waiting.toLocaleString(locale)} + {jobCounts.waiting.toLocaleString($locale)} {:else} {/if} diff --git a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte index a6e128a0bb..b20d897870 100644 --- a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte +++ b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte @@ -7,6 +7,7 @@ import { getBytesWithUnit, asByteUnitString } from '../../../utils/byte-units'; import { onMount, onDestroy } from 'svelte'; import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; + import { locale } from '$lib/stores/preferences.store'; export let allUsers: Array; @@ -37,8 +38,6 @@ // Stats are unavailable if data is not loaded yet $: [spaceUsage, spaceUnit] = getBytesWithUnit(stats ? stats.usageRaw : 0); - - const locale = navigator.language;

@@ -83,8 +82,10 @@ }`} > {getFullName(user.userId)} - {user.photos.toLocaleString(locale)} - {user.videos.toLocaleString(locale)} + {user.photos.toLocaleString($locale)} + {user.videos.toLocaleString($locale)} {asByteUnitString(user.usageRaw)} {/each} diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index 43bb400145..0dedd6a781 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -17,6 +17,7 @@ import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; import CircleIconButton from '../shared-components/circle-icon-button.svelte'; import noThumbnailUrl from '$lib/assets/no-thumbnail.png'; + import { locale } from '$lib/stores/preferences.store'; export let album: AlbumResponseDto; @@ -52,8 +53,6 @@ onMount(async () => { imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl; }); - - const locale = navigator.language;
-

{album.assetCount.toLocaleString(locale)} {album.assetCount == 1 ? `item` : `items`}

+

+ {album.assetCount.toLocaleString($locale)} + {album.assetCount == 1 ? `item` : `items`} +

{#if album.shared}

·

diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index aa0f7b4256..228760e24d 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -39,6 +39,7 @@ import ThemeButton from '../shared-components/theme-button.svelte'; import { openFileUploadDialog } from '$lib/utils/file-uploader'; import { bulkDownload } from '$lib/utils/asset-utils'; + import { locale } from '$lib/stores/preferences.store'; import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte'; import ImmichLogo from '../shared-components/immich-logo.svelte'; @@ -88,7 +89,6 @@ } }); - const locale = navigator.language; const albumDateFormat: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', @@ -99,8 +99,8 @@ const startDate = new Date(album.assets[0].fileCreatedAt); const endDate = new Date(album.assets[album.assetCount - 1].fileCreatedAt); - const startDateString = startDate.toLocaleDateString(locale, albumDateFormat); - const endDateString = endDate.toLocaleDateString(locale, albumDateFormat); + const startDateString = startDate.toLocaleDateString($locale, albumDateFormat); + const endDateString = endDate.toLocaleDateString($locale, albumDateFormat); // If the start and end date are the same, only show one date return startDateString === endDateString @@ -380,7 +380,7 @@ >

- Selected {multiSelectAsset.size.toLocaleString(locale)} + Selected {multiSelectAsset.size.toLocaleString($locale)}

diff --git a/web/src/lib/components/album-page/asset-selection.svelte b/web/src/lib/components/album-page/asset-selection.svelte index 9682a8ec92..3550053b11 100644 --- a/web/src/lib/components/album-page/asset-selection.svelte +++ b/web/src/lib/components/album-page/asset-selection.svelte @@ -11,12 +11,12 @@ assetsInAlbumStoreState, selectedAssets } from '$lib/stores/asset-interaction.store'; + import { locale } from '$lib/stores/preferences.store'; const dispatch = createEventDispatcher(); export let albumId: string; export let assetsInAlbum: AssetResponseDto[]; - const locale = navigator.language; onMount(() => { $assetsInAlbumStoreState = assetsInAlbum; @@ -51,7 +51,7 @@

Add to album

{:else}

- {$selectedAssets.size.toLocaleString(locale)} selected + {$selectedAssets.size.toLocaleString($locale)} selected

{/if}
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index d202376f54..d06016b4d6 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -24,6 +24,7 @@ import { assetStore } from '$lib/stores/assets.store'; import { addAssetsToAlbum } from '$lib/utils/asset-utils'; + import { browser } from '$app/environment'; export let asset: AssetResponseDto; export let publicSharedKey = ''; @@ -54,7 +55,9 @@ }); onDestroy(() => { - document.removeEventListener('keydown', onKeyboardPress); + if (browser) { + document.removeEventListener('keydown', onKeyboardPress); + } }); $: asset.id && getAllAlbums(); // Update the album information when the asset ID changes diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index 7e57158705..14d90bea15 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -8,6 +8,7 @@ import { browser } from '$app/environment'; import { AssetResponseDto, AlbumResponseDto } from '@api'; import { asByteUnitString } from '../../utils/byte-units'; + import { locale } from '$lib/stores/preferences.store'; type Leaflet = typeof import('leaflet'); type LeafletMap = import('leaflet').Map; @@ -69,8 +70,6 @@ return undefined; }; - - const locale = navigator.language;
@@ -101,7 +100,7 @@

- {assetDateTimeOriginal.toLocaleDateString(locale, { + {assetDateTimeOriginal.toLocaleDateString($locale, { month: 'short', day: 'numeric', year: 'numeric' @@ -109,7 +108,7 @@

- {assetDateTimeOriginal.toLocaleString(locale, { + {assetDateTimeOriginal.toLocaleString($locale, { weekday: 'short', hour: 'numeric', minute: '2-digit', @@ -149,14 +148,14 @@

{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}

-

{`ƒ/${asset.exifInfo.fNumber.toLocaleString(locale)}` || ''}

+

{`ƒ/${asset.exifInfo.fNumber.toLocaleString($locale)}` || ''}

{#if asset.exifInfo.exposureTime}

{`${asset.exifInfo.exposureTime}`}

{/if} {#if asset.exifInfo.focalLength} -

{`${asset.exifInfo.focalLength.toLocaleString(locale)} mm`}

+

{`${asset.exifInfo.focalLength.toLocaleString($locale)} mm`}

{/if} {#if asset.exifInfo.iso} diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte index 931cbbdf24..d54aedffbf 100644 --- a/web/src/lib/components/photos-page/asset-date-group.svelte +++ b/web/src/lib/components/photos-page/asset-date-group.svelte @@ -13,12 +13,13 @@ selectedAssets, selectedGroup } from '$lib/stores/asset-interaction.store'; + import { locale } from '$lib/stores/preferences.store'; + export let assets: AssetResponseDto[]; export let bucketDate: string; export let bucketHeight: number; export let isAlbumSelectionMode = false; - const locale = navigator.language; const groupDateFormat: Intl.DateTimeFormatOptions = { weekday: 'short', month: 'short', @@ -31,7 +32,7 @@ let hoveredDateGroup = ''; $: assetsGroupByDate = lodash .chain(assets) - .groupBy((a) => new Date(a.fileCreatedAt).toLocaleDateString(locale, groupDateFormat)) + .groupBy((a) => new Date(a.fileCreatedAt).toLocaleDateString($locale, groupDateFormat)) .sortBy((group) => assets.indexOf(group[0])) .value(); @@ -115,7 +116,7 @@ > {#each assetsGroupByDate as assetsInDateGroup, groupIndex (assetsInDateGroup[0].id)} {@const dateGroupTitle = new Date(assetsInDateGroup[0].fileCreatedAt).toLocaleDateString( - locale, + $locale, groupDateFormat )} diff --git a/web/src/lib/components/share-page/individual-shared-viewer.svelte b/web/src/lib/components/share-page/individual-shared-viewer.svelte index 27d19a06ee..50aaec3ca5 100644 --- a/web/src/lib/components/share-page/individual-shared-viewer.svelte +++ b/web/src/lib/components/share-page/individual-shared-viewer.svelte @@ -18,6 +18,7 @@ notificationController, NotificationType } from '../shared-components/notification/notification'; + import { locale } from '$lib/stores/preferences.store'; export let sharedLink: SharedLinkResponseDto; export let isOwned: boolean; @@ -86,8 +87,6 @@ clearMultiSelectAssetAssetHandler(); } }; - - const locale = navigator.language;
@@ -99,7 +98,7 @@ >

- Selected {selectedAssets.size.toLocaleString(locale)} + Selected {selectedAssets.size.toLocaleString($locale)}

diff --git a/web/src/lib/components/shared-components/side-bar/side-bar.svelte b/web/src/lib/components/shared-components/side-bar/side-bar.svelte index bea3b34e40..83272d6d44 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar.svelte @@ -9,6 +9,7 @@ import LoadingSpinner from '../loading-spinner.svelte'; import StatusBox from '../status-box.svelte'; import SideBarButton from './side-bar-button.svelte'; + import { locale } from '$lib/stores/preferences.store'; const getAssetCount = async () => { const { data: assetCount } = await api.assetApi.getAssetCountByUserId(); @@ -35,8 +36,6 @@ owned: albumCount.owned }; }; - - const locale = navigator.language;