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;
@@ -74,7 +73,7 @@
{:then data}
-
{(data.shared + data.sharing).toLocaleString(locale)} Albums
+
{(data.shared + data.sharing).toLocaleString($locale)} Albums
{/await}
@@ -108,7 +107,7 @@
{:then data}
-
{data.owned.toLocaleString(locale)} Albums
+
{data.owned.toLocaleString($locale)} Albums
{/await}
diff --git a/web/src/lib/components/shared-components/theme-button.svelte b/web/src/lib/components/shared-components/theme-button.svelte
index 7f6c90dc41..7965f0ab9d 100644
--- a/web/src/lib/components/shared-components/theme-button.svelte
+++ b/web/src/lib/components/shared-components/theme-button.svelte
@@ -1,74 +1,38 @@
diff --git a/web/src/lib/components/user-settings-page/user-api-key-list.svelte b/web/src/lib/components/user-settings-page/user-api-key-list.svelte
index b266d38cbd..c87c059772 100644
--- a/web/src/lib/components/user-settings-page/user-api-key-list.svelte
+++ b/web/src/lib/components/user-settings-page/user-api-key-list.svelte
@@ -12,6 +12,7 @@
notificationController,
NotificationType
} from '../shared-components/notification/notification';
+ import { locale } from '$lib/stores/preferences.store';
let keys: APIKeyResponseDto[] = [];
@@ -20,7 +21,6 @@
let deleteKey: APIKeyResponseDto | null = null;
let secret = '';
- const locale = navigator.language;
const format: Intl.DateTimeFormatOptions = {
month: 'short',
day: 'numeric',
@@ -154,7 +154,7 @@
>
{key.name} |
{new Date(key.createdAt).toLocaleDateString(locale, format)}
+ >{new Date(key.createdAt).toLocaleDateString($locale, format)}
|
|