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:
waclaw66 2024-06-24 15:50:01 +02:00 committed by GitHub
parent df9e074304
commit dd2c7400a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
90 changed files with 635 additions and 322 deletions

View file

@ -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}

View file

@ -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;
}
});

View file

@ -228,7 +228,7 @@
id={`${listboxId}-${0}`}
on:click={() => closeDropdown()}
>
No results
{$t('no_results')}
</li>
{/if}
{#each filteredOptions as option, index (option.label)}

View file

@ -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">

View file

@ -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');

View file

@ -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}

View file

@ -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'));
}
};

View file

@ -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}

View file

@ -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');
});
});

View file

@ -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

View file

@ -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;

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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<{

View file

@ -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">

View file

@ -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">