mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
chore(web): another missing translations (#10274)
* chore(web): another missing translations * unused removed * more keys * lint fix * test fixed * dynamic translation fix * fixes * people search translation * params fixed * keep filter setting fix * lint fix * $t fixes * Update web/src/lib/i18n/en.json Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * another missing * activity translation * link sharing translations * expiration dropdown fix - didn't work localized * notification title * device logout * search results * reset to default * unsaved change * select from computer * selected * select-2 * select-3 * unmerge * pluralize, force icu message * Update web/src/lib/components/asset-viewer/asset-viewer.svelte Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * review fixes * remove user * plural fixes * ffmpeg settings * fixes * error title * plural fixes * onboarding * change password * more more * console log fix * another * api key desc * map marker * format fix * key fix * asset-utils * utils * misc --------- Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
This commit is contained in:
parent
df9e074304
commit
dd2c7400a6
90 changed files with 635 additions and 322 deletions
|
|
@ -99,17 +99,16 @@
|
|||
|
||||
{#if !shared}
|
||||
<p class="px-5 py-3 text-xs">
|
||||
{#if search.length === 0}ALL
|
||||
{/if}ALBUMS
|
||||
{(search.length === 0 ? $t('all_albums') : $t('albums')).toUpperCase()}
|
||||
</p>
|
||||
{/if}
|
||||
{#each filteredAlbums as album (album.id)}
|
||||
<AlbumListItem {album} searchQuery={search} on:album={() => handleSelect(album)} />
|
||||
{/each}
|
||||
{:else if albums.length > 0}
|
||||
<p class="px-5 py-1 text-sm">It looks like you do not have any albums with this name yet.</p>
|
||||
<p class="px-5 py-1 text-sm">{$t('no_albums_with_name_yet')}</p>
|
||||
{:else}
|
||||
<p class="px-5 py-1 text-sm">It looks like you do not have any albums yet.</p>
|
||||
<p class="px-5 py-1 text-sm">{$t('no_albums_yet')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
// skip error when a newer search is happening
|
||||
if (latestSearchTimeout === searchTimeout) {
|
||||
places = [];
|
||||
handleError(error, $t('cant_search_places'));
|
||||
handleError(error, $t('errors.cant_search_places'));
|
||||
showLoadingSpinner = false;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@
|
|||
id={`${listboxId}-${0}`}
|
||||
on:click={() => closeDropdown()}
|
||||
>
|
||||
No results
|
||||
{$t('no_results')}
|
||||
</li>
|
||||
{/if}
|
||||
{#each filteredOptions as option, index (option.label)}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@
|
|||
sharedLink = makeSharedLinkUrl($serverConfig.externalDomain, data.key);
|
||||
dispatch('created');
|
||||
} catch (error) {
|
||||
handleError(error, 'Failed to create shared link');
|
||||
handleError(error, $t('errors.failed_to_create_shared_link'));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
|
||||
onClose();
|
||||
} catch (error) {
|
||||
handleError(error, 'Failed to edit shared link');
|
||||
handleError(error, $t('errors.failed_to_edit_shared_link'));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -150,19 +150,18 @@
|
|||
<section>
|
||||
{#if shareType === SharedLinkType.Album}
|
||||
{#if !editingLink}
|
||||
<div>Let anyone with the link see photos and people in this album.</div>
|
||||
<div>{$t('album_with_link_access')}</div>
|
||||
{:else}
|
||||
<div class="text-sm">
|
||||
Public album | <span class="text-immich-primary dark:text-immich-dark-primary"
|
||||
>{editingLink.album?.albumName}</span
|
||||
>
|
||||
{$t('public_album')} |
|
||||
<span class="text-immich-primary dark:text-immich-dark-primary">{editingLink.album?.albumName}</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if shareType === SharedLinkType.Individual}
|
||||
{#if !editingLink}
|
||||
<div>Let anyone with the link see the selected photo(s)</div>
|
||||
<div>{$t('create_link_to_share_description')}</div>
|
||||
{:else}
|
||||
<div class="text-sm">
|
||||
{$t('individual_share')} |
|
||||
|
|
@ -204,13 +203,13 @@
|
|||
<div class="my-3">
|
||||
<SettingSwitch
|
||||
bind:checked={allowDownload}
|
||||
title={'Allow public user to download'}
|
||||
title={$t('allow_public_user_to_download')}
|
||||
disabled={!showMetadata}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<SettingSwitch bind:checked={allowUpload} title={'Allow public user to upload'} />
|
||||
<SettingSwitch bind:checked={allowUpload} title={$t('allow_public_user_to_upload')} />
|
||||
</div>
|
||||
|
||||
<div class="text-sm">
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let title = $t('confirm');
|
||||
export let prompt = 'Are you sure you want to do this?';
|
||||
export let prompt = $t('are_you_sure_to_do_this');
|
||||
export let confirmText = $t('confirm');
|
||||
export let confirmColor: Color = 'red';
|
||||
export let cancelText = $t('cancel');
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
|
||||
import { fileUploadHandler } from '$lib/utils/file-uploader';
|
||||
import { isAlbumsRoute, isSharedLinkRoute } from '$lib/utils/navigation';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
$: albumId = isAlbumsRoute($page.route?.id) ? $page.params.albumId : undefined;
|
||||
$: isShare = isSharedLinkRoute($page.route?.id);
|
||||
|
|
@ -64,6 +65,6 @@
|
|||
}}
|
||||
>
|
||||
<ImmichLogo noText class="m-16 w-48 animate-bounce" />
|
||||
<div class="text-2xl">Drop files anywhere to upload</div>
|
||||
<div class="text-2xl">{$t('drop_files_to_upload')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
import { navigate } from '$lib/utils/navigation';
|
||||
import { AppRoute, AssetAction } from '$lib/constants';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
const dispatch = createEventDispatcher<{ intersected: { container: HTMLDivElement; position: BucketPosition } }>();
|
||||
|
||||
|
|
@ -52,7 +53,7 @@
|
|||
await navigate({ targetRoute: 'current', assetId: $viewingAsset.id });
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Cannot navigate to the next asset');
|
||||
handleError(error, $t('errors.cannot_navigate_next_asset'));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -63,7 +64,7 @@
|
|||
await navigate({ targetRoute: 'current', assetId: $viewingAsset.id });
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Cannot navigate to previous asset');
|
||||
handleError(error, $t('errors.cannot_navigate_previous_asset'));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,9 @@
|
|||
src={getAssetThumbnailUrl(feature.properties?.id)}
|
||||
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary"
|
||||
alt={feature.properties?.city && feature.properties.country
|
||||
? `Map marker for images taken in ${feature.properties.city}, ${feature.properties.country}`
|
||||
? $t('map_marker_for_images', {
|
||||
values: { city: feature.properties.city, country: feature.properties.country },
|
||||
})
|
||||
: $t('map_marker_with_image')}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe('NotificationCard component', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(sut.getByTestId('title')).toHaveTextContent('Info');
|
||||
expect(sut.getByTestId('title')).toHaveTextContent('info');
|
||||
expect(sut.getByTestId('message')).toHaveTextContent('Notification message');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@
|
|||
<div class="flex place-items-center gap-2">
|
||||
<Icon path={icon} color={primaryColor[notification.type]} size="20" />
|
||||
<h2 style:color={primaryColor[notification.type]} class="font-medium" data-testid="title">
|
||||
{notification.type.toString()}
|
||||
{#if notification.type == NotificationType.Error}{$t('error')}
|
||||
{:else if notification.type == NotificationType.Warning}{$t('warning')}
|
||||
{:else if notification.type == NotificationType.Info}{$t('info')}{/if}
|
||||
</h2>
|
||||
</div>
|
||||
<CircleIconButton
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
if (await hasTransparentPixels(blob)) {
|
||||
notificationController.show({
|
||||
type: NotificationType.Error,
|
||||
message: 'Profile pictures cannot have transparent pixels. Please zoom in and/or move the image.',
|
||||
message: $t('errors.profile_picture_transparent_pixels'),
|
||||
timeout: 3000,
|
||||
});
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<div class="flex flex-wrap gap-x-5 gap-y-2 mt-1">
|
||||
<Checkbox id="not-in-album-checkbox" label={$t('not_in_any_album')} bind:checked={filters.isNotInAlbum} />
|
||||
<Checkbox id="archive-checkbox" label={$t('archive')} bind:checked={filters.isArchive} />
|
||||
<Checkbox id="favorite-checkbox" label={$t('favorite')} bind:checked={filters.isFavorite} />
|
||||
<Checkbox id="favorite-checkbox" label={$t('favorites')} bind:checked={filters.isFavorite} />
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
const res = await getAllPeople({ withHidden: false });
|
||||
return orderBySelectedPeopleFirst(res.people);
|
||||
} catch (error) {
|
||||
handleError(error, $t('failed_to_get_people'));
|
||||
handleError(error, $t('errors.failed_to_get_people'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,10 +93,10 @@
|
|||
>
|
||||
{#if showAllPeople}
|
||||
<span><Icon path={mdiClose} ariaHidden /></span>
|
||||
Collapse
|
||||
{$t('collapse')}
|
||||
{:else}
|
||||
<span><Icon path={mdiArrowRight} ariaHidden /></span>
|
||||
See all people
|
||||
{$t('see_all_people')}
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
on:click={() => dispatch('reset', { default: true })}
|
||||
class="bg-none text-sm font-medium text-immich-primary hover:text-immich-primary/75 dark:text-immich-dark-primary hover:dark:text-immich-dark-primary/75"
|
||||
>
|
||||
Reset to default
|
||||
{$t('reset_to_default')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import Checkbox from '$lib/components/elements/checkbox.svelte';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let value: string[];
|
||||
export let options: { value: string; text: string }[];
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let title: string;
|
||||
export let comboboxPlaceholder: string;
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import Dropdown, { type RenderedOption } from '$lib/components/elements/dropdown.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let title: string;
|
||||
export let subtitle = '';
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
import type { FormEventHandler } from 'svelte/elements';
|
||||
import { fly } from 'svelte/transition';
|
||||
import PasswordField from '../password-field.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let inputType: SettingInputFieldType;
|
||||
export let value: string | number;
|
||||
|
|
@ -54,7 +55,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let value: string | number;
|
||||
export let options: { value: string | number; text: string }[];
|
||||
|
|
@ -34,7 +35,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { createEventDispatcher } from 'svelte';
|
||||
import Slider from '$lib/components/elements/slider.svelte';
|
||||
import { generateId } from '$lib/utils/generate-id';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let title: string;
|
||||
export let subtitle = '';
|
||||
|
|
@ -31,7 +32,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let value: string;
|
||||
export let label = '';
|
||||
|
|
@ -26,7 +27,7 @@
|
|||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
Unsaved change
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
const shortcuts: Shortcuts = {
|
||||
general: [
|
||||
{ key: ['←', '→'], action: $t('previous_or_next_photo') },
|
||||
{ key: ['Esc'], action: 'Back, close, or deselect' },
|
||||
{ key: ['Esc'], action: $t('back_close_deselect') },
|
||||
{ key: ['Ctrl', 'k'], action: $t('search_your_photos') },
|
||||
{ key: ['Ctrl', '⇧', 'k'], action: $t('open_the_search_filters') },
|
||||
],
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
{ key: ['⇧', 'a'], action: $t('archive_or_unarchive_photo') },
|
||||
{ key: ['⇧', 'd'], action: $t('download') },
|
||||
{ key: ['Space'], action: $t('play_or_pause_video') },
|
||||
{ key: ['Del'], action: 'Trash/Delete Asset', info: 'press ⇧ to permanently delete asset' },
|
||||
{ key: ['Del'], action: $t('trash_delete_asset'), info: $t('shift_to_permanent_delete') },
|
||||
],
|
||||
};
|
||||
const dispatch = createEventDispatcher<{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
|
||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||
import { mdiCog, mdiWindowMinimize, mdiCancel, mdiCloudUploadOutline } from '@mdi/js';
|
||||
import { s } from '$lib/utils';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
let showDetail = false;
|
||||
|
|
@ -38,18 +37,18 @@
|
|||
on:outroend={() => {
|
||||
if ($errorCounter > 0) {
|
||||
notificationController.show({
|
||||
message: `Upload completed with ${$errorCounter} error${s($errorCounter)}, refresh the page to see new upload assets.`,
|
||||
message: $t('upload_errors', { values: { count: $errorCounter } }),
|
||||
type: NotificationType.Warning,
|
||||
});
|
||||
} else if ($successCounter > 0) {
|
||||
notificationController.show({
|
||||
message: 'Upload success, refresh the page to see new upload assets.',
|
||||
message: $t('upload_success'),
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
}
|
||||
if ($duplicateCounter > 0) {
|
||||
notificationController.show({
|
||||
message: `Skipped ${$duplicateCounter} duplicate asset${s($duplicateCounter)}`,
|
||||
message: $t('upload_skipped_duplicates', { values: { count: $duplicateCounter } }),
|
||||
type: NotificationType.Warning,
|
||||
});
|
||||
}
|
||||
|
|
@ -65,12 +64,18 @@
|
|||
<div class="place-item-center mb-4 flex justify-between">
|
||||
<div class="flex flex-col gap-1">
|
||||
<p class="immich-form-label text-xm">
|
||||
Remaining {$remainingUploads} - Processed {$successCounter + $errorCounter}/{$totalUploadCounter}
|
||||
{$t('upload_progress', {
|
||||
values: {
|
||||
remaining: $remainingUploads,
|
||||
processed: $successCounter + $errorCounter,
|
||||
total: $totalUploadCounter,
|
||||
},
|
||||
})}
|
||||
</p>
|
||||
<p class="immich-form-label text-xs">
|
||||
Uploaded <span class="text-immich-success">{$successCounter}</span> - Error
|
||||
<span class="text-immich-error">{$errorCounter}</span>
|
||||
- Duplicates <span class="text-immich-warning">{$duplicateCounter}</span>
|
||||
{$t('upload_status_uploaded')} <span class="text-immich-success">{$successCounter}</span> -
|
||||
{$t('upload_status_errors')} <span class="text-immich-error">{$errorCounter}</span> -
|
||||
{$t('upload_status_duplicates')} <span class="text-immich-warning">{$duplicateCounter}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col items-end">
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
</script>
|
||||
|
||||
{#if showModal}
|
||||
<FullScreenModal title="🎉 NEW VERSION AVAILABLE" onClose={() => (showModal = false)}>
|
||||
<FullScreenModal title="🎉 {$t('new_version_available')}" onClose={() => (showModal = false)}>
|
||||
<div>
|
||||
<FormatMessage key="version_announcement_message" let:tag let:message>
|
||||
{#if tag === 'link'}
|
||||
|
|
@ -53,9 +53,9 @@
|
|||
<div class="mt-4 font-medium">Your friend, Alex</div>
|
||||
|
||||
<div class="font-sm mt-8">
|
||||
<code>Server Version: {serverVersion}</code>
|
||||
<code>{$t('server_version')}: {serverVersion}</code>
|
||||
<br />
|
||||
<code>Latest Version: {releaseVersion}</code>
|
||||
<code>{$t('latest_version')}: {releaseVersion}</code>
|
||||
</div>
|
||||
|
||||
<svelte:fragment slot="sticky-bottom">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue