- {#each Object.entries(schema.properties ?? {}) as [childKey, childSchema] (childKey)}
+ {#each getSchemaProperties(schema) as [childKey, childSchema] (childKey)}
{/each}
-{:else if schema.uiHint === 'AlbumId'}
+{:else if schema.uiHint?.type === 'AlbumId'}
{:else if schema.enum && schema.array}
diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts
index 41d98df097..ee5a03bb1b 100644
--- a/web/src/lib/types.ts
+++ b/web/src/lib/types.ts
@@ -96,7 +96,10 @@ export type JSONSchemaProperty = {
array?: boolean;
properties?: Record;
required?: string[];
- uiHint?: 'AlbumId' | 'AssetId' | 'PersonId';
+ uiHint?: {
+ type?: 'AlbumId' | 'AssetId' | 'PersonId';
+ order?: number;
+ };
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
diff --git a/web/src/routes/(user)/workflows/[workflowId]/WorkflowStepCard.svelte b/web/src/routes/(user)/workflows/[workflowId]/WorkflowStepCard.svelte
index 5dcf431b39..d3dec41f48 100644
--- a/web/src/routes/(user)/workflows/[workflowId]/WorkflowStepCard.svelte
+++ b/web/src/routes/(user)/workflows/[workflowId]/WorkflowStepCard.svelte
@@ -55,7 +55,7 @@
);
const isGhost = $derived(step.id === 'ghost');
- const getUiHint = (key: string) => schema?.properties?.[key]?.uiHint;
+ const getUiHint = (key: string) => schema?.properties?.[key]?.uiHint?.type;
const toIds = (value: unknown): string[] => (Array.isArray(value) ? value.map(String) : [String(value)]);
let dragImage = $state();
let isDropTarget = $state(false);
From 06f3b4f25922d08d00ff06c42d4c4f9a4ff38b2a Mon Sep 17 00:00:00 2001
From: Mees Frensel <33722705+meesfrensel@users.noreply.github.com>
Date: Tue, 23 Jun 2026 17:08:46 +0200
Subject: [PATCH 024/435] refactor(web): simple actions (#29257)
---
.../asset-viewer/AssetViewer.svelte | 12 ++--
.../asset-viewer/AssetViewerNavBar.svelte | 57 +++++++------------
.../actions/SetProfilePictureAction.svelte | 20 -------
web/src/lib/services/asset.service.spec.ts | 6 ++
web/src/lib/services/asset.service.ts | 35 +++++++++++-
5 files changed, 65 insertions(+), 65 deletions(-)
delete mode 100644 web/src/lib/components/asset-viewer/actions/SetProfilePictureAction.svelte
diff --git a/web/src/lib/components/asset-viewer/AssetViewer.svelte b/web/src/lib/components/asset-viewer/AssetViewer.svelte
index 9606077d52..e99bf13148 100644
--- a/web/src/lib/components/asset-viewer/AssetViewer.svelte
+++ b/web/src/lib/components/asset-viewer/AssetViewer.svelte
@@ -110,11 +110,11 @@
let sharedLink = getSharedLink();
let fullscreenElement = $state();
- let playOriginalVideo = $state($alwaysLoadOriginalVideo);
+ let isPlayingOriginalVideo = $state($alwaysLoadOriginalVideo);
let slideshowStartAssetId = $state();
const setPlayOriginalVideo = (value: boolean) => {
- playOriginalVideo = value;
+ isPlayingOriginalVideo = value;
};
const refreshStack = async () => {
@@ -504,7 +504,7 @@
{onUndoDelete}
onClose={onClose ? () => onClose(stack?.primaryAssetId ?? asset.id) : undefined}
{onRemoveFromAlbum}
- {playOriginalVideo}
+ {isPlayingOriginalVideo}
{setPlayOriginalVideo}
/>
@@ -542,7 +542,7 @@
onClose={closeViewer}
onVideoEnded={() => navigateAsset()}
onVideoStarted={handleVideoStarted}
- {playOriginalVideo}
+ playOriginalVideo={isPlayingOriginalVideo}
/>
{:else if viewerKind === 'LiveVideoViewer'}
navigateAsset('previous')}
onNextAsset={() => navigateAsset('next')}
onVideoEnded={() => (assetViewerManager.isPlayingMotionPhoto = false)}
- {playOriginalVideo}
+ playOriginalVideo={isPlayingOriginalVideo}
/>
{:else if viewerKind === 'ImagePanaramaViewer'}
@@ -574,7 +574,7 @@
onClose={closeViewer}
onVideoEnded={() => navigateAsset()}
onVideoStarted={handleVideoStarted}
- {playOriginalVideo}
+ playOriginalVideo={isPlayingOriginalVideo}
/>
{/if}
diff --git a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte
index d6d90aca8a..241ab6a4f2 100644
--- a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte
+++ b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte
@@ -1,5 +1,4 @@
@@ -169,41 +170,21 @@
{#if person}
{/if}
- {#if asset.type === AssetTypeEnum.Image && !isLocked}
-
- {/if}
- {#if !isLocked}
- {#if isOwner}
-
- {#if !asset.isArchived && !asset.isTrashed}
- goto(Route.photos({ at: stack?.primaryAssetId ?? asset.id }))}
- text={$t('view_in_timeline')}
- />
- {/if}
- {/if}
- {#if !asset.isArchived && !asset.isTrashed && smartSearchEnabled}
- goto(Route.search({ queryAssetId: stack?.primaryAssetId ?? asset.id }))}
- text={$t('view_similar_photos')}
- />
- {/if}
+
+
+ {#if isOwner && !isLocked}
+
{/if}
+
+
{#if !asset.isTrashed && isOwner}
{/if}
- {#if asset.type === AssetTypeEnum.Video}
- setPlayOriginalVideo(!playOriginalVideo)}
- text={playOriginalVideo ? $t('play_transcoded_video') : $t('play_original_video')}
- />
- {/if}
+
+
{#if isOwner}
diff --git a/web/src/lib/components/asset-viewer/actions/SetProfilePictureAction.svelte b/web/src/lib/components/asset-viewer/actions/SetProfilePictureAction.svelte
deleted file mode 100644
index d647e67bf8..0000000000
--- a/web/src/lib/components/asset-viewer/actions/SetProfilePictureAction.svelte
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- modalManager.show(ProfileImageCropperModal, { asset })}
- text={$t('set_as_profile_picture')}
-/>
diff --git a/web/src/lib/services/asset.service.spec.ts b/web/src/lib/services/asset.service.spec.ts
index 7c533997b1..68a3b0db09 100644
--- a/web/src/lib/services/asset.service.spec.ts
+++ b/web/src/lib/services/asset.service.spec.ts
@@ -31,6 +31,12 @@ vitest.mock('$lib/utils', async () => {
};
});
+vi.mock(import('$lib/managers/feature-flags-manager.svelte'), function () {
+ return {
+ featureFlagsManager: { init: vi.fn(), loadFeatureFlags: vi.fn(), value: {} } as never,
+ };
+});
+
describe('AssetService', () => {
describe('getAssetActions', () => {
beforeEach(() => {
diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts
index 3e629b413f..1288aa6100 100644
--- a/web/src/lib/services/asset.service.ts
+++ b/web/src/lib/services/asset.service.ts
@@ -11,8 +11,10 @@ import {
} from '@immich/sdk';
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
import {
+ mdiAccountCircleOutline,
mdiAlertOutline,
mdiCogRefreshOutline,
+ mdiCompare,
mdiContentCopy,
mdiDatabaseRefreshOutline,
mdiDownload,
@@ -22,6 +24,7 @@ import {
mdiHeart,
mdiHeartOutline,
mdiImageRefreshOutline,
+ mdiImageSearch,
mdiInformationOutline,
mdiMagnifyMinusOutline,
mdiMagnifyPlusOutline,
@@ -34,14 +37,18 @@ import {
mdiTune,
} from '@mdi/js';
import type { MessageFormatter } from 'svelte-i18n';
+import { goto } from '$app/navigation';
import { ProjectionType } from '$lib/constants';
import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte';
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { eventManager } from '$lib/managers/event-manager.svelte';
+import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import AssetAddToAlbumModal from '$lib/modals/AssetAddToAlbumModal.svelte';
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
+import ProfileImageCropperModal from '$lib/modals/ProfileImageCropperModal.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
+import { Route } from '$lib/route';
import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
import { getAssetMediaUrl, getSharedLink, sleep } from '$lib/utils';
import { downloadUrl } from '$lib/utils';
@@ -92,10 +99,11 @@ export const getAssetBulkActions = ($t: MessageFormatter) => {
return { AddToAlbum, RefreshFacesJob, RefreshMetadataJob, RegenerateThumbnailJob, TranscodeVideoJob };
};
-export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
+export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto & { stackPrimaryAssetId?: string }) => {
const sharedLink = getSharedLink();
const authUser = authManager.authenticated ? authManager.user : undefined;
const isOwner = !!(authUser && authUser.id === asset.ownerId);
+ const smartSearchEnabled = featureFlagsManager.value.smartSearch;
const Share: ActionItem = {
title: $t('share'),
@@ -242,6 +250,28 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
shortcuts: [{ key: 'e' }],
};
+ const SetProfilePicture: ActionItem = {
+ title: $t('set_as_profile_picture'),
+ icon: mdiAccountCircleOutline,
+ $if: () => asset.type === AssetTypeEnum.Image && asset.visibility !== AssetVisibility.Locked,
+ onAction: () => modalManager.show(ProfileImageCropperModal, { asset }),
+ };
+
+ const ViewInTimeline: ActionItem = {
+ title: $t('view_in_timeline'),
+ icon: mdiImageSearch,
+ $if: () => isOwner && asset.visibility !== AssetVisibility.Locked && !asset.isArchived && !asset.isTrashed,
+ onAction: () => goto(Route.photos({ at: asset.stackPrimaryAssetId ?? asset.id })),
+ };
+
+ const ViewSimilar: ActionItem = {
+ title: $t('view_similar_photos'),
+ icon: mdiCompare,
+ $if: () =>
+ asset.visibility !== AssetVisibility.Locked && !asset.isArchived && !asset.isTrashed && smartSearchEnabled,
+ onAction: () => goto(Route.search({ queryAssetId: asset.stackPrimaryAssetId ?? asset.id })),
+ };
+
const RefreshFacesJob: ActionItem = {
title: $t('refresh_faces'),
icon: mdiHeadSyncOutline,
@@ -286,6 +316,9 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
Tag,
TagPeople,
Edit,
+ SetProfilePicture,
+ ViewInTimeline,
+ ViewSimilar,
RefreshFacesJob,
RefreshMetadataJob,
RegenerateThumbnailJob,
From 0b1019c3447abfeb463f3fb92d58cb5c73f0302d Mon Sep 17 00:00:00 2001
From: "Weblate (bot)"
Date: Tue, 23 Jun 2026 17:50:30 +0200
Subject: [PATCH 025/435] chore(web): update translations (#29204)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Translate-URL: https://hosted.weblate.org/projects/immich/immich/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/bg/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/bn/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ca/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de_CH/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/en_GB/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/eo/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/et/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/eu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fil/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ga/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/gsw/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/it/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lt/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ne/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/tr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ur/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/vi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/yue_Hant/
Translation: Immich/immich
Co-authored-by: Aindriú Mac Giolla Eoin
Co-authored-by: AntonPalmqvist
Co-authored-by: Benjamin Kunz
Co-authored-by: Cohinem
Co-authored-by: Conrad Menz
Co-authored-by: Damian Krysta
Co-authored-by: DevServs
Co-authored-by: Edmundas
Co-authored-by: Enric Pagès i Gassull
Co-authored-by: Fjuro
Co-authored-by: Hồ Nhất Duy
Co-authored-by: Indrek Haav
Co-authored-by: Insoo Seok
Co-authored-by: Jayden Lo
Co-authored-by: Leo Bottaro
Co-authored-by: Luis Fernando Illapa
Co-authored-by: Manar Aldroubi
Co-authored-by: MarcSerraPeralta
Co-authored-by: Matjaž T.
Co-authored-by: Mees Frensel
Co-authored-by: Melih Ozkan
Co-authored-by: Mr.Biswas
Co-authored-by: Muxutruk <156070698+Muxutruk2@users.noreply.github.com>
Co-authored-by: Nagy Krisztián
Co-authored-by: Nicolas Ceballos
Co-authored-by: Para
Co-authored-by: Piero B.
Co-authored-by: PierreLapolla
Co-authored-by: Ronnel
Co-authored-by: Sakib Iqbal
Co-authored-by: Saugat Tripathi
Co-authored-by: Tim Morley
Co-authored-by: Umair Jibran
Co-authored-by: Unimpeded Lemur
Co-authored-by: User 123456789
Co-authored-by: Vitor Coelho
Co-authored-by: grgergo
Co-authored-by: muysup <79565421+MuySup@users.noreply.github.com>
Co-authored-by: Òscar Casajuana
---
i18n/ar.json | 39 +-
i18n/be.json | 1 -
i18n/bg.json | 2 +-
i18n/bn.json | 4 +
i18n/ca.json | 9 +-
i18n/cs.json | 2 +-
i18n/cv.json | 1 -
i18n/da.json | 1 -
i18n/de.json | 2 +-
i18n/de_CH.json | 1 +
i18n/el.json | 1 -
i18n/en_GB.json | 2 +-
i18n/eo.json | 101 +++-
i18n/es.json | 4 +-
i18n/et.json | 12 +-
i18n/eu.json | 1243 +++++++++++++++++++++++++++++++++++++++++++-
i18n/fa.json | 1 -
i18n/fi.json | 1 -
i18n/fil.json | 8 +
i18n/fr.json | 2 +-
i18n/ga.json | 6 +-
i18n/gl.json | 1 -
i18n/gsw.json | 6 +-
i18n/he.json | 1 -
i18n/hi.json | 1 -
i18n/hr.json | 1 -
i18n/hu.json | 4 +-
i18n/id.json | 1 -
i18n/it.json | 3 +-
i18n/ja.json | 1 -
i18n/kn.json | 1 -
i18n/ko.json | 15 +-
i18n/lt.json | 9 +-
i18n/lv.json | 1 -
i18n/ml.json | 1 -
i18n/mr.json | 1 -
i18n/nb_NO.json | 7 +-
i18n/ne.json | 18 +-
i18n/nl.json | 62 +--
i18n/pl.json | 6 +-
i18n/pt.json | 1 -
i18n/pt_BR.json | 7 +-
i18n/ro.json | 1 -
i18n/ru.json | 4 +-
i18n/sk.json | 1 -
i18n/sl.json | 2 +-
i18n/sr_Cyrl.json | 1 -
i18n/sr_Latn.json | 1 -
i18n/sv.json | 2 +-
i18n/ta.json | 1 -
i18n/te.json | 1 -
i18n/th.json | 1 -
i18n/tr.json | 64 ++-
i18n/uk.json | 1 -
i18n/ur.json | 5 +
i18n/vi.json | 847 +++++++++++++++++-------------
i18n/yue_Hant.json | 6 +
i18n/zh_Hans.json | 1 -
i18n/zh_Hant.json | 1 -
59 files changed, 2058 insertions(+), 473 deletions(-)
diff --git a/i18n/ar.json b/i18n/ar.json
index 0f9e98efc7..5743ba9ab8 100644
--- a/i18n/ar.json
+++ b/i18n/ar.json
@@ -1,9 +1,9 @@
{
"about": "حول",
- "account": "حساب",
+ "account": "الحساب",
"account_settings": "إعدادات الحساب",
"acknowledge": "أُدرك ذلك",
- "action": "إجراء",
+ "action": "الإجراء",
"action_common_update": "تحديث",
"action_description": "مجموعة إجراءات لتنفيذها على المحتويات المصفاة",
"actions": "عمليات",
@@ -189,13 +189,25 @@
"machine_learning_smart_search_enabled": "تفعيل البحث الذكي",
"machine_learning_smart_search_enabled_description": "إذا تم تعطيله، فلن يتم ترميز الصور للبحث الذكي.",
"machine_learning_url_description": "عنوان URL لخادم التعلم الآلي. إذا تم توفير أكثر من عنوان URL واحد، سيتم محاولة الاتصال بكل خادم على حدة حتى يستجيب أحدهم بنجاح، بدءًا من الأول إلى الأخير. سيتم تجاهل الخوادم التي لا تستجيب مؤقتًا حتى تعود للعمل.",
+ "maintenance_backup_management": "إدارة النسخ الاحتياطي",
"maintenance_delete_backup": "حذف النسخ الاحتياطي",
"maintenance_delete_backup_description": "هذا الملف سيتم حذفه بشكل لا رجعه فيه.",
"maintenance_delete_error": "فشل حذف النسخ الاحتياطي.",
+ "maintenance_integrity_check": "تحقق",
"maintenance_integrity_check_all": "تحديد الكل",
"maintenance_integrity_checksum_mismatch": "عدم تطابق رمز التحقق",
+ "maintenance_integrity_checksum_mismatch_description": "الملفات التي لا يتطابق المجموع التدقيقي لها على القرص مع المجموع التدقيقي المخزن في قاعدة بيانات Immich.",
+ "maintenance_integrity_checksum_mismatch_job": "التحقق من عدم تطابق المجموع التدقيقي",
+ "maintenance_integrity_checksum_mismatch_refresh_job": "تحديث تقارير عدم تطابق المجموع التدقيقي",
"maintenance_integrity_missing_file": "الملفات المفقودة",
+ "maintenance_integrity_missing_file_description": "الملفات التي يتتبعها Immich في قاعدة بياناته ولكنها غير موجودة في نظام الملفات.",
"maintenance_integrity_missing_file_job": "التحقق من الملفات المفقودة",
+ "maintenance_integrity_missing_file_refresh_job": "تحديث تقارير الملفات المفقودة",
+ "maintenance_integrity_report": "تقرير السلامة",
+ "maintenance_integrity_untracked_file": "الملفات غير المتتبعة",
+ "maintenance_integrity_untracked_file_description": "الملفات الموجودة في مجلدات Immich بدون وجود سجلات لها.",
+ "maintenance_integrity_untracked_file_job": "التحقق من الملفات غير المتتبعة",
+ "maintenance_integrity_untracked_file_refresh_job": "تحديث تقارير الملفات غير المتتبعة",
"maintenance_restore_backup": "استعادة النسخ الاحتياطي",
"maintenance_restore_backup_description": "سيتم مسح بيانات Immich واستعادتها من النسخة الاحتياطي المختار. سيتم إنشاء نسخة احتياطية قبل المتابعة.",
"maintenance_restore_backup_different_version": "هذا النسخ الاحتياطي تم انشائه باستخدام اصدار مختلف من Immich!",
@@ -575,6 +587,7 @@
"asset_added_to_album": "تمت إضافته إلى الألبوم",
"asset_adding_to_album": "جارٍ الإضافة إلى الألبوم…",
"asset_created": "انشئ اصل",
+ "asset_day_count": "{date}: {count, plural, zero {لا توجد ملفات} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفًا} other {# ملف}}",
"asset_description_updated": "تم تحديث وصف المحتوى",
"asset_filename_is_offline": "الأصل {filename} غير متصل",
"asset_has_unassigned_faces": "يحتوي الأصل على وجوه غير مخصصة",
@@ -704,6 +717,7 @@
"backup_settings_subtitle": "إدارة إعدادات التحميل",
"backup_upload_details_page_more_details": "اضغط لتفاصيل اضافية",
"backward": "الى الوراء",
+ "battery_optimization_backup_reliability": "إيقاف تحسين البطارية يزيد من استقرار النسخ الاحتياطي في الخلفية",
"biometric_auth_enabled": "المصادقة البايومترية مفعله",
"biometric_locked_out": "لقد قفلت عنك المصادقة البيومترية",
"biometric_no_options": "لا توجد خيارات بايومترية متوفرة",
@@ -918,6 +932,8 @@
"deduplicate_all": "إلغاء تكرار الكل",
"default_locale": "الإعدادات المحلية الافتراضية",
"default_locale_description": "تنسيق التواريخ والأرقام بناءً على الإعدادات المحلية للمتصفح",
+ "default_quality_subtitle": "الجودة المستخدمة عند الضغط على \"مشاركة\". اضغط مطولاً على زر المشاركة لاختيار الجودة في كل مرة.",
+ "default_share_quality": "جودة المشاركة الافتراضية",
"delete": "حذف",
"delete_action_confirmation_message": "هل انت متأكد من حذف هذا الملف؟ هذا سؤدي الى نقل الملف الى سلة مهملات الخادم وسيتم اشعارك ان كنت تريد حذفه على الجهاز",
"delete_action_prompt": "تم حذف {count}",
@@ -1227,6 +1243,7 @@
"failed": "فشل",
"failed_count": "فشل: {count}",
"failed_to_authenticate": "فشل في المصادقة",
+ "failed_to_delete_file": "فشل حذف الملف",
"failed_to_load_assets": "فشل تحميل الأصول",
"failed_to_load_folder": "فشل تحميل المجلد",
"favorite": "مفضل",
@@ -1357,6 +1374,7 @@
"individual_share": "حصة فردية",
"individual_shares": "المشاركات الفردية",
"info": "معلومات",
+ "integrity_checks": "فحوصات السلامة",
"interval": {
"day_at_onepm": "كل يوم الساعة الواحدة ظهرا",
"hours": "كل {hours, plural, one {ساعة} other {{hours, number} ساعة}}",
@@ -1404,6 +1422,7 @@
"leave": "مغادرة",
"leave_album": "اترك الالبوم",
"lens_model": "نموذج العدسات",
+ "less": "أقل",
"let_others_respond": "دع الآخرين يستجيبون",
"level": "المستوى",
"library": "مكتبة",
@@ -1428,6 +1447,7 @@
"linked_oauth_account": "حساب مرتبط بـ OAuth",
"list": "قائمة",
"live": "حي",
+ "load_more": "تحميل المزيد",
"loading": "تحميل",
"loading_search_results_failed": "فشل تحميل نتائج البحث",
"local": "محلّي",
@@ -1528,7 +1548,6 @@
"map_location_picker_page_use_location": "استخدم هذا الموقع",
"map_location_service_disabled_content": "يجب تمكين خدمة الموقع لعرض الأصول من موقعك الحالي.هل تريد تمكينه الآن؟",
"map_location_service_disabled_title": "خدمة الموقع معطل",
- "map_marker_for_images": "علامة الخريطة للصور الملتقطة في {city}، {country}",
"map_marker_with_image": "علامة الخريطة مع الصورة",
"map_no_location_permission_content": "هناك حاجة إلى إذن الموقع لعرض الأصول من موقعك الحالي.هل تريد السماح به الآن؟",
"map_no_location_permission_title": "تم رفض إذن الموقع",
@@ -1597,6 +1616,8 @@
"merge_people_prompt": "هل تريد دمج هؤلاء الناس؟ هذا الإجراء لا رجعة فيه.",
"merge_people_successfully": "تم دمج الأشخاص بنجاح",
"merged_people_count": "دمج {count, plural, one {شخص واحد} other {# أشخاص}}",
+ "minFaces": "الحد الأدنى للوجوه",
+ "minFaces_description": "الحد الأدنى لعدد الوجوه المتعرف عليها لكي يتم عرض الشخص",
"minimize": "تصغير",
"minute": "دقيقة",
"minutes": "دقائق",
@@ -1692,6 +1713,7 @@
"not_selected": "لم يختار",
"notes": "ملاحظات",
"nothing_here_yet": "لا يوجد شيء هنا بعد",
+ "notification_backup_reliability": "فعل الإشعارات للزيادة من استقرار النسخ الاحتياطي في الخلفية",
"notification_permission_dialog_content": "لتمكين الإخطارات ، انتقل إلى الإعدادات و اختار السماح.",
"notification_permission_list_tile_content": "منح إذن لتمكين الإخطارات.",
"notification_permission_list_tile_enable_button": "تمكين الإخطارات",
@@ -2083,6 +2105,7 @@
"select_person": "اختر شخص",
"select_person_to_tag": "اختر شخص لوضع علامة",
"select_photos": "تحديد الصور",
+ "select_quality": "تحديد الدقة",
"select_trash_all": "تحديد حذف الكلِ",
"select_user_for_sharing_page_err_album": "فشل في إنشاء ألبوم",
"selected": "التحديد",
@@ -2146,6 +2169,8 @@
"share_assets_selected": "اختيار {count}",
"share_dialog_preparing": "تحضير...",
"share_link": "مشاركة رابط",
+ "share_original": "استخدام الملف الأصلي",
+ "share_preview": "استخدام الصورة المصغرة",
"shared": "مُشتَرك",
"shared_album_activities_input_disable": "التعليق معطل",
"shared_album_activity_remove_content": "هل تريد حذف هذا النشاط؟",
@@ -2247,6 +2272,7 @@
"slideshow_repeat_description": "العودة إلى البداية عند انتهاء عرض الشرائح",
"slideshow_settings": "إعدادات عرض الشرائح",
"smart_album": "ألبوم ذكي",
+ "some_assets_already_have_a_location_warning": "بعض الملفات المحددة تحتوي بالفعل على موقع جغرافي",
"sort_albums_by": "رتب الألبومات حسب...",
"sort_created": "تاريخ الإنشاء",
"sort_items": "عدد العناصر",
@@ -2367,11 +2393,13 @@
"trash_page_title": "سلة المهملات ({count})",
"trashed_items_will_be_permanently_deleted_after": "سيتم حذفُ العناصر المحذوفة نِهائيًا بعد {days, plural, one {# يوم} other {# أيام }}.",
"trigger": "مفعِل",
+ "trigger_asset_metadata_extraction": "استخراج البيانات الوصفية للملفات",
+ "trigger_asset_metadata_extraction_description": "يتم تفعيله عند استخراج البيانات الوصفية (EXIF) للملف",
"trigger_asset_uploaded": "رفع الاصل",
"trigger_asset_uploaded_description": "يتم تفعيله عند تحميل أصل جديد",
"trigger_description": "حدث يبدأ سير العمل",
"trigger_person_recognized": "تم التعرف على شخص",
- "trigger_person_recognized_description": "يتم تفعيله عند اكتشاف شخص",
+ "trigger_person_recognized_description": "يتم تفعيله عند التعرف على شخص",
"trigger_type": "نوع المفعل",
"troubleshoot": "استكشاف المشاكل",
"type": "النوع",
@@ -2413,6 +2441,7 @@
"updated_password": "تم تحديث كلمة المرور",
"upload": "رفع",
"upload_concurrency": "الرفع المتزامن",
+ "upload_day_count": "{date}: {count, plural, one {# رفع الملف} other {# رفع الملفات}}",
"upload_details": "تفاصيل الرفع",
"upload_dialog_info": "هل تريد النسخ الاحتياطي للأصول (الأصول) المحددة إلى الخادم؟",
"upload_dialog_title": "تحميل الأصول",
@@ -2428,6 +2457,8 @@
"upload_to_immich": "الرفع الىImmich ({count})",
"uploading": "جاري الرفع",
"uploading_media": "رفع الوسائط",
+ "uploads": "عمليات الرفع",
+ "uploads_count": "{count, plural, one {# رفع الملف} other {# رفع الملفات}}",
"url": "عنوان URL",
"usage": "الاستخدام",
"use_biometric": "استخدم البايومتري",
diff --git a/i18n/be.json b/i18n/be.json
index cf3993483f..024c4ae91c 100644
--- a/i18n/be.json
+++ b/i18n/be.json
@@ -1520,7 +1520,6 @@
"map_location_picker_page_use_location": "Выкарыстаць гэта месцазнаходжанне",
"map_location_service_disabled_content": "Каб паказваць аб’екты з вашага бягучага месцазнаходжання, трэба ўключыць службу геалакацыі. Жадаеце ўключыць яе зараз?",
"map_location_service_disabled_title": "Служба геалакацыі адключана",
- "map_marker_for_images": "Маркер на карце для відарысаў, зробленых у {city}, {country}",
"map_marker_with_image": "Маркер на карце з відарысам",
"map_no_location_permission_content": "Каб паказваць аб’екты з вашага бягучага месцазнаходжання, патрэбен дазвол на геалакацыю. Дазволіць зараз?",
"map_no_location_permission_title": "Адмоўлена ў дазволе на геалакацыю",
diff --git a/i18n/bg.json b/i18n/bg.json
index 840331d693..48f3497783 100644
--- a/i18n/bg.json
+++ b/i18n/bg.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Използвай това местоположение",
"map_location_service_disabled_content": "За да се показват обектите от текущото място, трябва да бъде включена услугата за местоположение. Искате ли да я включите сега?",
"map_location_service_disabled_title": "Услугата за местоположение е изключена",
- "map_marker_for_images": "Маркери на картата за снимки направени в {city}, {country}",
+ "map_marker_for_image": "Маркер на картата за снимка, направена в {city}, {country}",
"map_marker_with_image": "Маркер на картата с изображение",
"map_no_location_permission_content": "За да се показват обектите от текущото място, трябва разрешение за определяне на местоположението. Искате ли да предоставите разрешение сега?",
"map_no_location_permission_title": "Отказан достъп до местоположение",
diff --git a/i18n/bn.json b/i18n/bn.json
index ea70f9ad3e..a6b0b09fa1 100644
--- a/i18n/bn.json
+++ b/i18n/bn.json
@@ -27,6 +27,7 @@
"add_partner": "অংশীদার যোগ করুন",
"add_path": "পাথ যুক্ত করুন",
"add_photos": "ছবি যুক্ত করুন",
+ "add_step": "ধাপ যোগ করুন",
"add_tag": "ট্যাগ যুক্ত করুন",
"add_to": "যুক্ত করুন…",
"add_to_album": "এলবাম এ যোগ করুন",
@@ -78,6 +79,7 @@
"cron_expression_description": "Cron ফরম্যাট ব্যবহার করে স্ক্যানিং ইন্টারভ্যাল নির্ধারণ করুন। আরও তথ্যের জন্য দয়া করে Crontab Guru দেখুন",
"cron_expression_presets": "Cron এক্সপ্রেশন প্রিসেট",
"disable_login": "লগইন অক্ষম করুন",
+ "download_csv": "CSV ডাউনলোড করুন",
"duplicate_detection_job_description": "সদৃশ ছবি শনাক্ত করতে অ্যাসেটগুলোর উপর মেশিন লার্নিং চালান। এটি Smart Search-এর উপর নির্ভর করে",
"exclusion_pattern_description": "এক্সক্লুশন প্যাটার্ন ব্যবহার করে লাইব্রেরি স্ক্যান করার সময় নির্দিষ্ট ফাইল ও ফোল্ডার উপেক্ষা করা যায়। এটি তখনই উপকারী যখন কিছু ফোল্ডারে এমন ফাইল থাকে যা আপনি ইমপোর্ট করতে চান না, যেমন RAW ফাইল।",
"export_config_as_json_description": "বর্তমান সিস্টেম কনফিগারেশনটিকে একটি JSON ফাইল হিসেবে ডাউনলোড করুন",
@@ -187,9 +189,11 @@
"machine_learning_smart_search_enabled": "স্মার্ট সার্চ সক্ষম করুন",
"machine_learning_smart_search_enabled_description": "নিষ্ক্রিয় থাকলে, স্মার্ট সার্চের জন্য ছবিগুলো এনকোড (encode) করা হবে না।",
"machine_learning_url_description": "মেশিন লার্নিং সার্ভারের URL। যদি একের বেশি URL প্রদান করা হয়, তবে একটি সফলভাবে সাড়া না দেওয়া পর্যন্ত প্রতিটি সার্ভারে এক এক করে চেষ্টা করা হবে (প্রথম থেকে শেষ ক্রমানুসারে)। যে সার্ভারগুলো সাড়া দেবে না, সেগুলো পুনরায় সচল হওয়া পর্যন্ত সাময়িকভাবে উপেক্ষা করা হবে।",
+ "maintenance_backup_management": "ব্যাকআপ ব্যবস্থাপনা",
"maintenance_delete_backup": "ব্যাকআপ (Backup)মুছুন",
"maintenance_delete_backup_description": "এই ফাইলটি চিরতরে মুছে ফেলা হবে।",
"maintenance_delete_error": "ব্যাকআপ মুছে ফেলতে ব্যর্থ হয়েছে।",
+ "maintenance_integrity_check": "যাচাই",
"maintenance_restore_backup": "ব্যাকআপ পুনরুদ্ধার(Restore) করুন",
"maintenance_restore_backup_description": "Immich মুছে ফেলা হবে এবং নির্বাচিত ব্যাকআপ থেকে পুনরুদ্ধার করা হবে। কার্যক্রম চালিয়ে যাওয়ার আগে একটি ব্যাকআপ তৈরি করা হবে।",
"maintenance_restore_backup_different_version": "এই ব্যাকআপটি Immich-এর একটি ভিন্ন সংস্করণের মাধ্যমে তৈরি করা হয়েছিল!",
diff --git a/i18n/ca.json b/i18n/ca.json
index 3c3a312fbf..01a8227b94 100644
--- a/i18n/ca.json
+++ b/i18n/ca.json
@@ -189,18 +189,23 @@
"machine_learning_smart_search_enabled": "Activa la cerca intel·ligent",
"machine_learning_smart_search_enabled_description": "Si està desactivada, les imatges no es codificaran per la cerca intel·ligent.",
"machine_learning_url_description": "L'URL del servidor d'aprenentatge automàtic. Si es proporciona més d'un URL, s'intentarà accedir a cada servidor en ordre fins que un d'ells respongui correctament.",
+ "maintenance_backup_management": "Gestió de còpies de seguretat",
"maintenance_delete_backup": "Elimina la còpia de seguretat",
"maintenance_delete_backup_description": "Aquest fitxer s'eliminarà de forma permanent.",
"maintenance_delete_error": "No s'ha pogut suprimir la còpia de seguretat.",
+ "maintenance_integrity_check": "Verificació",
"maintenance_integrity_check_all": "Verificar tot",
"maintenance_integrity_checksum_mismatch": "Checksum incorrecte",
+ "maintenance_integrity_checksum_mismatch_description": "Fitxers els quals la suma de verificació al disc no coincideix amb la que Immich té emmagatzemada a la base de dades.",
"maintenance_integrity_checksum_mismatch_job": "Comprovar checksums",
"maintenance_integrity_checksum_mismatch_refresh_job": "Actualitzar errors de checksums",
"maintenance_integrity_missing_file": "Manquen fitxers",
+ "maintenance_integrity_missing_file_description": "Fitxers que l'Immich té registrats a la seva base de dades però que no existeixen al sistema de fitxers.",
"maintenance_integrity_missing_file_job": "Verificar fitxers que falten",
"maintenance_integrity_missing_file_refresh_job": "Refrescar informe de fitxers desapareguts",
"maintenance_integrity_report": "Informe Integritat",
"maintenance_integrity_untracked_file": "Arxius no rastrejats",
+ "maintenance_integrity_untracked_file_description": "Fitxers presents als directoris d'Immich que Immich no en té cap registre.",
"maintenance_integrity_untracked_file_job": "Consulta de fitxers no rastrejats",
"maintenance_integrity_untracked_file_refresh_job": "Actualitza els informes de fitxers no rastrejats",
"maintenance_restore_backup": "Restaura la còpia de seguretat",
@@ -483,7 +488,7 @@
"advanced_settings_prefer_remote_title": "Prefereix imatges remotes",
"advanced_settings_proxy_headers_subtitle": "Definiu les capçaleres de proxy que Immich per enviar amb cada sol·licitud de xarxa",
"advanced_settings_proxy_headers_title": "Capçaleres de proxy particulars [EXPERIMENTAL]",
- "advanced_settings_readonly_mode_subtitle": "Habilita el només de lectura mode on les fotos poden ser només vist, a coses els agrada seleccionant imatges múltiples, compartint, càsting, elimina és tot discapacitat. Habilita/Desactiva només de lectura via avatar d'usuari des de la pantalla major",
+ "advanced_settings_readonly_mode_subtitle": "Activa el mode de només lectura, en què les fotos només es poden veure. Accions com seleccionar múltiples imatges, compartir, enviar a un dispositiu o eliminar queden desactivades. Activa o desactiva el mode de només lectura des de l’avatar d’usuari de la pantalla principal",
"advanced_settings_readonly_mode_title": "Mode de només lectura",
"advanced_settings_self_signed_ssl_subtitle": "Omet la verificació del certificat SSL del servidor. Requerit per a certificats autosignats.",
"advanced_settings_self_signed_ssl_title": "Permet certificats SSL autosignats [EXPERIMENTAL]",
@@ -1543,7 +1548,7 @@
"map_location_picker_page_use_location": "Utilitzar aquesta ubicació",
"map_location_service_disabled_content": "El servei de localització s'ha d'activar per mostrar els elements de la teva ubicació actual. Vols activar-lo ara?",
"map_location_service_disabled_title": "Servei de localització desactivat",
- "map_marker_for_images": "Marcador de mapa per a imatges fetes a {city}, {country}",
+ "map_marker_for_image": "Marcador de mapa per a imatge obtinguda a {city}, {country}",
"map_marker_with_image": "Marcador de mapa amb imatge",
"map_no_location_permission_content": "Es necessita el permís de localització per mostrar els elements de la teva ubicació actual. Vols permetre-ho ara?",
"map_no_location_permission_title": "Permís de localització denegat",
diff --git a/i18n/cs.json b/i18n/cs.json
index cf2be80fc6..022614599b 100644
--- a/i18n/cs.json
+++ b/i18n/cs.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Použít tuto polohu",
"map_location_service_disabled_content": "Pro zobrazení fotek z vaší aktuální polohy musí být povolena služba určování polohy. Chcete ji nyní povolit?",
"map_location_service_disabled_title": "Služba určování polohy je zakázána",
- "map_marker_for_images": "Značka na mapě pro snímky pořízené v {city}, {country}",
+ "map_marker_for_image": "Značka na mapě pro obrázek pořízený ve městě {city}, {country}",
"map_marker_with_image": "Značka mapy s obrázkem",
"map_no_location_permission_content": "Oprávnění polohy je nutné pro zobrazení fotek z vaší aktuální polohy. Chcete oprávnění nyní povolit?",
"map_no_location_permission_title": "Oprávnění polohy zamítnuto",
diff --git a/i18n/cv.json b/i18n/cv.json
index 52008a176f..6ceb8fb0c9 100644
--- a/i18n/cv.json
+++ b/i18n/cv.json
@@ -70,7 +70,6 @@
"feature_photo_updated": "Уйрӑм сӑнӳкерчӗк ҫӗнетнӗ",
"manage_sharing_with_partners": "Партнерсемпе пайланассине йӗркелесе пырӑр",
"map": "Карттӑ",
- "map_marker_for_images": "{city}, {country} ҫинче ӳкернӗ ӳкерчӗксем валли карттӑ маркерӗ",
"map_marker_with_image": "Карттӑ маркерӗ ӳкерчӗкпе",
"map_settings": "Карттӑ ĕнерленĕвĕ",
"no_explore_results_message": "Хӑвӑр коллекципе киленмешкӗн сӑнӳкерчӗксем ытларах тийӗр.",
diff --git a/i18n/da.json b/i18n/da.json
index 534d7761d9..e852945143 100644
--- a/i18n/da.json
+++ b/i18n/da.json
@@ -1526,7 +1526,6 @@
"map_location_picker_page_use_location": "Brug denne placering",
"map_location_service_disabled_content": "Placeringstjenesten skal aktiveres for at vise elementer fra din nuværende placering. Vil du aktivere den nu?",
"map_location_service_disabled_title": "Placeringstjenesten er deaktiveret",
- "map_marker_for_images": "Kortmarkør for billeder taget i {city}, {country}",
"map_marker_with_image": "Kortmarkør med billede",
"map_no_location_permission_content": "Der kræves tilladelse til placeringen for at vise elementer fra din nuværende placering. Vil du give tilladelse?",
"map_no_location_permission_title": "Placeringstilladelse blev afvist",
diff --git a/i18n/de.json b/i18n/de.json
index 319a60af0c..38b9f710c1 100644
--- a/i18n/de.json
+++ b/i18n/de.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Diesen Standort verwenden",
"map_location_service_disabled_content": "Ortungsdienste müssen aktiviert sein, um Inhalte am aktuellen Standort anzuzeigen. Willst du die Ortungsdienste jetzt aktivieren?",
"map_location_service_disabled_title": "Ortungsdienste deaktiviert",
- "map_marker_for_images": "Kartenmarkierung für Bilder, die in {city}, {country} aufgenommen wurden",
+ "map_marker_for_image": "Kartenmarkierung für in {city}, {country} aufgenommenes Bild",
"map_marker_with_image": "Kartenmarkierung mit Bild",
"map_no_location_permission_content": "Ortungsdienste müssen aktiviert sein, um Inhalte am aktuellen Standort anzuzeigen. Willst du die Ortungsdienste jetzt aktivieren?",
"map_no_location_permission_title": "Kein Zugriff auf den Standort",
diff --git a/i18n/de_CH.json b/i18n/de_CH.json
index c463b5fe36..3d70d64caa 100644
--- a/i18n/de_CH.json
+++ b/i18n/de_CH.json
@@ -79,6 +79,7 @@
"cron_expression_description": "Setze das Scanintervall im Cron-Format. Für mehr Informationen, siehe z. B. Crontab Guru",
"cron_expression_presets": "Vorlagen für Cron-Ausdrücke",
"disable_login": "Login deaktivierä",
+ "download_csv": "CSV herunterladen",
"duplicate_detection_job_description": "Verwendet maschinelles Lernen auf den Dateien, um Duplikate zu finden. Baut auf der intelligenten Suche auf",
"exclusion_pattern_description": "Mit Ausschlussmustern können Dateien und Ordner beim Scannen deiner Bibliothek ignoriert werden. Dies ist nützlich, wenn du Ordner hast, die Dateien enthalten, die du nicht importieren möchtest, wie z. B. RAW-Dateien.",
"export_config_as_json_description": "Aktuelle Systemkonfiguration als JSON-Datei herunterladen",
diff --git a/i18n/el.json b/i18n/el.json
index b810bfccec..d08ce395ff 100644
--- a/i18n/el.json
+++ b/i18n/el.json
@@ -1495,7 +1495,6 @@
"map_location_picker_page_use_location": "Χρησιμοποιήστε αυτήν την τοποθεσία",
"map_location_service_disabled_content": "Η υπηρεσία τοποθεσίας πρέπει να είναι ενεργοποιημένη για την εμφάνιση στοιχείων από την τρέχουσα τοποθεσία σας. Θέλετε να το ενεργοποιήσετε τώρα;",
"map_location_service_disabled_title": "Η υπηρεσία τοποθεσίας απενεργοποιήθηκε",
- "map_marker_for_images": "Δείκτης χάρτη για εικόνες που τραβήχτηκαν σε {city}, {country}",
"map_marker_with_image": "Χάρτης δείκτη με εικόνα",
"map_no_location_permission_content": "Απαιτείται άδεια τοποθεσίας για την εμφάνιση στοιχείων από την τρέχουσα τοποθεσία σας. Θέλετε να το επιτρέψετε τώρα;",
"map_no_location_permission_title": "Η άδεια τοποθεσίας απορρίφθηκε",
diff --git a/i18n/en_GB.json b/i18n/en_GB.json
index 5129a334ef..899db6395a 100644
--- a/i18n/en_GB.json
+++ b/i18n/en_GB.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Use this location",
"map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?",
"map_location_service_disabled_title": "Location Service disabled",
- "map_marker_for_images": "Map marker for images taken in {city}, {country}",
+ "map_marker_for_image": "Map marker for image taken in {city}, {country}",
"map_marker_with_image": "Map marker with image",
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
"map_no_location_permission_title": "Location Permission denied",
diff --git a/i18n/eo.json b/i18n/eo.json
index 0af54cd172..5cb8ee952e 100644
--- a/i18n/eo.json
+++ b/i18n/eo.json
@@ -199,6 +199,15 @@
"maintenance_integrity_checksum_mismatch_description": "Dosieroj pri kiuj la kontrolsumo stokita sur disko ne kongruas kun tiu en la datumbazo de Immich.",
"maintenance_integrity_checksum_mismatch_job": "Kontroli pri nekongruaj kontrolsumoj",
"maintenance_integrity_checksum_mismatch_refresh_job": "Refreŝigi la raporton pri nekongruaj kontrolsumoj",
+ "maintenance_integrity_missing_file": "Dosieroj mankantaj",
+ "maintenance_integrity_missing_file_description": "Dosieroj menciitaj en la datumbazo de Immich, sed kiuj ne (plu) ekzistas en la dosiersistemo.",
+ "maintenance_integrity_missing_file_job": "Detekti mankantajn dosierojn",
+ "maintenance_integrity_missing_file_refresh_job": "Refreŝigi raporton pri mankantaj dosieroj",
+ "maintenance_integrity_report": "Raporto pri integreco",
+ "maintenance_integrity_untracked_file": "Senspuraj dosieroj",
+ "maintenance_integrity_untracked_file_description": "Dosieroj en la dosierujoj de Immich, sed pri kiuj Immich havas neniun spuron.",
+ "maintenance_integrity_untracked_file_job": "Detekti senspurajn dosierojn",
+ "maintenance_integrity_untracked_file_refresh_job": "Refreŝigi raporton pri senspuraj dosieroj",
"maintenance_restore_backup": "Restaŭri savkopion",
"maintenance_restore_backup_description": "Immich estos forigita kaj reinstalita de la elektita savkopio. Nova savkopio estos kreita antaŭe.",
"maintenance_restore_backup_different_version": "Tiu ĉi savkopio estis kreita per alia versio de Immich!",
@@ -740,7 +749,7 @@
"cache_settings_title": "Agordoj pri kaŝmemoro",
"camera": "Fotilo",
"camera_brand": "Fabrikanto de fotilo",
- "camera_model": "Modelo de fotilo",
+ "camera_model": "Tipo de fotilo",
"cancel": "Nuligi",
"cancel_search": "Nuligi serĉon",
"canceled": "Nuligita",
@@ -1454,6 +1463,7 @@
"log_out_all_devices": "Elsalutigi ĉiujn aparatojn",
"logged_in_as": "Ensalutita kiel {user}",
"logged_out_all_devices": "Ĉiuj aparatoj elsalutigitaj",
+ "logged_out_device": "Elsalutigita aparato",
"login": "Ensaluti",
"login_disabled": "Ensalutado malebligita",
"login_form_api_exception": "Eraro de API. Bonvolu kontroli la URL-on de la servilo, kaj reprovi.",
@@ -1529,7 +1539,6 @@
"map_location_picker_page_use_location": "Uzi tiun ĉi lokon",
"map_location_service_disabled_content": "Vi devas ŝalti la lokadan servon de via aparato por vidi elementojn de via aktuala loko. Ĉu vi volas nun ŝalti tion?",
"map_location_service_disabled_title": "Servo de lokado malŝaltita",
- "map_marker_for_images": "Map-markilo por fotoj faritaj en {city}, {country}",
"map_marker_with_image": "Map-markilo kun bildo",
"map_no_location_permission_content": "Vi devas permesi al la apo detekti vian aktualan lokon por vidi tieajn elementojn. Ĉu vi volas nun permesi tion?",
"map_no_location_permission_title": "Detektado de loko ne permesita",
@@ -1638,6 +1647,9 @@
"navigate_to_time": "Navigi al dato/horo",
"network_requirement_photos_upload": "Uzi datumojn de poŝtelefona reto por savkopii fotojn",
"network_requirement_videos_upload": "Uzi datumojn de poŝtelefona reto por savkopii videojn",
+ "network_requirements": "Retaj postuloj",
+ "network_requirements_updated": "Retaj postuloj ŝanĝiĝis, savkopia vico restarigita",
+ "networking_settings": "Retkonektoj",
"networking_subtitle": "Administri agordojn pri finpunktoj de la servilo",
"never": "Neniam",
"new_album": "Nova albumo",
@@ -1888,6 +1900,13 @@
"readonly_mode_disabled": "Nurlega reĝimo malŝaltita",
"readonly_mode_enabled": "Nurlega reĝimo ŝaltita",
"ready_for_upload": "Preta por alŝuto",
+ "reassign": "Reatribui",
+ "reassigned_assets_to_existing_person": "Reatribuis {count, plural, one {# elementon} other {# elementojn}} al {name, select, null {ekzistanta homo} other {{name}}}",
+ "reassigned_assets_to_new_person": "Reatribuis {count, plural, one {# elementon} other {# elementojn}} al nova homo",
+ "reassing_hint": "Reatribuis elektitajn elementojn al ekzistanta homo",
+ "recent": "Lastatempa(j)",
+ "recent_albums": "Lastatempaj albumoj",
+ "recent_searches": "Lastatempaj serĉoj",
"recently_added": "Lastatempe aldonita(j)",
"recently_added_page_title": "Lastatempe aldonita(j)",
"recently_taken": "Lastatempe fotita(j)",
@@ -1911,21 +1930,73 @@
"remove_assets_shared_link_confirmation": "Ĉu vi certas, ke vi volas forigi {count, plural, one {# elementon} other {# elementojn}} de tiu dividita ligilo?",
"remove_assets_title": "Ĉu forigi elementojn?",
"remove_custom_date_range": "Forigi la dat-intervalon",
+ "remove_filter": "Forigi filtron",
+ "remove_from_album": "Forpreni de albumo",
+ "remove_from_album_action_prompt": "{count} forprenitaj de la albumo",
"remove_from_favorites": "Forigi el preferataĵoj",
+ "remove_from_lock_folder_action_prompt": "{count} forprenitaj de la ŝlosita dosierujo",
+ "remove_from_locked_folder": "Forpreni de la ŝlosita dosierujo",
+ "remove_from_locked_folder_confirmation": "Ĉu vi certas, ke vi volas forpreni tiujn fotojn/videojn el la ŝlosita dosierujo? Ili poste estos videblaj en via biblioteko.",
"remove_from_shared_link": "Forigi el dividita ligilo",
+ "remove_memory": "Forigi memoraĵon",
+ "remove_photo_from_memory": "Forpreni foton el tiu memoraĵo",
+ "remove_tag": "Forigi etikedon",
+ "remove_url": "Forigi URL-on",
+ "remove_user": "Forigi uzanton",
+ "removed_api_key": "Forigita API-ŝlosilo: {name}",
+ "removed_from_archive": "Forigita de la arĥivo",
"removed_from_favorites": "Forigita(j) el preferataĵoj",
"removed_from_favorites_count": "{count, plural, other {Forigis #}} el Preferataĵoj",
+ "removed_memory": "Memoraĵo forigita",
+ "removed_photo_from_memory": "Forprenis foton de la memoraĵo",
+ "removed_tagged_assets": "Forigis etikedon de {count, plural, one {# elemento} other {# elementoj}}",
+ "rename": "Renomi",
+ "repair": "Ripari",
+ "repair_no_results_message": "Senspuraj kaj mankantaj dosieroj aperas ĉi tie",
+ "replace_with_upload": "Anstataŭigi per alŝutaĵo",
+ "repository": "Deponejo",
+ "require_password": "Postuli pasvorton",
+ "require_user_to_change_password_on_first_login": "Devigi al uzanto ŝanĝi pasvorton je unua ensaluto",
"rescan": "Reanalizi",
"reset": "Restartigi",
+ "reset_password": "Restarigi pasvorton",
+ "reset_people_visibility": "Restarigi videblecon de homoj",
+ "reset_pin_code": "Restarigi PIN-kodon",
+ "reset_pin_code_description": "Se vi forgesis vian PIN-kodon, vi povas kontakti la administranto de via servilo por restarigi ĝin",
+ "reset_pin_code_success": "Sukcese restarigis PIN-kodon",
+ "reset_pin_code_with_password": "Vi povas restarigi vian PIN-kodon pere de via pasvorto",
+ "reset_sqlite": "Restarigi la SQLite-datumbazon",
"reset_sqlite_clear_app_data": "Forviŝi datumojn",
"reset_sqlite_confirmation": "Ĉu vi certas, ke vi volas forviŝi la datumojn de la apo? Tio forigos ĉiujn agordojn kaj elsalutigos vin.",
"reset_sqlite_confirmation_note": "Noto: vi devos relanĉi la apon por la forviŝo.",
"reset_sqlite_done": "Datumoj de la apo estas forviŝitaj. Bonvolu relanĉi Immich kaj ensalutu denove.",
+ "reset_sqlite_success": "Sukcese restarigis la SQLite-datumbazon",
+ "reset_to_default": "Restarigi la defaŭltojn",
+ "resolution": "Distingivo",
+ "resolve_duplicates": "Solvi duoblaĵojn",
+ "resolved_all_duplicates": "Solvis ĉiujn duoblaĵojn",
"restore": "Restaŭri",
"restore_all": "Restaŭri ĉiujn",
"restore_trash_action_prompt": "{count} restaŭrita(j) el rubujo",
"restore_user": "Restaŭri uzanton",
"restored_asset": "Restaŭri elementon",
+ "resume": "Daŭrigi",
+ "resume_paused_jobs": "Daŭrigi {count, plural, one {# paŭzitan taskon} other {# paŭzitajn taskojn}}",
+ "retry_upload": "Reprovi alŝuton",
+ "review_duplicates": "Kontroli duoblaĵojn",
+ "review_large_files": "Kontroli grandajn dosierojn",
+ "role": "Rolo",
+ "role_editor": "Redaktanto",
+ "role_viewer": "Spektanto",
+ "running": "Aktuale plenumata(j)",
+ "save": "Konservi",
+ "save_to_gallery": "Konservi en galerio",
+ "saved": "Konservita(j)",
+ "saved_api_key": "Konservis API-ŝlosilon",
+ "saved_profile": "Konservis profilon",
+ "saved_settings": "Konservis agordojn",
+ "say_something": "Skribu ion",
+ "scaffold_body_error_occurred": "Eraro okazis",
"scaffold_body_error_unrecoverable": "Neriparebla eraro okazis. Bonvolu sendi al ni la eraron kaj la stakspuron per Discord aŭ per Github por ke ni povu helpi. Vi povas forviŝi la ĉi-subajn datumojn de la apo se vi volas.",
"scan": "Analizi",
"scan_all_libraries": "Analizi ĉiujn bibliotekojn",
@@ -1933,7 +2004,33 @@
"scan_settings": "Agordoj pri analizado",
"scanning": "Analizado",
"scanning_for_album": "Serĉado de albumo...",
+ "screencast_mode_description": "Montri indikilojn surekrane pri tuŝoj de klavaro kaj muso",
+ "screencast_mode_title": "Baskuligi reĝimon de elsendo",
+ "search": "Serĉi",
+ "search_albums": "Serĉi albumojn",
+ "search_by_context": "Serĉi laŭ kunteksto",
+ "search_by_description": "Serĉi laŭ priskribo",
+ "search_by_description_example": "Promenado en Poznań",
+ "search_by_filename": "Serĉi laŭ dosiernomo aŭ sufikso",
+ "search_by_filename_example": "ekz. IMG_1234.jpg aŭ png",
+ "search_by_full_path": "Serĉi laŭ dosier-vojo aŭ dosierujo",
+ "search_by_full_path_example": "/Silvja/Projektoj/3D_Printado/2026-07-01 - vi povas serĉi 'Projektoj', '3D', 'Printado', '2026', ktp.",
+ "search_by_ocr": "Serĉi per optika signo-rekono",
+ "search_by_ocr_example": "Invitilo",
"search_camera_lens_model": "Serĉi tipon de objektivo...",
+ "search_camera_make": "Serĉi fabrikanton de fotilo...",
+ "search_camera_model": "Serĉi tipon de fotilo...",
+ "search_city": "Serĉi urbon...",
+ "search_country": "Serĉi landon...",
+ "search_filter_apply": "Apliki filtrilon",
+ "search_filter_camera_title": "Elektu tipon de fotilo",
+ "search_filter_date": "Dato",
+ "search_filter_date_interval": "de {start} ĝis {end}",
+ "search_filter_date_title": "Elektu intervalon de datoj",
+ "search_filter_display_option_not_in_album": "Ne en albumo",
+ "search_filter_display_options": "Agordoj pri aranĝo sur ekrano",
+ "search_filter_filename": "Serĉi laŭ dosiernomo",
+ "search_filter_location": "Loko",
"search_suggestion_list_smart_search_hint_1": "Inteligenta serĉado defaŭlte estas ŝaltita. Por serĉi metadatumojn, uzu sintakson tiel ",
"select_user_for_sharing_page_err_album": "Malsukcesis krei albumon",
"server_privacy": "Privateco de servilo",
diff --git a/i18n/es.json b/i18n/es.json
index f0326062ee..7dd8a91714 100644
--- a/i18n/es.json
+++ b/i18n/es.json
@@ -59,7 +59,7 @@
"backup_onboarding_1_description": "Copia en un lugar externo, en la nube u otra ubicación física.",
"backup_onboarding_2_description": "copias locales en diferentes dispositivos. Incluye los archivos principales y una copia de seguridad local de dichos archivos.",
"backup_onboarding_3_description": "copias totales de tu data, incluyendo los archivos originales. Incluye 1 copia fuera de sitio y 2 copias locales.",
- "backup_onboarding_description": "Se recomienda una estrategia de copia de seguridad 3-2-1 para proteger tus datos. Deberías mantener copias de las fotos y vídeos que subas, así como de la base de datos de Immich, para contar con una solución de copia de seguridad completa.",
+ "backup_onboarding_description": "Una estrategia de copia de seguridad 3-2-1 es recomendada para proteger tus datos. Deberías mantener copias de las fotos y vídeos que subas, así como de la base de datos de Immich, para contar con una solución de copia de seguridad completa.",
"backup_onboarding_footer": "Para obtener más información sobre cómo hacer una copia de seguridad de Immich, consulta la documentación.",
"backup_onboarding_parts_title": "Una copia de seguridad 3-2-1 incluye:",
"backup_onboarding_title": "Copias de seguridad",
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Usar esta ubicación",
"map_location_service_disabled_content": "Los servicios de ubicación deben estar activados para mostrar recursos de tu ubicación actual. ¿Deseas activarlos ahora?",
"map_location_service_disabled_title": "Servicios de ubicación desactivados",
- "map_marker_for_images": "Marcador de mapa para imágenes tomadas en {city}, {country}",
+ "map_marker_for_image": "Marcador del mapa para la imagen tomada en {city}, {country}",
"map_marker_with_image": "Marcador de mapa con imagen",
"map_no_location_permission_content": "Se necesitan permisos de ubicación para mostrar recursos de tu ubicación actual. ¿Deseas activarlos ahora?",
"map_no_location_permission_title": "Permisos de ubicación denegados",
diff --git a/i18n/et.json b/i18n/et.json
index 6f169370f3..10d3874578 100644
--- a/i18n/et.json
+++ b/i18n/et.json
@@ -189,11 +189,17 @@
"machine_learning_smart_search_enabled": "Luba nutiotsing",
"machine_learning_smart_search_enabled_description": "Kui keelatud, siis ei kodeerita pilte nutiotsingu jaoks.",
"machine_learning_url_description": "Masinõppe serveri URL. Kui ette on antud rohkem kui üks URL, proovitakse neid järjest ükshaaval, kuni üks edukalt vastab. Servereid, mis ei vasta, ignoreeritakse ajutiselt, kuni ühendus taastub.",
+ "maintenance_backup_management": "Varunduse haldus",
"maintenance_delete_backup": "Kustuta varukoopia",
"maintenance_delete_backup_description": "See fail kustutatakse jäädavalt.",
"maintenance_delete_error": "Varukoopia kustutamine ebaõnnestus.",
"maintenance_integrity_check_all": "Märgi kõik",
+ "maintenance_integrity_checksum_mismatch": "Kontrollsumma ebakõla",
+ "maintenance_integrity_checksum_mismatch_description": "Failid, mille kontrollsumma ei klapi sellega, mis on Immich'i andmebaasis.",
+ "maintenance_integrity_checksum_mismatch_job": "Otsi kontrollsumma ebakõlasid",
+ "maintenance_integrity_checksum_mismatch_refresh_job": "Värskenda kontrollsumma ebakõlade aruanne",
"maintenance_integrity_missing_file": "Puuduvad failid",
+ "maintenance_integrity_missing_file_description": "Failid, mida Immich jälgib andmebaasis, kuid mida ei eksisteeri failisüsteemis.",
"maintenance_integrity_missing_file_job": "Otsi puuduvaid faile",
"maintenance_integrity_missing_file_refresh_job": "Värskenda puuduvate failide aruanne",
"maintenance_integrity_untracked_file": "Mittejälgitavad failid",
@@ -923,6 +929,8 @@
"deduplicate_all": "Dedubleeri kõik",
"default_locale": "Vaikimisi lokaat",
"default_locale_description": "Vorminda kuupäevad ja arvud vastavalt brauseri lokaadile",
+ "default_quality_subtitle": "Kvaliteet, mida jagamisel kasutada. Hoia jagamise nuppu all, et iga kord valida.",
+ "default_share_quality": "Vaikimisi jagamise kvaliteet",
"delete": "Kustuta",
"delete_action_confirmation_message": "Kas oled kindel, et soovid selle üksuse kustutada? See toiming liigutab üksuse serveri prügikasti ja küsib, kas soovid selle lokaalselt kustutada",
"delete_action_prompt": "{count} kustutatud",
@@ -1535,7 +1543,7 @@
"map_location_picker_page_use_location": "Kasuta seda asukohta",
"map_location_service_disabled_content": "Praeguse asukoha üksuste kuvamiseks tuleb lubada asukoha teenus. Kas soovid seda praegu lubada?",
"map_location_service_disabled_title": "Asukoha teenus keelatud",
- "map_marker_for_images": "Kaardimarker kohas {city}, {country} tehtud piltide jaoks",
+ "map_marker_for_image": "Kaardimarker pildile, mis on tehtud kohas {city}, {country}",
"map_marker_with_image": "Kaardimarker pildiga",
"map_no_location_permission_content": "Praeguse asukoha üksuste kuvamiseks on vaja asukoha luba. Kas soovid seda praegu lubada?",
"map_no_location_permission_title": "Asukoha luba keelatud",
@@ -2376,6 +2384,8 @@
"trash_page_title": "Prügikast ({count})",
"trashed_items_will_be_permanently_deleted_after": "Prügikasti tõstetud üksused kustutatakse jäädavalt {days, plural, one {# päeva} other {# päeva}} pärast.",
"trigger": "Päästik",
+ "trigger_asset_metadata_extraction": "Üksuste metaandmete eraldamine",
+ "trigger_asset_metadata_extraction_description": "Käivitub, kui üksusest eraldatakse EXIF metaandmed",
"trigger_asset_uploaded": "Üksuse üleslaadimine",
"trigger_asset_uploaded_description": "Käivitub uue üksuse üleslaadimisel",
"trigger_description": "Sündmus, mis käivitab töövoo",
diff --git a/i18n/eu.json b/i18n/eu.json
index f2477e8a95..69f677cb7e 100644
--- a/i18n/eu.json
+++ b/i18n/eu.json
@@ -101,44 +101,200 @@
"image_prefer_wide_gamut": "Nahiago gamut zabala",
"image_prefer_wide_gamut_setting_description": "Erabili Display P3 miniaturentzako (thumbnails). Honek hobeto mantentzen du kolore-espazio zabaleko irudien bizitasuna, baina irudiak ezberdin ikus daitezke arakatzaile bertsio zaharra duten gailu zaharkituetan. sRGB irudiak sRGB gisa mantentzen dira kolore-aldaketak saihesteko.",
"image_preview_description": "Tamaina baxuko irudia metadaturik gabe, baliabide bakarra bistaratzerakoan eta ikasketa automatikoan erabiltzeko",
- "image_preview_quality_description": "Aurrebisten kalitatea (1-100). Zenbat eta altuagoa, orduan eta hobea, baina fitxategi handiagoak sortzen ditu eta aplikazioaren jarioa moteldu dezake. Balio baxu bat ezartzeak ikasketa automatikoaren kalitatea kaltetu dezake.",
+ "image_preview_quality_description": "Aurrebisten kalitatea (1-100). Zenbat eta altuagoa, orduan eta hobea, baina fitxategi handiagoak sortzen ditu eta aplikazioaren jariakortasuna moteldu dezake. Balio baxu bat ezartzeak ikasketa automatikoaren kalitatea kaltetu dezake.",
"image_preview_title": "Aurreikusiaen Konfigurazioa",
"image_progressive": "Progresiboa",
"image_progressive_description": "Kodetu JPEG irudiak progresiboki, pixkanaka kargatzen joan daitezen. Honek ez du eraginik WebP irudietan.",
"image_quality": "Kalitatea",
"image_resolution": "Erresoluzioa",
+ "image_resolution_description": "Bereizmen handiagoek xehetasun gehiago gorde ditzakete, baina denbora gehiago behar dute kodetzeko, fitxategi tamaina handiagoak izan eta aplikazioaren jariakortasuna murriztu dezake.",
"image_settings": "Argazkien Konfigurazioa",
"image_settings_description": "Kudeatu sortutako irudien kalitatea eta erresoluzioa",
+ "image_thumbnail_description": "Metadaturik gabeko miniatura, argazki-taldeak denbora-lerro nagusia bezala ikusten direnean erabiltzen da",
+ "image_thumbnail_quality_description": "Miniaturaren kalitatea 1-100. Handia hobea da, baina fitxategi handiagoak sortzen ditu eta aplikazioen jariakortasuna murriztu dezake.",
"image_thumbnail_title": "Argazki Txikien Konfigurazioa",
"import_config_from_json_description": "Inportatu sistema konfigurazioa JSON konfigurazio fitxategia kargatuz",
"job_concurrency": "{job} konkurrentzia",
"job_created": "Zeregina sortuta",
+ "job_not_concurrency_safe": "Ataza hau ez da segurua aldiberekotasunerako.",
"job_settings": "Zereginaren konfigurazioa",
"job_settings_description": "Kudeatu lanen konkurrentzia",
+ "jobs_delayed": "{jobCount, plural, one {Atzeratutako bat} other {# atzeratutako}}",
+ "jobs_failed": "{jobCount, plural, one {Oker bat} other {# oker}}",
"jobs_over_time": "Lanak denboran zehar",
"library_created": "Sortutako liburutegia: {library}",
"library_deleted": "Liburutegia ezabatuta",
"library_details": "Liburutegiaren xehetasunak",
+ "library_folder_description": "Zehaztu inportatzeko karpeta bat. Karpeta honetan,eta haren azpikarpetetan irudiak eta bideoak bilatuko dira.",
+ "library_remove_exclusion_pattern_prompt": "Ziur bazterketa-eredu hau kendu nahi duzula?",
"library_remove_folder_prompt": "Ziur zaude inportazio karpeta hau ezabatu nahi duzula?",
+ "library_scanning": "Aldizkako eskaneatzea",
+ "library_scanning_description": "Konfiguratu liburutegiko aldizkako eskaneatzea",
+ "library_scanning_enable_description": "Aldizkako liburutegiaren eskaneoa gaitu",
+ "library_settings": "Kanpoko liburutegia",
+ "library_settings_description": "Kudeatu kanpoko liburutegiaren ezarpenak",
+ "library_tasks_description": "Kanpoko liburutegietan aldatutakoak baliabideak edo baliabide berriak edo bilatu",
+ "library_updated": "Liburutegia eguneratuta",
+ "library_watching_enable_description": "Behatu kanpoko liburutegien fitxategi aldaketak",
+ "library_watching_settings": "Liburutegien behaketa",
+ "library_watching_settings_description": "Fitxategi aldaketak behatu automatikoki",
"logging_enable_description": "Gaitu erregistroak",
"logging_level_description": "Erregistroak gaituta daudenean, nolako erregistro maila erabili.",
"logging_settings": "Erregistroak",
+ "machine_learning_availability_checks": "Eskuragarritasun egiaztapenak",
+ "machine_learning_availability_checks_description": "Automatikoki detektatu eta hobetsi eskuragarri dauden ikaskuntza automatikoko zerbitzariak",
+ "machine_learning_availability_checks_enabled": "Eskuragarritasun egiaztapenak gaitu",
+ "machine_learning_availability_checks_interval": "Egiaztapen denbora-tartea",
+ "machine_learning_availability_checks_interval_description": "Denbora-tartea milisegundotan eskuragarritasun egiaztapenen artean",
+ "machine_learning_availability_checks_timeout": "Eskakizun denbora-muga",
+ "machine_learning_availability_checks_timeout_description": "Eskakizun denbora-muga milisegundotan eskuragarritasun egiaztapenentzat",
+ "machine_learning_clip_model": "CLIP Modeloa (Kontrastezko hizkuntza-irudi aurre-prestakuntza)",
+ "machine_learning_clip_model_description": "hemen zerrendatutako CLIP eredu baten izena. Kontuan izan 'Bilaketa adimentsua' lana berriro exekutatu behar duzula irudi guztientzat modelo bat aldatzen duzunean.",
"machine_learning_duplicate_detection": "Bizkoizketa Detekzioa",
"machine_learning_duplicate_detection_enabled": "Gaitu bikoizketa detekezioa",
+ "machine_learning_duplicate_detection_enabled_description": "Desgaituta badago, berdin-berdinak diren baliabideak desbikoiztu egingo dira.",
+ "machine_learning_duplicate_detection_setting_description": "Erabili CLIP txertaketak bikoiztuak aurkitzeko",
+ "machine_learning_enabled": "Gaitu ikaskuntza automatikoa",
+ "machine_learning_enabled_description": "Desgaituta badago, ML ezaugarri guztiak desgaitu egingo dira beheko ezarpenak kontuan hartu gabe.",
"machine_learning_facial_recognition": "Aurpegi-Ezagutza",
"machine_learning_facial_recognition_description": "Detektatu, ezagutu eta aurpegiak banatu argazkietan",
"machine_learning_facial_recognition_model": "Aurpegi-Ezagutza eredua",
+ "machine_learning_facial_recognition_model_description": "Modeloak tamainaren beheranzko ordenan zerrendatzen dira. Modelo handiagoek motelagoak dira eta memoria gehiago erabiltzen dute, baina emaitza hobeak ematen dituzte. Kontuan izan eredu bat aldatzen duzunean aurpegiak hautemateko lana berriro exekutatu behar duzula irudi guztientzat.",
"machine_learning_facial_recognition_setting": "Aurpegi-Ezagutza Gaitu",
+ "machine_learning_facial_recognition_setting_description": "Desgaituta badago, irudiak ez dira kodetuko aurpegia ezagutzeko eta ez dute Arakatu orriko Pertsonak atala beteko.",
+ "machine_learning_max_detection_distance": "Detekzio distantzia maximoa",
+ "machine_learning_max_detection_distance_description": "Bi irudien arteko gehienezko distantzia bikoiztutzat hartzeko, 0,001-0,1 bitartekoa. Balio altuagoek bikoiztu gehiago detektatuko dituzte, baina positibo faltsuak sor ditzakete.",
+ "machine_learning_max_recognition_distance": "Antzemateko distantzia maximoa",
+ "machine_learning_max_recognition_distance_description": "Bi aurpegiren arteko gehienezko distantzia pertsona berdintzat hartzeko, 0-2 bitartekoa. Hori gutxitzeak bi pertsona pertsona bera bezala etiketatzea ekidin dezake, eta igotzeak, berriz, pertsona bera bi pertsona ezberdin gisa etiketatzea ekidin dezake. Kontuan izan errazagoa dela bi pertsona batzea pertsona bat bitan zatitzea baino, beraz, huts egin atalase baxuago baten alde, ahal denean.",
+ "machine_learning_min_detection_score": "Gutxieneko detekzio puntuazioa",
+ "machine_learning_min_detection_score_description": "0-1etik detektatu beharreko aurpegi baten gutxieneko konfiantza puntuazioa. Balio baxuagoek aurpegi gehiago detektatuko dituzte, baina positibo faltsuak sor ditzakete.",
+ "machine_learning_min_recognized_faces": "Gutxieneko antzemandako aurpegiak",
+ "machine_learning_min_recognized_faces_description": "Sortu beharreko pertsona batek aitortutako aurpegien gutxieneko kopurua. Hau handitzeak Aurpegi-ezagutza zehatzagoa bihurtzen du aurpegia pertsona bati esleitzeko aukera areagotzearen truke.",
+ "machine_learning_ocr": "OCR",
+ "machine_learning_ocr_description": "Erabili ikaskuntza automatikoa irudietan testua ezagutzeko",
+ "machine_learning_ocr_enabled": "OCR gaitu",
+ "machine_learning_ocr_enabled_description": "Desgaituta badago, irudiek ez dute testu-ezagutzarik izango.",
+ "machine_learning_ocr_max_resolution": "Gehienezko bereizmena",
+ "machine_learning_ocr_max_resolution_description": "Bereizmen honen gaineko aurrebistak tamaina aldatuko dira aspektu-erlazioa mantenduz. Balio altuagoak zehatzagoak dira, baina denbora gehiago behar dute prozesatzeko eta memoria gehiago behar dute.",
+ "machine_learning_ocr_min_detection_score": "Gutxieneko detekzio puntuazioa",
+ "machine_learning_ocr_min_detection_score_description": "Detektatu beharreko testuaren gutxieneko konfiantza puntuazioa 0-1etik. Balio baxuagoek testu gehiago detektatuko dute, baina positibo faltsuak sor ditzakete.",
+ "machine_learning_ocr_min_recognition_score": "Antzemateko gutxieneko puntuazioa",
+ "machine_learning_ocr_min_score_recognition_description": "0-1etik antzeman beharreko detektaturiko testuaren gutxieneko konfiantza-puntuazioa. Balio baxuagoek testu gehiago ezagutuko dute, baina positibo faltsuak sor ditzakete.",
+ "machine_learning_ocr_model": "OCR modeloa",
+ "machine_learning_ocr_model_description": "Zerbitzari-modeloak mugikorren modeloak baino zehatzagoak dira, baina denbora gehiago eta memoria gehiago behar dute prozesatzeko.",
+ "machine_learning_settings": "Ikaskuntza automatikoaren ezarpenak",
+ "machine_learning_settings_description": "Kudeatu ikaskuntza automatikoaren ezaugarri eta ezarpenak",
+ "machine_learning_smart_search": "Bilaketa adimentsua",
+ "machine_learning_smart_search_description": "Bilatu irudiak semantikoki CLIP txertaketak erabiliz",
"machine_learning_smart_search_enabled": "Gaitu bilaketa arina",
+ "machine_learning_smart_search_enabled_description": "Desgaituta badago, irudiak ez dira kodetuko bilaketa adimentsurako.",
+ "machine_learning_url_description": "Ikaskuntza automatikoko zerbitzariaren URLa. URL bat baino gehiago ematen bada, zerbitzari bakoitza banan-banan saiatuko da batek behar bezala erantzun arte, lehenengotik azkenera arte. Erantzuten ez duten zerbitzariei aldi baterako ez ikusi egingo zaie sarera itzuli arte.",
+ "maintenance_backup_management": "Segurtasun-kopien kudeaketa",
+ "maintenance_delete_backup": "Segurtasun-kopia ezabatu",
+ "maintenance_delete_backup_description": "Fitxategi hau behin-betiko ezabatuko da.",
+ "maintenance_delete_error": "Akatsa segurtasun-kopia ezabatzerakoan.",
+ "maintenance_integrity_check": "Egiaztatu",
+ "maintenance_integrity_check_all": "Denak egiaztatu",
+ "maintenance_integrity_checksum_mismatch": "Egiaztapeneko baturaren desakordioa",
+ "maintenance_integrity_checksum_mismatch_description": "Fitxategiak non diskoko egiaztapeneko batura Immichek bere datu-basean gordeta duenarekin desakordioan dago.",
+ "maintenance_integrity_checksum_mismatch_job": "Egiaztapeneko baturen desakordioak egiaztatu",
+ "maintenance_integrity_checksum_mismatch_refresh_job": "Freskatu kontrol-sumen desadoztasun txostenak",
+ "maintenance_integrity_missing_file": "Falta diren fitxategiak",
+ "maintenance_integrity_missing_file_description": "Immich-ek bere datu-basean jarraitu dituen baina fitxategi-sisteman existitzen ez diren fitxategiak.",
+ "maintenance_integrity_missing_file_job": "Egiaztatu falta diren fitxategiak",
+ "maintenance_integrity_missing_file_refresh_job": "Freskatu falta diren fitxategien txostenak",
+ "maintenance_integrity_report": "Osotasun txostena",
+ "maintenance_integrity_untracked_file": "Jarraitu gabeko fitxategiak",
+ "maintenance_integrity_untracked_file_description": "Immich-ek bere direktorioetako fitxategien erregistrorik ez duen fitxategiak.",
+ "maintenance_integrity_untracked_file_job": "Egiaztatu jarraitu gabeko fitxategiak",
+ "maintenance_integrity_untracked_file_refresh_job": "Freskatu jarraitu gabeko fitxategien txostenak",
+ "maintenance_restore_backup": "Segurtasun-kopia berrezarri",
+ "maintenance_restore_backup_description": "Immich aukeratutako babeskopiatik ezabatu eta leheneratu egingo da. Jarraitu aurretik, babeskopia bat sortuko da.",
+ "maintenance_restore_backup_different_version": "Babeskopia hau Immich-en beste bertsio batekin sortu da!",
+ "maintenance_restore_backup_unknown_version": "Ezin izan da babeskopiaren bertsioa zehaztu.",
+ "maintenance_restore_database_backup": "Berrezarri datu-basearen babeskopia",
+ "maintenance_restore_database_backup_description": "Itzuli datu-basearen aurreko egoera batera babeskopia fitxategi bat erabiliz",
+ "maintenance_settings": "Mantentzea",
+ "maintenance_settings_description": "Jarri Immich mantentze moduan.",
+ "maintenance_start": "Aldatu mantentze modura",
+ "maintenance_start_error": "Aldatu mantentze modura.",
+ "maintenance_upload_backup": "Kargatu datu-basearen babeskopia fitxategia",
+ "maintenance_upload_backup_error": "Ezin izan da babeskopia kargatu, .sql/.sql.gz fitxategia al da?",
+ "manage_concurrency": "Aldiberekotasuna kudeatu",
+ "manage_concurrency_description": "Nabigatu atazen orrira atazen aldiberekotasuna kudeatzeko",
"manage_log_settings": "Kudeatu erregistroen konfigurazioa",
"map_dark_style": "Beltz estiloa",
+ "map_enable_description": "Gaitu maparen ezaugarriak",
"map_gps_settings": "Mapa eta GPS Konfigurazioa",
+ "map_gps_settings_description": "Kudeatu mapa eta GPS (alderantzizko geokodeketa) ezarpenak",
+ "map_implications": "Maparen funtzioak kanpoko fitxa-zerbitzu batean oinarritzen da (tiles.immich.cloud)",
"map_light_style": "Zuri estiloa",
+ "map_manage_reverse_geocoding_settings": "Kudeatu Alderantzizko geokodeketa ezarpenak",
+ "map_reverse_geocoding": "Alderantziko geokodeketa",
+ "map_reverse_geocoding_enable_description": "Alderantzizko geokodeketa gaitu",
+ "map_reverse_geocoding_settings": "Alderantzizko geokodeketaren ezarpenak",
"map_settings": "Mapa",
+ "map_settings_description": "Kudeatu maparen ezarpenak",
+ "map_style_description": "URL-a style.json Maparen itxura fitxategi batera",
+ "memory_cleanup_job": "Gogorapen garbiketa",
+ "memory_generate_job": "Gogorapen sorkuntza",
+ "metadata_extraction_job": "Metadatuen erauzketa",
+ "metadata_extraction_job_description": "Atera metadatuen informazioa baliabide bakoitzetik, hala nola GPSa, aurpegiak eta bereizmena",
"metadata_faces_import_setting": "Gaitu aurpegien inportazioa",
+ "metadata_faces_import_setting_description": "Inportatu aurpegiak irudien EXIF datuetatik eta Sidecar fitxategietatik",
"metadata_settings": "Metadata Konfigurazioa",
"metadata_settings_description": "Kudeatu metadaten konfigurazioa",
"migration_job": "Migrazio",
+ "migration_job_description": "Migratu baliabideen eta aurpegien miniaturak karpeten egitura berrienera",
+ "nightly_tasks_cluster_faces_setting_description": "Exekutatu aurpegi-ezagutza detektatu berri diren aurpegietan",
+ "nightly_tasks_cluster_new_faces_setting": "Aurpegi berriak multzokatu",
+ "nightly_tasks_database_cleanup_setting": "Datu-base garbiketa zereginak",
+ "nightly_tasks_database_cleanup_setting_description": "Garbitu datu zaharrak eta iraungitako datuak datu-basetik",
+ "nightly_tasks_generate_memories_setting": "Gogorapenak sortu",
+ "nightly_tasks_generate_memories_setting_description": "Gogorapen berriak sortu balibadeetatik",
+ "nightly_tasks_missing_thumbnails_setting": "Falta diren miniaturak sortu",
+ "nightly_tasks_missing_thumbnails_setting_description": "Jarri miniaturarik gabeko baliabideak ilaran miniaturak sortzeko",
+ "nightly_tasks_settings": "Gaueko atazen ezarpenak",
+ "nightly_tasks_settings_description": "Gaueko atazak kudeatu",
+ "nightly_tasks_start_time_setting": "Hasiera denbora",
+ "nightly_tasks_start_time_setting_description": "Zerbitzaria gaueko atazak exekutatzen hasten den ordua",
+ "nightly_tasks_sync_quota_usage_setting": "Sinkronizazio kuotaren erabilera",
+ "nightly_tasks_sync_quota_usage_setting_description": "Eguneratu erabiltzaileen biltegiratze-kuota, egungo erabileraren arabera",
+ "no_paths_added": "Ez da biderik sartu",
+ "no_pattern_added": "Ez da eredurik sartu",
+ "note_apply_storage_label_previous_assets": "Oharra: Aurretik kargatutako baliabideei biltegiratze-etiketa aplikatzeko, exekutatu",
+ "note_cannot_be_changed_later": "OHARRA: Ezin da geroago aldatu!",
+ "notification_email_from_address": "Nondik",
+ "notification_email_from_address_description": "Bidaltzailearen helbide elektronikoa, adibidez: \"Immich Photo Server \". Ziurtatu mezu elektronikoak bidaltzeko baimena daukazun helbide bat erabiltzen duzula.",
+ "notification_email_host_description": "Posta elektronikoko zerbitzariaren ostalaria (adibidez, smtp.immich.app)",
+ "notification_email_ignore_certificate_errors": "Ziurtagiri akatsak kontuan ez hartu",
+ "notification_email_ignore_certificate_errors_description": "TLS ziurtagiri egiaztapen akatsak kontuan ez hartu (ez da gomendatzen)",
+ "notification_email_password_description": "E-mail zerbitzariarekin autentikatzerakoan erabiltzeko pasahitza",
+ "notification_email_port_description": "E-mail zerbitzariaren portua (adibidez, 25, 465 edo 587)",
+ "notification_email_secure": "SMTPS",
+ "notification_email_secure_description": "SMTPS erabili (SMTP TLS bitartez)",
+ "notification_email_sent_test_email_button": "Bidali E-mail froga mezua eta gorde",
+ "notification_email_setting_description": "E-mail bidezko jakinarazpenak bidaltzeko ezarpenak",
+ "notification_email_test_email": "E-mail froga mezua bidali",
+ "notification_email_test_email_failed": "Ezin izan dira probako e-maila bidali, egiaztatu zure balioak",
+ "notification_email_test_email_sent": "Proba-mezu bat bidali da {email} helbidera. Mesedez, egiaztatu zure sarrera-ontzia.",
+ "notification_email_username_description": "E-mail zerbitzariarekin autentifikatzean erabili beharreko erabiltzaile-izena",
+ "notification_enable_email_notifications": "E-mail jakinarazpenak gaitu",
+ "notification_settings": "Jakinarazpenen ezarpenak",
+ "notification_settings_description": "Kudeatu jakinarazpen-ezarpenak, posta elektronikoa barne",
+ "oauth_allow_insecure_requests": "Onartu segurtasunik gabeko eskaerak",
+ "oauth_allow_insecure_requests_description": "OHARRA: honek OAuth eskaeretarako TLS ziurtagirien baliozkotzea desgaitzen du eta MITM erasoak jasan ditzakezu.",
+ "oauth_auto_launch": "Hasieratze automatikoa",
+ "oauth_auto_launch_description": "Hasi OAuth saio-hasiera-fluxua automatikoki saioa hasteko orrira nabigatzean",
+ "oauth_auto_register": "Erregistro automatikoa",
+ "oauth_auto_register_description": "Erregistratu automatikoki erabiltzaile berriak OAuth-ekin saioa hasi ondoren",
+ "oauth_button_text": "Botoiaren testua",
+ "oauth_client_secret_description": "Bezero konfidentzialarentzat beharrezkoa da, edo bezero publikoarentzat PKCE (Kodeak trukatzeko froga-gakoa) onartzen ez bada.",
+ "oauth_enable_description": "Saioa hasi OAuth erabiliz",
+ "oauth_end_session_url_description": "Birbideratu erabiltzailea URI honetara saioa amaitzean.",
+ "oauth_mobile_redirect_uri": "Mugikorren birbideratze URIa",
+ "oauth_mobile_redirect_uri_override": "Mugikorreko birbideratze URIa gainidatzi",
+ "oauth_mobile_redirect_uri_override_description": "Gaitu OAuth hornitzaileak mugikorren URIrik onartzen ez duenean, adibidez, ''{callback}''",
"oauth_prompt_description": "Prompt parametroa",
"oauth_role_claim": "Rol aldarrikapena",
"oauth_role_claim_description": "Eman automatikoki administratzaile sarbidea erreklamazio honen presentzian oinarrituta. Erreklamazioak 'erabiltzailea' edo 'administratzailea' izan dezake.",
@@ -148,400 +304,1428 @@
"oauth_storage_label_claim": "Memoriaren etiketa eskaera",
"oauth_storage_label_claim_description": "Erabiltzailearen memoria-etiketa automatikoki finkatzea, eskatutako balioan.",
"oauth_storage_quota_claim": "Eskatutako memoriaren kuota",
+ "oauth_storage_quota_claim_description": "Ezarri automatikoki erabiltzailearen biltegiratze-kuota balio honekin.",
+ "oauth_storage_quota_default": "Biltegiratze-kuota lehenetsia (GiB)",
+ "oauth_storage_quota_default_description": "Erreklamaziorik ematen ez denean erabili beharreko biltegiratze-kuota (GiB).",
+ "oauth_timeout": "Eskaera denbora-muga",
+ "oauth_timeout_description": "Eskaeren denbora-muga milisegundotan",
+ "ocr_job_description": "Erabili ikaskuntza automatikoa irudietan testua antzemateko",
+ "password_enable_description": "Saioa hasi E-mail eta pasahitza erabiliz",
+ "password_settings": "Pasahitz bidezko saio hasiera",
+ "password_settings_description": "Kudeatu pasahitz bidezko saio hasiera",
+ "paths_validated_successfully": "Bide guztiak arrakastaz balioetsita",
+ "person_cleanup_job": "Pertsonen garbiketa",
+ "queue_details": "Ilararen xehetasunak",
+ "queues": "Ataza ilara",
+ "queues_page_description": "Ataza ilaren kudeaketa orria",
+ "quota_size_gib": "Kuota tamaina (GiB)",
+ "refreshing_all_libraries": "Liburutegi guztiak freskatu",
+ "registration": "Kudeatzaile erregistroa",
+ "registration_description": "Sistemako lehen erabiltzailea zarenez, Administratzaile gisa esleituko zara eta administrazio-zereginez arduratuko zara, eta erabiltzaile gehigarriak zuk sortuko dituzu.",
+ "release_channel_release_candidate": "Bertsio kandidatua",
+ "release_channel_stable": "Egonkorra",
+ "remove_failed_jobs": "Akatsdun atazak ezabatu",
+ "require_password_change_on_login": "Eskatu erabiltzaileari pasahitza aldatzea lehen saio hasieran",
+ "reset_settings_to_default": "Berrezarri ezarpenak lehenespenera",
+ "reset_settings_to_recent_saved": "Berrezarri ezarpenak azken gordetako ezarpenetara",
+ "scanning_library": "Liburutegia eskaneatzen",
+ "search_jobs": "Atazak bilatu…",
+ "send_welcome_email": "Ongietorri e-maila bidali",
+ "server_external_domain_settings": "Kanpoko domeinua",
+ "server_external_domain_settings_description": "Kanpoko estekentzako erabiltzen den domeinua",
+ "server_public_users": "Erabiltzaile publikoak",
+ "server_public_users_description": "Erabiltzaile guztiak (izena eta helbide elektronikoa) zerrendatzen dira erabiltzaile bat partekatutako albumetan gehitzean. Desgaituta dagoenean, erabiltzaileen zerrenda administratzaileentzako soilik egongo da erabilgarri.",
+ "server_settings": "Zerbizariaren ezarpenak",
+ "server_settings_description": "Zerbitzariaren ezarpenak kudeatu",
+ "server_stats_page_description": "Administrarien zerbitzariaren estatistikak",
+ "server_welcome_message": "Ongietorri mezua",
+ "server_welcome_message_description": "Saioa hasteko orrian bistaratzen den mezua.",
+ "settings_page_description": "Administrari ezarpenen orria",
+ "sidecar_job": "Sidecar metadatuak",
+ "sidecar_job_description": "Ezagutu edo sinkronizatu sidecar metadatuak fitxategi-sistematik",
+ "slideshow_duration_description": "Irudi bakoitza bistaratzeko segundo kopurua",
+ "smart_search_job_description": "Exekutatu ikasketa automatikoa baliabideetan bilaketa adimenduna laguntzeko",
+ "storage_template_date_time_description": "Baliabidearen sorreraren ordu-zigilua data-orduaren informazioarako erabiltzen da",
+ "storage_template_date_time_sample": "Denbora eredua {date}",
+ "storage_template_enable_description": "Biltegiratze txantiloien motorra gaitu",
+ "storage_template_hash_verification_enabled": "Hash egiaztapena gaituta dago",
+ "storage_template_hash_verification_enabled_description": "Hash egiaztapena gaitzen du, ez desgaitu hau ondorioen berri jakin ezean",
+ "storage_template_migration": "Biltegiratze txantiloi migrazioa",
+ "storage_template_migration_description": "Aplikatu uneko {template} aldez aurretik igotako baliabideei",
+ "storage_template_migration_info": "Biltegiratzeko txantiloiak luzapen guztiak letra xehetara bihurtuko ditu. Txantiloi-aldaketak baliabide berriei soilik aplikatuko zaizkie. Txantiloia aurretik kargatutako baliabideei atzeraeraginean aplikatzeko, exekutatu {job}.",
+ "storage_template_migration_job": "Biltegiratze-txantiloia migratzeko ataza",
+ "storage_template_more_details": "Ezaugarri honi buruzko xehetasun gehiago lortzeko, ikusi Biltegiratzeko txantiloia eta bere inplikazioak",
+ "storage_template_onboarding_description_v2": "Gaituta dagoenean, ezaugarri honek fitxategiak automatikoki antolatuko ditu erabiltzaileak definitutako txantiloi batean oinarrituta. Informazio gehiago lortzeko, ikusi dokumentazioa.",
+ "storage_template_path_length": "Gutxi gorabeherako bide-luzeraren muga: {length, number}/{limit, number}",
+ "storage_template_settings": "Biltegiratze txantiloia",
+ "storage_template_settings_description": "Kudeatu igotako baliabidearen karpeta-egitura eta fitxategi-izena",
+ "storage_template_user_label": "{label} da erabiltzailearen biltegiratze etiketa",
+ "system_settings": "Sistema ezarpenak",
+ "tag_cleanup_job": "Etiketak garbitu",
+ "template_email_available_tags": "Aldagai hauek erabil ditzakezu txantiloian: {tags}",
+ "template_email_if_empty": "Txantiloia hutsik badago, posta elektroniko lehenetsia erabiliko da.",
+ "template_email_invite_album": "Album gonbidapen txantiloia",
"template_email_preview": "Aurrebista",
+ "template_email_settings": "E-mail txantiloiak",
+ "template_email_update_album": "Eguneratu album txantiloia",
+ "template_email_welcome": "Ongietorri e-mail mezuaren txantiloia",
+ "template_settings": "Jakinarazpen txantiloiak",
+ "template_settings_description": "Kudeatu jakinarazpenetarako txantiloi pertsonalizatuak",
+ "theme_custom_css_settings": "CSS pertsonalizatua",
+ "theme_custom_css_settings_description": "Estilo-orriek Immich diseinua pertsonalizatzeko aukera ematen dute.",
+ "theme_settings": "Gaiaren ezarpenak",
+ "theme_settings_description": "Kudeatu Immich web interfazearen pertsonalizazioa",
+ "thumbnail_generation_job": "Sortu miniaturak",
+ "thumbnail_generation_job_description": "Sortu miniatura handiak, txikiak eta lausoak baliabide bakoitzeko, baita pertsona bakoitzarentzako miniaturak ere",
+ "transcoding_acceleration_api": "Azelerazioaren APIa",
+ "transcoding_acceleration_api_description": "Transkodifikazioa bizkortzeko zure gailuarekin elkarreragingo duen APIa. Ezarpen hau 'ahalegin onena' da: huts egiten badu software bidezko transkodifikaziora itzuliko da. VP9-k funtziona dezake edo ez zure hardwarearen arabera.",
+ "transcoding_acceleration_nvenc": "NVENC (NVIDIA GPU-a behar du)",
+ "transcoding_acceleration_qsv": "Quick Sync (7. belaunaldiko Intel prozesadorea edo handiagoa behar du)",
+ "transcoding_acceleration_rkmpp": "RKMPP (Rockchip-en SOC-an soilik)",
"transcoding_acceleration_vaapi": "VAAPI",
+ "transcoding_accepted_audio_codecs": "Onartutako audio-kodekak",
+ "transcoding_accepted_audio_codecs_description": "Hautatu zein audio-kodek transkodetu behar ez diren. Transkodetze-politika jakin batzuetarako bakarrik erabiltzen da.",
+ "transcoding_accepted_containers": "Onartutako kontenedoreak",
+ "transcoding_accepted_containers_description": "Hautatu zein kontenedore formatu ez diren MP4ra birmixatu behar. Transkodetze-politika jakin batzuetarako bakarrik erabiltzen da.",
+ "transcoding_accepted_video_codecs": "Onartutako bideo-kodekak",
+ "transcoding_accepted_video_codecs_description": "Hautatu zein bideo-kodek transkodetu behar ez diren. Transkodetze-politika jakin batzuetarako bakarrik erabiltzen da.",
+ "transcoding_advanced_options_description": "Erabiltzaile gehienek aldatu behar ez dituzten aukerak",
+ "transcoding_audio_codec": "Audio-kodeka",
+ "transcoding_audio_codec_description": "Opus kalitate goreneko aukera da, baina gailu edo software zaharrekin bateragarritasun txikiagoa du.",
+ "transcoding_bitrate_description": "Gehienezko bit-tasa baino handiagoa edo onartutako formatuan ez dauden bideoak",
+ "transcoding_codecs_learn_more": "Hemen erabiltzen den terminologiari buruz gehiago jakiteko, jo FFmpeg-en dokumentaziora. H.264 kodeka, HEVC kodeka eta VP9 kodeka .",
+ "transcoding_constant_quality_mode": "Kalitate iraunkorreko modua",
+ "transcoding_constant_quality_mode_description": "ICQ CQP baino hobea da, baina hardware-azelerazio-gailu batzuek ez dute modu hau onartzen. Aukera hau ezartzeak zehaztutako modua hobetsiko du kalitatean oinarritutako kodeketa erabiltzean. NVENC-ek ez du jaramonik egingo ICQ onartzen ez duelako.",
+ "transcoding_constant_rate_factor": "Tasa konstantearen faktorea (-crf)",
+ "transcoding_constant_rate_factor_description": "Bideoaren kalitate maila. Balio tipikoak H.264rako 23, HEVCrako 28, VP9rako 31 eta AV1erako 35 dira. Baxuagoa hobea da, baina fitxategi handiagoak sortzen ditu.",
+ "transcoding_disabled_description": "Ez transkodetu bideorik, baliteke bezero batzuen erreprodukzioa haustea",
+ "transcoding_encoding_options": "Kodetze aukerak",
+ "transcoding_encoding_options_description": "Ezarri kodekak, bereizmena, kalitatea eta beste aukera batzuk kodetutako bideoetarako",
+ "transcoding_hardware_acceleration": "Hardware bidezko azelerazioa",
+ "transcoding_hardware_acceleration_description": "Esperimentala: transkodeketa azkarragoa dakar baina kalitatea murriztu dezake bit-tasa berean",
+ "transcoding_hardware_decoding": "Hardware bidezko deskodetzea",
+ "transcoding_hardware_decoding_setting_description": "Mutur-muturreko azelerazioa gaitzen du soilik kodeketa bizkortu beharrean. Baliteke bideo guztietan ez funtzionatzea.",
+ "transcoding_max_b_frames": "Gehienezko B-fotogramak",
+ "transcoding_max_b_frames_description": "Balio altuagoek konpresioaren eraginkortasuna hobetzen dute, baina kodeketa moteldu egiten dute. Baliteke gailu zaharretako hardware-azelerazioarekin bateragarria ez izatea. 0 balioak B-koardoak desgaitzen ditu, eta -1 balioak balio hau automatikoki ezartzen du.",
+ "transcoding_max_bitrate": "Gehienezko bit-tasa",
+ "transcoding_max_bitrate_description": "Gehienezko bit-tasa ezartzeak fitxategien tamainak aurreikusgarriagoak egite ditu kalitatearen kostu txikiarekin. 720p-n, balio tipikoak VP9 edo HEVCrako 2600 kbit/s edo H.264rako 4500 kbit/s dira. Desgaituta dago 0 moduan ezartzen bada. Unitaterik zehazten ez denean, k (kbit/s-rako) suposatzen da; beraz, 5000, 5000k eta 5M (Mbit/s-rako) baliokideak dira.",
+ "transcoding_max_keyframe_interval": "Gehieneko gako-fotograma tartea",
+ "transcoding_max_keyframe_interval_description": "Gako-fotogramen arteko gehienezko fotograma-distantzia ezartzen du. Balio baxuagoek konpresio-eraginkortasuna okertzen dute, baina bilaketa-denborak hobetzen dituzte eta baliteke kalitatea hobetzea mugimendu azkarra duten eszenetan. 0-k balio hau automatikoki ezartzen du.",
+ "transcoding_optimal_description": "Helburuko bereizmenetik gorako bideoak edo onartutako formatuan ez daudenak",
+ "transcoding_policy": "Transkodetze politika",
+ "transcoding_policy_description": "Ezartzen du bideo bat noiz transkodetuko den",
+ "transcoding_preferred_hardware_device": "Hardware-gailu hobetsia",
+ "transcoding_preferred_hardware_device_description": "VAAPI-ri eta QSV-i soilik aplikatzen zaie. Hardware transkodetzeko erabilitako dri nodoa ezartzen du.",
+ "transcoding_preset_preset": "Txantiloia (-preset)",
+ "transcoding_preset_preset_description": "Konpresioaren abiadura. Txantiloi motelagoak fitxategi txikiagoak sortzen ditu eta kalitatea handitzen du bit-tasa jakin batera bideratzen denean. VP9-k \"azkarrago\"-tik gorako abiadura baztertzen du.",
+ "transcoding_realtime": "Denbora errealeko transkodeketa [ESPERIMENTALA]",
+ "transcoding_realtime_description": "Bideoa erreproduzitzen ari den heinean transkodetzea denbora errealean egiteko aukera ematen du. Kalitate aldaketa gaitzen du, baina zerbitzariaren gaitasunen arabera erreprodukzio-latentzia eta toteltze handiagoak sor ditzake.",
+ "transcoding_realtime_enabled": "Gaitu denbora errealeko transkodeketa",
+ "transcoding_realtime_enabled_description": "Desgaituta badago, zerbitzariak uko egingo dio denbora errealeko transkodetze saio berriei.",
+ "transcoding_reference_frames": "Erreferentzia fotogramak",
+ "transcoding_reference_frames_description": "Forograma jakin bat konprimitzean erreferentzia beharreko fotograma kopurua. Balio altuagoek konpresioaren eraginkortasuna hobetzen dute, baina kodeketa moteltzen dute. 0-k balio hau automatikoki ezartzen du.",
+ "transcoding_required_description": "Onartutako formatu batean ez dauden bideoak bakarrik",
+ "transcoding_settings": "Bideo transkodetze ezarpenak",
+ "transcoding_settings_description": "Kudeatu zein bideo transkodetu eta nola prozesatu",
+ "transcoding_target_resolution": "Bereizmen helburua",
+ "transcoding_target_resolution_description": "Bereizmen handiagoek xehetasun gehiago gorde ditzakete, baina denbora gehiago behar dute kodetzeko, fitxategi-tamaina handiagoak sortu eta aplikazioen jariakortasuna murriztu dezake.",
+ "transcoding_temporal_aq": "Aldi baterako AQ-a",
+ "transcoding_temporal_aq_description": "NVENC-i soilik aplikatzen da. Denboraldiaren Kuantizazio Egokigarriak (AQak) xehetasun handiko eta mugimendu baxuko eszenen kalitatea areagotzen du. Baliteke gailu zaharrekin bateragarria ez izatea.",
"transcoding_threads": "Hariak",
- "transcoding_tone_mapping": "Tonoen mapeoa"
+ "transcoding_threads_description": "Balio altuagoek kodeketa azkarragoa dakar, baina leku gutxiago uzten diote zerbitzariari beste zeregin batzuk prozesatzeko aktibo dagoen bitartean. Balio honek ez luke CPU-nukleoen kopurua baino handiagoa izan behar. Erabilera maximizatzen du 0 gisa ezartzen bada.",
+ "transcoding_tone_mapping": "Tonoen mapeoa",
+ "transcoding_tone_mapping_description": "SDR bihurtzean HDR bideoen itxura mantentzen saiatzen da. Algoritmo bakoitzak kolore, xehetasun eta distira konpromezu desberdinak egiten ditu. Hablek xehetasunak gordetzen ditu, Mobiusek kolorea eta Reinhardek distira.",
+ "transcoding_transcode_policy": "Transkodetze politika",
+ "transcoding_transcode_policy_description": "Bideo bat transkodetu behar den politika. YUV 4:2:0 ez den pixel formatua duten bideoak eta HDR bideoak beti transkodetuko dira (transkodetzea desgaituta badago izan ezik).",
+ "transcoding_two_pass_encoding": "Bi pasatako kodeketa",
+ "transcoding_two_pass_encoding_setting_description": "Transkodetu bi pasetan hobeto kodetutako bideoak sortzeko. Gehienezko bit-abiadura gaituta dagoenean (beharrezkoa da H.264 eta HEVC-ekin funtzionatzeko), modu honek bit-tasa maximoan oinarritutako bit-abiadura-tarte bat erabiltzen du eta CRF-a ez du aintzat hartzen. VP9rako, CRF erabil daiteke bit-tasa maximoa desgaituta badago.",
+ "transcoding_video_codec": "Bideo-kodekak",
+ "transcoding_video_codec_description": "VP9-k eraginkortasun eta web bateragarritasun handia du, baina denbora gehiago behar da transkodetzeko. HEVC antzera funtzionatzen du, baina web bateragarritasun txikiagoa du. H.264 oso bateragarria da eta transkodetzeko azkarra da, baina askoz fitxategi handiagoak sortzen ditu. AV1 kodeka eraginkorrena da, baina ez dira onartzen gailu zaharretan.",
+ "trash_enabled_description": "Zakarrontzia gaitu",
+ "trash_number_of_days": "Egun kopurua",
+ "trash_number_of_days_description": "Baliabideak zakarrontzian gorde behar diren egun kopurua behin betiko ezabatu aurretik",
+ "trash_settings": "Zakarrontziaren ezarpenak",
+ "trash_settings_description": "Kudeatu zakarrontziaren ezarpenak",
+ "unlink_all_oauth_accounts": "OAuth kontu guztietatik saioa itxi",
+ "unlink_all_oauth_accounts_description": "Gogoratu hornitzaile berri batera migratu aurretik OAuth-eko kontu guztietatik saioa ixtea.",
+ "unlink_all_oauth_accounts_prompt": "Ziur OAuth kontu guztiak deskonektatu nahi dituzula? Honek erabiltzaile bakoitzaren OAuth IDa berrezarriko du eta ezin da desegin.",
+ "user_cleanup_job": "Erabiltzaile garbiketa",
+ "user_delete_delay": "{user} erabiltzailearen kontua eta baliabideak {delay, plural, one {egun bat} other {# egun}} barru behin betiko ezabatzeko programatuko dira.",
+ "user_delete_delay_settings": "Atzerapena ezabatu",
+ "user_delete_delay_settings_description": "Erabiltzaile baten kontua eta baliabideak behin betiko ezabatzeko egun kopurua. Erabiltzaileak ezabatzeko ataza gauerdian abiarazten da ezabatzeko prest dauden erabiltzaileak egiaztatzeko. Ezarpen honen aldaketak hurrengo exekuzioan ebaluatuko dira.",
+ "user_delete_immediately": "{user}-(r)en kontua eta baliabideak behin betiko ezabatzeko ilaran jarriko dira berehala.",
+ "user_delete_immediately_checkbox": "Erabiltzailea eta baliabideak berehala ezabatzeko ilaran jarri",
+ "user_details": "Erabiltzailearen xehetasunak",
+ "user_management": "Erabiltzaileen kudeaketa",
+ "user_password_has_been_reset": "Erabiltzailearen pasahitza eguneratu da:",
+ "user_password_reset_description": "Mesedez, ezarri aldi baterako pasahitza erabiltzaileari eta jakinarazi hurrengo saioa hasteko pasahitza aldatu beharko duela.",
+ "user_restore_description": "{user} erabiltzailearen kontua leheneratu egingo da.",
+ "user_restore_scheduled_removal": "Berrezarri erabiltzailea - programatutako kentzea {date, date, long} egunean",
+ "user_settings": "Erabiltzailearen ezarpenak",
+ "user_settings_description": "Erabiltzailearen ezarpenak kudeatu",
+ "user_successfully_removed": "{email} erabiltzailea behar bezala ezabatu da.",
+ "users_page_description": "Administrari erabiltzaileen orria",
+ "version_check_channel": "Argitalpen kanala",
+ "version_check_channel_description": "Aukeratu bertsio-iragarpenak jaso nahi dituzun bertsio-kanalak",
+ "version_check_enabled_description": "Bertsio baliozkotzea gaitu",
+ "version_check_implications": "Bertsio baliozkotzea {server}-(a)rekin aldizkako komunikazioaren beharra du",
+ "version_check_settings": "Bertsio baliozkotzea",
+ "version_check_settings_description": "Bertsio berriaren jakinarazpena gaitu/desgaitu",
+ "video_conversion_job": "Bideoak transkodeatu",
+ "video_conversion_job_description": "Bideoak arakatzaile eta gailuekin bateragarritasun handiagoa lortzeko transkodetu"
},
+ "admin_email": "Administrariaren e-maila",
+ "admin_password": "Administrari pasahitza",
+ "administration": "Administrazioa",
"advanced": "Aurreratua",
+ "advanced_settings_clear_image_cache": "Irudien cahcea garbitu",
+ "advanced_settings_clear_image_cache_error": "Ezin izan da argazkien cachea garbitu",
+ "advanced_settings_clear_image_cache_success": "{size} arrakastaz garbituta",
+ "advanced_settings_enable_alternate_media_filter_subtitle": "Erabili aukera hau sinkronizazioan baliabideak irizpide alternatiboetan oinarrituta iragazteko. Saiatu hau bakarrik aplikazioak album guztiak detektatzeko arazoak badituzu.",
+ "advanced_settings_enable_alternate_media_filter_title": "[ESPERIMENTALA] Erabili gailuaren albumen sinkronizazio-iragazki alternatiboa",
+ "advanced_settings_log_level_title": "Erregistro nibela: {level}",
+ "advanced_settings_prefer_remote_subtitle": "Gailu batzuk oso motelak dira tokiko aktiboetatik miniaturak sortzeko. Aktibatu ezarpen hau urruneko irudiak kargatzeko.",
+ "advanced_settings_prefer_remote_title": "Urruneko irudiak hobetsi",
+ "advanced_settings_proxy_headers_subtitle": "Definitu Immich-ek sareko eskaera bakoitzarekin bidali beharko lituzkeen proxy goiburuak",
+ "advanced_settings_proxy_headers_title": "Proxy goiburu pertsonalizatuak [ESPERIMENTALA]",
+ "advanced_settings_readonly_mode_subtitle": "Argazkiak soilik ikus daitezkeen irakurtzeko modua gaitzen du, hainbat irudi hautatzea, partekatzea, igortzea, ezabatzea bezalako gauzak desgaituta daude. Gaitu/Desgaitu irakurketa modua erabiltzailearen avatar bidez pantaila nagusitik",
"advanced_settings_readonly_mode_title": "Irakurri-soilik modua",
+ "advanced_settings_self_signed_ssl_subtitle": "Zerbitzariaren amaierako SSL ziurtagiriaren egiaztapena saltatzen du. Norberak sinatutako ziurtagirietarako beharrezkoa da.",
+ "advanced_settings_self_signed_ssl_title": "Baimendu norberak sinatutako SSL ziurtagiriak [ESPERIMENTALA]",
+ "advanced_settings_sync_remote_deletions_subtitle": "Ezabatu edo leheneratu automatikoki gailu honetako baliabide bat ekintza hori sarean egiten denean",
+ "advanced_settings_sync_remote_deletions_title": "Sinkronizatu urruneko ezabaketak [ESPERIMENTALA]",
+ "advanced_settings_tile_subtitle": "Erabiltzailearen ezarpen aurreratuak",
+ "advanced_settings_troubleshooting_subtitle": "Gaitu ezaugarri gehigarriak arazoak konpontzeko",
"advanced_settings_troubleshooting_title": "Arazoak detektatzea eta konpontzea",
+ "age_months": "Denbora {months, plural, one {Hilabete #} other {# hilabete}}",
+ "age_year_months": "Denbora urte bat, {months, plural, one {hilabete #} other {# hilabete}}",
+ "age_years": "Adina {years, plural, one {urte #} other {# urte}}",
+ "album": "Album",
+ "album_added": "Albuma gehituta",
+ "album_added_notification_setting_description": "Jaso jakinarazpen elektroniko bat partekatutako album batera gehitzen zarenean",
+ "album_cover_updated": "Albumaren azala eguneratu da",
+ "album_delete_confirmation": "Ziur zaude {album} albuma ezabatu nahi duzula?",
+ "album_delete_confirmation_description": "Album hau partekatzen bada, beste erabiltzaileek ezin izango dute atzitu.",
+ "album_deleted": "Albuma ezabatuta",
"album_info_card_backup_album_excluded": "BAZTERTUTAKOAK",
"album_info_card_backup_album_included": "BARNEKOAK",
+ "album_info_updated": "Albumaren informazioa eguneratu da",
+ "album_leave": "Albuma utzi?",
+ "album_leave_confirmation": "Ziur zaude {album} albuma utzi nahi duzula?",
+ "album_name": "Albumaren izena",
+ "album_options": "Albumaren ezarpenak",
+ "album_remove_user": "Erabiltzailea kendu?",
+ "album_remove_user_confirmation": "Ziur zaude {user} erabiltzailea kendu nahi duzula?",
+ "album_search_not_found": "Ez da aurkitu zure bilaketarekin bat datorren albumik",
+ "album_selected": "Albuma aukeratuta",
+ "album_share_no_users": "Album hau erabiltzaile guztiekin partekatu duzula dirudi edo ez duzula erabiltzailerik partekatzeko.",
+ "album_summary": "Albumaren laburpena",
+ "album_updated": "Albuma eguneratu da",
+ "album_updated_setting_description": "Jaso e-posta bidezko jakinarazpena partekatutako album batek baliabide berriak dituenean",
+ "album_upload_assets": "Kargatu baliabideak ordenagailutik eta gehitu albumera",
+ "album_user_left": "{album}-a utzi du",
+ "album_user_removed": "{user} kendu da",
+ "album_viewer_appbar_delete_confirm": "Ziur zaude album hau zure kontutik ezabatu nahi duzula?",
+ "album_viewer_appbar_share_err_delete": "Ezin izan da albuma ezabatu",
+ "album_viewer_appbar_share_err_leave": "Ezin izan da albuma utzi",
+ "album_viewer_appbar_share_err_remove": "Arazoak daude albumetik baliabideak kentzean",
+ "album_viewer_appbar_share_err_title": "Ezin izan da albumaren izenburua aldatu",
"album_viewer_appbar_share_leave": "Albuma utzi",
"album_viewer_appbar_share_to": "Albuma partekatu",
"album_viewer_page_share_add_users": "Erabiltzaileak gehitu",
+ "album_with_link_access": "Utzi esteka duen edonori album honetako argazkiak eta jendea ikustea.",
+ "albums": "Albumak",
+ "albums_count": "{count, plural, one {Album bat} other {{count, number} Album}}",
+ "albums_default_sort_order": "Albumen ordena lehenetsia",
+ "albums_default_sort_order_description": "Album berriak sortzean baliabideak ordenatzeko hasierako ordena.",
+ "albums_feature_description": "Beste erabiltzaile batzuekin parteka daitezkeen baliabide bildumak.",
+ "albums_on_device_count": "Albumak gailuan ({count})",
+ "albums_selected": "{count, plural, one {album bat aukeratuta} other {# album aukeratuta}}",
+ "all": "Denak",
+ "all_albums": "Album guztiak",
+ "all_people": "Pertsona guztiak",
+ "all_photos": "Argazki guztiak",
+ "all_videos": "Bideo guztiak",
+ "allow_dark_mode": "Modu iluna baimendu",
+ "allow_edits": "Edizioa onartu",
+ "allow_public_user_to_download": "Erabiltzaile publikoei deskargatzea baimendu",
+ "allow_public_user_to_upload": "Erabiltzaile publikoei kargatzea baimendu",
+ "allowed": "Baimenduta",
+ "alt_text_qr_code": "QR-kodea",
+ "always_keep": "Beti mantendu",
+ "always_keep_photos_hint": "Biltegiratze garbitzaileak argazki guztiak mantenduko ditu gailu honetan.",
+ "always_keep_videos_hint": "Biltegiratze garbitzaileak bideo guztiak mantenduko ditu gailu honetan.",
"anti_clockwise": "Erloju-orratzen noranzkoaren aurka",
+ "api_key": "API Gakoa",
+ "api_key_description": "Balio hau behin bakarrik erakutsiko da. Mesedez, ziurtatu leihoa itxi aurretik kopiatu duzula.",
+ "api_key_empty": "Zure API gakoaren izenak ez du hutsik egon behar",
+ "api_keys": "API gakoak",
+ "app_architecture_variant": "Aldaera (Arkitektura)",
+ "app_bar_signout_dialog_content": "Ziur saioa amaitu nahi duzula?",
"app_bar_signout_dialog_ok": "Bai",
"app_bar_signout_dialog_title": "Saioa itxi",
+ "app_download_links": "Aplikazioa deskargatzeko estekak",
+ "app_settings": "Aplikazio ezarpenak",
+ "app_stores": "Aplikazio dendak",
+ "app_update_available": "Aplikazioaren eguneratzea eskuragarri dago",
+ "appears_in": "Hemen agertzen da",
"apply_count": "Ezarri ({count, number})",
"archive": "Artxibo",
+ "archive_action_prompt": "{count} artxibategira bidalita",
+ "archive_or_unarchive_photo": "Argazkia artxibatu edo berrezarri",
+ "archive_page_no_archived_assets": "Ez da artxibatutako baliabiderik aurkitu",
"archive_page_title": "Artxibo ({count})",
+ "archive_size": "Artxibo tamaina",
+ "archive_size_description": "Konfiguratu artxiboaren tamaina deskargak egiteko (GiB-tan)",
"archived": "Artxibatua",
+ "archived_count": "{count, plural, one {artxibatu bat} other {# artxibatu}}",
+ "are_these_the_same_person": "Pertsona bera al dira hauek?",
+ "are_you_sure_to_do_this": "Ziur hau egin nahi duzula?",
+ "array_field_not_fully_supported": "Array-eremuek JSONaren eskuzko edizioa behar dute",
+ "asset_action_delete_err_read_only": "Ezin dira ezabatu irakurtzeko soilik diren aktiboak, saltatu egin da",
+ "asset_action_share_err_offline": "Ezin dira lineaz kanpoko baliabideak eskuratu. Saltatu egin dira",
+ "asset_added_to_album": "Albumera gehituta",
+ "asset_adding_to_album": "Albumera gehitzen…",
+ "asset_created": "Baliabidea sortuta",
+ "asset_day_count": "{date}: {count, plural, one {baliabide bat} other {# baliabide}}",
+ "asset_description_updated": "Baliabidearen deskribapena eguneratu da",
+ "asset_filename_is_offline": "{filename} baliabidea konexiorik gabe dago",
+ "asset_has_unassigned_faces": "Baliabideak esleitu gabeko aurpegiak ditu",
"asset_hashing": "Hasha kalkulatzen…",
- "asset_list_group_by_sub_title": "Multzokatu",
+ "asset_list_group_by_sub_title": "Elkartu",
"asset_list_layout_settings_dynamic_layout_title": "Diseinu dinamikoa",
"asset_list_layout_settings_group_automatically": "Automatikoa",
+ "asset_list_layout_settings_group_by": "Honen bidez taldekatu",
+ "asset_list_layout_settings_group_by_month_day": "Hilabetea + eguna",
"asset_list_layout_sub_title": "Antolaketa",
+ "asset_list_settings_subtitle": "Argazki-sarearen diseinu-ezarpenak",
"asset_list_settings_title": "Irudi lauki-sarea",
+ "asset_not_found_on_device_android": "Baliabidea ez da gailuan aurkitu",
+ "asset_not_found_on_device_ios": "Ez da baliabidea aurkitu gailuan. iCloud erabiltzen ari bazara, baliteke baliabidea eskuraezin izatea iCloud-en gordetako fitxategi txarra dela eta",
+ "asset_not_found_on_icloud": "Ez da aurkitu baliabidea iCloud-en. baliteke baliabidea eskuraezin izatea iCloud-en gordetako fitxategi txarra dela eta",
+ "asset_offline": "Baliabidea lineaz kanpo",
+ "asset_offline_description": "Kanpoko baliabide hau jada ez da diskoan aurkitzen. Mesedez, jarri harremanetan Immich-eko administratzailearekin laguntza eskatzeko.",
+ "asset_restored_successfully": "Baliabidea arrakastaz berrezarria",
"asset_skipped": "Alde batera utzita",
+ "asset_skipped_in_trash": "Zakarrontzian",
+ "asset_trashed": "Baliabidea ezabatua",
+ "asset_troubleshoot": "Baliabidearen diagnosia",
"asset_uploaded": "Igota",
"asset_uploading": "Igotzen…",
+ "asset_viewer_settings_subtitle": "Kudeatu galeria-ikuslearen ezarpenak",
"asset_viewer_settings_title": "Baliabide ikuslea",
"assets": "Baliabideak",
+ "assets_added_count": "{count, plural, one {Baliabide bat} other {# baliabide}} gehituta",
+ "assets_added_to_album_count": "{count, plural, one {Baliabide bat} other {# baliabide}} albumera gehituta",
"assets_added_to_albums_count": "Gehituta {assetTotal, plural, one {# asset} other {# assets}} to {albumTotal, plural, one {# album} other {# albums}}",
+ "assets_cannot_be_added_to_album_count": "{count, plural, one {Baliabidea ezin izan da albumera gehitu} other {Baliabideak ezin izan dira albumera gehitu}}",
"assets_cannot_be_added_to_albums": "{count, plural, one {Asset} other {Assets}} ezin izan da albumetara gehitu",
- "assets_were_part_of_albums_count": "{count, plural, one {Asset was} other {Assets were}} dagoeneko albumean dago",
+ "assets_count": "{count, plural, one {Baliabide bat} other {# baliabide}}",
+ "assets_deleted_permanently": "{count, plural, one {Baliabidea behin-betiko ezabatu da} other {# baliabide behin-betiko ezabatu dira}}",
+ "assets_deleted_permanently_from_server": "{count, plural, one {Baliabide bat} other {# baliabide}} Immich zerbitzaritik ezabatu dira",
+ "assets_downloaded_failed": "{count, plural, one {Deskargatutako fitxategia - {error} okerra} other {# deskargatutako fitxategiak - {error} oker}}",
+ "assets_downloaded_successfully": "{count, plural, one {Fitxategia arrakastaz deskargatu da} other {# fitxategi arrakastaz deskargatu dira}}",
+ "assets_moved_to_trash_count": "{count, plural, one {Baliabidea zakarrontzira eraman da} other {# baliabide zakarrontzira eraman dira}}",
+ "assets_permanently_deleted_count": "{count, plural, one {Baliabidea behin-betiko ezabatu da} other {# baliabide behin-betiko ezabatu dira}}",
+ "assets_removed_count": "{count, plural, one {Baliabidea ezabatu da} other {# baliabide ezabatu dira}}",
+ "assets_removed_permanently_from_device": "{count, plural, one {Baliabidea behin-betiko ezabatu da} other {# baliabide behin-betiko ezabatu dira}} zure gailutik",
+ "assets_restore_confirmation": "Ziur zaude zaborrontziko baliabide guztiak leheneratu nahi dituzula? Ezin duzu ekintza hau desegin! Kontuan izan konexiorik gabeko baliabideak ezin direla modu honetan berrezarri.",
+ "assets_restored_count": "{count, plural, one {Baliabidea berrezarri da} other {# baliabide berrezarri dira}}",
+ "assets_restored_successfully": "{count, plural, one {Baliabidea arrakastaz berrezarri da} other {# baliabide arrakastaz berrezarri dira}}",
+ "assets_trashed": "{count, plural, one {Baliabidea zakarrontzira eraman da} other {# baliabide zakarrontzira eraman dira}}",
+ "assets_trashed_count": "{count, plural, one {Baliabidea zakarrontzira eraman da} other {# baliabide zakarrontzira eraman dira}}",
+ "assets_trashed_from_server": "{count, plural, one {Baliabidea Immich zerbitzaritik zakarrontzira eraman da} other {# baliabide Immich zerbitzaritik zakarrontzira eraman dira}}",
+ "assets_were_part_of_album_count": "{count, plural, one {Baliabidea iada albumaren parte da} other {Baliabideak iada albumaren parte dira}}",
+ "assets_were_part_of_albums_count": "{count, plural, one {Baliabidea iada albumen parte da} other {Baliabideak iada albumrn parte dira}}",
+ "authorized_devices": "Baimendutako gailuak",
+ "automatic_endpoint_switching_subtitle": "Konektatu lokalean izendatutako Wi-Fi bidez erabilgarri dagoenean eta erabili beste nonbait konexio alternatiboak",
+ "automatic_endpoint_switching_title": "URL aldaketa automatikoa",
+ "autoplay_slideshow": "Erreproduzitu automatikoki diapositiba-aurkezpena",
"back": "Atzera",
+ "back_close_deselect": "Atzera, itxi edo desautatu",
+ "background_backup_running_error": "Atzeko planoko segurtasun-kopia exekutatzen ari da, ezin da eskuzko segurtasun-kopia hasi",
+ "background_location_permission": "Atzeko planoko kokapenaren baimena",
+ "background_location_permission_content": "Atzeko planoan exekutatzen denean sarez aldatzeko, Immichek *beti* izan behar du kokapen zehatzaren sarbidea, aplikazioak Wi-Fi sarearen izena irakur dezan",
+ "background_options": "Atzeko planoko aukerak",
"backup": "Babes-kopia",
+ "backup_album_selection_page_albums_device": "Albumak gailuan ({count})",
+ "backup_album_selection_page_albums_tap": "Sakatu sartzeko, sakatu birritan baztertzeko",
+ "backup_album_selection_page_assets_scatter": "Baliabideak hainbat albumetan barreiatu daitezke. Horrela, albumak babeskopia prozesuan sartu edo baztertu daitezke.",
"backup_album_selection_page_select_albums": "Albumak aukeratu",
"backup_album_selection_page_selection_info": "Aukeraren informazioa",
+ "backup_album_selection_page_total_assets": "Baliabide desberdinak guztira",
+ "backup_albums_sync": "Segurtasun-kopia albumen sinkronizazioa",
"backup_all": "Denak",
+ "backup_background_service_backup_failed_message": "Ezin izan da baliabideen segurtasun-kopia sortu. Berriro saiatzen…",
+ "backup_background_service_complete_notification": "Baliabideen babes-kopia arrakastaz osatua",
+ "backup_background_service_connection_failed_message": "Ezin izan da zerbitzarira konektatu. Berriro saiatzen…",
"backup_background_service_current_upload_notification": "{filename} igotzen",
+ "backup_background_service_default_notification": "Baliabide berririk dauden egiaztatzen…",
"backup_background_service_error_title": "Akatsa babes-kopia egiterakoan",
+ "backup_background_service_in_progress_notification": "Zure baliabideen segurtasun-kopia sortzen…",
+ "backup_background_service_upload_failure_notification": "Ezin izan da {filename} igo",
"backup_controller_page_albums": "Seguratsun-kopia albumak",
+ "backup_controller_page_background_app_refresh_disabled_content": "Gaitu atzeko planoko aplikazioa freskatzea Ezarpenak > Orokorra > Atzeko planoko aplikazioa freskatzea atalean, atzeko planoko babeskopiak erabiltzeko.",
+ "backup_controller_page_background_app_refresh_disabled_title": "Atzeko planoko aplikazioa freskatzea desgaituta dago",
+ "backup_controller_page_background_app_refresh_enable_button_text": "Joan ezarpenetara",
+ "backup_controller_page_background_battery_info_link": "Erakutsi nazazu nola",
+ "backup_controller_page_background_battery_info_message": "Atzeko planoko babeskopien esperientzia onena lortzeko, desgaitu Immich-en atzeko planoko jarduera murrizten duten bateriaren optimizazio guztiak.\n\nGailuari espezifikoa denez, mesedez bilatu behar den informazioa zure gailuaren fabrikatzailearentzat.",
"backup_controller_page_background_battery_info_ok": "Onartu",
"backup_controller_page_background_battery_info_title": "Bateria optimizazioak",
+ "backup_controller_page_background_charging": "Kargatzean bakarrik",
+ "backup_controller_page_background_configure_error": "Ezin izan da konfiguratu atzeko planoko zerbitzua",
+ "backup_controller_page_background_delay": "Atzeratu baliabide berrien babeskopia: {duration}",
+ "backup_controller_page_background_description": "Aktibatu atzeko planoko zerbitzua edozein baliabide berren segurtasun-kopia automatikoki egiteko, aplikazioa ireki beharrik gabe",
+ "backup_controller_page_background_is_off": "Atzeko planoko segurtasun-kopia automatikoa desaktibatuta dago",
+ "backup_controller_page_background_is_on": "Atzeko planoko segurtasun-kopia automatikoa aktibatuta dago",
+ "backup_controller_page_background_turn_off": "Desaktibatu atzeko planoko zerbitzua",
+ "backup_controller_page_background_turn_on": "Aktibatu atzeko planoko zerbitzua",
+ "backup_controller_page_background_wifi": "Wi-Fi bidez bakarrik",
"backup_controller_page_backup": "Babes-kopia",
"backup_controller_page_backup_selected": "Aukeratutakoa: ",
+ "backup_controller_page_backup_sub": "Argazkien eta bideoen segurtasun-kopiak egin dira",
+ "backup_controller_page_created": "Sortuta: {date}",
+ "backup_controller_page_desc_backup": "Aktibatu lehen planoko babeskopiak aplikazioa irekitzean baliabide berriak zerbitzarira automatikoki igotzeko.",
"backup_controller_page_excluded": "Baztertutakoa: ",
"backup_controller_page_failed": "Akatsak ({count})",
+ "backup_controller_page_filename": "Fitxategia: {filename} [{size}]",
"backup_controller_page_id": "ID: {id}",
"backup_controller_page_info": "Segurtasun-kopiaren informazioa",
"backup_controller_page_none_selected": "Aukerarik ez",
"backup_controller_page_remainder": "Gainerakoak",
+ "backup_controller_page_remainder_sub": "Hautapenetik babeskopiak egiteko gainerako argazki eta bideoak",
"backup_controller_page_server_storage": "Zerbitzariko memoria",
"backup_controller_page_start_backup": "Segurtasun-kopia hasi",
+ "backup_controller_page_status_off": "Lehen planoko babeskopia automatikoa desaktibatuta dago",
+ "backup_controller_page_status_on": "Lehen planoko babeskopia automatikoa aktibatuta dago",
+ "backup_controller_page_storage_format": "{total}-tik {used} erabilita",
+ "backup_controller_page_to_backup": "Segurtasun-kopia egiteko albumak",
+ "backup_controller_page_total_sub": "Hautatutako albumetako argazki eta bideo guztiak",
+ "backup_controller_page_turn_off": "Desaktibatu lehen planoko babeskopiak",
+ "backup_controller_page_turn_on": "Aktibatu lehen planoko babeskopiak",
+ "backup_controller_page_uploading_file_info": "Fitxategiaren informazioa kargatzen",
+ "backup_err_only_album": "Ezin da album bakarra ezabatu",
+ "backup_error_sync_failed": "Sinkronizazioak huts egin du. Ezin da segurtasun-kopia prozesatu.",
"backup_info_card_assets": "baliabide",
"backup_manual_cancelled": "Ezeztatuta",
+ "backup_manual_in_progress": "Igoera iada martxan dago. Saiatu berriro",
"backup_manual_success": "Arrakastatsua",
"backup_manual_title": "Igoera egoera",
+ "backup_options": "Segurtasun-kopien ezarpenak",
"backup_options_page_title": "Babes-kopia ezarpenak",
+ "backup_setting_subtitle": "Kudeatu atzeko planoko eta lehen planoko kargatzeko ezarpenak",
+ "backup_settings_subtitle": "Kudeatu karga-ezarpenak",
+ "backup_upload_details_page_more_details": "Sakatu xehetasun gehiago lortzeko",
"backward": "Atzeruntz",
+ "battery_optimization_backup_reliability": "Bateriaren optimizazioak desgaitzeak atzeko planoko babeskopien fidagarritasuna hobetu dezake",
+ "biometric_auth_enabled": "Autentifikazio biometrikoa gaituta",
+ "biometric_locked_out": "Autentifikazio biometrikotik kanpo geratu zara",
+ "biometric_no_options": "Ez dago aukera biometrikorik eskuragarri",
+ "biometric_not_available": "Gailu honetan ez dago erabilgarri autentifikazio biometrikoa",
+ "birthdate_saved": "Jaiotze-data ongi gorde da",
+ "birthdate_set_description": "Jaiotze-data argazki baten unean pertsona horren adina kalkulatzeko erabiltzen da.",
+ "blurred_background": "Atzeko plano lausoa",
+ "browse_templates": "Arakatu txantiloiak",
+ "bugs_and_feature_requests": "Akatsak eta ezaugarri-eskaerak",
"build": "Bertsioa",
+ "build_image": "Konpilazio irudia",
+ "bulk_delete_duplicates_confirmation": "Ziur zaude {count, plural, one {bikoiztutako baliabide bat ezabatu nahi duzula} other {bikoiztutako # baliabide ezabatu nahi dituzula}}? Honek talde bakoitzaren baliabiderik handiena gordeko du eta betiko ezabatuko ditu gainerako bikoiztuak. Ezin duzu ekintza hau desegin!",
+ "bulk_keep_duplicates_confirmation": "Ziur zaude {count, plural, one {bikoiztutako baliabide bat mantendu nahi duzula} other {bikoiztutako # baliabide mantendu nahi dituzula}}? Horrek bikoiztutako talde guztiak konponduko ditu ezer ezabatu gabe.",
+ "bulk_trash_duplicates_confirmation": "Ziur zaude {count, plural, one {bikoiztutako baliabide bat zakarrontzira bildu nahi duzula} other {bikoiztutako # baliabide zakarrontzira bildu nahi dituzula}}? Honek talde bakoitzaren aktibo handiena gordeko du eta gainerako bikoiztu guztiak zakarrontzira eramango ditu.",
+ "buy": "Immich erosi",
"cache_settings_clear_cache_button": "Cache-memoria garbitu",
+ "cache_settings_clear_cache_button_title": "Aplikazioaren cachea garbitzen du. Horrek eragin handia izango du aplikazioaren errendimenduan, cachea berreraiki arte.",
"cache_settings_duplicated_assets_clear_button": "GARBITU",
+ "cache_settings_duplicated_assets_subtitle": "Aplikazioak aintzat hartzen ez dituen argazkiak eta bideoak",
+ "cache_settings_duplicated_assets_title": "Bikoiztutako baliabideak ({count})",
"cache_settings_statistics_album": "Liburutegiaren miniaturak",
"cache_settings_statistics_full": "Tamainu osoko irudiak",
+ "cache_settings_statistics_shared": "Partekatutako albumen miniaturak",
"cache_settings_statistics_thumbnail": "Miniatura",
"cache_settings_statistics_title": "Cache-memoria erabilera",
+ "cache_settings_subtitle": "Kontrolatu Immich mugikorreko aplikazioaren cachearen portaera",
+ "cache_settings_tile_subtitle": "Kontrolatu tokiko biltegiratze portaera",
"cache_settings_tile_title": "Memoria lokala",
"cache_settings_title": "Cache-memoria ezarpenak",
"camera": "Kamera",
+ "camera_brand": "Kamera fabrikatzailea",
+ "camera_model": "Kamera modeloa",
"cancel": "Ezeztatu",
+ "cancel_search": "Bilaketa ezeztatu",
"canceled": "Ezeztatua",
"canceling": "Desgaitzen",
+ "cannot_merge_people": "Ezin izan dira pertsonak batu",
+ "cannot_undo_this_action": "Ezin duzu ekintza hau desegin!",
+ "cannot_update_the_description": "Ezin izan da deskribapena eguneratu",
"cast": "Transmititu",
+ "cast_description": "Konfiguratu eskuragarri dauden igorpen-helmugak",
+ "change": "Aldatu",
+ "change_date": "Data aldatu",
+ "change_description": "Deskribapena aldatu",
+ "change_display_order": "Bistaratzeko ordena aldatu",
+ "change_expiration_time": "Iraungitze denbora aldatu",
+ "change_location": "Kokapena aldatu",
+ "change_name": "Izena eguneratu",
+ "change_name_successfully": "Izena arrakastaz eguneratuta",
+ "change_password": "Pasahitza eguneratu",
+ "change_password_description": "Hau da sisteman saioa hasten duzun lehen aldia edo pasahitza aldatzeko eskaera egin den. Mesedez, sartu pasahitz berria behean.",
"change_password_form_confirm_password": "Pasahitza baieztu",
+ "change_password_form_description": "Kaixo {name},\n\nHau da sisteman saioa hasten duzun lehen aldia edo pasahitza aldatzeko eskaera egin den. Mesedez, sartu pasahitz berria behean.",
+ "change_password_form_log_out": "Amaitu saioa gainerako gailu guztietan",
+ "change_password_form_log_out_description": "Beste gailu guztietan saioa amaitzea gomendatzen da",
"change_password_form_new_password": "Pasahitza berria",
+ "change_password_form_password_mismatch": "Pasahitzak ez datoz bat",
+ "change_password_form_reenter_new_password": "Sartu berriro pasahitz berria",
+ "change_pin_code": "PIN kodea eguneratu",
+ "change_trigger": "Abiarazlea aldatu",
+ "change_trigger_prompt": "Ziur abiarazlea aldatu nahi duzula? Horrek lehendik dauden ekintza eta iragazki guztiak kenduko ditu.",
+ "change_your_password": "Eguneratu zure pasahitza",
+ "changed_visibility_successfully": "Ikusgarritasuna arrakastaz aldatuta",
+ "charging": "Kargatzen",
+ "charging_requirement_mobile_backup": "Atzeko planoko segurtasun-kopia sortzeko gailua kargatzen egon behar du",
+ "check_corrupt_asset_backup": "Egiaztatu hondatuta dauden baliabideen segurtasun-kopiak",
"check_corrupt_asset_backup_button": "Egiaztapena burutu",
+ "check_corrupt_asset_backup_description": "Exekutatu egiaztapen hau Wi-Fi bidez soilik eta baliabide guztien segurtasun-kopia egin ondoren. Prozedurak minutu batzuk iraun ditzake.",
+ "check_logs": "Erregistroak egiaztatu",
+ "checksum": "Egiaztapeneko batura",
+ "choose": "Aukeratu",
+ "choose_matching_people_to_merge": "Aukeratu pertsona beraren agerraldi bikoiztuak bateratzeko",
"city": "Hiria",
+ "cleanup_confirm_description": "Immich-ek zerbitzarian kargatuta {date} baino lehenago sortutako {count, plural, one {baliabide bat aurkitu du} other {# baliabide aurkitu ditu}}. Gailu honetatik tokiko kopiak kendu nahi dituzu?",
+ "cleanup_confirm_prompt_title": "Gailu honetatik kendu?",
+ "cleanup_deleted_assets": "{count, plural, one {baliabide bat eraman da} other {# baliabide eraman dira}} gailuaren zakarrontzira",
+ "cleanup_deleting": "Zakarrontzira eramaten...",
+ "cleanup_found_assets": "Babeskopia egin {count, plural, one {duen baliabide bat aurkitu da} other {duten # baliabide aurkitu dira}}",
+ "cleanup_found_assets_with_size": "Babeskopia egin {count, plural, one {duen baliabide bat aurkitu da} other {duten # baliabide aurkitu dira}} ({size})",
+ "cleanup_icloud_shared_albums_excluded": "iCloudeko partekatutako albumak eskaneotik kanpo geratzen dira",
+ "cleanup_no_assets_found": "Ez da aurkitu goiko irizpideekin bat datorren baliabiderik. Biltegiratze garbitzaileak zerbitzarian babeskopia duten baliabideak soilik kendu ditzake",
+ "cleanup_preview_title": "Kendu beharreko aktiboak ({count})",
+ "cleanup_step3_description": "Bilatu zure datarekin bat datozen babeskopiak dituzten baliabideak eta gorde ezarpenak.",
+ "cleanup_step4_summary": "{date} baino lehenagoko {count, plural, one {baliabide bat} other {# baliabide}} zure gailutik kentzeko. Argazkiak Immich aplikaziotik eskuragarri egongo dira.",
+ "cleanup_trash_hint": "Biltegiratzeko lekua guztiz berreskuratzeko, ireki sistemaren galeria aplikazioa eta hustu zakarrontzia",
"clear": "Garbitu",
+ "clear_all": "Denak garbitu",
+ "clear_all_recent_searches": "Garbitu azken bilaketa guztiak",
+ "clear_failed_count": "{count, plural, one {Garbitetak huts egin du} other {# garbiketek huts egin dute}}",
+ "clear_file_cache": "Garbitu fitxategien cachea",
+ "clear_message": "Mezua garbitu",
+ "clear_value": "Balioa garbitu",
"client_cert_dialog_msg_confirm": "Ok",
"client_cert_enter_password": "Pasahitza sartu",
"client_cert_import": "Inportatu",
+ "client_cert_import_success_msg": "Bezeroaren ziurtagiria inportatu da",
+ "client_cert_invalid_msg": "Ziurtagiri fitxategi baliogabea edo pasahitz okerra",
+ "client_cert_password_message": "Sartu ziurtagiri honen pasahitza",
+ "client_cert_password_title": "Ziurtagiriaren pasahitza",
+ "client_cert_remove_msg": "Bezeroaren ziurtagiria kendu da",
+ "client_cert_subtitle": "PKCS12 (.p12, .pfx) formatua soilik onartzen du. Ziurtagiriaren inportazioa/kentzea saioa hasi aurretik bakarrik dago erabilgarri",
+ "client_cert_title": "SSL bezero-ziurtagiria [ESPERIMENTALA]",
"clockwise": "Erloju-orratzen noranzkoan",
"close": "Itxi",
"collapse": "Taldekatu",
+ "collapse_all": "Dena tolestu",
"color": "Kolorea",
+ "color_theme": "Koloreen gaia",
+ "command": "Agindua",
+ "command_palette_prompt": "Orriak, ekintzak edo komandoak azkar aurkitu",
+ "command_palette_to_close": "ixteko",
+ "command_palette_to_navigate": "sartzeko",
+ "command_palette_to_select": "hautatzeko",
+ "command_palette_to_show_all": "dena erakusteko",
+ "comment_deleted": "Iruzkina ezabatuta",
+ "comment_options": "Iruzkinaren aukerak",
+ "comments_and_likes": "Iruzkinak eta gustokoak",
+ "comments_are_disabled": "Iruzkinak desgaituta daude",
+ "common_create_new_album": "Album berria sortu",
"completed": "Burututa",
+ "configuration": "Konfigurazioa",
"confirm": "Onartu",
+ "confirm_admin_password": "Administrari pasahitza baieztatu",
+ "confirm_delete_face": "Ziur zaude {name}-(r)en aurpegia baliabidetik kendu nahi duzula?",
+ "confirm_delete_shared_link": "Ziur zaude partekatutako esteka hau ezabatu nahi duzula?",
+ "confirm_keep_this_delete_others": "Pilako gainerako baliabide guztiak kenduko dira baliabide hau izan ezik. Ziur zaude jarraitu nahi duzula?",
+ "confirm_new_pin_code": "PIK gako berria baieztatu",
+ "confirm_password": "Pasahitza baieztatu",
+ "confirm_tag_face": "Aurpegi hau {name} gisa etiketatu nahi duzu?",
+ "confirm_tag_face_unnamed": "Aurpegi hau etiketatu nahi duzu?",
+ "connected_device": "Konektatutako gailua",
+ "connected_to": "Hona konektatuta",
"contain": "Egokitu",
"context": "Kontextua",
"continue": "Jarraitu",
+ "control_bottom_app_bar_add_tags": "Etiketak gehitu",
+ "control_bottom_app_bar_create_new_album": "Album berria sortu",
+ "control_bottom_app_bar_delete_from_immich": "Immich-etik ezabatu",
+ "control_bottom_app_bar_delete_from_local": "Gailutik ezabatu",
"control_bottom_app_bar_edit_location": "Kokapena eguneratu",
+ "control_bottom_app_bar_edit_time": "Data eta denbora eguneratu",
"control_bottom_app_bar_share_link": "Esteka partekatu",
- "control_bottom_app_bar_share_to": "Partekatu",
+ "control_bottom_app_bar_share_to": "Partekatu honekin",
+ "control_bottom_app_bar_trash_from_immich": "Zakarrontzira bidali",
+ "copied_image_to_clipboard": "Irudia arbelean kopiatu da .",
+ "copied_to_clipboard": "Kopiatu da arbelean!",
+ "copy_error": "Kopiatzerakoan errorea",
+ "copy_file_path": "Fitxategi bidea kopiatu",
+ "copy_image": "Irudia kopiatu",
+ "copy_json": "JSON kopiatu",
+ "copy_link": "Esteka kopiatu",
+ "copy_link_to_clipboard": "Esteka arbelera kopiatu",
+ "copy_password": "Pasahitza kopiatu",
+ "copy_to_clipboard": "Arbelera kopiatu",
"country": "Herrialdea",
"cover": "Portada",
"covers": "Portada",
"create": "Sortu",
+ "create_album": "Albuma sortu",
"create_album_page_untitled": "Izengabea",
+ "create_api_key": "API Gakoa sortu",
+ "create_first_workflow": "Lehenengo lan-fluxua sortu",
+ "create_library": "Liburutegia sortu",
+ "create_link": "Esteka sortu",
+ "create_link_to_share": "Partekatzeko esteka sortu",
+ "create_link_to_share_description": "Utzi esteka duen edonori aukeratutako argazkiak ikusten",
"create_new": "BERRIA SORTU",
+ "create_new_face": "Aurpegi berria sortu",
+ "create_new_person": "Pertsona berria sortu",
+ "create_new_person_hint": "Esleitu hautatutako baliabideak pertsona berri bati",
+ "create_new_user": "Sortu erabiltzaile berria",
+ "create_person": "Pertsona sortu",
+ "create_person_subtitle": "Gehitu izen bat hautatutako aurpegiari pertsona berria sortzeko eta etiketatzeko",
"create_shared_album_page_share_add_assets": "BALIABIDEAK GEHITU",
"create_shared_album_page_share_select_photos": "Argazkiak aukeratu",
+ "create_shared_link": "Sortu partekatutako esteka",
+ "create_tag": "Sortu etiketa",
+ "create_tag_description": "Sortu etiketa berri bat. Habiaratutako etiketetarako, idatzi etiketaren bide osoa, barrak barne.",
+ "create_user": "Sortu erabiltzailea",
+ "create_workflow": "Sortu lan-fluxua",
"created": "Sortuta",
"created_at": "Sortze-data",
+ "creating_linked_albums": "Lotutako albumak sortzen...",
"crop": "Ebaki",
+ "crop_aspect_ratio_fixed": "Finkoa",
+ "crop_aspect_ratio_free": "Askea",
+ "crop_aspect_ratio_original": "Originala",
+ "crop_aspect_ratio_square": "Laukia",
"curated_object_page_title": "Objektuak",
+ "current_device": "Gailu hau",
+ "current_pin_code": "Egungo PIN kodea",
+ "current_server_address": "Egungo zerbitzariaren helbidea",
+ "custom_date": "Data pertsonalizatua",
+ "custom_locale": "Lokalizazio pertsonalizatua",
+ "custom_locale_description": "Formateatu datak, orduak eta zenbakiak hautatutako hizkuntza eta eskualdearen arabera",
+ "custom_url": "URL pertsonalizatua",
+ "cutoff_date_description": "Mantendu epe honetan sartzen diren argazkiak…",
+ "cutoff_day": "{count, plural, one {egun} other {egun}}",
+ "cutoff_year": "{count, plural, one {urte} other {urte}}",
"dark": "Iluna",
+ "dark_theme": "Gai iluna gaitu",
+ "date": "Data",
+ "date_after": "Data hau baino berriago",
+ "date_and_time": "Data eta denbora",
+ "date_before": "Data hau baino zaharrago",
+ "date_of_birth": "Jaiotze-data",
+ "date_of_birth_saved": "Jaiotze-data arrakastaz gordeta",
+ "date_range": "Data tartea",
+ "date_time_original": "Data/Debora Originala",
"day": "Eguna",
"days": "Egunak",
+ "deduplicate_all": "Denak desbikoiztu",
+ "default_locale": "Lokalizazio lehentsia",
+ "default_locale_description": "Formateatu datak eta zenbakiak zure arakatzailearen lokalizazioan oinarrituta",
+ "default_quality_subtitle": "Partekatzerakoan erabiltzen den kalitatea. Luze sakatu partekatzeko botoia aldi bakoitzean aukeratzeko.",
+ "default_share_quality": "Partekatze-kalitate lehenetsia",
"delete": "Ezabatu",
+ "delete_action_confirmation_message": "Ziur zaude baliabide hau ezabatu nahi duzula? Ekintza honek baliabidea zerbitzariaren zakarrontzira eramango du eta lokalean ezabatu nahi duzun galdetuko dizu",
+ "delete_action_prompt": "{count} ezabatuta",
+ "delete_album": "Albuma ezabtu",
+ "delete_api_key_prompt": "Ziur zaude API gako hau ezabatu nahi duzula?",
+ "delete_dialog_alert": "Elementu hauek betiko ezabatuko dira Immich-etik eta zure gailutik",
+ "delete_dialog_alert_local": "Elementu hauek betiko kenduko dira zure gailutik, baina oraindik eskuragarri egongo dira Immich zerbitzarian",
+ "delete_dialog_alert_local_non_backed_up": "Elementu batzuen babeskopia ez dago Immich-en eta betiko kenduko dira zure gailutik",
+ "delete_dialog_alert_remote": "Elementu hauek betiko ezabatuko dira Immich zerbitzaritik",
"delete_dialog_ok_force": "Hala ere ezabatu",
"delete_dialog_title": "Behin betiko ezabatu",
+ "delete_duplicates_confirmation": "Ziur zaude bikoiztu hauek behin betiko ezabatu nahi dituzula?",
+ "delete_face": "Aurpegia ezabatu",
+ "delete_key": "Gakoa ezabatu",
+ "delete_library": "Liburutegia ezabatu",
+ "delete_link": "Esteka ezabatu",
+ "delete_local_action_prompt": "{count} gailutik ezabatuta",
+ "delete_local_dialog_ok_backed_up_only": "Ezabatu soilik segurtasun kopia duten baliabideak",
"delete_local_dialog_ok_force": "Hala ere ezabatu",
+ "delete_others": "Besteak ezabatu",
+ "delete_permanently": "Behin betiko ezabatu",
+ "delete_permanently_action_prompt": "{count} behin betiko ezabatuta",
+ "delete_shared_link": "Partekatutako esteka ezabatu",
+ "delete_shared_link_dialog_title": "Partekatutako esteka ezabatu",
+ "delete_tag": "Etiketa ezabatu",
+ "delete_tag_confirmation_prompt": "Ziur zaude {tagName} etiketa ezabatu nahi duzula?",
+ "delete_user": "Erabiltzailea ezabatu",
+ "deleted_shared_link": "Partekatutako esteka ezabatuta",
+ "deletes_missing_assets": "Ezabatu disko gogorrean falta diren baliabideak",
"description": "Deskribapena",
"description_input_hint_text": "Deskribapena ezarri…",
+ "description_input_submit_error": "Errore bat gertatu da deskribapena eguneratzean, begiratu xehetasunak ikusteko",
+ "deselect_all": "Deshautatu guztiak",
"details": "Xehetasunak",
"direction": "Norabidea",
+ "disable": "Desgaitu",
"disabled": "Desgaituta",
+ "disallow_edits": "Ez baimendu aldaketak",
"discord": "Discord",
"discover": "Aurkitu",
+ "discovered_devices": "Aurkitutako gailuak",
+ "dismiss_all_errors": "Errore guztiak baztertu",
+ "dismiss_error": "Errorea baztertu",
+ "display_options": "Bistaratzeko aukerak",
+ "display_order": "Bistaratzeko ordena",
+ "display_original_photos": "Erakutsi jatorrizko argazkiak",
+ "display_original_photos_setting_description": "Irudi bat ikustean, jatorrizko argazkia hobesten da miniaturaren ordez, jatorrizkoa web bateragarria bada. Baliteke argazkiak kargatzeko denbora gehiago behar izatea.",
+ "do_not_show_again": "Ez erakutsi mezu hau berriz",
"documentation": "Dokumentazioa",
"done": "Amaitu",
"download": "Deskargatu",
+ "download_action_prompt": "{count, plural, one {Baliabide bat} other {# baliabide}} deskargatzen",
"download_canceled": "Deskarga ezeztatuta",
"download_complete": "Deskarga burututa",
"download_enqueue": "Deskarga ilaran",
"download_error": "Akatsa deskargatzerakoan",
"download_failed": "Akatsa deskargatzerakoan",
"download_finished": "Deskarga burututa",
+ "download_include_embedded_motion_videos": "Txertaturiko bideoak",
+ "download_include_embedded_motion_videos_description": "Sartu argazki bizidunetan txertatutako bideoak fitxategi bereizi gisa",
+ "download_notfound": "Ez da deskarga aurkitu",
+ "download_original": "Jatorrizkoa deskargatu",
"download_paused": "Deskarga geldituta",
"download_settings": "Deskargak",
+ "download_settings_description": "Kudeatu baliabideak deskargatzearekin lotutako ezarpenak",
"download_started": "Deskarga hasieratua",
"download_sucess": "Deskarga arrakastatsua",
+ "download_sucess_android": "Multimedia DCIM/Immich-era deskargatu da",
+ "download_waiting_to_retry": "Berriro saiatzeko zain",
"downloading": "Deskargatzen",
+ "downloading_asset_filename": "{filename} baliabidea deskargatzen",
+ "downloading_from_icloud": "iCloud-etik deskargatzen",
"downloading_media": "Baliabideak deskargatzen",
+ "drag_to_reorder": "Arrastatu berrantolatzeko",
+ "drop_files_to_upload": "Jaregin fitxategiak edonon kargatzeko",
+ "duplicate": "Kopia egin",
+ "duplicate_workflow": "Lan-fluxuaren kopia sortu",
"duplicates": "Kopiak",
+ "duplicates_description": "Ebatzi talde bakoitza, bikoiztuak dauden adieraziz.",
"duration": "Iraupena",
"edit": "Editatu",
+ "edit_album": "Albuma editatu",
+ "edit_avatar": "Abatarra editatu",
+ "edit_birthday": "Urtebetetze-eguna editatu",
+ "edit_date": "Data editatu",
+ "edit_date_and_time": "Data eta ordua editatu",
+ "edit_date_and_time_action_prompt": "{count, plural, one {Datu eta ordua eguneratu da} other {# datu eta ordu eguneratu dira}}",
+ "edit_date_and_time_by_offset": "Aldatu data desplazamendu bat erabiliz",
+ "edit_date_and_time_by_offset_interval": "Data-tarte berria: {from} - {to}",
+ "edit_description": "Deskribapena editatu",
+ "edit_description_prompt": "Mesedez aukeratu deskribapen berri bat:",
+ "edit_exclusion_pattern": "Editatu bazterketa eredua",
+ "edit_faces": "Aurpegiak kudeatu",
+ "edit_key": "Gakoa editatu",
+ "edit_link": "Esteka editatu",
+ "edit_location": "Kokapena editatu",
+ "edit_location_action_prompt": "{count, plural, one {Kokapena eguneratuta} other {# kokapen eguneratuta}}",
"edit_location_dialog_title": "Kokapena",
+ "edit_name": "Izena editatu",
+ "edit_people": "Pertsonak editatu",
+ "edit_tag": "Etiketa editatu",
+ "edit_title": "Izenburua editatu",
+ "edit_user": "Erabiltzailea editatu",
+ "edit_workflow": "Lan-fluxua editatu",
"editor": "Editorea",
+ "editor_close_without_save_prompt": "Aldaketak ez dira gordeko",
+ "editor_close_without_save_title": "Editorea itxi?",
+ "editor_confirm_reset_all_changes": "Ziur zaude aldaketa guztiak berrezarri nahi dituzula?",
+ "editor_discard_edits_confirm": "Aldaketak baztertu",
+ "editor_discard_edits_prompt": "Gorde gabeko aldaketak dituzu. Ziur baztertu nahi dituzula?",
+ "editor_discard_edits_title": "Aldaketak baztertu?",
+ "editor_edits_applied_error": "Ezin izan dira aldaketak aplikatu",
+ "editor_edits_applied_success": "Aldaketak arrakastaz aplikatuak",
+ "editor_flip_horizontal": "Horizontalki islatu",
+ "editor_flip_vertical": "Bertikalki islatu",
+ "editor_handle_corner": "{corner, select, top_left {Goiko ezkerreko} top_right {Goiko eskuineko} bottom_left {Beheko ezkerreko} bottom_right {Beheko eskuineko} other {Izkinako} } kontrolatzailea",
+ "editor_handle_edge": "{edge, select, top {Goiko} bottom {Beheko} left {Ezkerreko} right {Eskuineko} other {Ertzeko} } kontrolatzailea",
+ "editor_orientation": "Orientazioa",
+ "editor_reset_all_changes": "Aldaketak berrezarri",
+ "editor_rotate_left": "Biratu 90º erlojuaren kontra",
+ "editor_rotate_right": "Biratu 90º erlojuaren alde",
"email": "E-mail",
+ "email_notifications": "E-mail jakinarazpenak",
+ "empty_folder": "Karpeta hau hutsik dago",
+ "empty_trash": "Zakarrontzia hustu",
+ "empty_trash_confirmation": "Ziur zaude zakarrontzia hustu nahi duzula? Horrela, zakarrontziko baliabide guztiak behin betiko ezabatuko dira Immich-etik.\nEzin duzu ekintza hau desegin!",
"enable": "Gaitu",
+ "enable_backup": "Babeskopia gaitu",
+ "enable_biometric_auth_description": "Sartu zure PIN kodea autentifikazio biometrikoa gaitzeko",
"enabled": "Gaituta",
+ "end_date": "Amaiera data",
"enqueued": "Ilaran gehituta",
+ "enter_wifi_name": "Sartu Wi-Fi izena",
+ "enter_your_pin_code": "Sartu zure PIN kodea",
+ "enter_your_pin_code_subtitle": "Sartu zure PIN kodea blokeatutako karpetara sartzeko",
"error": "Akatsa",
+ "error_change_sort_album": "Ezin izan da albumen ordenaketa aldatu",
+ "error_delete_face": "Ezin izan da aurpegia baliabidetik ezabatu",
+ "error_getting_places": "Ezin izan dira tokiak jaso",
+ "error_loading_albums": "Ezin izan dira albumak kargatu",
+ "error_loading_image": "Ezin izan da argazkia kargatu",
+ "error_loading_partners": "Ezin izan dira kideak kargatu: {error}",
+ "error_retrieving_asset_information": "Ezin izan da baliabidearen informazioa berreskuratu",
"error_saving_image": "Akatsa: {error}",
+ "error_tag_face_bounding_box": "Ezin izan da irudia etiketatu - ezin dira marko koordenatuak lortu",
+ "error_title": "Akatsa - Zerbaitek huts egin du",
+ "error_while_navigating": "Ezin izan da baliabidera nabigatu",
+ "errors": {
+ "cannot_navigate_next_asset": "Ezin duzu hurrengo baliabidera nabigatu",
+ "cannot_navigate_previous_asset": "Ezin duzu aurreko baliabidera nabigatu",
+ "cant_apply_changes": "Ezin dira aldaketak aplikatu",
+ "cant_change_activity": "Ezin izan da jarduera {enabled, select, true {desaktibatu} other {aktibatu}}",
+ "cant_change_asset_favorite": "Ezin izan da gogokoa aldatu baliabide honetan",
+ "cant_change_metadata_assets_count": "Ezin izan da {count, plural, one {baliabidearen} other {# baliabideren}} metadatuak aldatu",
+ "cant_get_faces": "Ezin izan dira aurpegiak jaso",
+ "cant_get_number_of_comments": "Ezin izan da iruzkin kopurua jaso",
+ "cant_search_people": "Ezin izan dira pertsonak bilatu",
+ "cant_search_places": "Ezin izan dira tokiak bilatu",
+ "error_adding_assets_to_album": "Ezin izan dira baliabideak albumean sartu",
+ "error_adding_users_to_album": "Ezin izan dira erabiltzaileak albumean sartu",
+ "error_deleting_shared_user": "Ezin izan da partekatutako erabiltzailea ezabatu",
+ "error_downloading": "Ezin izan da {filename} deskargatu",
+ "error_hiding_buy_button": "Ezin izan da erosi botoia ezkutatu",
+ "error_removing_assets_from_album": "Errore bat gertatu da albumetik baliabideak ezabatzean; ikus kontsola xehetasunetarako",
+ "error_selecting_all_assets": "Ezin izan dira baliabide guztiak hautatu",
+ "exclusion_pattern_already_exists": "Bazterketa eradu hau iada existitzen da.",
+ "failed_to_create_album": "Ezin izan da albuma sortu",
+ "failed_to_create_shared_link": "Ezin izan da partekatutako esteka sortu",
+ "failed_to_edit_shared_link": "Ezin izan da partekatutako esteka editatu",
+ "failed_to_get_people": "Ezin izan dira pertsonak jaso",
+ "failed_to_keep_this_delete_others": "Ezin izan da baliabide hau gorde eta besteak ezabatu",
+ "failed_to_load_asset": "Ezin izan da baliabidea kargatu",
+ "failed_to_load_assets": "Ezin izan dira baliabideak kargatu",
+ "failed_to_load_notifications": "Ezin izan dira jakinarazpenak jaso",
+ "failed_to_load_people": "Ezin izan dira pertsonak kargatu",
+ "failed_to_remove_product_key": "Ezin izan da produktu gakoa ezabatu",
+ "failed_to_reset_pin_code": "Ezin izan da PIN gakoa berrezarri",
+ "failed_to_stack_assets": "Ezin izan dira baliabideak multzokatu",
+ "failed_to_tag_assets": "Ezin izan dira baliabideak etiketatu",
+ "failed_to_unstack_assets": "Ezin izan dira baliabideak desmultzokatu",
+ "failed_to_update_notification_status": "Errore bat gertatu da jakinarazpen-egoera eguneratzean",
+ "incorrect_email_or_password": "Pasahitz edo e-mail okerra",
+ "library_folder_already_exists": "Inportazio bide hau jada existitzen da.",
+ "page_not_found": "Ez da orria aurkitu",
+ "paths_validation_failed": "{paths, plural, one {Bideak} other {# bidek}} baliozkotzean huts egin {paths, plural, one {du} other {dute}}",
+ "profile_picture_transparent_pixels": "Profileko irudiek ezin du pixel gardenik izan. Mesedez, handitu eta/edo mugitu irudia.",
+ "quota_higher_than_disk_size": "Diskoaren tamaina baino kuota handiagoa ezarri da",
+ "something_went_wrong": "Zerbait gaizki joan da",
+ "unable_to_add_album_users": "Ezin izan dira erabiltzaileak albumean gehitu",
+ "unable_to_add_assets_to_shared_link": "Ezin dira baliabideak partekatutako estekan gehitu",
+ "unable_to_add_comment": "Ezin izan da iruzkina gehitu",
+ "unable_to_add_exclusion_pattern": "Ezin izan da bazterketa eredua gehitu",
+ "unable_to_add_partners": "Ezin izan dira kideak gehitu",
+ "unable_to_add_remove_archive": "Ezin izan da baliabidea {archived, select, true {artxibategitik kendu} other {artxibatu}}"
+ },
+ "errors_text": "Akatsak",
"exif": "Exif",
"exif_bottom_sheet_description": "Deskribapena ezarri…",
+ "exif_bottom_sheet_description_error": "Ezin izan da deskribapena eguneratu",
"exif_bottom_sheet_details": "XEHETASUNAK",
"exif_bottom_sheet_location": "KOKAPENA",
"exif_bottom_sheet_people": "PERTSONAK",
"exif_bottom_sheet_person_add_person": "Izena gehitu",
+ "expand": "Zabaldu",
+ "experimental_settings_new_asset_list_subtitle": "Zirriborra garapenean",
"experimental_settings_title": "Esperimental",
"expired": "Iraungita",
- "explore": "Bilatu",
- "explorer": "Bilatzailea",
+ "explore": "Arakatu",
+ "explorer": "Arakatzailea",
"export": "Esportatu",
"extension": "Hedapena",
"external": "Kanpokoa",
"external_network": "Kanpoko sarea",
"face_unassigned": "Ezarri gabea",
"failed": "Akatsduna",
+ "failed_to_authenticate": "Ezin izan da autentifikatu",
"favorite": "Gogokoa",
"favorites": "Gogokoenak",
"features": "Ezaugarriak",
+ "features_in_development": "Ezaugarriak garapen prozesuan",
"filename": "Fitxategia",
"filetype": "Fitxategi mota",
"filter": "Iragazkia",
+ "filter_places": "Tokiak iragazi",
"first": "Lehenengo «Lehenik»",
"folder": "Karpeta",
+ "folder_not_found": "Ez da karpeta aurkitu",
"folders": "Karpetak",
+ "forgot_pin_code_question": "PIN kodea ahaztu al duzu?",
"forward": "Aurreruntz",
+ "free_up_space": "Biltegiratze garbitzailea",
+ "full_path": "Bide osoa: {path}",
"general": "General",
+ "get_people_error": "Ezin izan da pertsonarik jaso",
"gps": "GPS",
"gps_missing": "Ez dago GPS",
"grant_permission": "Baimendu",
+ "group_owner": "Jabearen arabera multzokatu",
+ "group_places_by": "Lekuan honen arabera multzokatu...",
+ "group_year": "Urtearen arabera multzokatu",
+ "haptic_feedback_switch": "Ikumen-feedback-a gaitu",
"haptic_feedback_title": "Ukipen-feedbacka",
"hashing": "Hasha sortzen",
"header_settings_add_header_tip": "Goiburua gehitu",
"header_settings_header_name_input": "Goiburu izena",
"header_settings_header_value_input": "Goiburu balioa",
- "host": "Host",
+ "headers_settings_tile_title": "Proxy-goiburu pertsonalizatuak",
+ "hi_user": "Kaixo {name} ({email})",
+ "hide_all_people": "Pertsona guztiak ezkutatu",
+ "hide_named_person": "{name} pertsona ezkutatu",
+ "hide_text_recognition": "Testu-ezagutza ezkutatu",
+ "hide_unnamed_people": "Izengabeko pertsonak ezkutatu",
+ "home_page_building_timeline": "Denbora-lerroa sortzen",
+ "host": "Ostalaria",
"hour": "Ordua",
"hours": "Orduak",
"id": "ID",
"idle": "Jarduerarik gabe",
+ "ignore_icloud_photos": "iCloud argazkiak baztertu",
"image": "Irudia",
"image_saved_successfully": "Irudia gordeta",
"image_viewer_page_state_provider_download_started": "Deskarga hasieratua",
"image_viewer_page_state_provider_download_success": "Deskarga arrakastatsua",
+ "image_viewer_page_state_provider_share_error": "Share akatsa",
+ "immich_web_interface": "Immich Web interfazea",
+ "import_from_json": "JSON-etik inportatu",
+ "in_year_selector": "Urtea",
+ "include_shared_albums": "Partekatutako albumak barne hartu",
"info": "Informazioa",
+ "invalid_date": "Data okerra",
+ "invalid_date_format": "Datu formatu okerra",
+ "invite_to_album": "Albumera gonbidatu",
+ "ios_debug_info_fetch_ran_at": "Bilaketa exekutatu da {dateTime}",
+ "ios_debug_info_last_sync_at": "Azken sinkronizazioa {dateTime}",
+ "ios_debug_info_processing_ran_at": "Prozesatzea exekutatu da {dateTime}",
"jobs": "Atazak",
"keep": "Mantendu",
"language": "Hizkuntza",
+ "language_no_results_title": "Ez da hizkuntzarik aurkitu",
"last": "Azkena",
"latitude": "Latitudea",
"leave": "Bertan behera utzi",
+ "less": "Gutxiago",
+ "let_others_respond": "Baimendu beste erabiltzaileak erantzutea",
"level": "Maila",
"library": "Liburutegia",
+ "library_page_device_albums": "Albumak gailuan",
+ "library_page_new_album": "Album berria",
+ "library_page_sort_asset_count": "Baliabide kopurua",
+ "library_page_sort_created": "Duela gutxi sortuta",
+ "library_page_sort_last_modified": "Duela gutxi aldatuta",
+ "library_page_sort_title": "Izenburuaren arabera",
"licenses": "Lizentziak",
"light": "Argia",
"like": "Gustoko",
+ "link": "Esteka",
+ "link_motion_video": "Estekatu bideo biziduna",
+ "link_to_oauth": "OAuth-era esteka",
+ "linked_oauth_account": "OAuth kontua lotuta",
"list": "Zerrenda",
"loading": "Kargatzen",
"local": "Lokal",
+ "local_media_summary": "Bertako multimedien laburpena",
+ "local_network": "Bertako sarea",
+ "location": "Kokapena",
+ "location_permission": "Kokapen baimena",
+ "location_picker_choose_on_map": "Mapan aukeratu",
"lock": "Blokeatu",
+ "logged_out_device": "Gailua deskonektatua",
"login": "Saioa hasi",
"login_form_back_button_text": "Atzera",
"login_form_email_hint": "zure@emaila.com",
"login_form_endpoint_hint": "http://zerbitzariaren-ip-a:portua",
+ "login_form_endpoint_url": "Zerbitzariaren URL endpoint-a",
+ "login_form_err_invalid_email": "E-mail okerra",
+ "login_form_err_invalid_url": "URL okerra",
+ "login_form_err_leading_whitespace": "Zuriunea hasieran",
+ "login_form_err_trailing_whitespace": "Zuriunea amaieran",
"login_form_password_hint": "pasahitza",
+ "login_form_save_login": "Saioa mantendu",
+ "login_password_changed_success": "Pasahitza arrakastaz eguneratu",
"logs": "Erregistroak",
"longitude": "Longitudea",
"look": "Itxura",
"main_menu": "Menu nagusia",
+ "maintenance_end": "Mantentze modua itxi",
+ "maintenance_restore_from_backup": "Segurtasun-kopiatik berrezarri",
+ "maintenance_restore_library": "Zure liburutegia berrezarri",
+ "maintenance_restore_library_folder_pass": "Irakurgarria eta idazgarria",
+ "maintenance_task_migrations": "Datu-basearen migrazioak exekutatzen",
"make": "Marka",
"manage_geolocation": "Kudeatu kokapena",
+ "manage_media_access_title": "Multimedia sarbidea kudeatu",
+ "manage_shared_links": "Partekatutako estekak kudeatu",
+ "manage_your_account": "Zure kontua kudeatu",
"map": "Mapa",
"map_location_dialog_yes": "Bai",
+ "map_location_picker_page_use_location": "Kokapen hau erabili",
+ "map_location_service_disabled_title": "Kokapen zerbitzua desgaitua",
+ "map_no_location_permission_title": "Kokapen baimena ukatuta",
+ "map_settings_dark_mode": "Gai iluna",
+ "map_settings_date_range_option_day": "Azken 24 orduak",
+ "map_settings_date_range_option_days": "Azken {days} egunak",
+ "map_settings_date_range_option_year": "Iaz",
+ "map_settings_date_range_option_years": "Past {years} urteak",
+ "map_settings_dialog_title": "Mapa ezarpenak",
+ "map_settings_include_show_archived": "Artxibatuak barne",
+ "map_settings_include_show_partners": "Kideak barne",
+ "map_settings_only_show_favorites": "Gogokoak soilik erakutsi",
+ "map_settings_theme_settings": "Maparen gaia",
+ "mark_as_read": "Markatu irakurritako gisa",
"matches": "Bat etorritakoak",
+ "media_chrome": {
+ "auto": "Auto",
+ "captions": "Azpitituluak",
+ "captions_off": "Desgaituta",
+ "loop": "Bulkea",
+ "mute": "Isilarazi"
+ },
+ "media_type": "Multimedia mota",
"memories": "Gogorapenak",
+ "memories_all_caught_up": "Egunean zaude",
+ "memories_start_over": "Berriro hasi",
"memory": "Gogorapena",
+ "memory_lane_title": "Gogorapen kutxa {title}",
"menu": "Menua",
"merge": "Batu",
+ "merge_people": "Pertsonak batu",
+ "merge_people_successfully": "Pertsonak arrakastaz batuta",
"minimize": "Txikitu",
"minute": "Minutua",
"minutes": "Minutuak",
+ "mirror_horizontal": "Horizontala",
+ "mirror_vertical": "Bertikala",
"missing": "Hutsegiteak",
"model": "Modeloa",
"month": "Hilabetea",
"more": "Gehiago",
"move": "Mugitu",
+ "moved_to_trash": "Zakarrontzira eraman da",
+ "mute_memories": "Gogorapenak isilarazi",
+ "my_albums": "Nire albumak",
"name": "Izena",
+ "name_or_nickname": "Izena edo ezizena",
+ "name_required": "Izena derrigorrezkoa da",
+ "navigate": "Nabigatu",
+ "navigate_to_time": "Denborara nabigatu",
"networking_settings": "Sarea",
"never": "Inoiz ez",
+ "new_album": "Album berria",
+ "new_api_key": "API gako berria",
+ "new_date_range": "Data tarte berria",
+ "new_password": "Pasahitz berria",
+ "new_person": "Pertsona berria",
+ "new_pin_code": "PIN gako berria",
+ "new_user_created": "Erabiltzaile berria sortuta",
+ "new_version_available": "BERTSIO BERRIA ESKURAGARRI",
+ "newest_first": "Berriena lehenen",
"next": "Hurrengoa",
+ "next_memory": "Hurrengo gogorapena",
"no": "Ez",
+ "no_configuration_needed": "Ez da ezarpenik behar",
+ "no_devices": "Baimendutako gailurik ez",
+ "no_location_set": "Kokapena ezarri gabe",
+ "no_name": "Izenik ez",
+ "no_places": "Tokirik ez",
+ "no_results": "Emaitzarik ez",
+ "none": "Bat ere ez",
+ "not_selected": "Hautatu gabe",
"notes": "Oharra",
+ "nothing_here_yet": "Momentuz hutsik",
+ "notification_permission_list_tile_enable_button": "Jakinarazpenak gaitu",
+ "notification_permission_list_tile_title": "Jakinarazpen baimena",
+ "notification_toggle_setting_description": "E-mail jakinarazpenak gaitu",
"notifications": "Jakinarazpenak",
+ "notifications_setting_description": "Jakinarazpenak kudeatu",
"oauth": "OAuth",
+ "ocr": "OCR",
+ "official_immich_resources": "Immich-en baliabide ofizialak",
"offline": "Lineaz kanpo",
"offset": "Desbiderapena",
"ok": "Bai",
+ "oldest_first": "Zaharrena lehenengo",
+ "on_this_device": "Gailu honetan",
"onboarding": "Ezartzen",
+ "onboarding_welcome_user": "Ongi etorri, {user}",
"online": "Linean",
+ "only_favorites": "Gogokoak soilik",
"open": "Zabalik",
+ "open_in_openstreetmap": "OpenStreetMap-en zabaldu",
"options": "Ezarpenak",
"or": "edo",
"organize_into_albums": "Albumetan antolatu",
+ "organize_your_library": "Zure liburutegia antolatu",
"original": "Originala",
"other": "Beste batzuk",
+ "other_devices": "Beste gailuak",
+ "other_variables": "Beste aldagaiak",
"owned": "Berezkoak",
"owner": "Jabea",
"partner": "Kidea",
+ "partner_can_access": "{partner}-ek sarbidea du",
+ "partner_list_user_photos": "{user}-(r)en argazkiak",
+ "partner_list_view_all": "Denak ikusi",
+ "partner_page_select_partner": "Kidea hautatu",
+ "partner_page_shared_to_title": "Honekin partekatuta",
+ "partner_sharing": "Kideekin partekatu",
"partners": "Kideak",
"password": "Pasahitza",
+ "password_required": "Pasahitza derrigorrezkoa da",
+ "password_reset_success": "Pasahitz eguneraketa arrakaztatsua",
"path": "Bidea",
"pattern": "Patroia",
"pause": "Gelditu",
+ "pause_memories": "Gogorapenak gelditu",
"paused": "Geldituta",
"pending": "Itxarotzen",
"people": "Pertsonak",
+ "permanent_deletion_warning": "Behin betiko ezabaketa oharra",
+ "permanently_delete": "Behin betiko ezabatu",
+ "permanently_deleted_asset": "Baliabidea behin betiko ezabatuta",
"permission": "Baimena",
"permission_onboarding_back": "Atzera",
+ "permission_onboarding_continue_anyway": "Halaere jarraitu",
+ "permission_onboarding_get_started": "Hasi",
+ "permission_onboarding_go_to_settings": "Jo ezarpenetara",
"person": "Pertsona",
+ "person_birthdate": "{date} -(a)n jaiota",
"photos": "Argazkiak",
+ "photos_and_videos": "Argazkiak eta bideoak",
+ "pick_a_location": "Toki bat aukeratu",
+ "pin_verification": "PIN kodearen egiaztapena",
"place": "Tokia",
"places": "Tokiak",
"play": "Erreproduzitu",
+ "play_memories": "Gogorapenak erreproduzitu",
+ "play_motion_photo": "Argazki biziduna erreproduzitu",
+ "play_original_video": "Jatorrizko bideoa erreproduzitu",
+ "play_transcoded_video": "Transkodetutako bideoa erreproduzitu",
"port": "Portua",
"preferences_settings_title": "Ezarpenak",
+ "preparing": "Prestatzen",
"preset": "Txantiloia",
"preview": "Aurrebista",
"previous": "Aurrekoa",
+ "previous_memory": "Aurreko gogorapena",
+ "previous_or_next_photo": "Aurreko/hurrengo irudia",
"primary": "Nagusia",
"privacy": "Pribatutasuna",
"profile": "Profila",
"profile_drawer_app_logs": "Erregistroak",
"profile_drawer_github": "GitHub",
- "purchase_account_info": "Laguntzaile",
+ "profile_picture_set": "Profil-argazkia ezarrita.",
+ "public_album": "Album publikoa",
+ "public_share": "Share publikoa",
+ "purchase_account_info": "Babeslea",
+ "purchase_activated_time": "{date}-(a)n aktibatuta",
"purchase_button_activate": "Aktibatu",
"purchase_button_buy": "Erosi",
+ "purchase_button_buy_immich": "Immich erosi",
+ "purchase_button_never_show_again": "Ez erakutsi berriz",
+ "purchase_button_remove_key": "Gakoa kendu",
"purchase_button_select": "Aukeratu",
+ "purchase_individual_description_1": "Erabiltzaile batentzako",
+ "purchase_individual_description_2": "Babesle ikurra",
"purchase_individual_title": "Banakakoa",
+ "purchase_lifetime_description": "Bizitza osoko ordainketa",
+ "purchase_option_title": "ORDAINKETA AUKERAK",
+ "purchase_panel_title": "Proiektua babestu",
+ "purchase_per_server": "Zerbitzari bakoitzeko",
+ "purchase_per_user": "Erabiltzaile bakoitzeko",
+ "purchase_remove_product_key": "Produktu gakoa ezabatu",
+ "purchase_server_description_2": "Babesle ikurra",
"purchase_server_title": "Zerbitzaria",
"query_asset_id": "Aztertu aukeratutako ID-a",
+ "rating": "Izar puntuazioa",
+ "rating_clear": "Puntuazioa ezabatu",
+ "reaction_options": "Erreakzio aukerak",
+ "read_changelog": "Aldaketa erregistroa irakurri",
"readonly_mode_disabled": "Irakurri-bakarrik modua desgaituta",
"readonly_mode_enabled": "Irakurri-bakarrik modua gaituta",
+ "ready_for_upload": "Kargatzeko prest",
"reassign": "Berrezarri",
"recent": "Berria",
+ "recent_searches": "Duela gutxiko bilaketak",
+ "recently_added": "Duela gutxi gehitutakoak",
+ "recently_added_page_title": "Duela gutxi gehitutakoak",
+ "recently_taken": "Duela gutxi ateratakoak",
"refresh": "Freskatu",
+ "refresh_encoded_videos": "Kodetutako bideoak freskatu",
+ "refresh_faces": "Aurpegiak freskatu",
+ "refresh_metadata": "Metadatuak freskatu",
+ "refresh_thumbnails": "Miniaturak freskatu",
"refreshed": "Freskatuta",
+ "refreshing_encoded_video": "Kodetutako bideoak freskatzen",
+ "refreshing_faces": "Aurpegiak freskatzen",
+ "refreshing_metadata": "Metadatuak freskatzen",
+ "regenerating_thumbnails": "Miniaturak leheneratu",
"remote": "Urruneko zerbitzaria",
+ "remote_media_summary": "Kanpoko multimedien laburpena",
"remove": "Kendu",
+ "remove_assets_title": "Baliabideak ezabatu?",
+ "remove_deleted_assets": "Ezabatu lineaz kanpoko baliabideak",
+ "remove_from_album": "Ezabatu albumetik",
+ "remove_from_favorites": "Gogokoetatik ezabatu",
+ "remove_memory": "Gogorapena kendu",
+ "remove_url": "URL-a kendu",
+ "remove_user": "Erabiltzailea kendu",
+ "removed_from_archive": "Artxibategitik ezabatuta",
+ "removed_from_favorites": "Gogokoetatik ezabatuta",
+ "removed_memory": "Gogorapena kenduta",
"rename": "Izena aldatu",
"repair": "Konpondu",
+ "replace_with_upload": "Igo eta ordezkatu",
"repository": "Errepositorioa",
+ "require_password": "Pasahitza derrigortu",
"rescan": "Berreskaneatu",
"reset": "Berrasieratu",
+ "reset_password": "Pasahitza leheneratu",
+ "reset_people_visibility": "Pertsonen ikusgarritasuna berrezarri",
+ "reset_pin_code": "PIN gakoa berrezarri",
+ "reset_sqlite": "SQLite datu-basea berrasieratu",
+ "reset_to_default": "Balio lehenetsitara berrezarri",
+ "resolution": "Bereizmena",
+ "resolve_duplicates": "Kopiak ebatzi",
+ "resolved_all_duplicates": "Kopia guztiak ebatzita",
"restore": "Zaharberritu",
+ "restore_all": "Denak berrezarri",
+ "restore_user": "Erabiltzailea berrezarri",
+ "restored_asset": "Baliabidea berrezarri",
"resume": "Jarraitu",
+ "retry_upload": "Karga berriro saiatu",
+ "review_duplicates": "Kopiak berrikusi",
+ "review_large_files": "Fitxategi handiak berrikusi",
"role": "Rola",
"role_editor": "Editorea",
"role_viewer": "Ikuslea",
"running": "Martxan",
"save": "Gorde",
+ "save_to_gallery": "Galerian gorde",
+ "saved": "Gordeta",
+ "saved_api_key": "API gakoa arrakastaz gorde da",
+ "saved_profile": "Profila gordeta",
+ "saved_settings": "Ezarpenak gordeta",
+ "say_something": "Zerbait esan",
+ "scaffold_body_error_occurred": "Akats bat gertatu da",
+ "scan_all_libraries": "Liburutegi guztiak eskaneatu",
"scan_library": "Eskaneatu",
+ "scan_settings": "Eskaneo ezarpenak",
+ "scanning_for_album": "Albumak bilatzen...",
"search": "Bilatu",
+ "search_albums": "Albumak bilatu",
+ "search_by_context": "Testuinguruaren arabera bilatu",
+ "search_by_description": "Deskribapenaren arabera bilatu",
+ "search_by_ocr": "OCR bitartez bilatu",
+ "search_by_ocr_example": "Kafesnea",
+ "search_camera_lens_model": "Bilatu lente modeloa...",
+ "search_camera_make": "Kamera fabrikatzailea bilatu...",
+ "search_camera_model": "Kamara modeloa bilatu...",
+ "search_city": "Hiria bilatu…",
+ "search_country": "Herrialdea bailatu...",
+ "search_filter_apply": "Iragazkiak aplikatu",
+ "search_filter_camera_title": "Aukeratu kamera mota",
"search_filter_date": "Data",
+ "search_filter_date_interval": "{start}-(e)tik {end}-ra",
+ "search_filter_display_option_not_in_album": "Ez dago albumean",
+ "search_filter_display_options": "Bistaratzeko ezarpenak",
"search_filter_location": "Kokapena",
+ "search_filter_location_title": "Kokapena aukeratu",
+ "search_filter_media_type": "Multimedia mota",
+ "search_filter_media_type_title": "Aukeratu multimedia mota",
+ "search_filter_ocr": "OCR bidez bilatu",
+ "search_filter_people_title": "Pertsonak hautatu",
"search_for": "Bilatu",
+ "search_no_more_result": "Emaitza gehiagorik ez",
"search_no_people": "Pertsonarik ez",
"search_options": "Bilaketa ezarpenak",
"search_page_categories": "Kategoriak",
+ "search_page_motion_photos": "Argazki bizidunak",
"search_page_screenshots": "Pantaila-argazkiak",
"search_page_selfies": "Selfiak",
"search_page_things": "Gauzak eta Animaliak",
+ "search_page_view_all_button": "Denak ikusi",
+ "search_page_your_activity": "Zure jarduerak",
+ "search_page_your_map": "Zure mapa",
"search_people": "Pertsonak bilatu",
"search_places": "Tokiak bilatu",
+ "search_rating": "Puntuazioaren arabera bilatu...",
+ "search_result_page_new_search_hint": "Bilaketa berria",
"search_settings": "Ezarpenak bilatu",
"search_state": "Probintziaren arabera bilatu…",
"search_suggestion_list_smart_search_hint_2": "m:zure-bilaketa",
"search_tags": "Etiketak bilatu…",
"search_timezone": "Ordu-eremua bilatu…",
"search_type": "Bilaketa mota",
+ "search_your_photos": "Zure argazkiak bilatu",
"searching_locales": "Tokiak bilatzen…",
"second": "Segundua",
- "select": "Aukeratu",
+ "see_all_people": "Pertsona guztiak ikusi",
+ "select": "Hautatu",
+ "select_album_cover": "Albumaren portada aukeratu",
"select_all": "Dena aukeratu",
+ "select_all_duplicates": "Bikoiztutako guztiak aukeratu",
+ "select_avatar_color": "Abatar kolorea aukeratu",
+ "select_cutoff_date": "Data muga ezarri",
"select_face": "Aurpegia hautatu",
+ "select_featured_photo": "Argazki nagusia aukeratu",
+ "select_from_computer": "Ordenagailutik aukeratu",
+ "select_keep_all": "Denak mantendu",
+ "select_library_owner": "Liburutegi jabea aukeratu",
+ "select_new_face": "Aurpegi berria aukeratu",
"select_photos": "Argazkiak aukeratu",
+ "select_trash_all": "Denak ezabatu",
"selected": "Aukeratuta",
"selected_gps_coordinates": "GPS Koordenadak Aukeratuta",
"send_message": "Mezua bidali",
+ "send_welcome_email": "Ongietorri e-mail mezua bidali",
+ "server_endpoint": "Zerbitzariaren endpoint-a",
+ "server_info_box_app_version": "Aplikazio bertsioa",
+ "server_info_box_server_url": "Zerbitzariaren URLa",
"server_offline": "Zerbitzaria lineaz kanpo",
"server_online": "Zerbitzaria linean",
+ "server_restarting_title": "Zerbitzaria berrabiarazten ari da",
"server_stats": "Zerbitzariaren estatistikak",
"server_version": "Zerbitzariaren bertsioa",
"set": "Ezarri",
+ "set_profile_picture": "Ezarri profil-argazkia",
+ "setting_image_viewer_original_title": "Jatorrizko irudia kargatu",
+ "setting_image_viewer_preview_title": "Aurrebista irudia kargatu",
"setting_image_viewer_title": "Irudiak",
"setting_languages_apply": "Ezarri",
+ "setting_notifications_notify_hours": "{count, plural, one {Ordu bat} other {# ordu}}",
"setting_notifications_notify_immediately": "berehala",
+ "setting_notifications_notify_minutes": "{count, plural, one {Minutu bat} other {# minutu}}",
"setting_notifications_notify_never": "inoiz ez",
+ "setting_notifications_notify_seconds": "{count, plural, one {Segundu bat} other {# segundu}}",
+ "setting_video_viewer_auto_play_title": "Bideoak automatikoki erreproduzitu",
"setting_video_viewer_looping_title": "Errepikatu",
+ "setting_video_viewer_original_video_title": "Jatorrizko bideoa behartu",
"settings": "Ezarpenak",
"settings_saved": "Ezarpenak gordeta",
"share": "Partekatu",
+ "share_action_prompt": "{count, plural, one{Partekatutako baliabide bat} other{# partekatutako baliabide}}",
+ "share_add_photos": "Argazkiak gehitu",
+ "share_assets_selected": "{count} aukeratuta",
"share_dialog_preparing": "Prestatzen...",
"shared": "Partekatuta",
+ "shared_album_activities_input_disable": "Iruzkinak desgaituta daude",
+ "shared_album_activity_remove_title": "Jarduera ezabatu",
"shared_album_section_people_title": "PERTSONAK",
"shared_by": "Honek partekatuta",
+ "shared_by_user": "{user}-(e)k partekatuta",
+ "shared_by_you": "Zuk partekatuta",
+ "shared_from_partner": "{partner}-(e)n argazkiak",
+ "shared_link_app_bar_title": "Partekatutako estekak",
+ "shared_link_clipboard_copied_massage": "Esteka arbelera kopiatuta",
+ "shared_link_edit_expire_after_option_day": "Egun bat",
+ "shared_link_edit_expire_after_option_days": "{count} egun",
+ "shared_link_edit_expire_after_option_hour": "Ordu bat",
+ "shared_link_edit_expire_after_option_hours": "{count} ordu",
+ "shared_link_edit_expire_after_option_minute": "Minutu bat",
+ "shared_link_edit_expire_after_option_minutes": "{count} minutu",
+ "shared_link_edit_expire_after_option_months": "{count} hilabete",
+ "shared_link_edit_expire_after_option_year": "{count} urte",
+ "shared_link_edit_submit_button": "Esteka eguneratu",
+ "shared_link_expires_never": "Iraungiezina",
+ "shared_link_individual_shared": "Indibidualki partekatuta",
"shared_link_info_chip_metadata": "EXIF",
+ "shared_link_manage_links": "Partekatutako estekak kudeatu",
+ "shared_link_options": "Partekatutako esteken ezarpenak",
"shared_links": "Partekatutako estekak",
+ "shared_with_me": "Nirekin partekatutakoak",
+ "shared_with_partner": "{partner}-(r)ekin partekatuta",
"sharing": "Partekatzen",
+ "sharing_page_album": "Partekatutako albumak",
+ "sharing_page_empty_list": "ZERRENDA HUTSA",
+ "sharing_silver_appbar_create_shared_album": "Partekatutako album berria",
+ "sharing_silver_appbar_share_partner": "Kidearekin partekatu",
+ "show_album_options": "Erakutsi albumaren azarpenak",
"show_albums": "Albumak erakutsi",
+ "show_all_people": "Pertsona guztiak erakutsi",
+ "show_file_location": "Erakutsi fitxategiaren kokapena",
"show_gallery": "Galeria erakutsi",
+ "show_hidden_people": "Erakutsi ezkutatutako pertsonak",
+ "show_in_timeline": "Erakutsi denbora-lerroan",
+ "show_keyboard_shortcuts": "Erakutsi lasterbideak",
"show_metadata": "Metadatuak erakutsi",
"show_password": "Pasahitza erakutsi",
- "show_supporter_badge": "Kolaboratzaile entseina",
+ "show_person_options": "Erakutsi pertsonaren ezarpenak",
+ "show_progress_bar": "Aurrerapen-barra erakutsi",
+ "show_search_options": "Erakutsi bilaketa ezarpenak",
+ "show_shared_links": "Erakutsi partekatutako estekak",
+ "show_slideshow_transition": "Erakutsi diapositiba-trantsizioak",
+ "show_supporter_badge": "Babesle insignia",
+ "show_supporter_badge_description": "Erakutsi babesle insignia",
+ "show_text_recognition": "Testu-ezagutza erakutsi",
"shuffle": "Nahasi",
"sidebar": "Alboko panela",
"sign_out": "Saioa itxi",
"sign_up": "Erregistratu",
"size": "Tamaina",
+ "skip_to_content": "Edukira salto egin",
+ "skip_to_folders": "Karpetetara salto egin",
+ "skip_to_tags": "Etiketetara salto egin",
"slideshow": "Diapositibak",
"slideshow_settings": "Diapositiba ezarpenak",
+ "sort_albums_by": "Albumak honen bidez ordenatu...",
"sort_created": "Sortze data",
+ "sort_items": "Baliabide kopurua",
"sort_modified": "Egunatze data",
"sort_newest": "Argazkirik berriena",
"sort_oldest": "Argazkirik zaharrena",
+ "sort_recent": "Argazkirik berriena",
"sort_title": "Izenburua",
"source": "Iturburua",
"stack": "Multzokatu",
"stack_duplicates": "Kopiak multzokatu",
+ "stack_selected_photos": "Aukeratutako argazkiak multzokatu",
"stacktrace": "Pila jarraipena",
"start": "Hasi",
"start_date": "Hasiera data",
"state": "Estatua / Probintzia",
"status": "Egoera",
+ "stop_motion_photo": "Gelditu argazki biziduna",
"storage": "Memoria edukiera",
"storage_label": "Memoria etiketa",
"submit": "Bidali",
"success": "Arrakastatsua",
"suggestions": "Iradokizunak",
"support": "Babesa",
+ "support_and_feedback": "Laguntza eta feedback-a",
+ "supporter": "Babeslea",
+ "swap_merge_direction": "Trukatu bateratze-norabidea",
"sync": "Sinkronizazioa",
+ "sync_albums": "Albumak sinkronizatu",
"tag": "Etiketa",
"tag_assets": "Baliabideak etiketatu",
+ "tag_created": "Etiketa sortuta: {tag}",
"tag_people": "Pertsonak etiketatu",
+ "tag_updated": "Etiketa eguneratuta: {tag}",
"tags": "Etiketak",
"template": "Txantiloia",
"theme": "Gaia",
"theme_selection": "Gaien aukeraketa",
+ "theme_setting_colorful_interface_title": "Interfaze koloreduna",
+ "theme_setting_image_viewer_quality_title": "Irudi arakatzailearen kalitatea",
+ "theme_setting_primary_color_title": "Kolore nagusia",
+ "theme_setting_system_primary_color_title": "Erabili sistemaren kolorea",
+ "theme_setting_three_stage_loading_title": "Erabili hiru faseko karga",
+ "then": "Orduan",
"third_party_resources": "Bitartekoen baliabideak",
+ "time": "Denbora",
"time_based_memories": "Denboran oinarritutako gogorapenak",
"timeline": "Kronologia",
"timezone": "Ordu-eremua",
@@ -549,6 +1733,7 @@
"to_change_password": "Pasahitza aldatu",
"to_favorite": "Gogokotzat ezarri",
"to_login": "Saioa hasi",
+ "to_parent": "Gurasoetara jo",
"to_select": "aukeratzeko",
"to_trash": "Baztertu",
"toggle_settings": "Ezarpenak aldizkatu",
@@ -556,7 +1741,14 @@
"total_usage": "Erabilpen osoa",
"trash": "Zakarrontzia",
"trash_all": "Denak ezabatu",
+ "trash_count": "Zakarrontzia {count, number}",
"trash_delete_asset": "Baliabidea ezabatu/zakarrontzira eraman",
+ "trash_emptied": "Zakarrontzia hustuta",
+ "trash_page_delete_all": "Denak ezabatu",
+ "trash_page_no_assets": "Zakarrontzian baliabiderik ez",
+ "trash_page_restore_all": "Denak berrezarri",
+ "trash_page_select_assets_btn": "Baliabideak hautatu",
+ "trash_page_title": "Zakarrontzia ({count})",
"troubleshoot": "Arazoak konpontzea",
"type": "Mota",
"unarchive": "Desartxibatu",
@@ -567,51 +1759,78 @@
"unknown_country": "Herrialde ezezaguna",
"unknown_year": "Urte ezezaguna",
"unlimited": "Mugagabea",
+ "unlink_motion_video": "Argazki biziduna deslotu",
"unlink_oauth": "OAuth deslotu",
+ "unlinked_oauth_account": "OAuth kontua deslotuta",
"unmute_memories": "Gogorapenen soinua gaitu",
"unnamed_album": "Izengabeko Albuma",
"unnamed_share": "Izengabeko baliabide partekatua",
"unsaved_change": "Gordegabeko aldaketa",
"unselect_all": "Aukeraketak garbitu",
+ "unselect_all_duplicates": "Bikoiztutakoak deshautatu",
"unstack": "Multzotik kendu",
+ "unsupported_field_type": "Eremu mota ez da bateragarria",
"untagged": "Etiketagabea",
"up_next": "Hurrengoa",
"updated_at": "Eguneratze-data",
"updated_password": "Pasahitza eguneratuta",
"upload": "Igo",
"upload_concurrency": "Igoera paraleloak",
+ "upload_dialog_title": "Baliabidea gora kargatu",
"upload_status_duplicates": "Kopiak",
"upload_status_errors": "Akatsak",
"upload_status_uploaded": "Igota",
"uploading": "Igotzen",
+ "uploads": "Igoerak",
"url": "URL-a",
"usage": "Erabilera",
+ "use_current_connection": "Erabili oraingo konexioa",
"user": "Erabiltzailea",
"user_id": "Erabiltzaile ID-a",
"user_purchase_settings": "Erosketa",
+ "user_purchase_settings_description": "Zure erosketa kudeatu",
+ "user_usage_detail": "Erabiltzailearen erabileraren xehetasunak",
+ "user_usage_stats": "Kontuaren erabilera estatistikak",
"username": "Erabiltzaile izena",
"users": "Erabiltzaileak",
"utilities": "Tresnak",
"validate": "Balioetsi",
"variables": "Aldagaiak",
"version": "Bertsioa",
+ "version_announcement_closing": "Zure laguna, Alex",
"version_history": "Bertsio-historia",
"video": "Bideoa",
"videos": "Bideoak",
"view": "Bista",
"view_album": "Albuma ikusi",
"view_all": "Denak ikusi",
+ "view_all_users": "Erabiltzaile guztiak erakutsi",
+ "view_asset_owners": "Baliabidearen jabeak erakutsi",
+ "view_in_timeline": "Denbora-lerroan ikusi",
"view_link": "Esteka ikusi",
"view_links": "Estekak ikusi",
"view_name": "Bista",
+ "view_next_asset": "Hurrengo baliabidea erakutsi",
+ "view_previous_asset": "Aurreko baliabidea erakutsi",
+ "view_qr_code": "QR kodea erakutsi",
"view_similar_photos": "Ikusi antzeko argazkiak",
"view_stack": "Pila ikusi",
+ "viewer_remove_from_stack": "Multzotik kendu",
"viewer_unstack": "Multzotik kendu",
+ "visibility": "Ikusgarritasuna",
"waiting": "Itxarotzen",
"warning": "Oharra",
"week": "Astea",
"welcome": "Ongi etorri",
+ "welcome_to_immich": "Ongi egorri Immich-era",
+ "when": "Noiz",
+ "wifi_name": "Wi-Fi izena",
+ "workflow_update_success": "Lan-fluxua arrakastaz eguneratua",
+ "wrong_pin_code": "PIN kode okerra",
+ "x_of_total": "{total}-(e)tik {x}",
"year": "Urtea",
"yes": "Bai",
- "zoom_image": "Irudia handitu"
+ "your_wifi_name": "Zure Wi-Fi izena",
+ "zoom_image": "Irudia handitu",
+ "zoom_to_bounds": "Muturretara doitu"
}
diff --git a/i18n/fa.json b/i18n/fa.json
index 2a87b929c5..79284ce8f5 100644
--- a/i18n/fa.json
+++ b/i18n/fa.json
@@ -605,7 +605,6 @@
"map_location_picker_page_use_location": "استفاده از این موقعیت مکانی",
"map_location_service_disabled_content": "برای نمایش داراییها بر اساس موقعیت مکانی، نیاز به فعالسازی سرویس مکانیابی دارید. میخواهید همین حالا فعال شود؟",
"map_location_service_disabled_title": "سرویس مکانیابی غیرفعال است",
- "map_marker_for_images": "نشانگر روی نقشه برای عکسهای گرفتهشده در {city}, {country}",
"map_marker_with_image": "علامتگذاری نقشه با عکس",
"map_no_location_permission_content": "برای نمایش عکسهای اطرافتان، برنامه نیاز به دسترسی به موقعیت مکانی دارد. اجازه دسترسی میدهید؟",
"map_no_location_permission_title": "دسترسی به موقعیت شما فعال نیست",
diff --git a/i18n/fi.json b/i18n/fi.json
index 17596c3d10..29a001f8f1 100644
--- a/i18n/fi.json
+++ b/i18n/fi.json
@@ -1504,7 +1504,6 @@
"map_location_picker_page_use_location": "Käytä tätä sijaintia",
"map_location_service_disabled_content": "Paikannuspalvelun pitää olla kytkettynä päälle, jotta nykyisen sijaintisi kohteita voidaan näyttää. Haluatko kytkeä sen päälle nyt?",
"map_location_service_disabled_title": "Paikannuspalvelu pois päältä",
- "map_marker_for_images": "Karttamarkerointi kuville, jotka on otettu kaupungissa {city}, maassa {country}",
"map_marker_with_image": "Karttamarkerointi kuvalla",
"map_no_location_permission_content": "Paikannuslupa tarvitaan, jotta nykyisen sijainnin kohteita voidaan näyttää. Haluatko sallia pääsyn sijaintiin?",
"map_no_location_permission_title": "Paikannuslupa estetty",
diff --git a/i18n/fil.json b/i18n/fil.json
index ecd9e219dd..3decd51559 100644
--- a/i18n/fil.json
+++ b/i18n/fil.json
@@ -15,29 +15,36 @@
"add_a_location": "Dagdagan ng lugar",
"add_a_name": "Dagdagan ng pangalan",
"add_a_title": "Dagdagan ng pamagat",
+ "add_action": "Magdagdag ng aksyon",
"add_assets": "Dagdagan ng asset",
"add_birthday": "Maglagay ng kaarawan",
"add_endpoint": "Dagdagan ng dulo",
+ "add_exclusion_pattern": "Magdagdag ng exlusion pattern",
"add_location": "Magdagdag ng lugar",
"add_more_users": "Magdagdag ng mga user",
"add_partner": "Magdagdag ng kasangga",
"add_path": "Magdagdag ng path",
"add_photos": "Magdagdag ng litrato",
+ "add_step": "Magdagdag ng step",
"add_tag": "Magdagdag ng tag",
"add_to": "Idagdag sa…",
"add_to_album": "Idagdag sa album",
"add_to_album_bottom_sheet_added": "Naidagdag sa {album}",
"add_to_album_bottom_sheet_already_exists": "Nasa {album} na",
+ "add_to_album_bottom_sheet_some_local_assets": "May ilang mga local assets ang hindi maidagdag sa album",
+ "add_to_album_toggle": "Toggle selection para sa {album}",
"add_to_albums": "Idagdag sa mga album",
"add_to_albums_count": "Idagdag sa mga album ({count})",
"add_to_bottom_bar": "Idagdag sa",
"add_to_shared_album": "Idagdag sa shared album",
+ "add_upload_to_stack": "Magdagdag ng upload para ma-stack",
"add_url": "Magdagdag ng URL",
"added_to_archive": "Naidagdag sa archive",
"added_to_favorites": "Naidagdag sa mga paborito",
"added_to_favorites_count": "Naidagdag ang {count, number} sa mga paborito",
"admin": {
"add_exclusion_pattern_description": "Dagdagan ng pattern para maibukod. Supportado ang pag-tutugma gamit ang *, **, at ?. Para hindi maisama ang mga file sa direktoryo na may pangalang \"Raw\", gamitin ang \"**/Raw/**\". Para hindi maisama ang lahat ng mga file na nagtatapos sa \".tif\", gamitin ang \"**/*.tif\". Para hindi maisama ang isang tiyak na folder, gamitin ang \"/path/to/ignore/**\".",
+ "admin_user": "Admin User",
"asset_offline_description": "Ang external library asset na ito ay hindi na makikita sa disk at nailipat na sa basurahan. Kung ang file ay nailipat sa loob ng library, tignan ang iyong timeline para sa kaukulang asset. Para maibalik ang asset na ito, siguraduhin na ang file ay maa-access ng Immich at muling i-scan ang library.",
"authentication_settings": "Setting ng mga Pagkakakilanlan",
"authentication_settings_description": "Pamahalaan ang password, OAuth, and iba pang setting ng pagkakakilanlan",
@@ -68,6 +75,7 @@
"disable_login": "I-disable ang login",
"duplicate_detection_job_description": "Hanapin ang mga magkakatulad na imahe gamit ang machine learning. Umaasa sa Smart Search",
"exclusion_pattern_description": "Maaaring gamitin ang mga pattern na pangbukod para hindi pansinin ang ilang file o folder habang binabasa ang iyong library. Mainam itong solusyon para sa mga folder na may file na ayaw niyong ma-import, tulad ng mga RAW na file.",
+ "face_detection": "Face detection",
"force_delete_user_warning": "BABALA: Tatanggalin itong user at lahat ng asset nila, Hindi ito mababawi at ang kanilang files ay hindi na mababalik",
"image_format": "Format",
"note_cannot_be_changed_later": "TANDAAN: Hindi na ito pwede baguhin sa susunod!",
diff --git a/i18n/fr.json b/i18n/fr.json
index 2abc30143e..b313e67fc5 100644
--- a/i18n/fr.json
+++ b/i18n/fr.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Utiliser ma position",
"map_location_service_disabled_content": "Le service de localisation doit être activé pour afficher les médias de votre emplacement actuel. Souhaitez-vous l'activer maintenant ?",
"map_location_service_disabled_title": "Service de localisation désactivé",
- "map_marker_for_images": "Marqueur de carte pour les images prises à {city}, {country}",
+ "map_marker_for_image": "Marqueur de carte pour une image prise à {city}, {country}",
"map_marker_with_image": "Marqueur de carte avec image",
"map_no_location_permission_content": "L'autorisation de localisation est nécessaire pour afficher les médias de votre emplacement actuel. Souhaitez-vous l'autoriser maintenant ?",
"map_no_location_permission_title": "Permission de localisation refusée",
diff --git a/i18n/ga.json b/i18n/ga.json
index 5d930c2ecc..a8f722d343 100644
--- a/i18n/ga.json
+++ b/i18n/ga.json
@@ -189,18 +189,23 @@
"machine_learning_smart_search_enabled": "Cumasaigh cuardach cliste",
"machine_learning_smart_search_enabled_description": "Mura bhfuil sé sin ar fáil, ní dhéanfar íomhánna a ionchódú le haghaidh cuardaigh chliste.",
"machine_learning_url_description": "URL an fhreastalaí foghlama meaisín. Má chuirtear níos mó ná URL amháin ar fáil, déanfar iarracht ar gach freastalaí ceann ag an am go dtí go bhfreagróidh ceann acu go rathúil, in ord ón gcéad cheann go dtí an ceann deireanach. Déanfar neamhaird shealadach ar fhreastalaithe nach bhfreagróidh go dtí go mbeidh siad ar líne arís.",
+ "maintenance_backup_management": "Bainistíocht chúltaca",
"maintenance_delete_backup": "Scrios Cúltaca",
"maintenance_delete_backup_description": "Scriosfar an comhad seo go neamh-inchúlghairthe.",
"maintenance_delete_error": "Theip ar an gcúltaca a scriosadh.",
+ "maintenance_integrity_check": "Seiceáil",
"maintenance_integrity_check_all": "Seiceáil Gach Rud",
"maintenance_integrity_checksum_mismatch": "Mí-chomhoiriúnacht suime seiceála",
+ "maintenance_integrity_checksum_mismatch_description": "Comhaid nach bhfuil an tsuim seiceála ar an diosca ag teacht leis an tsuim seiceála atá stóráilte ag Immich ina bhunachar sonraí.",
"maintenance_integrity_checksum_mismatch_job": "Seiceáil le haghaidh mí-oiriúnuithe suime seiceála",
"maintenance_integrity_checksum_mismatch_refresh_job": "Athnuachan tuairiscí mí-oiriúnachta suime seiceála",
"maintenance_integrity_missing_file": "Comhaid ar Iarraidh",
+ "maintenance_integrity_missing_file_description": "Comhaid atá rianaithe ag Immich ina bhunachar sonraí ach nach bhfuil ar fáil ar an gcóras comhad.",
"maintenance_integrity_missing_file_job": "Seiceáil le haghaidh comhaid atá ar iarraidh",
"maintenance_integrity_missing_file_refresh_job": "Athnuachan tuairiscí ar chomhaid atá ar iarraidh",
"maintenance_integrity_report": "Tuarascáil Ionracais",
"maintenance_integrity_untracked_file": "Comhaid Gan Rianú",
+ "maintenance_integrity_untracked_file_description": "Comhaid in eolairí Immich nach bhfuil aon taifead ag Immich orthu.",
"maintenance_integrity_untracked_file_job": "Seiceáil le haghaidh comhaid neamhrianaithe",
"maintenance_integrity_untracked_file_refresh_job": "Athnuachan tuarascálacha comhad neamhrianaithe",
"maintenance_restore_backup": "Athchóirigh Cúltaca",
@@ -1543,7 +1548,6 @@
"map_location_picker_page_use_location": "Úsáid an suíomh seo",
"map_location_service_disabled_content": "Ní mór seirbhís suímh a chumasú chun sócmhainní ó do shuíomh reatha a thaispeáint. Ar mhaith leat é a chumasú anois?",
"map_location_service_disabled_title": "Seirbhís Suímh díchumasaithe",
- "map_marker_for_images": "Marcóir léarscáile le haghaidh íomhánna a tógadh i {city}, {country}",
"map_marker_with_image": "Marcóir léarscáile le híomhá",
"map_no_location_permission_content": "Tá cead suímh ag teastáil chun sócmhainní a thaispeáint ó do shuíomh reatha. Ar mhaith leat é a cheadú anois?",
"map_no_location_permission_title": "Cead Suímh diúltaithe",
diff --git a/i18n/gl.json b/i18n/gl.json
index 81acb15595..dcee16c357 100644
--- a/i18n/gl.json
+++ b/i18n/gl.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Usar esta localización",
"map_location_service_disabled_content": "O servizo de localización debe estar activado para mostrar activos da súa localización actual. Quere activalo agora?",
"map_location_service_disabled_title": "Servizo de localización deshabilitado",
- "map_marker_for_images": "Marcador de mapa para imaxes tomadas en {city}, {country}",
"map_marker_with_image": "Marcador de mapa con imaxe",
"map_no_location_permission_content": "Necesítase permiso de localización para mostrar activos da súa localización actual. Quere permitilo agora?",
"map_no_location_permission_title": "Permiso de localización denegado",
diff --git a/i18n/gsw.json b/i18n/gsw.json
index 4f2381054d..0841a4be59 100644
--- a/i18n/gsw.json
+++ b/i18n/gsw.json
@@ -1391,7 +1391,6 @@
"map_location_picker_page_use_location": "Ufnahmeort verwände",
"map_location_service_disabled_content": "D’Ortigsdienscht müend aktiviert si, um Inhält am aktuelle Standort aazeige z chönne. Wotsch d’Ortigsdienscht jetzt aktiviere?",
"map_location_service_disabled_title": "Ortigsdienscht deaktiviert",
- "map_marker_for_images": "Charte-Markierige für Bilder, wo i {city}, {country} ufgnoh worde sind",
"map_marker_with_image": "Charte-Markierig mit Bild",
"map_no_location_permission_content": "D’Ortigsdienscht müend aktiviert si, um Inhält am aktuelle Standort aazeige z chönne. Wotsch d’Ortigsdienscht jetzt aktiviere?",
"map_no_location_permission_title": "Kei Zuegriff uf dä Standort",
@@ -1528,5 +1527,8 @@
"on_this_device": "Uf däm Grät",
"onboarding": "Iistig",
"onboarding_locale_description": "Wähl dini bevorzugti Sprooch. Du chasch die au spöter i dine Iistellige ändere.",
- "onboarding_privacy_description": "Diä folgende (optionali) Funktione hänged vo externä Diänscht ab und chönd jederziit i de Iistellige deaktiviärt wärde."
+ "onboarding_privacy_description": "Diä folgende (optionali) Funktione hänged vo externä Diänscht ab und chönd jederziit i de Iistellige deaktiviärt wärde.",
+ "upload_finished": "Ufelade beändet",
+ "users": "Benutzer",
+ "waiting": "Usstehend"
}
diff --git a/i18n/he.json b/i18n/he.json
index 87e7259533..e9e66275b7 100644
--- a/i18n/he.json
+++ b/i18n/he.json
@@ -1498,7 +1498,6 @@
"map_location_picker_page_use_location": "השתמש במיקום הזה",
"map_location_service_disabled_content": "שירות המיקום צריך להיות מופעל כדי להציג תמונות מהמיקום הנוכחי שלך. האם ברצונך להפעיל אותו עכשיו?",
"map_location_service_disabled_title": "שירות מיקום מבוטל",
- "map_marker_for_images": "סמן מפה לתמונות שצולמו ב{city}, {country}",
"map_marker_with_image": "סמן מפה עם תמונה",
"map_no_location_permission_content": "יש צורך בהרשאה למיקום כדי להציג תמונות מהמיקום הנוכחי שלך. האם ברצונך לאפשר זאת עכשיו?",
"map_no_location_permission_title": "הרשאה למיקום נדחתה",
diff --git a/i18n/hi.json b/i18n/hi.json
index f2e357bc70..4707abf338 100644
--- a/i18n/hi.json
+++ b/i18n/hi.json
@@ -1479,7 +1479,6 @@
"map_location_picker_page_use_location": "इस स्थान का उपयोग करें",
"map_location_service_disabled_content": "आपके वर्तमान स्थान की संपत्तियाँ प्रदर्शित करने के लिए स्थान सेवा सक्षम होनी चाहिए। क्या आप इसे अभी सक्षम करना चाहते हैं?",
"map_location_service_disabled_title": "स्थान सेवा अक्षम",
- "map_marker_for_images": "{city}, {country} में ली गई छवियों के लिए मानचित्र मार्कर",
"map_marker_with_image": "छवि के साथ मानचित्र मार्कर",
"map_no_location_permission_content": "आपके वर्तमान स्थान से संपत्तियाँ प्रदर्शित करने के लिए स्थान अनुमति आवश्यक है। क्या आप इसे अभी अनुमति देना चाहते हैं?",
"map_no_location_permission_title": "स्थान की अनुमति अस्वीकृत",
diff --git a/i18n/hr.json b/i18n/hr.json
index 21c6fc7c75..3242a9d870 100644
--- a/i18n/hr.json
+++ b/i18n/hr.json
@@ -1414,7 +1414,6 @@
"map_location_picker_page_use_location": "Koristi ovu lokaciju",
"map_location_service_disabled_content": "Usluga lokacije mora biti omogućena za prikaz stavki s vaše trenutne lokacije. Želite li je sada omogućiti?",
"map_location_service_disabled_title": "Usluga lokacije onemogućena",
- "map_marker_for_images": "Oznaka karte za slike snimljene u {city}, {country}",
"map_marker_with_image": "Oznaka karte sa slikom",
"map_no_location_permission_content": "Potrebno je dopuštenje za lokaciju kako bi se prikazale stavke s vaše trenutne lokacije. Želite li ga sada omogućiti?",
"map_no_location_permission_title": "Dopuštenje za lokaciju odbijeno",
diff --git a/i18n/hu.json b/i18n/hu.json
index fa0bc733df..529faf46f8 100644
--- a/i18n/hu.json
+++ b/i18n/hu.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Kiválasztott hely használata",
"map_location_service_disabled_content": "A helymeghatározás szolgáltatást engedélyezni kell a jelenlegi helyednél lévő elemek megjelenítéséhez. Szeretnéd most engedélyezni?",
"map_location_service_disabled_title": "Helymeghatározás szolgáltatás letiltva",
- "map_marker_for_images": "{country}, {city} helyen készült képek térképjelölője",
+ "map_marker_for_image": "Térképjelölő a következő helyen készült képhez: {city}, {country}",
"map_marker_with_image": "Térképjelölő képpel",
"map_no_location_permission_content": "A helymeghatározást engedélyezni kell a jelenlegi helyednél lévő elemek megjelenítéséhez. Szeretnéd most engedélyezni?",
"map_no_location_permission_title": "Helymeghatározás letiltva",
@@ -2122,7 +2122,7 @@
"server_privacy": "Szerver biztonság",
"server_restarting_description": "Az oldal pillanatokon belül frissül.",
"server_restarting_title": "A szerver újraindul",
- "server_stats": "Szerver statisztikák",
+ "server_stats": "Szerver statisztika",
"server_update_available": "Szerverfrissítés érhető el",
"server_version": "Szerver verzió",
"set": "Beállít",
diff --git a/i18n/id.json b/i18n/id.json
index 921a6ef02a..11ff302352 100644
--- a/i18n/id.json
+++ b/i18n/id.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Gunakan lokasi ini",
"map_location_service_disabled_content": "Layanan lokasi perlu diaktifkan untuk menampilkan aset yang terletak di lokasi Anda saat ini. Ingin mengaktifkan layanan tersebut sekarang?",
"map_location_service_disabled_title": "Layanan Lokasi nonaktif",
- "map_marker_for_images": "Penanda peta untuk gambar yang diambil di {city}, {country}",
"map_marker_with_image": "Penanda peta dengan gambar",
"map_no_location_permission_content": "Izin lokasi diperlukan untuk menampilkan aset yang terletak di lokasi Anda. Ingin mengizinkannya sekarang?",
"map_no_location_permission_title": "Izin Lokasi ditolak",
diff --git a/i18n/it.json b/i18n/it.json
index c2b0ff43a1..f1521ef214 100644
--- a/i18n/it.json
+++ b/i18n/it.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Usa questa posizione",
"map_location_service_disabled_content": "I servizi di geolocalizzazione devono essere attivati per poter visualizzare le risorse dalla tua posizione attuale. Vuoi attivarli adesso?",
"map_location_service_disabled_title": "Servizio Localizzazione disattivato",
- "map_marker_for_images": "Indicatore mappa per le immagini scattate in {city}, {country}",
"map_marker_with_image": "Segnaposto con immagine",
"map_no_location_permission_content": "L'accesso alla posizione è necessario per visualizzare le risorse dalla tua posizione attuale. Vuoi consentirlo adesso?",
"map_no_location_permission_title": "Autorizzazione Posizione negata",
@@ -1603,7 +1602,7 @@
},
"media_type": "Tipo Media",
"memories": "Ricordi",
- "memories_all_caught_up": "Tutto a posto",
+ "memories_all_caught_up": "Niente di nuovo",
"memories_check_back_tomorrow": "Torna domani per altri ricordi",
"memories_setting_description": "Gestisci cosa vedi nei tuoi ricordi",
"memories_start_over": "Ricomincia",
diff --git a/i18n/ja.json b/i18n/ja.json
index 5244a07aeb..8fa46e1f4d 100644
--- a/i18n/ja.json
+++ b/i18n/ja.json
@@ -1532,7 +1532,6 @@
"map_location_picker_page_use_location": "この位置情報を使う",
"map_location_service_disabled_content": "現在地の項目を表示するには位置情報がオンである必要があります。有効化しますか?",
"map_location_service_disabled_title": "位置情報がオフです",
- "map_marker_for_images": "{country} {city}で撮影された写真の地図マーカー",
"map_marker_with_image": "画像の地図マーカー",
"map_no_location_permission_content": "現在地の項目を表示するには位置情報へのアクセスが必要です。許可しますか?",
"map_no_location_permission_title": "位置情報へのアクセスが拒否されました",
diff --git a/i18n/kn.json b/i18n/kn.json
index f2abb33927..cecb86b8d4 100644
--- a/i18n/kn.json
+++ b/i18n/kn.json
@@ -1101,7 +1101,6 @@
"map": "ನಕ್ಷೆ",
"map_cannot_get_user_location": "ಬಳಕೆದಾರರ ಸ್ಥಳವನ್ನು ಪಡೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ",
"map_location_service_disabled_content": "ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಸ್ಥಳದಿಂದ ಸ್ವತ್ತುಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸ್ಥಳ ಸೇವೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವ ಅಗತ್ಯವಿದೆ. ನೀವು ಈಗ ಅದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಬಯಸುವಿರಾ?",
- "map_marker_for_images": "{city}, {country} ದಲ್ಲಿ ತೆಗೆದ ಚಿತ್ರಗಳಿಗಾಗಿ ನಕ್ಷೆ ಮಾರ್ಕರ್",
"map_marker_with_image": "ಚಿತ್ರದೊಂದಿಗೆ ನಕ್ಷೆ ಮಾರ್ಕರ್",
"map_no_location_permission_content": "ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಸ್ಥಳದಿಂದ ಸ್ವತ್ತುಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸ್ಥಳ ಅನುಮತಿ ಅಗತ್ಯವಿದೆ. ನೀವು ಈಗ ಅದನ್ನು ಅನುಮತಿಸಲು ಬಯಸುವಿರಾ?",
"map_zoom_to_see_photos": "ಫೋಟೋಗಳನ್ನು ನೋಡಲು ಝೂಮ್ ಔಟ್ ಮಾಡಿ",
diff --git a/i18n/ko.json b/i18n/ko.json
index 98bbde4bb2..869054d555 100644
--- a/i18n/ko.json
+++ b/i18n/ko.json
@@ -56,9 +56,9 @@
"backup_database": "데이터베이스 덤프 생성",
"backup_database_enable_description": "데이터베이스 덤프 활성화",
"backup_keep_last_amount": "보관할 이전 덤프 수",
- "backup_onboarding_1_description": "개는 클라우드나 다른 물리적 위치에 보관합니다.",
- "backup_onboarding_2_description": "개는 서로 다른 로컬 장치에 보관하고,",
- "backup_onboarding_3_description": "개의 데이터 사본을 만듭니다.",
+ "backup_onboarding_1_description": "클라우드 또는 다른 물리적 위치에 오프사이트 사본을 보관합니다.",
+ "backup_onboarding_2_description": "여러 장치에 로컬 복사본이 있습니다. 여기에는 주요 파일과 해당 파일의 로컬 백업이 포함됩니다.",
+ "backup_onboarding_3_description": "원본 파일을 포함한 데이터의 모든 사본 수입니다. 여기에는 오프사이트 사본 1개와 로컬 사본 2개가 포함됩니다.",
"backup_onboarding_description": "데이터 보호를 위해 3-2-1 백업 전략 사용을 권장합니다. 백업에는 업로드한 사진 및 동영상뿐 아니라 Immich 데이터베이스도 포함되어야 합니다.",
"backup_onboarding_footer": "Immich 백업에 대한 자세한 내용은 공식 문서를 참조하세요.",
"backup_onboarding_parts_title": "3-2-1 백업이란:",
@@ -181,7 +181,7 @@
"machine_learning_ocr_min_recognition_score": "최소 인식 점수",
"machine_learning_ocr_min_score_recognition_description": "인식할 텍스트의 최소 신뢰도 점수를 0~1 범위에서 설정합니다. 값이 작을수록 더 많은 텍스트를 인식하지만 잘못 인식될 가능성도 높아집니다.",
"machine_learning_ocr_model": "OCR 모델",
- "machine_learning_ocr_model_description": "서버 모델은 모바일 모델보다 정확하지만, 처리 시간이 길어지고 메모리 사용량도 늘어납니다.",
+ "machine_learning_ocr_model_description": "서버 모델은 모바일 모델보다 정확도가 높지만 처리 시간이 더 오래 걸리고 메모리 사용량도 더 많습니다.",
"machine_learning_settings": "기계 학습 설정",
"machine_learning_settings_description": "기계 학습 시 사용할 모델과 세부 설정을 관리합니다.",
"machine_learning_smart_search": "스마트 검색",
@@ -196,13 +196,16 @@
"maintenance_integrity_check": "체크",
"maintenance_integrity_check_all": "전체선택",
"maintenance_integrity_checksum_mismatch": "체크섬 불일치",
+ "maintenance_integrity_checksum_mismatch_description": "디스크의 체크섬이 Immich 데이터베이스에 저장된 체크섬과 일치하지 않는 파일입니다.",
"maintenance_integrity_checksum_mismatch_job": "파일 무결성 검사",
"maintenance_integrity_checksum_mismatch_refresh_job": "무결성 오류 보고서 새로고침",
"maintenance_integrity_missing_file": "누락된 파일",
+ "maintenance_integrity_missing_file_description": "Immich가 데이터베이스에서 추적했지만 파일 시스템에는 존재하지 않는 파일입니다.",
"maintenance_integrity_missing_file_job": "누락된 파일 확인",
"maintenance_integrity_missing_file_refresh_job": "누락된 파일 보고서 새로고침",
"maintenance_integrity_report": "무결성 보고서",
"maintenance_integrity_untracked_file": "추적되지 않은 파일",
+ "maintenance_integrity_untracked_file_description": "Immich의 디렉터리에 있지만 Immich가 기록을 가지고 있지 않은 파일들.",
"maintenance_integrity_untracked_file_job": "추적되지 않은 파일 확인",
"maintenance_integrity_untracked_file_refresh_job": "추적되지 않은 파일 보고서 새로고침",
"maintenance_restore_backup": "백업 복원",
@@ -1545,7 +1548,7 @@
"map_location_picker_page_use_location": "이 위치 사용",
"map_location_service_disabled_content": "현재 위치의 항목을 표시하려면 위치 서비스를 활성화해야 합니다. 지금 활성화하시겠습니까?",
"map_location_service_disabled_title": "위치 서비스 비활성화됨",
- "map_marker_for_images": "{country}, {city}에서 촬영된 이미지의 지도 마커",
+ "map_marker_for_image": "{city}, {country}에서 촬영한 이미지의 지도 마커입니다.",
"map_marker_with_image": "이미지가 있는 지도 마커",
"map_no_location_permission_content": "현재 위치의 항목을 표시하려면 위치 권한이 필요합니다. 지금 허용하시겠습니까?",
"map_no_location_permission_title": "위치 권한 거부됨",
@@ -1838,7 +1841,7 @@
"play_motion_photo": "모션 포토 재생",
"play_or_pause_video": "동영상 재생/일시 정지",
"play_original_video": "원본 동영상 재생",
- "play_original_video_setting_description": "트랜스코딩된 영상보다 원본 영상을 우선 재생합니다. 원본이 호환되지 않는 형식인 경우 정상적으로 재생되지 않을 수 있습니다.",
+ "play_original_video_setting_description": "변환된 영상보다는 원본 영상을 재생하는 것을 권장합니다. 원본 영상이 호환되지 않으면 제대로 재생되지 않을 수 있습니다.",
"play_transcoded_video": "트랜스코딩 동영상 재생",
"please_auth_to_access": "계속 진행하려면 인증하세요.",
"plugin_method_filter_type": "필터",
diff --git a/i18n/lt.json b/i18n/lt.json
index b6194eba1c..9b7c2f02ad 100644
--- a/i18n/lt.json
+++ b/i18n/lt.json
@@ -189,18 +189,23 @@
"machine_learning_smart_search_enabled": "Įjungti išmaniąją paiešką",
"machine_learning_smart_search_enabled_description": "Jei išjungta, vaizdai nebus užkoduoti išmaniajai paieškai.",
"machine_learning_url_description": "Mašininio mokymosi serverio URL. Jei pateikta daugiau nei vienas URL, serveriai bus bandomi eilės tvarka nuo pirmo iki paskutinio tol, kol bus rastas vienas veikiantis serveris.",
+ "maintenance_backup_management": "Atsarginių kopijų tvarkymas",
"maintenance_delete_backup": "Ištrinti atsarginę kopiją",
"maintenance_delete_backup_description": "Šis failas bus negrįžtamai ištrintas.",
"maintenance_delete_error": "Nepavyko ištrinti atsarginės kopijos.",
+ "maintenance_integrity_check": "Tikrinti",
"maintenance_integrity_check_all": "Tikrinti Visus",
"maintenance_integrity_checksum_mismatch": "Checksum neatitikimas",
+ "maintenance_integrity_checksum_mismatch_description": "Failai, kurių kontrolinė suma diske nesutampa su Immich duomenų bazėje įrašyta kontroline suma.",
"maintenance_integrity_checksum_mismatch_job": "Tikrinti checksum neatitikimų",
"maintenance_integrity_checksum_mismatch_refresh_job": "Atnaujinti checksum neatitikimo ataskaitas",
"maintenance_integrity_missing_file": "Trūkstami failai",
+ "maintenance_integrity_missing_file_description": "Failai, įtraukti į Immich duomenų bazę, tačiau neegzistuojantys failų sistemoje.",
"maintenance_integrity_missing_file_job": "Tikrinti, ar nėra trūkstamų failų",
"maintenance_integrity_missing_file_refresh_job": "Atnaujinti trūkstamų failų ataskaitas",
"maintenance_integrity_report": "Vientisumo Ataskaita",
"maintenance_integrity_untracked_file": "Nesekami Failai",
+ "maintenance_integrity_untracked_file_description": "Failai Immich kataloguose, apie kuriuos Immich neturi jokių įrašų.",
"maintenance_integrity_untracked_file_job": "Patikrinti, ar nėra nesekamų failų",
"maintenance_integrity_untracked_file_refresh_job": "Atnaujinti nesekamų failų ataskaitas",
"maintenance_restore_backup": "Atstatyti atsarginę kopiją",
@@ -209,7 +214,7 @@
"maintenance_restore_backup_unknown_version": "Nepavyko nustatyti atsarginės kopijos versijos.",
"maintenance_restore_database_backup": "Atstatyti duomenų bazę",
"maintenance_restore_database_backup_description": "Grąžinti į ankstesnę duomenų bazės būseną naudojant atsarginę kopiją",
- "maintenance_settings": "Aptarnavimas",
+ "maintenance_settings": "Priežiūra",
"maintenance_settings_description": "Perjungti „Immich“ į aptarnavimo režimą.",
"maintenance_start": "Perjungti į aptarnavimo režimą",
"maintenance_start_error": "Nepavyko paleisti aptarnavimo režimo.",
@@ -1543,7 +1548,7 @@
"map_location_picker_page_use_location": "Naudoti šią vietovę",
"map_location_service_disabled_content": "Vietovės servisas turi būti įjungtas, kad rodytų elementus iš dabartinės vietovės. Įjungti vietovės servisą?",
"map_location_service_disabled_title": "Vietovės servisas išjungtas",
- "map_marker_for_images": "Žemėlapio žymeklis nuotraukoms yra {city}, {country}",
+ "map_marker_for_image": "Žemėlapio žymeklis nuotraukai, padarytai {city}, {country}",
"map_marker_with_image": "Žemėlapio žymeklis su nuotrauka",
"map_no_location_permission_content": "Reikalingas vietovės leidimas, kad rodytų elementus iš dabartinės vietovės. Ar norite suteikti leidimą?",
"map_no_location_permission_title": "Vietovės leidimas atmestas",
diff --git a/i18n/lv.json b/i18n/lv.json
index 37afd3e2dd..95e4ff12b2 100644
--- a/i18n/lv.json
+++ b/i18n/lv.json
@@ -1498,7 +1498,6 @@
"map_location_picker_page_use_location": "Izvēlēties šo atrašanās vietu",
"map_location_service_disabled_content": "Lai tiktu rādīti jūsu pašreizējās atrašanās vietas faili, ir jāaktivizē atrašanās vietas pakalpojums. Vai vēlaties to iespējot tagad?",
"map_location_service_disabled_title": "Atrašanās vietas Pakalpojums atslēgts",
- "map_marker_for_images": "Kartes marķieris attēliem, kas uzņemti {city}, {country}",
"map_marker_with_image": "Kartes marķieris ar attēlu",
"map_no_location_permission_content": "Atrašanās vietas atļauja ir nepieciešama, lai parādītu jūsu pašreizējās atrašanās vietas aktīvus. Vai vēlaties to atļaut tagad?",
"map_no_location_permission_title": "Atrašanās vietas Atļaujas liegtas",
diff --git a/i18n/ml.json b/i18n/ml.json
index a6365aff39..760bd8b47a 100644
--- a/i18n/ml.json
+++ b/i18n/ml.json
@@ -1346,7 +1346,6 @@
"map_location_picker_page_use_location": "ഈ സ്ഥലം ഉപയോഗിക്കുക",
"map_location_service_disabled_content": "നിങ്ങളുടെ നിലവിലെ സ്ഥാനത്ത് നിന്നുള്ള അസറ്റുകൾ പ്രദർശിപ്പിക്കുന്നതിന് ലൊക്കേഷൻ സേവനം പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്. ഇപ്പോൾ പ്രവർത്തനക്ഷമമാക്കണോ?",
"map_location_service_disabled_title": "ലൊക്കേഷൻ സേവനം പ്രവർത്തനരഹിതമാക്കി",
- "map_marker_for_images": "{city}, {country} എന്നിവിടങ്ങളിൽ എടുത്ത ചിത്രങ്ങൾക്കുള്ള മാപ്പ് മാർക്കർ",
"map_marker_with_image": "ചിത്രത്തോടുകൂടിയ മാപ്പ് മാർക്കർ",
"map_no_location_permission_content": "നിങ്ങളുടെ നിലവിലെ സ്ഥാനത്ത് നിന്നുള്ള അസറ്റുകൾ പ്രദർശിപ്പിക്കുന്നതിന് ലൊക്കേഷൻ അനുമതി ആവശ്യമാണ്. ഇപ്പോൾ അനുവദിക്കണോ?",
"map_no_location_permission_title": "ലൊക്കേഷൻ അനുമതി നിഷേധിച്ചു",
diff --git a/i18n/mr.json b/i18n/mr.json
index 2052cc2b5b..42260406e7 100644
--- a/i18n/mr.json
+++ b/i18n/mr.json
@@ -1341,7 +1341,6 @@
"map_location_picker_page_use_location": "हे लोकेशन वापरा",
"map_location_service_disabled_content": "सध्याच्या लोकेशनवरील अॅसेट्स दाखवण्यासाठी लोकेशन सेवा सक्षम असणे आवश्यक आहे. तुम्हाला ती आत्ता सक्षम करायची आहे का?",
"map_location_service_disabled_title": "लोकेशन सेवा बंद आहे",
- "map_marker_for_images": "{city}, {country} येथे घेतलेल्या प्रतिमांसाठी नकाशा मार्कर",
"map_marker_with_image": "प्रतिमेसह नकाशा मार्कर",
"map_no_location_permission_content": "सध्याच्या लोकेशनवरील अॅसेट्स दाखवण्यासाठी लोकेशन परवानगी आवश्यक आहे. तुम्हाला ती परवानगी आत्ता द्यायची आहे का?",
"map_no_location_permission_title": "लोकेशन परवानगी नाकारली",
diff --git a/i18n/nb_NO.json b/i18n/nb_NO.json
index 871d62cd9b..f4dd1592fa 100644
--- a/i18n/nb_NO.json
+++ b/i18n/nb_NO.json
@@ -80,7 +80,7 @@
"cron_expression_presets": "Forhåndsinnstillinger for Cron-uttrykk",
"disable_login": "Deaktiver innlogging",
"download_csv": "Last ned CSV",
- "duplicate_detection_job_description": "Kjør maskinlæring på filer for å oppdage lignende bilder. Krever bruk av Smart Søk",
+ "duplicate_detection_job_description": "Kjør maskinlæring på filer for å oppdage lignende bilder. Krever bruk av smartsøk",
"exclusion_pattern_description": "Ekskluderingsmønstre lar deg ignorere filer og mapper når du skanner biblioteket ditt. Dette er nyttig hvis du har mapper som inneholder filer du ikke vil importere, for eksempel RAW-filer.",
"export_config_as_json_description": "Last ned nåværende systemkonfigurasjon som en JSON fil",
"external_libraries_page_description": "Administrering for eksterne bibliotek",
@@ -187,7 +187,7 @@
"machine_learning_smart_search": "Smart søk",
"machine_learning_smart_search_description": "Søk etter bilder semantisk ved å bruke CLIP-embeddings",
"machine_learning_smart_search_enabled": "Aktiver smart søk",
- "machine_learning_smart_search_enabled_description": "Hvis deaktivert, vil bilder ikke bli enkodet for smart søk.",
+ "machine_learning_smart_search_enabled_description": "Hvis deaktivert så blir ikke bilder kodet for smartsøk.",
"machine_learning_url_description": "URL til maskinlærings-serveren. Hvis mer enn en URL er lagt inn, hver server vill bli forsøkt en om gangen frem til en svarer suksessfullt, i rekkefølge fra først til sist. Servere som ikke svarer vil midlertidig bli oversett frem til dem svarer igjen.",
"maintenance_backup_management": "Administrasjon av sikkerhetskopier",
"maintenance_delete_backup": "Slett sikkerhetskopi",
@@ -205,7 +205,7 @@
"maintenance_integrity_missing_file_refresh_job": "Oppdater rapporten for manglende filer",
"maintenance_integrity_report": "Integritetsrapport",
"maintenance_integrity_untracked_file": "Usporede filer",
- "maintenance_integrity_untracked_file_description": "Filer i Immich-mappene som ikke er registrert i databasen.",
+ "maintenance_integrity_untracked_file_description": "Filer i Immichs mapper som Immich ikke har noen oversikt over.",
"maintenance_integrity_untracked_file_job": "Sjekk etter usporede filer",
"maintenance_integrity_untracked_file_refresh_job": "Oppdater rapporten for usporede filer",
"maintenance_restore_backup": "Gjenopprett Sikkerhetskopi",
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Bruk dette stedet",
"map_location_service_disabled_content": "Lokasjonstjeneste må være aktivert for å vise elementer fra din nåværende lokasjon. Vil du aktivere det nå?",
"map_location_service_disabled_title": "Lokasjonstjeneste deaktivert",
- "map_marker_for_images": "Kart makeringer for bilder tatt i {city}, {country}",
"map_marker_with_image": "Kartmarkør med bilde",
"map_no_location_permission_content": "Lokasjonstilgang er påkrevet for å vise elementer fra din nåværende lokasjon. Vil du tillate det nå?",
"map_no_location_permission_title": "Lokasjonstilgang avvist",
diff --git a/i18n/ne.json b/i18n/ne.json
index 0967ef424b..029f8bb9e6 100644
--- a/i18n/ne.json
+++ b/i18n/ne.json
@@ -1 +1,17 @@
-{}
+{
+ "about": "बारे",
+ "account": "खाता",
+ "account_settings": "खाता सेटिङ",
+ "acknowledge": "स्वीकार",
+ "action": "कार्य",
+ "action_description": "छानियेको चिजमा सामुहिक कार्य",
+ "add_a_description": "थप विवरण",
+ "add_a_location": "स्थान थप्नुहोस्",
+ "add_a_name": "नाम हाल्नुहोस्",
+ "add_a_title": "शीर्षक हाल्नुहोस्",
+ "add_action": "कार्य थप्नुहोस्",
+ "add_action_description": "कार्य गर्नको लागि थप कार्यमा क्लिक गर्नुहोस्",
+ "add_assets": "फोटोहरू थप्नुहोस्",
+ "add_birthday": "जन्मदिन हाल्नुहोस",
+ "add_endpoint": "अन्तिम बिन्दु थप्नुहोस्"
+}
diff --git a/i18n/nl.json b/i18n/nl.json
index 804d07c311..b5d5198668 100644
--- a/i18n/nl.json
+++ b/i18n/nl.json
@@ -609,7 +609,7 @@
"asset_skipped": "Overgeslagen",
"asset_skipped_in_trash": "In prullenbak",
"asset_trashed": "Asset verwijderd",
- "asset_troubleshoot": "Asset probleemoplossing",
+ "asset_troubleshoot": "Item probleemoplossing",
"asset_uploaded": "Geüpload",
"asset_uploading": "Uploaden…",
"asset_viewer_settings_subtitle": "Beheer je instellingen voor galerijweergave",
@@ -638,14 +638,14 @@
"assets_were_part_of_album_count": "{count, plural, one {Item was} other {Items waren}} al onderdeel van het album",
"assets_were_part_of_albums_count": "{count, plural, one {Item is} other {Items zijn}} al onderdeel van de albums",
"authorized_devices": "Geautoriseerde apparaten",
- "automatic_endpoint_switching_subtitle": "Maak indien beschikbaar lokaal verbinding via het aangewezen wifi-netwerk en gebruik elders alternatieve verbindingen",
+ "automatic_endpoint_switching_subtitle": "Maak indien beschikbaar lokaal verbinding via het aangewezen wifinetwerk en gebruik elders alternatieve verbindingen",
"automatic_endpoint_switching_title": "Automatische serverwissel",
"autoplay_slideshow": "Diavoorstelling automatisch afspelen",
"back": "Terug",
"back_close_deselect": "Terug, sluiten of deselecteren",
"background_backup_running_error": "Back-up draait op de achtergrond, handmatige back-up kan niet worden gestart",
"background_location_permission": "Achtergrond locatie toestemming",
- "background_location_permission_content": "Om van netwerk te wisselen terwijl de app op de achtergrond draait, heeft Immich *altijd* toegang tot de exacte locatie nodig om de naam van het WiFi-netwerk te kunnen lezen",
+ "background_location_permission_content": "Om van netwerk te wisselen terwijl de app op de achtergrond draait, heeft Immich *altijd* toegang tot de exacte locatie nodig om de naam van het wifinetwerk te kunnen lezen",
"background_options": "Achtergrond opties",
"backup": "Back-up",
"backup_album_selection_page_albums_device": "Albums op apparaat ({count})",
@@ -680,7 +680,7 @@
"backup_controller_page_background_is_on": "Automatische achtergrond back-up staat aan",
"backup_controller_page_background_turn_off": "Achtergrondservice uitzetten",
"backup_controller_page_background_turn_on": "Achtergrondservice aanzetten",
- "backup_controller_page_background_wifi": "Alleen op WiFi",
+ "backup_controller_page_background_wifi": "Alleen op wifi",
"backup_controller_page_backup": "Back-up",
"backup_controller_page_backup_selected": "Geselecteerd: ",
"backup_controller_page_backup_sub": "Geback-upte foto's en video's",
@@ -785,7 +785,7 @@
"charging_requirement_mobile_backup": "Achtergrond backup vereist dat het apparaat wordt opgeladen",
"check_corrupt_asset_backup": "Controleer op corrupte back-ups van items",
"check_corrupt_asset_backup_button": "Controle uitvoeren",
- "check_corrupt_asset_backup_description": "Voer deze controle alleen uit via WiFi en nadat alle items zijn geback-upt. De procedure kan een paar minuten duren.",
+ "check_corrupt_asset_backup_description": "Voer deze controle alleen uit via wifi en nadat van alle items een back-up gemaakt is. De procedure kan een paar minuten duren.",
"check_logs": "Controleer logboek",
"checksum": "Controlegetal",
"choose": "Kies",
@@ -795,14 +795,14 @@
"cleanup_confirm_prompt_title": "Van dit apparaat verwijderen?",
"cleanup_deleted_assets": "{count} items verplaats naar prullenbak van apparaat",
"cleanup_deleting": "Naar prullenbak verplaatsen...",
- "cleanup_found_assets": "Er zijn {count} backup bestanden gevonden",
- "cleanup_found_assets_with_size": "Er zijn {count} back-upbestanden gevonden ({size})",
+ "cleanup_found_assets": "Er zijn {count} back-upbestanden gevonden",
+ "cleanup_found_assets_with_size": "Er zijn {count} back-upbestanden gevonden ({size})",
"cleanup_icloud_shared_albums_excluded": "Gedeelde albums van iCloud zijn uitgesloten van de scan",
"cleanup_no_assets_found": "Er zijn geen bestanden gevonden die aan bovenstaande criteria voldoen. Free Up Space kan alleen bestanden verwijderen die op de server zijn geback-upt",
"cleanup_preview_title": "Bestanden te verwijderen ({count})",
"cleanup_step3_description": "Scan naar back-upbestanden die overeenkomen met uw datum en behoud uw instellingen.",
"cleanup_step4_summary": "{count} bestanden (gemaakt vóór {date}) die van uw lokale apparaat moeten worden verwijderd. Foto's blijven toegankelijk via de Immich-app.",
- "cleanup_trash_hint": "Om de opslagruimte volledig vrij te maken, opent u de systeemgalerij-app en leegt u de prullenbak",
+ "cleanup_trash_hint": "Open de galerij-app en leeg de prullenbak om de opslagruimte volledig vrij te maken",
"clear": "Wissen",
"clear_all": "Alles wissen",
"clear_all_recent_searches": "Wis alle recente zoekopdrachten",
@@ -814,7 +814,7 @@
"client_cert_enter_password": "Voer wachtwoord in",
"client_cert_import": "Importeren",
"client_cert_import_success_msg": "Cliëntcertificaat is geïmporteerd",
- "client_cert_invalid_msg": "Ongeldig certificaatbestand of verkeerd wachtwoord",
+ "client_cert_invalid_msg": "Ongeldig certificaatbestand of verkeerd wachtwoord",
"client_cert_password_message": "Voer het wachtwoord voor dit certificaat in",
"client_cert_password_title": "Certificaat wachtwoord",
"client_cert_remove_msg": "Clientcertificaat is verwijderd",
@@ -850,7 +850,7 @@
"confirm_tag_face_unnamed": "Wil je dit gezicht taggen?",
"connected_device": "Verbonden apparaat",
"connected_to": "Verbonden met",
- "contain": "Bevat",
+ "contain": "Passend",
"context": "Context",
"continue": "Doorgaan",
"control_bottom_app_bar_add_tags": "Tags toevoegen",
@@ -1066,7 +1066,7 @@
"enabled": "Ingeschakeld",
"end_date": "Einddatum",
"enqueued": "In de wachtrij",
- "enter_wifi_name": "Voer de WiFi-naam in",
+ "enter_wifi_name": "Voer de naam van het wifinetwerk in",
"enter_your_pin_code": "Voer uw pincode in",
"enter_your_pin_code_subtitle": "Voer uw pincode in om toegang te krijgen tot de vergrendelde map",
"error": "Fout",
@@ -1114,7 +1114,7 @@
"failed_to_stack_assets": "Fout bij stapelen van items",
"failed_to_tag_assets": "Fout bij taggen van items",
"failed_to_unstack_assets": "Fout bij ontstapelen van items",
- "failed_to_update_notification_status": "Kon notificatiestatus niet updaten",
+ "failed_to_update_notification_status": "Kan notificatiestatus niet updaten",
"incorrect_email_or_password": "Onjuist e-mailadres of wachtwoord",
"library_folder_already_exists": "Dit importpad bestaat al.",
"page_not_found": "Pagina niet gevonden",
@@ -1237,7 +1237,7 @@
"external": "Extern",
"external_libraries": "Externe bibliotheken",
"external_network": "Extern netwerk",
- "external_network_sheet_info": "Als je niet verbonden bent met het opgegeven WiFi-netwerk, maakt de app verbinding met de server via de eerst bereikbare URL in de onderstaande lijst, van boven naar beneden",
+ "external_network_sheet_info": "Als je niet verbonden bent met het opgegeven wifinetwerk, maakt de app verbinding met de server via de eerst bereikbare URL in de onderstaande lijst, van boven naar beneden",
"f_number": "Diafragma",
"face_unassigned": "Niet toegewezen",
"failed": "Mislukt",
@@ -1261,7 +1261,7 @@
"filename": "Bestandsnaam",
"filetype": "Bestandstype",
"filter": "Filter",
- "filter_description": "Filtervoorwaarden voor doel items",
+ "filter_description": "Filtervoorwaarden voor betreffende items",
"filter_people": "Filteren op persoon",
"filter_places": "Filteren op locatie",
"filter_tags": "Filteren op label",
@@ -1273,7 +1273,7 @@
"folder": "Map",
"folder_not_found": "Map niet gevonden",
"folders": "Mappen",
- "folders_feature_description": "Bladeren door de mapweergave van de foto's en video's op het bestandssysteem",
+ "folders_feature_description": "Bladeren door de mapweergave van de foto's en video's op het bestandssysteem",
"forgot_pin_code_question": "Pincode vergeten?",
"forward": "Vooruit",
"free_up_space": "Maak opslag vrij",
@@ -1287,7 +1287,7 @@
"geolocation_instruction_location": "Klik op een item met gps-coördinaten om de locatie te gebruiken, of kies een locatie direct op de kaart",
"get_help": "Hulp vragen",
"get_people_error": "Fout bij ophalen mensen",
- "get_wifiname_error": "Kon de WiFi-naam niet ophalen. Zorg ervoor dat je de benodigde machtigingen hebt verleend en verbonden bent met een WiFi-netwerk",
+ "get_wifiname_error": "Kon de naam van het netwerk niet ophalen. Zorg ervoor dat je de benodigde machtigingen hebt verleend en verbonden bent met een wifinetwerk",
"getting_started": "Aan de slag",
"go_back": "Ga terug",
"go_to_folder": "Ga naar map",
@@ -1387,9 +1387,9 @@
"invite_to_album": "Uitnodigen voor album",
"ios_debug_info_fetch_ran_at": "Ophalen gelukt op {dateTime}",
"ios_debug_info_last_sync_at": "Laatst gesynchroniseerd {dateTime}",
- "ios_debug_info_no_processes_queued": "Geen achtergrondprocessen in de wachtrij",
+ "ios_debug_info_no_processes_queued": "Geen achtergrondprocessen in de wachtrij",
"ios_debug_info_no_sync_yet": "Er is nog geen achtergrondsynchronisatie uitgevoerd",
- "ios_debug_info_processes_queued": "{count, plural, one {{count} achtergrondproces in de wachtrij} other {{count} achtergrondprocessen in de wachtrij}}",
+ "ios_debug_info_processes_queued": "{count, plural, one {{count} achtergrondproces} other {{count} achtergrondprocessen}} in de wachtrij",
"ios_debug_info_processing_ran_at": "Verwerking uitgevoerd op {dateTime}",
"iso": "ISO",
"items_count": "{count, plural, one {# item} other {# items}}",
@@ -1456,10 +1456,10 @@
"local_id": "Lokaal ID",
"local_media_summary": "Lokale media samenvatting",
"local_network": "Lokaal netwerk",
- "local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt",
+ "local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven wifinetwerk wordt gebruikt",
"location": "Locatie",
"location_permission": "Locatietoestemming",
- "location_permission_content": "Om de functie voor automatische serverwissel te gebruiken, heeft Immich toegang tot de exacte locatie nodig om de naam van het huidige WiFi-netwerk te kunnen bepalen",
+ "location_permission_content": "Om de functie voor automatische serverwissel te gebruiken, heeft Immich toegang tot de exacte locatie nodig om de naam van het huidige wifinetwerk te kunnen bepalen",
"location_picker_choose_on_map": "Kies op kaart",
"location_picker_latitude_error": "Voer een geldige breedtegraad in",
"location_picker_latitude_hint": "Voer hier je breedtegraad in",
@@ -1502,8 +1502,8 @@
"longitude": "Lengtegraad",
"look": "Uiterlijk",
"loop_videos": "Video's herhalen",
- "loop_videos_description": "Inschakelen om video's automatisch te herhalen in de detailweergave.",
- "main_branch_warning": "Je gebruikt een ontwikkelingsversie. We raden je ten zeerste aan een releaseversie te gebruiken!",
+ "loop_videos_description": "Inschakelen om video's automatisch te herhalen in de detailweergave.",
+ "main_branch_warning": "Je gebruikt een ontwikkelingsversie. We raden je ten zeerste aan een releaseversie te gebruiken!",
"main_menu": "Hoofdmenu",
"maintenance_action_restore": "Database wordt hersteld",
"maintenance_description": "Immich is in de onderhoudsmodus gezet.",
@@ -1512,7 +1512,7 @@
"maintenance_logged_in_as": "Momenteel ingelogd als {user}",
"maintenance_restore_from_backup": "Herstellen vanaf backup",
"maintenance_restore_library": "Bibliotheek herstellen",
- "maintenance_restore_library_confirm": "Als dit er goed uit ziet ga dan verder om de backup terug te zetten!",
+ "maintenance_restore_library_confirm": "Als dit er goed uit ziet, ga dan verder om de back-up terug te zetten!",
"maintenance_restore_library_description": "Database wordt hersteld",
"maintenance_restore_library_folder_has_files": "{folder} heeft {count} map(pen)",
"maintenance_restore_library_folder_no_files": "{folder} mist bestanden!",
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Gebruik deze locatie",
"map_location_service_disabled_content": "Locatie service moet ingeschakeld zijn om items van je huidige locatie weer te geven. Wil je het nu inschakelen?",
"map_location_service_disabled_title": "Locatie service uitgeschakeld",
- "map_marker_for_images": "Kaartmarkering voor afbeeldingen gemaakt in {city}, {country}",
+ "map_marker_for_image": "Kaartmarkering voor afbeelding gemaakt in {city}, {country}",
"map_marker_with_image": "Kaartmarkering met afbeelding",
"map_no_location_permission_content": "Locatietoestemming is nodig om items van je huidige locatie weer te geven. Wil je dit nu toestaan?",
"map_no_location_permission_title": "Locatietoestemming geweigerd",
@@ -1983,7 +1983,7 @@
"reset_sqlite": "SQLite database resetten",
"reset_sqlite_clear_app_data": "Wis gegevens",
"reset_sqlite_confirmation": "Weet je zeker dat je de app-gegevens wilt wissen? Hiermee worden alle instellingen verwijderd en word je uitgelogd.",
- "reset_sqlite_confirmation_note": "Let op: Je moet de app opnieuw opstarten nadat je deze hebt gewist.",
+ "reset_sqlite_confirmation_note": "Let op: je moet de app opnieuw opstarten nadat je deze hebt gewist.",
"reset_sqlite_done": "App data is gewist. Start Immich opnieuw op en log opnieuw in.",
"reset_sqlite_success": "De SQLite database is succesvol gereset",
"reset_to_default": "Resetten naar standaard",
@@ -1996,7 +1996,7 @@
"restore_user": "Gebruiker herstellen",
"restored_asset": "Item hersteld",
"resume": "Hervatten",
- "resume_paused_jobs": "Hervat {count, plural, one {# gepauseerde taak} other {# gepauseerde taken}}",
+ "resume_paused_jobs": "{count, plural, one {# gepauzeerde taak} other {# gepauzeerde taken}} hervatten",
"retry_upload": "Opnieuw uploaden",
"review_duplicates": "Controleer duplicaten",
"review_large_files": "Grote bestanden beoordelen",
@@ -2470,8 +2470,8 @@
"use_template": "Gebruik template",
"user": "Gebruiker",
"user_has_been_deleted": "Deze gebruiker is verwijderd.",
- "user_id": "Gebruikers ID",
- "user_liked": "{user} heeft {type, select, photo {deze foto} video {deze video} asset {} other {dit item}} geliket",
+ "user_id": "Gebruikers-ID",
+ "user_liked": "{user} vindt {type, select, photo {deze foto} video {deze video} asset {} other {dit item}} leuk",
"user_pin_code_settings": "Pincode",
"user_pin_code_settings_description": "Beheer je pincode",
"user_privacy": "Gebruikersprivacy",
@@ -2479,7 +2479,7 @@
"user_purchase_settings_description": "Beheer je aankoop",
"user_role_set": "{user} instellen als {role}",
"user_usage_detail": "Gedetailleerd gebruik van gebruikers",
- "user_usage_stats": "Statistieken van accountgebruik",
+ "user_usage_stats": "Accountstatistieken",
"user_usage_stats_description": "Bekijk statistieken van accountgebruik",
"username": "Gebruikersnaam",
"users": "Gebruikers",
@@ -2532,7 +2532,7 @@
"welcome_to_immich": "Welkom bij Immich",
"when": "Wanneer",
"width": "Breedte",
- "wifi_name": "WiFi-naam",
+ "wifi_name": "Wifinetwerk",
"workflow": "Werkstroom",
"workflow_delete_prompt": "Weet je zeker dat je deze werkstroom wilt verwijderen?",
"workflow_deleted": "Werkstroom verwijderd",
@@ -2554,7 +2554,7 @@
"years_ago": "{years, plural, one {Een jaar} other {# jaar}} geleden",
"yes": "Ja",
"you_dont_have_any_shared_links": "Je hebt geen gedeelde links",
- "your_wifi_name": "Je WiFi-naam",
+ "your_wifi_name": "Je wifinetwerk",
"zero_to_clear_rating": "druk op 0 om de sterwaardering te verwijderen",
"zoom_image": "Inzoomen",
"zoom_to_bounds": "Zoom naar randen"
diff --git a/i18n/pl.json b/i18n/pl.json
index a92ef20f1a..e7e5a76c8b 100644
--- a/i18n/pl.json
+++ b/i18n/pl.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Użyj tej lokalizacji",
"map_location_service_disabled_content": "Aby wyświetlić zasoby z Twojej bieżącej lokalizacji, należy włączyć usługę lokalizacyjną. Czy chcesz to teraz włączyć?",
"map_location_service_disabled_title": "Usługa lokalizacji wyłączona",
- "map_marker_for_images": "Wskaźnik mapy dla zdjęć zrobionych w {city}, {country}",
+ "map_marker_for_image": "Znacznik na mapie dla zdjęcia wykonanego w {city}, {country}",
"map_marker_with_image": "Znacznik na mapie ze zdjęciem",
"map_no_location_permission_content": "Aby wyświetlić zasoby z Twojej bieżącej lokalizacji, potrzebne jest pozwolenie na lokalizację. Czy chcesz teraz na to pozwolić?",
"map_no_location_permission_title": "Odmowa dostępu do lokalizacji",
@@ -2031,7 +2031,7 @@
"search_by_full_path": "Wyszukaj według pełnej ścieżki lub folderu",
"search_by_full_path_example": "/John/Projekty/Drukowanie_3D/2026-07-01 – możesz wyszukiwać hasła takie jak Projekty, 3D, Drukowanie, 2026 itp.",
"search_by_ocr": "Wyszukaj przy użyciu OCR",
- "search_by_ocr_example": "Latte",
+ "search_by_ocr_example": "Kawa, trampolina",
"search_camera_lens_model": "Wyszukaj model obiektywu...",
"search_camera_make": "Wyszukaj markę aparatu...",
"search_camera_model": "Wyszukaj model aparatu...",
@@ -2185,7 +2185,7 @@
"shared_by_you": "Udostępnione przez ciebie",
"shared_from_partner": "Zdjęcia od {partner}",
"shared_intent_upload_button_progress_text": "{current} / {total} Przesłano",
- "shared_link_app_bar_title": "Udostępnione",
+ "shared_link_app_bar_title": "Udostępnione linki",
"shared_link_clipboard_copied_massage": "Skopiowane do schowka",
"shared_link_clipboard_text": "Link: {link}\nHasło: {password}",
"shared_link_create_error": "Błąd podczas tworzenia linka do udostępnienia",
diff --git a/i18n/pt.json b/i18n/pt.json
index 0dabf8ff60..13d790f04c 100644
--- a/i18n/pt.json
+++ b/i18n/pt.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Utilizar esta localização",
"map_location_service_disabled_content": "Serviço de localização precisa de estar ativado para mostrar recursos da localização atual. Deseja ativar agora?",
"map_location_service_disabled_title": "Serviço de localização desativado",
- "map_marker_for_images": "Marcador no mapa para fotos tiradas em {city}, {country}",
"map_marker_with_image": "Marcador de mapa com imagem",
"map_no_location_permission_content": "A permissão da localização é necessária para mostrar recursos da localização atual. Deseja conceder a permissão agora?",
"map_no_location_permission_title": "Permissão de localização foi negada",
diff --git a/i18n/pt_BR.json b/i18n/pt_BR.json
index cbb96657db..bedf3314ee 100644
--- a/i18n/pt_BR.json
+++ b/i18n/pt_BR.json
@@ -189,18 +189,23 @@
"machine_learning_smart_search_enabled": "Habilitar a Pesquisa Inteligente",
"machine_learning_smart_search_enabled_description": "Se desativado, as imagens não serão codificadas para pesquisa inteligente.",
"machine_learning_url_description": "A URL do servidor de aprendizado de máquina. Se mais de uma URL for fornecida, elas serão tentadas, uma de cada vez e na ordem indicada, até que uma responda com sucesso. Servidores que não responderem serão ignorados temporariamente até voltarem a estar conectados.",
+ "maintenance_backup_management": "Gerenciamento de backup",
"maintenance_delete_backup": "Excluir Backup",
"maintenance_delete_backup_description": "Este arquivo será excluído de forma irreversível.",
"maintenance_delete_error": "Falha ao excluir o backup.",
+ "maintenance_integrity_check": "Verificar",
"maintenance_integrity_check_all": "Verificar tudo",
"maintenance_integrity_checksum_mismatch": "Checksum não corresponde",
+ "maintenance_integrity_checksum_mismatch_description": "Arquivos cujo o checksum atual não corresponde ao checksum que Immich armazenou no banco de dados.",
"maintenance_integrity_checksum_mismatch_job": "Verificar se há erros de checksum",
"maintenance_integrity_checksum_mismatch_refresh_job": "Atualizar # de checksum sem correspondência",
"maintenance_integrity_missing_file": "Arquivos não encontrados",
+ "maintenance_integrity_missing_file_description": "Arquivos que Immich rastreou em seu banco de dados, mas que não existem no sistema de arquivos.",
"maintenance_integrity_missing_file_job": "Verificar se há arquivos não encontrados",
"maintenance_integrity_missing_file_refresh_job": "Atualizar # de arquivos não encontrados",
"maintenance_integrity_report": "Relatório de integridade",
"maintenance_integrity_untracked_file": "Arquivos não rastreados",
+ "maintenance_integrity_untracked_file_description": "Arquivos não rastreados dentro dos diretórios do Immich.",
"maintenance_integrity_untracked_file_job": "Verificar se há arquivos não rastreados",
"maintenance_integrity_untracked_file_refresh_job": "Atualizar # de arquivos não rastreados",
"maintenance_restore_backup": "Restaurar Backup",
@@ -1543,7 +1548,7 @@
"map_location_picker_page_use_location": "Use esta localização",
"map_location_service_disabled_content": "O serviço de localização precisa estar ativado para exibir os arquivos da sua localização atual. Deseja ativar agora?",
"map_location_service_disabled_title": "Serviço de localização desativado",
- "map_marker_for_images": "Marcador de mapa para imagens tiradas em {city}, {country}",
+ "map_marker_for_image": "Marcador do mapa para a foto tirada em {city}, {country}",
"map_marker_with_image": "Marcador de mapa com imagem",
"map_no_location_permission_content": "É necessária a permissão de localização para exibir os arquivos da sua localização atual. Deseja conceder a permissão agora?",
"map_no_location_permission_title": "Permissão de localização foi negada",
diff --git a/i18n/ro.json b/i18n/ro.json
index 89ddec48f8..ab092d591d 100644
--- a/i18n/ro.json
+++ b/i18n/ro.json
@@ -1523,7 +1523,6 @@
"map_location_picker_page_use_location": "Folosește această locație",
"map_location_service_disabled_content": "Serviciul de localizare trebuie să fie activat pentru a afișa resursele din locația actuală. Dorești să o activezi acum?",
"map_location_service_disabled_title": "Serviciul de localizare este dezactivat",
- "map_marker_for_images": "Marcator de hartă pentru imaginile realizate în {city}, {country}",
"map_marker_with_image": "Marcator de hartă cu imagine",
"map_no_location_permission_content": "Permisiunea de localizare este necesară pentru a afișa resursele din locația actuală. Dorești să o activezi acum?",
"map_no_location_permission_title": "Permisiunea de localizare este dezactivată",
diff --git a/i18n/ru.json b/i18n/ru.json
index 7aca149e69..095fc0fb8b 100644
--- a/i18n/ru.json
+++ b/i18n/ru.json
@@ -1548,8 +1548,8 @@
"map_location_picker_page_use_location": "Это местоположение",
"map_location_service_disabled_content": "Для отображения объектов в текущем месте необходимо включить службу определения местоположения. Включить?",
"map_location_service_disabled_title": "Служба определения местоположения отключена",
- "map_marker_for_images": "Маркер на карте для изображений, сделанных в {city}, {country}",
- "map_marker_with_image": "Маркер на карте с изображением",
+ "map_marker_for_image": "Маркер на карте для объекта, сделанного в {city}, {country}",
+ "map_marker_with_image": "Маркер на карте для объекта",
"map_no_location_permission_content": "Для отображения объектов в текущем месте необходимо разрешение на определение местоположения. Предоставить разрешение?",
"map_no_location_permission_title": "Доступ к местоположению отклонен",
"map_settings": "Настройки карты",
diff --git a/i18n/sk.json b/i18n/sk.json
index 095500418e..866a2e668b 100644
--- a/i18n/sk.json
+++ b/i18n/sk.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "Použiť túto polohu",
"map_location_service_disabled_content": "Služba určovania polohy musí byť povolená, aby sa zobrazovali položky z vašej aktuálnej polohy. Chcete ju teraz zapnúť?",
"map_location_service_disabled_title": "Služba určovania polohy vypnutá",
- "map_marker_for_images": "Značka na mape pre obrázky odfotené v {city}, {country}",
"map_marker_with_image": "Mapová značka pre obrázok",
"map_no_location_permission_content": "Na zobrazenie položiek z vašej aktuálnej polohy je potrebné povolenie na polohu. Chcete to teraz povoliť?",
"map_no_location_permission_title": "Povolenie polohy zamietnuté",
diff --git a/i18n/sl.json b/i18n/sl.json
index 0a73487909..d3a41f5f9a 100644
--- a/i18n/sl.json
+++ b/i18n/sl.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Uporabi to lokacijo",
"map_location_service_disabled_content": "Lokacijska storitev mora biti omogočena za prikaz sredstev z vaše trenutne lokacije. Ali jo želite takoj omogočiti?",
"map_location_service_disabled_title": "Lokacijska storitev onemogočena",
- "map_marker_for_images": "Oznaka zemljevida za slike, posnete v {city}, {country}",
+ "map_marker_for_image": "Oznaka na zemljevidu za sliko, posneto v {city}, {country}",
"map_marker_with_image": "Oznaka zemljevida s sliko",
"map_no_location_permission_content": "Za prikaz sredstev z vaše trenutne lokacije je potrebno dovoljenje za lokacijo. Ali to želite takoj dovoliti?",
"map_no_location_permission_title": "Dovoljenje za lokacijo je zavrnjeno",
diff --git a/i18n/sr_Cyrl.json b/i18n/sr_Cyrl.json
index 3bd900a8d9..2733eb693b 100644
--- a/i18n/sr_Cyrl.json
+++ b/i18n/sr_Cyrl.json
@@ -1184,7 +1184,6 @@
"map_location_picker_page_use_location": "Користите ову локацију",
"map_location_service_disabled_content": "Услуга локације мора бити омогућена да би се приказивала средства са ваше тренутне локације. Да ли желите да је сада омогућите?",
"map_location_service_disabled_title": "Услуга локације је онемогућена",
- "map_marker_for_images": "Означивач на мапи за слике снимљене у {city}, {country}",
"map_marker_with_image": "Маркер на мапи са сликом",
"map_no_location_permission_content": "Потребна је дозвола за локацију да би се приказали ресурси са ваше тренутне локације. Да ли желите да је сада дозволите?",
"map_no_location_permission_title": "Дозвола за локацију је одбијена",
diff --git a/i18n/sr_Latn.json b/i18n/sr_Latn.json
index 16793f86ce..0bb3885461 100644
--- a/i18n/sr_Latn.json
+++ b/i18n/sr_Latn.json
@@ -1370,7 +1370,6 @@
"map_location_picker_page_use_location": "Koristite ovu lokaciju",
"map_location_service_disabled_content": "Usluga lokacije mora biti omogućena da bi se prikazivala sredstva sa vaše trenutne lokacije. Da li želite da je sada omogućite?",
"map_location_service_disabled_title": "Usluga lokacije je onemogućena",
- "map_marker_for_images": "Označivač na mapi za slike snimljene u {city}, {country}",
"map_marker_with_image": "Marker na mapi sa slikom",
"map_no_location_permission_content": "Potrebna je dozvola za lokaciju da bi se prikazali resursi sa vaše trenutne lokacije. Da li želite da je sada dozvolite?",
"map_no_location_permission_title": "Dozvola za lokaciju je odbijena",
diff --git a/i18n/sv.json b/i18n/sv.json
index 9d8f0a06b1..d702b585c9 100644
--- a/i18n/sv.json
+++ b/i18n/sv.json
@@ -1548,7 +1548,7 @@
"map_location_picker_page_use_location": "Använd den här platsen",
"map_location_service_disabled_content": "Platstjänst måste vara aktiverad för att visa objekt från din nuvarande plats. Vill du aktivera den nu?",
"map_location_service_disabled_title": "Platstjänst inaktiverad",
- "map_marker_for_images": "Kartmarkering för bilder tagna i {city}, {country}",
+ "map_marker_for_image": "Kartmarkör för bild tagen i {city}, {country}",
"map_marker_with_image": "Kartmarkör med bild",
"map_no_location_permission_content": "Platsrättighet är nödvändigt för att kunna visa objekt från din nuvarande plats. Vill du tillåta det nu?",
"map_no_location_permission_title": "Platsrättighet nekad",
diff --git a/i18n/ta.json b/i18n/ta.json
index 4812d40a7d..2e58a1ce4e 100644
--- a/i18n/ta.json
+++ b/i18n/ta.json
@@ -1485,7 +1485,6 @@
"map_location_picker_page_use_location": "இந்த இருப்பிடத்தைப் பயன்படுத்தவும்",
"map_location_service_disabled_content": "உங்கள் தற்போதைய இருப்பிடத்திலிருந்து சொத்துக்களைக் காட்ட இருப்பிட பணி இயக்கப்பட வேண்டும். இப்போது அதை இயக்க விரும்புகிறீர்களா?",
"map_location_service_disabled_title": "இருப்பிட பணி முடக்கப்பட்டது",
- "map_marker_for_images": "{city}, {country}",
"map_marker_with_image": "படத்துடன் வரைபட மார்க்கர்",
"map_no_location_permission_content": "உங்கள் தற்போதைய இருப்பிடத்திலிருந்து சொத்துக்களைக் காட்ட இருப்பிட இசைவு தேவை. இப்போது அதை அனுமதிக்க விரும்புகிறீர்களா?",
"map_no_location_permission_title": "இருப்பிட இசைவு மறுக்கப்பட்டது",
diff --git a/i18n/te.json b/i18n/te.json
index eb8fe59f43..6c2b46136d 100644
--- a/i18n/te.json
+++ b/i18n/te.json
@@ -837,7 +837,6 @@
"manage_your_devices": "మీ లాగిన్ అయిన పరికరాలను నిర్వహించండి",
"manage_your_oauth_connection": "మీ OAuth కనెక్షన్ని నిర్వహించండి",
"map": "మ్యాప్",
- "map_marker_for_images": "{city}, {country} లో తీసిన చిత్రాల కోసం మ్యాప్ మార్కర్",
"map_marker_with_image": "చిత్రంతో మ్యాప్ మార్కర్",
"map_settings": "మ్యాప్ సెట్టింగ్లు",
"matches": "మ్యాచ్లు",
diff --git a/i18n/th.json b/i18n/th.json
index 08d95434d3..08fe16d210 100644
--- a/i18n/th.json
+++ b/i18n/th.json
@@ -1468,7 +1468,6 @@
"map_location_picker_page_use_location": "ใช้ตำแหน่งนี้",
"map_location_service_disabled_content": "ต้องเปิดตำแหน่งเพื่อแสดงทรัพยากรจากตำแหน่งปัจจุบัน เปิดตอนนี้?",
"map_location_service_disabled_title": "บริการตำแหน่งถูกปิด",
- "map_marker_for_images": "หมุดแผนที่สำหรับรูปถ่ายที่ {city}, {country}",
"map_marker_with_image": "หมุดแผนที่กับรูปถ่าย",
"map_no_location_permission_content": "จำเป็นต้องมีสิทธิ์เข้าถึงตำแหน่งเพื่อแสดงทรัพยากรจากตำแหน่งปัจจุบัน อนุญาตตอนนี้?",
"map_no_location_permission_title": "สิทธิ์เข้าถึงตำแหน่งถูกปฏิเสธ",
diff --git a/i18n/tr.json b/i18n/tr.json
index 761e020fea..be14dfedc1 100644
--- a/i18n/tr.json
+++ b/i18n/tr.json
@@ -79,6 +79,7 @@
"cron_expression_description": "Cron formatını kullanarak tarama aralığını belirle. Daha fazla bilgi için örneğin Crontab Guru’ya bakın",
"cron_expression_presets": "Cron ifadesi ön ayarları",
"disable_login": "Girişi devre dışı bırak",
+ "download_csv": "CSV’yi indir",
"duplicate_detection_job_description": "Benzer fotoğrafları bulmak için makine öğrenmesini çalıştır. Bu işlem Akıllı Arama'ya bağlıdır",
"exclusion_pattern_description": "Kütüphaneyi tararken dosya ve klasörleri görmezden gelmek için dışlama desenlerini kullanabilirsiniz. RAW dosyaları gibi bazı dosya ve klasörleri içe aktarmak istemediğinizde bu seçeneği kullanabilirsiniz.",
"export_config_as_json_description": "Geçerli sistem yapılandırmasını JSON dosyası olarak indir",
@@ -188,9 +189,23 @@
"machine_learning_smart_search_enabled": "Akıllı aramayı etkinleştir",
"machine_learning_smart_search_enabled_description": "Eğer devre dışı bırakılırsa fotoğraflar akıllı arama için işlenmeyecek.",
"machine_learning_url_description": "Makine öğrenimi sunucusunun URL’si. Birden fazla URL sağlanırsa, her sunucu sırayla tek tek denenir ve biri başarılı yanıt verene kadar devam edilir. Yanıt vermeyen sunucular, çevrimiçi duruma gelene kadar geçici olarak yok sayılır.",
+ "maintenance_backup_management": "Yedekleme sistemi",
"maintenance_delete_backup": "Yedeği Sil",
"maintenance_delete_backup_description": "Bu dosya geri alınamaz şekilde silinecektir.",
"maintenance_delete_error": "Yedek silinemedi.",
+ "maintenance_integrity_check": "Kontrol et",
+ "maintenance_integrity_check_all": "Hepsini kontrol et",
+ "maintenance_integrity_checksum_mismatch_description": "Disk üzerindeki sağlama toplamı, Immich'in veritabanında sakladığı sağlama toplamıyla uyuşmayan dosyalar.",
+ "maintenance_integrity_checksum_mismatch_job": "Sağlama toplamı uyuşmazlıklarını kontrol et",
+ "maintenance_integrity_missing_file": "Eksik Dosyalar",
+ "maintenance_integrity_missing_file_description": "Immich'in veritabanında izlediği ancak dosya sisteminde bulunmayan dosyalar.",
+ "maintenance_integrity_missing_file_job": "Eksik dosyaları kontrol et",
+ "maintenance_integrity_missing_file_refresh_job": "Eksik dosya raporlarını yenile",
+ "maintenance_integrity_report": "Entegrasyon Raporu",
+ "maintenance_integrity_untracked_file": "İzlenmeyen Dosyalar",
+ "maintenance_integrity_untracked_file_description": "Immich'in dizinlerinde bulunan ancak Immich'in hiçbir kaydının bulunmadığı dosyalar.",
+ "maintenance_integrity_untracked_file_job": "İzlenmeyen dosyaları kontrol et",
+ "maintenance_integrity_untracked_file_refresh_job": "İzlenmeyen dosya raporlarını yenile",
"maintenance_restore_backup": "Yedeği Geri Yükle",
"maintenance_restore_backup_description": "Immich tamamen silinecek ve seçilen yedekten geri yüklenecektir. İşleme devam etmeden önce bir yedek oluşturulacaktır.",
"maintenance_restore_backup_different_version": "Bu yedek, Immich’in farklı bir sürümüyle oluşturulmuş!",
@@ -305,6 +320,7 @@
"refreshing_all_libraries": "Tüm kütüphaneler yenileniyor",
"registration": "Yönetici Kaydı",
"registration_description": "Sistemdeki ilk kullanıcı olduğunuz için hesabınız Yönetici olarak ayarlandı. Yeni oluşturulan üyeliklerin, ve yönetici görevlerinin sorumlusu olarak atandınız.",
+ "release_channel_release_candidate": "Yayın adayı",
"release_channel_stable": "Stabil",
"remove_failed_jobs": "Başarısız işleri kaldır",
"require_password_change_on_login": "Kullanıcının ilk girişinde şifre değiştirmesini zorunlu kıl",
@@ -400,6 +416,9 @@
"transcoding_preferred_hardware_device_description": "Sadece VAAPI ve QSV için uygulanır. Donanım kod çevrimi için DRI Node ayarlar.",
"transcoding_preset_preset": "Ön ayar (-ön)",
"transcoding_preset_preset_description": "Sıkıştırma hızı. Daha yavaş olan ayarlar belirli bitrate ayarları için daha küçük ve daha kaliteli dosya üretir. VP9 ayarı 'daha hızlı' ayarının üstündeki ayarları görmezden gelir.",
+ "transcoding_realtime": "Gerçek Zamanlı Kod Dönüştürme [DENEYSEL]",
+ "transcoding_realtime_enabled": "Gerçek zamanlı kod dönüştürmeyi etkinleştirin",
+ "transcoding_realtime_enabled_description": "Devre dışı bırakılırsa, sunucu yeni gerçek zamanlı kod dönüştürme oturumları başlatmayı reddedecektir.",
"transcoding_reference_frames": "Referans kareler",
"transcoding_reference_frames_description": "Belirli bir kareyi sıkıştırırken referans alınacak kare sayısı. Daha yüksek değerler sıkıştırma verimliliğini artırır, ancak kodlamayı yavaşlatır. 0 bu değeri otomatik olarak ayarlar.",
"transcoding_required_description": "Yalnızca kabul edilen formatta olmayan videolar",
@@ -443,6 +462,8 @@
"user_settings_description": "Kullanıcı ayarlarını yönet",
"user_successfully_removed": "Kullanıcı {email} başarıyla kaldırıldı.",
"users_page_description": "Yönetici kullanıcılar sayfası",
+ "version_check_channel": "Yayın kanalı",
+ "version_check_channel_description": "Sürüm duyurularını almak istediğiniz yayın kanalını seçin",
"version_check_enabled_description": "Sürüm kontrolü etkin",
"version_check_implications": "Sürüm kontrol özelliği, {server} ile periyodik iletişime dayanır",
"version_check_settings": "Sürüm Kontrolü",
@@ -692,6 +713,7 @@
"backup_settings_subtitle": "Yükleme ayarlarını yönet",
"backup_upload_details_page_more_details": "Daha fazla ayrıntı için dokunun",
"backward": "Geriye doğru",
+ "battery_optimization_backup_reliability": "Pil optimizasyonlarını devre dışı bırakmak, arka plan yedeklemesinin güvenilirliğini artırabilir",
"biometric_auth_enabled": "Biyometrik kimlik doğrulama etkin",
"biometric_locked_out": "Biyometrik kimlik doğrulaması kilitli",
"biometric_no_options": "Biyometrik seçenek yok",
@@ -733,6 +755,7 @@
"cannot_update_the_description": "Açıklama güncellenemiyor",
"cast": "Yansıt",
"cast_description": "Kullanılabilir yansıtma hedeflerini yapılandır",
+ "change": "Değiştir",
"change_date": "Tarihi değiştir",
"change_description": "Açıklamayı değiştir",
"change_display_order": "Görüntüleme sırasını değiştir",
@@ -779,6 +802,7 @@
"clear": "Temizle",
"clear_all": "Hepsini temizle",
"clear_all_recent_searches": "Son aramaların hepsini temizle",
+ "clear_failed_count": "Temizleme başarısız oldu ({count})",
"clear_file_cache": "Dosya Önbelleğini Temizle",
"clear_message": "Mesajı temizle",
"clear_value": "Değeri temizle",
@@ -904,6 +928,7 @@
"deduplicate_all": "Tüm kopyaları kaldır",
"default_locale": "Varsayılan Dil",
"default_locale_description": "Tarih ve sayıları tarayıcınızın yerel ayarlarına göre biçimlendirin",
+ "default_share_quality": "Varsayılan paylaşım kalitesi",
"delete": "Sil",
"delete_action_confirmation_message": "Bu öğeyi silmek istediğinizden emin misiniz? Bu işlem, öğeyi sunucunun çöp kutusuna taşıyacak ve yerel olarak silmek isteyip istemediğinizi soracaktır",
"delete_action_prompt": "{count} silindi",
@@ -977,8 +1002,10 @@
"downloading_asset_filename": "Öğe indiriliyor {filename}",
"downloading_from_icloud": "iCloud’dan indiriliyor",
"downloading_media": "Medya indiriliyor",
+ "drag_to_reorder": "Sırayı değiştirmek için sürükleyin",
"drop_files_to_upload": "Dosyaları yüklemek için herhangi bir yere bırakın",
"duplicate": "Kopyala",
+ "duplicate_workflow": "İş akışını kopyala",
"duplicates": "Kopyalar",
"duplicates_description": "Her bir grubu, varsa tekrarlanan öğeleri belirterek çözümleyin.",
"duration": "Süre",
@@ -1080,6 +1107,7 @@
"failed_to_remove_product_key": "Ürün anahtarı kaldırılamadı",
"failed_to_reset_pin_code": "PIN kodu sıfırlanamadı",
"failed_to_stack_assets": "Öğeler yığınlanamadı",
+ "failed_to_tag_assets": "Varlıkları etiketleme başarısız oldu",
"failed_to_unstack_assets": "Öğelerin yığını kaldırılamadı",
"failed_to_update_notification_status": "Bildirim durumu güncellenemedi",
"incorrect_email_or_password": "Yanlış e-posta veya şifre",
@@ -1204,10 +1232,12 @@
"external_libraries": "Harici kütüphaneler",
"external_network": "Harici ağlar",
"external_network_sheet_info": "Belirlenmiş Wi-Fi ağına bağlı olmadığında uygulama, yukarıdan aşağıya doğru ulaşabileceği aşağıdaki URL'lerden ilki aracılığıyla sunucuya bağlanacaktır",
+ "f_number": "F-Numarası",
"face_unassigned": "Yüz atanmadı",
"failed": "Başarısız",
"failed_count": "Başarısız: {count}",
"failed_to_authenticate": "Kimlik doğrulaması yapılamadı",
+ "failed_to_delete_file": "Dosya silme işlemi başarısız oldu",
"failed_to_load_assets": "Öğeler yüklenemedi",
"failed_to_load_folder": "Klasör yüklenemedi",
"favorite": "Favori",
@@ -1338,6 +1368,7 @@
"individual_share": "Bireysel paylaşım",
"individual_shares": "Kişisel paylaşımlar",
"info": "Bilgi",
+ "integrity_checks": "Bütünlük Kontrolleri",
"interval": {
"day_at_onepm": "Her gün saat 13:00'te",
"hours": "{hours, plural, one {Her saat} other {Her {hours, number} saatte}}",
@@ -1385,6 +1416,7 @@
"leave": "Ayrıl",
"leave_album": "Albümden çık",
"lens_model": "Mercek modeli",
+ "less": "Daha az",
"let_others_respond": "Diğerlerinin yanıt vermesine izin ver",
"level": "Seviye",
"library": "Kütüphane",
@@ -1409,6 +1441,7 @@
"linked_oauth_account": "Bağlı OAuth hesabı",
"list": "Liste",
"live": "Canlı",
+ "load_more": "Daha Fazla Yükle",
"loading": "Yükleniyor",
"loading_search_results_failed": "Arama sonuçları yüklenemedi",
"local": "Yerel",
@@ -1509,7 +1542,6 @@
"map_location_picker_page_use_location": "Bu konumu kullan",
"map_location_service_disabled_content": "Mevcut konumunuzdan öğeleri görüntülemek için konum hizmetinin etkinleştirilmesi gerekiyor. Şimdi etkinleştirmek istiyor musunuz?",
"map_location_service_disabled_title": "Konum hizmeti devre dışı bırakıldı",
- "map_marker_for_images": "{city}, {country} şehrinde çekilen fotoğraflar için harita işaretleyicisi",
"map_marker_with_image": "Resimli harita işaretleyicisi",
"map_no_location_permission_content": "Mevcut konumunuzdan öğeleri görüntülemek için konum iznine ihtiyaç var. Şimdi izin vermek istiyor musunuz?",
"map_no_location_permission_title": "Konum izni reddedildi",
@@ -1532,8 +1564,11 @@
"matching_assets": "Eşleşen Öğeler",
"media_chrome": {
"auto": "Otomatik",
+ "captions": "Altyazılar",
"captions_off": "Kapalı",
+ "closed_captions": "kapalı altyazılar",
"decode_error": "Kod çözümleme hatası",
+ "disable_captions": "Altyazıları devre dışı bırak",
"enable_captions": "Altyazılar açık",
"enter_fullscreen_mode": "Tam ekran kipini aç",
"exit_fullscreen_mode": "Tam ekran kipini kapat",
@@ -1553,6 +1588,8 @@
"seconds": "saniyeler",
"time_value_of_total_time": "{currentTime} / {totalTime}",
"time_value_remaining": "{time} kaldı",
+ "unmute": "Sesini açmak",
+ "unsupported_error_description": "Desteklenmeyen bir hata oluştu. Sunucu veya ağ hatası ya da tarayıcınız bu formatı desteklemiyor.",
"video_not_loaded_unknown_time": "video yüklenmedi, süre bilinmiyor.",
"video_player": "Video oynatıcı",
"volume": "Ses"
@@ -1573,6 +1610,8 @@
"merge_people_prompt": "Bu kişileri birleştirmek istiyor musunuz? Bu işlem geri alınamaz.",
"merge_people_successfully": "Kişiler başarılı bir şekilde birleştirildi",
"merged_people_count": "{count, plural, one {# kişi} other {# kişi}} birleştirildi",
+ "minFaces": "Minimum yüzler",
+ "minFaces_description": "Bir kişinin görüntülenebilmesi için minimum tanınan yüz sayısı",
"minimize": "Küçült",
"minute": "Dakika",
"minutes": "Dakika",
@@ -1659,6 +1698,7 @@
"no_results": "Sonuç bulunamadı",
"no_results_description": "Eş anlamlı ya da daha genel anlamlı bir kelime deneyin",
"no_shared_albums_message": "Fotoğrafları ve videoları ağınızdaki kişilerle paylaşmak için bir albüm oluşturun",
+ "no_steps": "Henüz hiçbir adım eklenmedi",
"no_uploads_in_progress": "Yükleme işlemi yok",
"none": "Yok",
"not_allowed": "İzin verilmiyor",
@@ -1667,6 +1707,7 @@
"not_selected": "Seçilmedi",
"notes": "Notlar",
"nothing_here_yet": "Burada henüz bir şey yok",
+ "notification_backup_reliability": "Arka plan yedeklemelerinin güvenirliğini iyileştirmek için bildirimlere izin verin",
"notification_permission_dialog_content": "Bildirimleri etkinleştirmek için cihaz ayarlarına gidin ve izin verin.",
"notification_permission_list_tile_content": "Bildirimleri etkinleştirmek için izin verin.",
"notification_permission_list_tile_enable_button": "Bildirimleri Etkinleştir",
@@ -1796,6 +1837,7 @@
"play_transcoded_video": "Kodlanmış videoyu oynat",
"please_auth_to_access": "Erişim için lütfen kimliğinizi doğrulayın",
"plugin_method_filter_type": "Süzgeç",
+ "plugin_method_filter_type_description": "Bu yöntem olayları filtreleyebilir ve koşullu olarak sonraki adımların çalışmasını engelleyebilir",
"port": "Port",
"preferences_settings_subtitle": "Uygulama tercihlerini düzenle",
"preferences_settings_title": "Tercihler",
@@ -1978,6 +2020,8 @@
"search_by_description_example": "Sapa'da yürüyüş günü",
"search_by_filename": "Dosya adına veya uzantısına göre ara",
"search_by_filename_example": "Örn. IMG_1234.JPG veya PNG",
+ "search_by_full_path": "Tam dosya yolu veya klasöre göre arama yapın",
+ "search_by_full_path_example": "/John/Projeler/3D_Baskı/2026-07-01 - Projeler, 3D, Baskı, 2026 vb. kelimelerle arama yapabilirsiniz.",
"search_by_ocr": "OCR'ye göre ara",
"search_by_ocr_example": "Sütlü Kahve",
"search_camera_lens_model": "Lens modelini ara...",
@@ -2054,6 +2098,7 @@
"select_person": "Kişileri seç",
"select_person_to_tag": "Etiketlemek için bir kişi seçin",
"select_photos": "Fotoğrafları seç",
+ "select_quality": "Kaliteyi seçin",
"select_trash_all": "Hepsini çöpe at",
"select_user_for_sharing_page_err_album": "Albüm oluşturulamadı",
"selected": "Seçildi",
@@ -2117,6 +2162,8 @@
"share_assets_selected": "{count} seçili",
"share_dialog_preparing": "Hazırlanıyor...",
"share_link": "Bağlantıyı Paylaş",
+ "share_original": "Orijinal (büyük) olanı kullanın",
+ "share_preview": "Küçük resmi kullan",
"shared": "Paylaşılan",
"shared_album_activities_input_disable": "Yoruma kapalı",
"shared_album_activity_remove_content": "Bu etkinliği silmek istiyor musunuz?",
@@ -2210,12 +2257,14 @@
"skip_to_folders": "Klasörlere atla",
"skip_to_tags": "Etiketlere atla",
"slideshow": "Slayt gösterisi",
+ "slideshow_metadata_overlay_mode": "Yer paylaşımı içeriği",
"slideshow_metadata_overlay_mode_description_only": "Sadece açıklama",
"slideshow_metadata_overlay_mode_full": "Dolu",
"slideshow_repeat": "Slayt gösterisini tekrarla",
"slideshow_repeat_description": "Slayt gösterisi bittiğinde başa dön",
"slideshow_settings": "Slayt gösterisi ayarları",
"smart_album": "Akıllı albüm",
+ "some_assets_already_have_a_location_warning": "Seçilen varlıkların bazılarının zaten bir konumu mevcut",
"sort_albums_by": "Albümleri sırala...",
"sort_created": "Oluşturulma tarihi",
"sort_items": "Öğe sayısı",
@@ -2239,6 +2288,7 @@
"state": "Eyalet/İl",
"status": "Durum",
"step_delete": "Adımı sil",
+ "step_delete_confirm": "Bu adımı silmek istediğinizden emin misiniz?",
"step_details": "Adım ayrıntıları",
"steps": "Adımlar",
"stop_casting": "Yansıtmayı durdur",
@@ -2334,11 +2384,13 @@
"trash_page_title": "Çöp Kutusu ({count})",
"trashed_items_will_be_permanently_deleted_after": "Silinen öğeler {days, plural, one {# gün} other {# gün}} sonra kalıcı olarak silinecek.",
"trigger": "Tetikleyici",
- "trigger_asset_uploaded": "Öğe Karşıya Yüklendi",
+ "trigger_asset_metadata_extraction": "Varlık Meta Veri Çıkarma",
+ "trigger_asset_metadata_extraction_description": "Bir varlığın EXIF meta verileri çıkarıldığında tetiklenir",
+ "trigger_asset_uploaded": "Öğe Karşıya Yüklenince",
"trigger_asset_uploaded_description": "Yeni bir öğe karşıya yüklendiğinde tetiklenir",
"trigger_description": "İş akışını başlatan bir olay",
"trigger_person_recognized": "Tanınan Kişi",
- "trigger_person_recognized_description": "Bir kişi algılandığında tetiklenir",
+ "trigger_person_recognized_description": "Bir kişi tanındığında tetiklenir",
"trigger_type": "Tetikleyici türü",
"troubleshoot": "Sorun giderme",
"type": "Tür",
@@ -2380,6 +2432,7 @@
"updated_password": "Güncellenen şifre",
"upload": "Yükle",
"upload_concurrency": "Yükleme eşzamanlılığı",
+ "upload_day_count": "{tarih}: {sayı, çoğul, bir {# yükleme} diğer {# yüklemeler}}",
"upload_details": "Yükleme Ayrıntıları",
"upload_dialog_info": "Seçili öğeleri sunucuya yedeklemek istiyor musunuz?",
"upload_dialog_title": "Öğe Yükle",
@@ -2395,6 +2448,7 @@
"upload_to_immich": "Immich'e Yükle ({count})",
"uploading": "Yükleniyor",
"uploading_media": "Medya yükleme",
+ "uploads": "Yüklemeler",
"url": "URL",
"usage": "Kullanım",
"use_biometric": "Biyometri kullan",
@@ -2402,6 +2456,7 @@
"use_browser_locale_description": "Tarih, saat ve sayılar tarayıcınızın yerel ayarlarına göre biçimlendirilsin",
"use_current_connection": "Mevcut bağlantıyı kullan",
"use_custom_date_range": "Bunun yerine özel tarih aralığını kullan",
+ "use_template": "Şablonu kullan",
"user": "Kullanıcı",
"user_has_been_deleted": "Bu kullanıcı silindi.",
"user_id": "Kullanıcı ID",
@@ -2431,6 +2486,7 @@
"video": "Video",
"video_hover_setting": "Üzerinde durulduğunda video ön izlemesi oynat",
"video_hover_setting_description": "Öğe üzerinde fareyle durulduğunda video küçük resmini oynatır. Bu özellik devre dışıyken, oynatma simgesine fareyle gidilerek oynatma başlatılabilir.",
+ "video_quality": "Video kalitesi",
"videos": "Videolar",
"videos_count": "{count, plural, one {# video} other {# video}}",
"videos_only": "Sadece videolar",
@@ -2463,6 +2519,7 @@
"week": "Hafta",
"welcome": "Hoş geldiniz",
"welcome_to_immich": "Immich'e hoş geldiniz",
+ "when": "Ne zaman",
"width": "Genişlik",
"wifi_name": "Wi-Fi Adı",
"workflow": "İş Akışı",
@@ -2475,6 +2532,7 @@
"workflow_name": "İş akışı adı",
"workflow_navigation_prompt": "Değişikliklerinizi kaydetmeden ayrılmak istediğinizden emin misiniz?",
"workflow_summary": "İş akışı özeti",
+ "workflow_templates": "İş akışı şablonları",
"workflow_update_success": "İş akışı başarıyla güncellendi",
"workflow_updated": "İş akışı güncellendi",
"workflows": "İş akışları",
diff --git a/i18n/uk.json b/i18n/uk.json
index 78812084ed..09be7c817d 100644
--- a/i18n/uk.json
+++ b/i18n/uk.json
@@ -1532,7 +1532,6 @@
"map_location_picker_page_use_location": "Використати це місце",
"map_location_service_disabled_content": "Служба визначення місця має бути увімкнена, щоб відображати елементи з вашого поточного місця. Увімкнути її зараз?",
"map_location_service_disabled_title": "Служба визначення місця вимкнена",
- "map_marker_for_images": "Маркер на мапі для зображень, знятих у {city}, {country}",
"map_marker_with_image": "Маркер на мапі із зображенням",
"map_no_location_permission_content": "Потрібен дозвіл, щоб показувати елементи із поточного місця. Надати його зараз?",
"map_no_location_permission_title": "Доступ до місця не надано",
diff --git a/i18n/ur.json b/i18n/ur.json
index 62b3621f98..eae1e037e0 100644
--- a/i18n/ur.json
+++ b/i18n/ur.json
@@ -27,6 +27,7 @@
"add_partner": "ساتھی شامل کریں",
"add_path": "راستہ شامل کریں",
"add_photos": "تصاویر شامل کریں",
+ "add_step": "مرحلہ بنائیں",
"add_tag": "ٹیگ شامل کریں",
"add_to": "اس میں شامل کریں…",
"add_to_album": "البم میں شامل کریں",
@@ -70,7 +71,11 @@
"confirm_reprocess_all_faces": "کیا آپ واقعی تمام چہروں کو دوبارہ پروسیس کرنا چاہتے ہیں؟ اس سے نام والے افراد بھی صاف ہو جائیں گے۔",
"confirm_user_password_reset": "کیا آپ {user} کا پاس ورڈ ری سیٹ کرنا چاہتے ہیں؟",
"confirm_user_pin_code_reset": "کیا آپ {user} کا پن کوڈ ری سیٹ کرنا چاہتے ہیں؟",
+ "copy_config_to_clipboard_description": "اپنی موجودہ سسٹم کے نظام کی ترتیب JSON کی شکل میں کلپ بورڈ میں کاپی کریں",
"create_job": "کام بنائیں",
+ "disable_login": "لاگ ان بند کریں",
+ "download_csv": "CSV ڈاون لوڈ کریں",
+ "duplicate_detection_job_description": "اپنی اجراۂ پر مشین لرننگ چلا کر ایک جیسی تصاویر کا پتہ لگا ئے۔ \"Smart Search\" پر انحصار کرتا ہے",
"face_detection": "چہرے کی پہچان",
"failed_job_command": "کام: {job} کے لیے کمانڈ: {command} ناکام ہو گئی",
"image_preview_title": "پیش نظارہ",
diff --git a/i18n/vi.json b/i18n/vi.json
index 0b59ba83ce..26ce09ba51 100644
--- a/i18n/vi.json
+++ b/i18n/vi.json
@@ -5,7 +5,7 @@
"acknowledge": "Ghi nhận",
"action": "Hành động",
"action_common_update": "Cập nhật",
- "action_description": "Một tập hợp các hành động cần thực hiện trên các tệp đã được lọc",
+ "action_description": "Một tập hợp các hành động cần thực hiện trên các tài nguyên đã được lọc",
"actions": "Hành động",
"active": "Đang hoạt động",
"active_count": "Hoạt động: {count}",
@@ -18,7 +18,7 @@
"add_a_title": "Thêm tên",
"add_action": "Thêm hành động",
"add_action_description": "Nhấn để thêm hành động cần thực hiện",
- "add_assets": "Thêm ảnh/video",
+ "add_assets": "Thêm tài nguyên",
"add_birthday": "Thêm sinh nhật",
"add_endpoint": "Thêm endpoint",
"add_exclusion_pattern": "Thêm quy tắc loại trừ",
@@ -33,10 +33,10 @@
"add_to_album": "Thêm vào album",
"add_to_album_bottom_sheet_added": "Đã thêm vào {album}",
"add_to_album_bottom_sheet_already_exists": "Đã có sẵn trong {album}",
- "add_to_album_bottom_sheet_some_local_assets": "Một số tệp trên thiết bị không thể được thêm vào album",
+ "add_to_album_bottom_sheet_some_local_assets": "Một số tài nguyên trên thiết bị không thể được thêm vào album",
"add_to_album_toggle": "Bật tắt tùy chọn cho {album}",
"add_to_albums": "Thêm vào album",
- "add_to_albums_count": "Đã thêm vào album {count}",
+ "add_to_albums_count": "Đã thêm vào ({count}) album",
"add_to_bottom_bar": "Thêm vào",
"add_to_shared_album": "Thêm vào album chia sẻ",
"add_upload_to_stack": "Tải lên thêm vào nhóm",
@@ -47,7 +47,7 @@
"admin": {
"add_exclusion_pattern_description": "Thêm quy tắc loại trừ. Hỗ trợ sử dụng ký tự *, **, và ?. Để bỏ qua bất kỳ tệp trong thư mục tên \"Raw\", hãy dùng \"**/Raw/**\". Để bỏ qua các tệp có đuôi \".tif\", hãy dùng \"**/*.tif\". Để bỏ qua một đường dẫn cố định, hãy dùng \"/path/to/ignore/**\".",
"admin_user": "Quản trị viên",
- "asset_offline_description": "Tệp thư viện bên ngoài này không còn trên ổ đĩa và đã bị chuyển vào thùng rác. Nếu tệp đã bị di chuyển trong thư viện, kiểm tra dòng thời gian của bạn để tìm ảnh mới tương ứng. Để khôi phục, hãy đảm bảo Immich có thể truy cập đường dẫn tệp bên dưới và quét lại thư viện.",
+ "asset_offline_description": "Tài nguyên thư viện ngoài này không còn trên ổ đĩa và đã bị chuyển vào thùng rác. Nếu tệp đã bị di chuyển trong thư viện, kiểm tra dòng thời gian của bạn để tìm tài nguyên mới tương ứng. Để khôi phục tài nguyên, hãy đảm bảo Immich có thể truy cập đường dẫn tệp bên dưới và quét lại thư viện.",
"authentication_settings": "Xác thực",
"authentication_settings_description": "Quản lý mật khẩu, OAuth và các cài đặt xác thực khác",
"authentication_settings_disable_all": "Bạn có chắc muốn vô hiệu hóa mọi phương thức đăng nhập? Đăng nhập sẽ bị vô hiệu hóa hoàn toàn.",
@@ -68,26 +68,27 @@
"cleared_jobs": "Đã xóa các tác vụ: {job}",
"config_set_by_file": "Cấu hình hiện tại đang được đặt bởi một tệp cấu hình",
"confirm_delete_library": "Bạn có chắc muốn xóa thư viện {library}?",
- "confirm_delete_library_assets": "Bạn có chắc muốn xóa thư viện này? Thao tác này sẽ xóa {count, plural, one {# tệp} other {tất cả # tệp}} khỏi Immich và không thể hoàn tác. Các tệp sẽ vẫn còn trên ổ đĩa.",
+ "confirm_delete_library_assets": "Bạn có chắc muốn xóa thư viện này? Thao tác này sẽ xóa {count, plural, one {# tệp} other {toàn bộ # tài nguyên}} khỏi Immich và không thể hoàn tác. Các tệp sẽ vẫn còn trên ổ đĩa.",
"confirm_email_below": "Để xác nhận, nhập \"{email}\" bên dưới",
"confirm_reprocess_all_faces": "Bạn có chắc muốn xử lý lại tất cả khuôn mặt? Thao tác này sẽ xóa tên người đã được gán.",
"confirm_user_password_reset": "Bạn có chắc muốn đặt lại mật khẩu của {user}?",
"confirm_user_pin_code_reset": "Bạn có chắc muốn đặt lại mã PIN của {user}?",
- "copy_config_to_clipboard_description": "Sao chép cấu hình hệ thống hiện tại dưới dạng đối tượng JSON vào bộ nhớ tạm",
+ "copy_config_to_clipboard_description": "Sao chép cấu hình hệ thống hiện tại dưới dạng đối tượng JSON vào clipboard",
"create_job": "Tạo tác vụ",
"cron_expression": "Biểu thức Cron",
"cron_expression_description": "Thiết lập khoảng thời gian để quét bằng biểu thức cron. Tham khảo Crontab Guru để biết thêm thông tin",
"cron_expression_presets": "Mẫu biểu thức Cron",
"disable_login": "Vô hiệu hóa đăng nhập",
- "duplicate_detection_job_description": "Chạy học máy để phát hiện các hình ảnh giống nhau. Dựa vào Tìm kiếm Thông Minh",
+ "download_csv": "Tải xuống CSV",
+ "duplicate_detection_job_description": "Chạy học máy để phát hiện các tài nguyên giống nhau. Dựa vào Tìm kiếm Thông Minh",
"exclusion_pattern_description": "Quy tắc loại trừ dùng để bỏ qua các tệp và thư mục khi quét thư viện của bạn. Điều này hữu ích nếu bạn có các thư mục chứa tệp bạn không muốn nhập, chẳng hạn như các tệp RAW.",
"export_config_as_json_description": "Tải xuống cấu hình hệ thống hiện tại dưới dạng tệp JSON",
- "external_libraries_page_description": "Trang thư viện bên ngoài của quản trị viên",
+ "external_libraries_page_description": "Trang thư viện ngoài của quản trị viên",
"face_detection": "Nhận diện khuôn mặt",
- "face_detection_description": "Sử dụng học máy để nhận diện khuôn mặt trong ảnh. Đối với video, sẽ sử dụng ảnh thu nhỏ. \"Làm mới\" sẽ xử lý lại tất cả tệp. \"Đặt lại\" sẽ xóa hết tất cả dữ liệu khuôn mặt và nhận dạng lại. \"Còn thiếu\" sẽ xử lý các ảnh còn thiếu. Các khuôn mặt được phát hiện sẽ được xử lý bởi tác vụ Nhận diện khuôn mặt để nhóm chúng vào những người đã có hoặc người mới.",
+ "face_detection_description": "Sử dụng học máy để nhận diện khuôn mặt trong ảnh. Đối với video, sẽ sử dụng ảnh thu nhỏ. \"Làm mới\" sẽ xử lý lại tất cả tệp. \"Đặt lại\" sẽ xóa hết tất cả dữ liệu khuôn mặt và nhận dạng lại. \"Còn thiếu\" sẽ xử lý các ảnh còn thiếu. Các khuôn mặt được nhận diện sẽ được xử lý bởi tác vụ Nhận Diện Khuôn Mặt để nhóm chúng vào những người đã có hoặc người mới.",
"facial_recognition_job_description": "Xếp nhóm những khuôn mặt đã nhận diện thành người. Bước này được thực hiện sau khi tác vụ Nhận diện khuôn mặt hoàn tất. \"Đặt lại\" sẽ xếp nhóm lại tất cả khuôn mặt. \"Còn thiếu\" sẽ xử lý các khuôn mặt chưa gán với người nào.",
"failed_job_command": "Lệnh {command} không thực hiện được tác vụ: {job}",
- "force_delete_user_warning": "CẢNH BÁO: Thao tác này sẽ ngay lập tức xóa người dùng và tất cả ảnh. Điều không thể hoàn tác và các tệp không thể khôi phục.",
+ "force_delete_user_warning": "CẢNH BÁO: Thao tác này sẽ ngay lập tức xóa người dùng và toàn bộ tài nguyên. Điều không thể hoàn tác và các tệp không thể khôi phục.",
"image_format": "Định dạng",
"image_format_description": "Định dạng WebP dung lượng nhỏ hơn JPEG, nhưng mã hóa chậm hơn.",
"image_fullsize_description": "Ảnh kích thước đẩy đủ với thông tin metadata bị loại bỏ, được dùng khi phóng to",
@@ -99,7 +100,7 @@
"image_prefer_embedded_preview_setting_description": "Dùng ảnh xem trước trong ảnh RAW khi có sẵn để xử lý hình ảnh. Điều này có thể giúp tái tạo màu sắc chính xác hơn cho một số ảnh, nhưng chất lượng của ảnh xem trước phụ thuộc vào máy ảnh và có thể bị nhiễu do nén.",
"image_prefer_wide_gamut": "Ưu tiên gam màu mở rộng",
"image_prefer_wide_gamut_setting_description": "Dùng gam màu Display P3 để hiển thị ảnh thu nhỏ. Điều này giúp giữ màu sắc rực rỡ của những hình ảnh có gam màu rộng, nhưng ảnh có thể trông khác trên các thiết bị và trình duyệt cũ. Ảnh sRGB được giữ nguyên để tránh thay đổi màu sắc.",
- "image_preview_description": "Ảnh kích thước trung bình đã loại bỏ metadata, được sử dụng khi xem một tệp duy nhất và cho học máy",
+ "image_preview_description": "Ảnh kích thước trung bình đã loại bỏ metadata, được sử dụng khi xem một tài nguyên duy nhất và cho học máy",
"image_preview_quality_description": "Chất lượng xem trước từ 1-100. Càng cao càng tốt, nhưng sẽ tạo ra các tệp lớn có thể làm giảm khả năng phản hồi của app. Sử dụng giá trị thấp có thể ảnh hưởng đến chất lượng tác vụ học máy.",
"image_preview_title": "Cài đặt Xem trước",
"image_progressive": "Mang tính tịnh tiến",
@@ -120,7 +121,7 @@
"job_settings_description": "Quản lý số lượng tác vụ chạy đồng thời",
"jobs_delayed": "{jobCount, plural, other {# bị hoãn lại}}",
"jobs_failed": "{jobCount, plural, other {# thất bại}}",
- "jobs_over_time": "Tác vụ quá thời gian",
+ "jobs_over_time": "Tác vụ qua thời gian",
"library_created": "Đã tạo thư viện: {library}",
"library_deleted": "Thư viện đã bị xóa",
"library_details": "Chi tiết thư viện",
@@ -130,11 +131,11 @@
"library_scanning": "Quét định kỳ",
"library_scanning_description": "Cấu hình quét thư viện định kỳ",
"library_scanning_enable_description": "Bật quét thư viện định kỳ",
- "library_settings": "Thư viện bên ngoài",
- "library_settings_description": "Quản lý cài đặt thư viện bên ngoài",
- "library_tasks_description": "Quét thư viện ngoài để tìm ảnh mới thêm hoặc bị thay đổi",
+ "library_settings": "Thư viện ngoài",
+ "library_settings_description": "Quản lý cài đặt thư viện ngoài",
+ "library_tasks_description": "Quét thư viện ngoài để tìm tài nguyên mới thêm hoặc bị thay đổi",
"library_updated": "Đã cập nhật thư viện",
- "library_watching_enable_description": "Tự động cập nhật các tệp bị thay đổi trong thư viện bên ngoài",
+ "library_watching_enable_description": "Tự động cập nhật các tệp bị thay đổi trong thư viện ngoài",
"library_watching_settings": "Theo dõi thư viện (THỬ NGHIỆM)",
"library_watching_settings_description": "Tự động cập nhật khi các tệp bị thay đổi",
"logging_enable_description": "Bật ghi log",
@@ -151,7 +152,7 @@
"machine_learning_clip_model_description": "Tên của mô hình CLIP được liệt kê tại đây. Bạn cần chạy lại tác vụ \"Tìm kiếm thông minh\" cho tất cả ảnh sau khi thay đổi mô hình.",
"machine_learning_duplicate_detection": "Tìm trùng lặp",
"machine_learning_duplicate_detection_enabled": "Bật tìm ảnh trùng lặp",
- "machine_learning_duplicate_detection_enabled_description": "Nếu bị tắt, các ảnh trùng lặp giống hệt nhau vẫn sẽ bị loại bỏ.",
+ "machine_learning_duplicate_detection_enabled_description": "Nếu bị tắt, các tài nguyên trùng lặp giống hệt nhau vẫn sẽ bị loại bỏ.",
"machine_learning_duplicate_detection_setting_description": "Sử dụng vector nhúng CLIP để tìm kiếm ảnh trùng lặp",
"machine_learning_enabled": "Bật học máy",
"machine_learning_enabled_description": "Nếu bị tắt, tất cả tính năng và cài đặt học máy sẽ bị loại bỏ.",
@@ -181,16 +182,32 @@
"machine_learning_ocr_min_score_recognition_description": "Điểm tin cậy tối thiểu để nhận dạng văn bản được phát hiện là từ 0-1. Giá trị thấp hơn sẽ nhận dạng được nhiều văn bản hơn nhưng có thể dẫn đến kết quả dương tính giả.",
"machine_learning_ocr_model": "Mô hình OCR",
"machine_learning_ocr_model_description": "Mô hình máy chủ chính xác hơn mô hình di động, nhưng mất nhiều thời gian xử lý hơn và sử dụng nhiều bộ nhớ hơn.",
- "machine_learning_settings": "Cài đặt Học máy",
+ "machine_learning_settings": "Học máy",
"machine_learning_settings_description": "Quản lý các tính năng và cài đặt học máy",
"machine_learning_smart_search": "Tìm kiếm Thông minh",
"machine_learning_smart_search_description": "Tìm kiếm hình ảnh theo ngữ cảnh với CLIP",
"machine_learning_smart_search_enabled": "Bật Tìm kiếm Thông minh",
"machine_learning_smart_search_enabled_description": "Nếu tắt, ảnh sẽ không được mã hóa để tìm kiếm thông minh.",
"machine_learning_url_description": "Địa chỉ máy chủ học máy. Nếu có nhiều hơn một địa chỉ được cung cấp, mỗi máy chủ sẽ được kiểm tra một lần cho đến khi có một máy chủ trả lời thành công, theo thứ tự từ máy chủ đầu tiên đến máy chủ cuối cùng. Máy chủ không phản hồi sẽ tạm thời được bỏ qua cho đến khi máy chủ online trở lại.",
+ "maintenance_backup_management": "Quản lý sao lưu",
"maintenance_delete_backup": "Xóa bản sao lưu",
- "maintenance_delete_backup_description": "Tệp này sẽ bị xoá vĩnh viễn.",
+ "maintenance_delete_backup_description": "Tệp này sẽ bị xóa vĩnh viễn.",
"maintenance_delete_error": "Lỗi khi xóa bản sao lưu.",
+ "maintenance_integrity_check": "Kiểm tra",
+ "maintenance_integrity_check_all": "Kiểm tra tất cả",
+ "maintenance_integrity_checksum_mismatch": "Checksum không khớp",
+ "maintenance_integrity_checksum_mismatch_description": "Các tệp có checksum trên đĩa không khớp với checksummà Immich đã lưu trữ trong cơ sở dữ liệu của mình.",
+ "maintenance_integrity_checksum_mismatch_job": "Kiểm tra checksum có khớp không",
+ "maintenance_integrity_checksum_mismatch_refresh_job": "Làm mới báo cáo trùng khớp checksum",
+ "maintenance_integrity_missing_file": "Tệp bị thiếu",
+ "maintenance_integrity_missing_file_description": "Các tệp mà Immich đã theo dõi trong cơ sở dữ liệu của mình nhưng không tồn tại trên hệ thống tệp.",
+ "maintenance_integrity_missing_file_job": "Kiểm tra các tệp bị thiếu",
+ "maintenance_integrity_missing_file_refresh_job": "Làm mới báo cáo tệp bị thiếu",
+ "maintenance_integrity_report": "Báo cáo liêm chính",
+ "maintenance_integrity_untracked_file": "Tệp không bị theo dõi",
+ "maintenance_integrity_untracked_file_description": "Các tệp trong thư mục của Immich mà Immich không có bất kỳ bản ghi nào.",
+ "maintenance_integrity_untracked_file_job": "Kiểm tra các tệp không theo dõi",
+ "maintenance_integrity_untracked_file_refresh_job": "Làm mới báo cáo tệp không theo dõi",
"maintenance_restore_backup": "Khôi phục sao lưu",
"maintenance_restore_backup_description": "Immich sẽ xóa sạch toàn bộ dữ liệu hiện tại và khôi phục dữ liệu từ bản sao lưu đã được chọn. Hệ thống sẽ tạo một bản sao lưu cho dữ liệu hiện tại trước khi bắt đầu.",
"maintenance_restore_backup_different_version": "Bản sao lưu này đã được tạo ra bằng một phiên bản khác của Immich!",
@@ -222,21 +239,21 @@
"memory_cleanup_job": "Dọn dẹp kỷ niệm",
"memory_generate_job": "Tạo kỷ niệm",
"metadata_extraction_job": "Trích xuất Metadata",
- "metadata_extraction_job_description": "Trích xuất Metadata từ mỗi ảnh, chẳng hạn như GPS, khuôn mặt và độ phân giải",
+ "metadata_extraction_job_description": "Trích xuất Metadata từ mỗi tài nguyên, chẳng hạn như GPS, khuôn mặt và độ phân giải",
"metadata_faces_import_setting": "Bật tính năng nhập khuôn mặt",
"metadata_faces_import_setting_description": "Nhập khuôn mặt từ dữ liệu EXIF ảnh và tệp đi kèm",
"metadata_settings": "Cài đặt Metadata",
"metadata_settings_description": "Quản lý cài đặt Metadata",
"migration_job": "Di chuyển dữ liệu",
- "migration_job_description": "Di chuyển ảnh thu nhỏ của ảnh và khuôn mặt sang cấu trúc thư mục mới",
+ "migration_job_description": "Di chuyển ảnh thu nhỏ của tài nguyên và khuôn mặt sang cấu trúc thư mục mới",
"nightly_tasks_cluster_faces_setting_description": "Chạy nhận diện khuôn mặt trên những khuôn mặt mới được phát hiện",
"nightly_tasks_cluster_new_faces_setting": "Nhóm các khuôn mặt mới",
"nightly_tasks_database_cleanup_setting": "Tác vụ dọn dẹp cơ sở dữ liệu",
"nightly_tasks_database_cleanup_setting_description": "Làm sạch dữ liệu cũ hoặc/và hết hạn trong cơ sở dữ liệu",
"nightly_tasks_generate_memories_setting": "Tạo kỷ niệm",
- "nightly_tasks_generate_memories_setting_description": "Tạo ra những kỷ niệm mới từ tệp",
+ "nightly_tasks_generate_memories_setting_description": "Tạo ra những kỷ niệm mới từ tài nguyên",
"nightly_tasks_missing_thumbnails_setting": "Tạo ảnh đại diện bị thiếu",
- "nightly_tasks_missing_thumbnails_setting_description": "Xếp hàng các tệp không có ảnh thu nhỏ để tạo ảnh thu nhỏ",
+ "nightly_tasks_missing_thumbnails_setting_description": "Xếp hàng các tài nguyên không có ảnh thu nhỏ để tạo ảnh thu nhỏ",
"nightly_tasks_settings": "Cài đặt các tác vụ hàng đêm",
"nightly_tasks_settings_description": "Quản lý các tác vụ hàng đêm",
"nightly_tasks_start_time_setting": "Thời gian bắt đầu",
@@ -245,7 +262,7 @@
"nightly_tasks_sync_quota_usage_setting_description": "Cập nhật hạn mức dung lượng của người dùng, dựa trên mức sử dụng hiện tại",
"no_paths_added": "Không có đường dẫn nào được thêm vào",
"no_pattern_added": "Không có quy tắc nào được thêm vào",
- "note_apply_storage_label_previous_assets": "Lưu ý: Để áp dụng Nhãn lưu trữ cho nội dung đã tải lên trước đó, hãy chạy",
+ "note_apply_storage_label_previous_assets": "Lưu ý: Để áp dụng Nhãn lưu trữ cho tài nguyên đã tải lên trước đó, hãy chạy",
"note_cannot_be_changed_later": "LƯU Ý: Cài đặt này không thể thay đổi được sau khi lưu!",
"notification_email_from_address": "Địa chỉ email người gửi",
"notification_email_from_address_description": "Địa chỉ email của người gửi, ví dụ: \"Immich Photo Server \". Hãy chắc là bạn dùng một địa chỉ mà bạn được phép gửi email ra.",
@@ -278,6 +295,7 @@
"oauth_mobile_redirect_uri": "URI chuyển hướng trên thiết bị di động",
"oauth_mobile_redirect_uri_override": "Ghi đè URI chuyển hướng cho thiết bị di động",
"oauth_mobile_redirect_uri_override_description": "Bật khi nhà cung cấp OAuth không cho phép URI di động, như ''{callback}''",
+ "oauth_prompt_description": "Tham số prompt (ví dụ: select_account, login, consent)",
"oauth_role_claim": "Vai trò claim",
"oauth_role_claim_description": "Tự động cấp quyền quản trị dựa trên sự hiện diện của yêu cầu này. Yêu cầu này có thể có tên là 'người dùng' hoặc 'quản trị viên'.",
"oauth_settings": "OAuth",
@@ -304,6 +322,8 @@
"refreshing_all_libraries": "Làm mới tất cả thư viện",
"registration": "Đăng ký Quản trị viên",
"registration_description": "Vì bạn là người dùng đầu tiên, bạn sẽ trở thành Quản trị viên và chịu trách nhiệm cho việc quản lý hệ thống. Ngoài ra, bạn có thể thêm các người dùng khác.",
+ "release_channel_release_candidate": "Phát hành sớm",
+ "release_channel_stable": "Chính thức",
"remove_failed_jobs": "Xóa các tác vụ không thành công",
"require_password_change_on_login": "Yêu cầu người dùng thay đổi mật khẩu trong lần đăng nhập đầu tiên",
"reset_settings_to_default": "Đặt lại cài đặt về mặc định",
@@ -312,7 +332,7 @@
"search_jobs": "Tìm kiếm tác vụ…",
"send_welcome_email": "Gửi email chào mừng",
"server_external_domain_settings": "Tên miền công khai",
- "server_external_domain_settings_description": "Tên miền dành cho các liên kết chia sẻ công khai",
+ "server_external_domain_settings_description": "Tên miền dành cho các link chia sẻ công khai",
"server_public_users": "Người dùng công khai",
"server_public_users_description": "Tất cả người dùng (tên và email) được liệt kê khi thêm một người dùng vào một album được chia sẻ. Khi tắt lựa chọn này, danh sách người dùng chỉ có thể được thấy bởi người dùng quản trị.",
"server_settings": "Máy chủ",
@@ -324,21 +344,21 @@
"sidecar_job": "Siêu dữ liệu đi kèm",
"sidecar_job_description": "Tìm hoặc đồng bộ các tệp siêu dữ liệu đi kèm từ hệ thống",
"slideshow_duration_description": "Số giây hiển thị từng ảnh",
- "smart_search_job_description": "Chạy học máy trên toàn bộ ảnh để hỗ trợ tìm kiếm thông minh",
- "storage_template_date_time_description": "Mốc thời gian tạo tệp được dùng làm thông tin ngày giờ",
+ "smart_search_job_description": "Chạy học máy trên toàn bộ tài nguyên để hỗ trợ tìm kiếm thông minh",
+ "storage_template_date_time_description": "Mốc thời gian tạo tài nguyên được dùng làm thông tin ngày giờ",
"storage_template_date_time_sample": "Thời gian mẫu {date}",
"storage_template_enable_description": "Bật công cụ mẫu lưu trữ",
"storage_template_hash_verification_enabled": "Bật xác minh băm",
"storage_template_hash_verification_enabled_description": "Bật xác minh băm, không tắt tính năng này trừ khi bạn chắc chắn về các rủi ro có thể xảy ra",
"storage_template_migration": "Di chuyển mẫu lưu trữ",
- "storage_template_migration_description": "Áp dụng {template} hiện tại cho các ảnh đã được tải lên trước đây",
- "storage_template_migration_info": "Mẫu lưu trữ sẽ chuyển tất cả định dạng tập tin thành chữ thường. Những thay đổi của mẫu này chỉ áp dụng cho các ảnh mới tải lên. Để áp dụng mẫu này cho các ảnh đã tải lên trước đây, hãy chạy {job}.",
+ "storage_template_migration_description": "Áp dụng {template} hiện tại cho các tài nguyên đã được tải lên trước đây",
+ "storage_template_migration_info": "Mẫu lưu trữ sẽ chuyển đổi tất cả các phần mở rộng thành chữ thường. Những thay đổi của mẫu này chỉ áp dụng cho các tài nguyên mới tải lên. Để áp dụng mẫu này cho các tài nguyên đã tải lên trước đây, hãy chạy {job}.",
"storage_template_migration_job": "Tác vụ di chuyển mẫu lưu trữ",
"storage_template_more_details": "Cần thêm thông tin chi tiết về tính năng này, vui lòng tham khảo Mẫu lưu trữ và các hệ quả của nó",
"storage_template_onboarding_description_v2": "Khi được bật, tính năng này sẽ tự động sắp xếp các tệp dựa trên mẫu do người dùng xác định. Để biết thêm thông tin, vui lòng xem tài liệu.",
"storage_template_path_length": "Giới hạn độ dài đường dẫn xấp xỉ: {length, number}/{limit, number}",
"storage_template_settings": "Mẫu lưu trữ",
- "storage_template_settings_description": "Quản lý cấu trúc thư mục và tên tệp của ảnh tải lên",
+ "storage_template_settings_description": "Quản lý cấu trúc thư mục và tên tệp của tài nguyên tải lên",
"storage_template_user_label": "Cụm từ {label} là Nhãn lưu trữ của người dùng",
"system_settings": "Cài đặt hệ thống",
"tag_cleanup_job": "Dọn dẹp thẻ",
@@ -356,7 +376,7 @@
"theme_settings": "Chủ đề",
"theme_settings_description": "Tùy biến giao diện web của Immich",
"thumbnail_generation_job": "Tạo ảnh thu nhỏ",
- "thumbnail_generation_job_description": "Tạo ảnh thu nhỏ lớn, nhỏ và mờ cho mỗi ảnh, cũng như ảnh thu nhỏ cho mỗi người",
+ "thumbnail_generation_job_description": "Tạo ảnh thu nhỏ lớn, nhỏ và mờ cho mỗi tài nguyên, cũng như ảnh thu nhỏ cho mỗi người",
"transcoding_acceleration_api": "API Gia tốc",
"transcoding_acceleration_api_description": "API này sẽ tương tác với thiết bị của bạn để gia tốc quá trình chuyển mã. Cài đặt này hoạt động theo nguyên tắc 'cố gắng hết sức'': nó sẽ quay lại chuyển mã phần mềm nếu gặp lỗi. VP9 có thể hoạt động hoặc không tùy thuộc vào phần cứng của bạn.",
"transcoding_acceleration_nvenc": "NVENC (yêu cầu GPU NVIDIA)",
@@ -377,7 +397,7 @@
"transcoding_constant_quality_mode": "Chế độ chất lượng cố định",
"transcoding_constant_quality_mode_description": "ICQ tốt hơn CQP, nhưng một số thiết bị tăng tốc phần cứng không hỗ trợ chế độ này. Cài đặt tùy chọn này sẽ ưu tiên chế độ được chỉ định khi sử dụng mã hóa dựa trên chất lượng. Bị bỏ qua bởi NVENC vì nó không hỗ trợ ICQ.",
"transcoding_constant_rate_factor": "Hệ số tỷ lệ cố định (-crf)",
- "transcoding_constant_rate_factor_description": "Mức chất lượng video. Các giá trị điển hình là 23 cho H.264, 28 cho HEVC, 31 cho VP9 và 35 cho AV1. Giá trị thấp hơn thì tốt hơn, nhưng tạo ra các tập tin lớn hơn.",
+ "transcoding_constant_rate_factor_description": "Chất lượng video. Giá trị điển hình là 23 (H.264), 28 (HEVC), 31 (VP9) và 35 (AV1). Giá trị thấp hơn thì tốt hơn, nhưng tạo ra các tệp lớn hơn.",
"transcoding_disabled_description": "Không chuyển mã bất kỳ video nào, có thể gây lỗi phát lại trên một số thiết bị",
"transcoding_encoding_options": "Các tùy chọn mã hóa",
"transcoding_encoding_options_description": "Thiết lập chuẩn nén video, độ phân giải, chất lượng và các tùy chọn khác cho video",
@@ -398,13 +418,17 @@
"transcoding_preferred_hardware_device_description": "Chỉ áp dụng cho VAAPI và QSV. Thiết lập nút dri được sử dụng cho chuyển mã phần cứng.",
"transcoding_preset_preset": "Mẫu có sẵn (-preset)",
"transcoding_preset_preset_description": "Tốc độ nén. Các mẫu có sẵn chậm hơn tạo ra các tệp nhỏ hơn và cải thiện chất lượng khi mục tiêu là một bitrate cụ thể. VP9 chỉ hỗ trợ các mẫu có sẵn từ 'ultrafast' đến 'faster'.",
+ "transcoding_realtime": "Chuyển mã thời gian thực [THỬ NGHIỆM]",
+ "transcoding_realtime_description": "Cho phép chuyển mã video theo thời gian thực khi video đang được phát trực tuyến. Cho phép chuyển đổi chất lượng, nhưng có thể gây ra độ trễ phát lại cao hơn và hiện tượng giật hình tùy thuộc vào khả năng của máy chủ.",
+ "transcoding_realtime_enabled": "Cho phép chuyển mã thời gian thực",
+ "transcoding_realtime_enabled_description": "Nếu tắt, máy chủ sẽ từ chối bắt đầu các phiên chuyển mã thời gian thực mới.",
"transcoding_reference_frames": "Khung hình tham chiếu",
"transcoding_reference_frames_description": "Số lượng khung hình tham chiếu khi nén một khung hình nhất định. Giá trị cao hơn cải thiện hiệu suất nén nhưng làm chậm quá trình mã hóa. Giá trị 0 để tự động thiết lập giá trị này.",
"transcoding_required_description": "Chỉ video không ở định dạng được chấp nhận",
"transcoding_settings": "Chuyển mã video",
"transcoding_settings_description": "Quản lý video chuyển mã và cách xử lý",
"transcoding_target_resolution": "Độ phân giải mục tiêu",
- "transcoding_target_resolution_description": "Độ phân giải cao hơn có thể giữ lại nhiều chi tiết hơn nhưng mất nhiều thời gian hơn để mã hóa, có kích thước tập tin lớn hơn và có thể làm giảm khả năng phản hồi của app.",
+ "transcoding_target_resolution_description": "Độ phân giải cao hơn có thể giữ lại nhiều chi tiết hơn nhưng mất nhiều thời gian hơn để mã hóa, có kích thước tệp lớn hơn và có thể làm giảm khả năng phản hồi của app.",
"transcoding_temporal_aq": "Lượng tử hóa thích ứng (Temporal AQ)",
"transcoding_temporal_aq_description": "Chỉ áp dụng cho NVENC. Lượng tử hóa Thích ứng Thời gian tăng chất lượng cho các cảnh có nhiều chi tiết và ít chuyển động. Có thể không tương thích với các thiết bị cũ.",
"transcoding_threads": "Luồng",
@@ -412,25 +436,25 @@
"transcoding_tone_mapping": "Ánh Xạ Sắc Thái (Tone-mapping)",
"transcoding_tone_mapping_description": "Cố gắng duy trì chất lượng video tốt nhất khi chuyển đổi từ HDR sang SDR. Mỗi thuật toán có sự đánh đổi khác nhau về màu sắc, chi tiết và độ sáng. Hable giữ chi tiết, Mobius giữ màu sắc và Reinhard giữ độ sáng.",
"transcoding_transcode_policy": "Quy tắc chuyển mã",
- "transcoding_transcode_policy_description": "Quy tắc khi nào video nên được chuyển mã. Các video HDR luôn được chuyển mã (ngoại trừ khi tính năng chuyển mã bị tắt).",
+ "transcoding_transcode_policy_description": "Quy tắc chuyển mã video. Các video HDR và video có định dạng pixel khác YUV 4:2:0 luôn được chuyển mã (trừ khi tính năng chuyển mã bị tắt).",
"transcoding_two_pass_encoding": "Mã hóa hai lần",
"transcoding_two_pass_encoding_setting_description": "Chuyển mã hai lần để tạo ra video được mã hóa tốt hơn. Khi bitrate tối đa được bật (bắt buộc để hoạt động với H.264 và HEVC), chế độ này sử dụng một phạm vi bitrate dựa trên bitrate tối đa và bỏ qua CRF. Đối với VP9, CRF có thể được sử dụng nếu bitrate tối đa bị tắt.",
"transcoding_video_codec": "Chuẩn nén video",
- "transcoding_video_codec_description": "VP9 có hiệu suất cao và tương thích tốt với web, nhưng thời gian chuyển mã lâu hơn. HEVC có hiệu suất tương tự, nhưng tương thích web thấp hơn. H.264 tương thích rộng rãi và chuyển mã nhanh, nhưng tạo ra các tập tin có kích thước lớn. AV1 là codec hiệu quả nhất nhưng không được hỗ trợ trên các thiết bị cũ.",
+ "transcoding_video_codec_description": "VP9 có hiệu suất cao và tương thích web tốt, nhưng thời gian chuyển mã lâu hơn. HEVC có hiệu suất tương tự, nhưng tương thích web thấp hơn. H.264 tương thích rộng rãi và chuyển mã nhanh, nhưng tạo ra các tệp có kích thước lớn. AV1 là codec hiệu quả nhất nhưng không được hỗ trợ trên các thiết bị cũ.",
"trash_enabled_description": "Bật tính năng Thùng rác",
"trash_number_of_days": "Số ngày",
- "trash_number_of_days_description": "Số ngày giữ các ảnh trong thùng rác trước khi xóa chúng vĩnh viễn",
+ "trash_number_of_days_description": "Số ngày giữ các tài nguyên trong thùng rác trước khi xóa chúng vĩnh viễn",
"trash_settings": "Thùng rác",
"trash_settings_description": "Quản lý cài đặt thùng rác",
"unlink_all_oauth_accounts": "Hủy liên kết tất cả tài khoản OAuth",
"unlink_all_oauth_accounts_description": "Hãy nhớ hủy liên kết tất cả tài khoản OAuth trước khi di chuyển sang nhà cung cấp mới.",
"unlink_all_oauth_accounts_prompt": "Bạn có chắc muốn hủy liên kết tất cả tài khoản OAuth không? Thao tác này sẽ đặt lại ID OAuth cho mỗi người dùng và không thể hoàn tác.",
"user_cleanup_job": "Dọn dẹp người dùng",
- "user_delete_delay": "Tài khoản và tệp của {user} sẽ được lên lịch xóa vĩnh viễn sau {delay, plural, one {# ngày} other {# ngày}}.",
+ "user_delete_delay": "Tài khoản và tài nguyên của {user} sẽ được lên lịch xóa vĩnh viễn sau {delay, plural, one {# ngày} other {# ngày}}.",
"user_delete_delay_settings": "Thời gian xóa",
- "user_delete_delay_settings_description": "Số ngày chờ xóa để xóa vĩnh viễn tài khoản và tệp của người dùng. Tác vụ xóa người dùng chạy vào giữa đêm để kiểm tra các người dùng sẵn sàng bị xóa. Thay đổi cài đặt này sẽ được đánh giá vào lần thực hiện tiếp theo.",
- "user_delete_immediately": "Tài khoản và ảnh của {user} sẽ được đưa vào hàng đợi để xóa vĩnh viễn ngay lập tức.",
- "user_delete_immediately_checkbox": "Xếp hàng người dùng và ảnh để xóa ngay lập tức",
+ "user_delete_delay_settings_description": "Số ngày chờ xóa để xóa vĩnh viễn tài khoản và tài nguyên của người dùng. Tác vụ xóa người dùng chạy vào giữa đêm để kiểm tra các người dùng sẵn sàng bị xóa. Thay đổi cài đặt này sẽ được đánh giá vào lần thực hiện tiếp theo.",
+ "user_delete_immediately": "Tài khoản và tài nguyên của {user} sẽ được đưa vào hàng đợi để xóa vĩnh viễn ngay lập tức.",
+ "user_delete_immediately_checkbox": "Xếp hàng người dùng và tài nguyên để xóa ngay lập tức",
"user_details": "Chi tiết Người dùng",
"user_management": "Quản lý người dùng",
"user_password_has_been_reset": "Mật khẩu của người dùng đã được đặt lại:",
@@ -441,24 +465,26 @@
"user_settings_description": "Quản lý cài đặt người dùng",
"user_successfully_removed": "Người dùng {email} đã được xóa thành công.",
"users_page_description": "Trang quản trị người dùng",
+ "version_check_channel": "Kênh phát hành",
+ "version_check_channel_description": "Chọn kênh phát hành mà bạn muốn nhận thông báo về phiên bản mới",
"version_check_enabled_description": "Bật kiểm tra phiên bản",
"version_check_implications": "Tính năng kiểm tra phiên bản yêu cầu kết nối thường xuyên đến {server}",
"version_check_settings": "Kiểm tra phiên bản",
"version_check_settings_description": "Bật/tắt thông báo phiên bản mới",
"video_conversion_job": "Chuyển mã video",
- "video_conversion_job_description": "Chuyển đổi định dạng video để tương thích rộng rãi hơn với trình duyệt và thiết bị"
+ "video_conversion_job_description": "Chuyển mã video để tương thích với nhiều trình duyệt và thiết bị hơn"
},
"admin_email": "Email Quản trị viên",
"admin_password": "Mật khẩu Quản trị viên",
"administration": "Quản trị",
"advanced": "Nâng cao",
- "advanced_settings_clear_image_cache": "Giải phóng bộ nhớ đệm",
- "advanced_settings_clear_image_cache_error": "Lỗi khi giải phóng bộ nhớ đệm",
+ "advanced_settings_clear_image_cache": "Xóa bộ nhớ đệm",
+ "advanced_settings_clear_image_cache_error": "Lỗi khi xóa bộ nhớ đệm",
"advanced_settings_clear_image_cache_success": "Đã giải phóng thành công {size}",
"advanced_settings_enable_alternate_media_filter_subtitle": "Dùng tùy chọn này để lọc phương tiện khi đồng bộ theo tiêu chí khác. Chỉ thử khi app không nhận diện được tất cả các album.",
"advanced_settings_enable_alternate_media_filter_title": "[THỬ NGHIỆM] Dùng bộ lọc đồng bộ album thay thế",
"advanced_settings_log_level_title": "Phân loại log: {level}",
- "advanced_settings_prefer_remote_subtitle": "Việc tải ảnh thu nhỏ từ ảnh trên một số thiết bị có thể diễn ra chậm. Kích hoạt cài đặt này để tải ảnh từ máy chủ.",
+ "advanced_settings_prefer_remote_subtitle": "Việc tải ảnh thu nhỏ từ tài nguyên trên một số thiết bị có thể diễn ra chậm. Kích hoạt cài đặt này để tải ảnh từ máy chủ.",
"advanced_settings_prefer_remote_title": "Ưu tiên ảnh từ máy chủ",
"advanced_settings_proxy_headers_subtitle": "Xác định các tiêu đề proxy Immich sẽ gửi kèm mỗi yêu cầu mạng",
"advanced_settings_proxy_headers_title": "Tùy chỉnh tiêu đề proxy [THỬ NGHIỆM]",
@@ -466,7 +492,7 @@
"advanced_settings_readonly_mode_title": "Chế độ chỉ-xem",
"advanced_settings_self_signed_ssl_subtitle": "Bỏ qua xác minh chứng chỉ SSL cho endpoint máy chủ. Yêu cầu cho chứng chỉ tự ký.",
"advanced_settings_self_signed_ssl_title": "Cho phép chứng chỉ SSL tự ký [THỬ NGHIỆM]",
- "advanced_settings_sync_remote_deletions_subtitle": "Tự động xóa hoặc khôi phục dữ liệu trên thiết bị này khi bạn thao tác trên web",
+ "advanced_settings_sync_remote_deletions_subtitle": "Tự động xóa hoặc khôi phục tài nguyên trên thiết bị này khi bạn thao tác trên web",
"advanced_settings_sync_remote_deletions_title": "Đồng bộ việc xóa từ thiết bị khác [THỬ NGHIỆM]",
"advanced_settings_tile_subtitle": "Dành cho người dùng nâng cao",
"advanced_settings_troubleshooting_subtitle": "Bật các tính năng bổ sung để xử lý sự cố",
@@ -475,7 +501,7 @@
"age_year_months": "1 tuổi, {months, plural, one {# tháng} other {# tháng}}",
"age_years": "{years, plural, other {# tuổi}}",
"album": "Album",
- "album_added": "Đã thêm album",
+ "album_added": "Được thêm vào album",
"album_added_notification_setting_description": "Nhận thông báo qua email khi bạn được thêm vào một album chia sẻ",
"album_cover_updated": "Đã cập nhật ảnh bìa album",
"album_delete_confirmation": "Bạn có chắc muốn xóa album {album}?",
@@ -494,25 +520,25 @@
"album_selected": "Album đã chọn",
"album_share_no_users": "Có vẻ như bạn đã chia sẻ album này với tất cả người dùng hoặc bạn không có người dùng nào để chia sẻ.",
"album_summary": "Mô tả album",
- "album_updated": "Đã cập nhật album",
- "album_updated_setting_description": "Nhận thông báo qua email khi một album chia sẻ có các ảnh mới",
- "album_upload_assets": "Tải ảnh/video từ máy tính của bạn lên và thêm vào album",
+ "album_updated": "Album có cập nhật",
+ "album_updated_setting_description": "Nhận thông báo qua email khi một album chia sẻ có các tài nguyên mới",
+ "album_upload_assets": "Tải tài nguyên từ máy tính của bạn lên và thêm vào album",
"album_user_left": "Đã rời khỏi {album}",
"album_user_removed": "Đã xóa {user}",
"album_viewer_appbar_delete_confirm": "Bạn có muốn xóa album này khỏi tài khoản của mình?",
"album_viewer_appbar_share_err_delete": "Xóa album thất bại",
"album_viewer_appbar_share_err_leave": "Rời khỏi album thất bại",
- "album_viewer_appbar_share_err_remove": "Có vấn đề khi xóa ảnh khỏi album",
+ "album_viewer_appbar_share_err_remove": "Có vấn đề khi xóa tài nguyên khỏi album",
"album_viewer_appbar_share_err_title": "Thay đổi tên album thất bại",
"album_viewer_appbar_share_leave": "Rời khỏi album",
"album_viewer_appbar_share_to": "Chia sẻ với",
"album_viewer_page_share_add_users": "Thêm người dùng",
- "album_with_link_access": "Ai có liên kết sẽ xem được các ảnh và người trong album này.",
+ "album_with_link_access": "Ai có link sẽ xem được các ảnh và người trong album này.",
"albums": "Album",
"albums_count": "{count, plural, one {{count, number} Album} other {{count, number} Album}}",
"albums_default_sort_order": "Thứ tự sắp xếp album mặc định",
- "albums_default_sort_order_description": "Thứ tự sắp xếp ban đầu cho các ảnh khi tạo album mới.",
- "albums_feature_description": "Các bộ sưu tập tệp có thể được chia sẻ với những người dùng khác.",
+ "albums_default_sort_order_description": "Thứ tự sắp xếp ban đầu cho các tài nguyên khi tạo album mới.",
+ "albums_feature_description": "Các bộ sưu tập tài nguyên có thể chia sẻ được với người khác",
"albums_on_device_count": "Album trên thiết bị ({count})",
"albums_selected": "{count, plural, one {# album đã chọn} other {# album đã chọn}}",
"all": "Tất cả",
@@ -534,7 +560,7 @@
"api_key_description": "Giá trị này chỉ được hiển thị một lần. Vui lòng sao chép nó trước khi đóng cửa sổ.",
"api_key_empty": "Tên khóa API của bạn không được để trống",
"api_keys": "Khóa API",
- "app_architecture_variant": "Variant (Kiến trúc)",
+ "app_architecture_variant": "Biến thể (Kiến trúc)",
"app_bar_signout_dialog_content": "Bạn có muốn đăng xuất?",
"app_bar_signout_dialog_ok": "Có",
"app_bar_signout_dialog_title": "Đăng xuất",
@@ -547,69 +573,70 @@
"archive": "Lưu trữ",
"archive_action_prompt": "{count} đã được thêm vào Lưu trữ",
"archive_or_unarchive_photo": "Lưu trữ hoặc bỏ lưu trữ ảnh",
- "archive_page_no_archived_assets": "Không tìm thấy tệp đã lưu trữ",
+ "archive_page_no_archived_assets": "Không tìm thấy tài nguyên đã lưu trữ",
"archive_page_title": "Kho lưu trữ ({count})",
- "archive_size": "Kích cỡ lưu trữ",
- "archive_size_description": "Cấu hình kích cỡ nén cho các tệp tải xuống (đơn vị GiB)",
+ "archive_size": "Dung lượng tệp nén",
+ "archive_size_description": "Cấu hình dung lượng tệp nén để tải xuống (đơn vị GiB)",
"archived": "Lưu trữ",
"archived_count": "{count, plural, other {Đã lưu trữ # mục}}",
"are_these_the_same_person": "Đây có phải cùng một người không?",
"are_you_sure_to_do_this": "Bạn có chắc muốn thực hiện điều này?",
"array_field_not_fully_supported": "Các trường mảng yêu cầu chỉnh sửa JSON thủ công",
- "asset_action_delete_err_read_only": "Không thể xóa tệp chỉ có quyền đọc, bỏ qua",
- "asset_action_share_err_offline": "Không thể tải tệp ngoại tuyến, bỏ qua",
+ "asset_action_delete_err_read_only": "Không thể xóa tài nguyên chỉ có quyền đọc, bỏ qua",
+ "asset_action_share_err_offline": "Không thể nạp tài nguyên ngoại tuyến, bỏ qua",
"asset_added_to_album": "Đã thêm vào album",
"asset_adding_to_album": "Đang thêm vào album…",
- "asset_created": "Đã tạo tệp",
- "asset_description_updated": "Mô tả ảnh đã được cập nhật",
- "asset_filename_is_offline": "Tệp {filename} đang ngoại tuyến",
- "asset_has_unassigned_faces": "Tệp chưa được gán khuôn mặt",
+ "asset_created": "Đã tạo tài nguyên",
+ "asset_day_count": "{date}: {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "asset_description_updated": "Mô tả tài nguyên đã được cập nhật",
+ "asset_filename_is_offline": "Tài nguyên {filename} đang ngoại tuyến",
+ "asset_has_unassigned_faces": "Tài nguyên chưa được gán khuôn mặt",
"asset_hashing": "Đang băm…",
"asset_list_group_by_sub_title": "Nhóm theo",
"asset_list_layout_settings_dynamic_layout_title": "Bố cục động",
"asset_list_layout_settings_group_automatically": "Tự động",
- "asset_list_layout_settings_group_by": "Nhóm tệp theo",
+ "asset_list_layout_settings_group_by": "Nhóm tài nguyên theo",
"asset_list_layout_settings_group_by_month_day": "Tháng + ngày",
"asset_list_layout_sub_title": "Bố cục",
"asset_list_settings_subtitle": "Bố cục lưới ảnh",
"asset_list_settings_title": "Lưới ảnh",
- "asset_not_found_on_device_android": "Không tìm thấy tệp trên thiết bị",
- "asset_not_found_on_device_ios": "Không tìm thấy tệp trên thiết bị. Nếu bạn đang dùng iCloud, có thể tệp lưu trên iCloud bị lỗi nên không thể được truy cập",
- "asset_not_found_on_icloud": "Không tìm thấy tệp trên iCloud. Có thể tệp lưu trên iCloud bị lỗi nên không thể được truy cập",
- "asset_offline": "Tệp Ngoại tuyến",
- "asset_offline_description": "Tệp bên ngoài này không còn trên ổ đĩa. Vui lòng liên hệ quản trị viên Immich của bạn để được trợ giúp.",
- "asset_restored_successfully": "Đã khôi phục tệp thành công",
+ "asset_not_found_on_device_android": "Không tìm thấy tài nguyên trên thiết bị",
+ "asset_not_found_on_device_ios": "Không tìm thấy tài nguyên trên thiết bị. Nếu bạn đang dùng iCloud, có thể tài nguyên lưu trên iCloud bị lỗi nên không thể được truy cập",
+ "asset_not_found_on_icloud": "Không tìm thấy tài nguyên trên iCloud. Có thể tài nguyên lưu trên iCloud bị lỗi nên không thể được truy cập",
+ "asset_offline": "Tài nguyên Ngoại tuyến",
+ "asset_offline_description": "Tài nguyên bên ngoài này không còn trên ổ đĩa. Vui lòng liên hệ quản trị viên Immich của bạn để được trợ giúp.",
+ "asset_restored_successfully": "Đã khôi phục tài nguyên thành công",
"asset_skipped": "Đã bỏ qua",
"asset_skipped_in_trash": "Trong thùng rác",
- "asset_trashed": "Đã chuyển tệp đến thùng rác",
- "asset_troubleshoot": "Khắc phục sự cố tệp",
+ "asset_trashed": "Đã chuyển tài nguyên vào thùng rác",
+ "asset_troubleshoot": "Khắc phục sự cố tài nguyên",
"asset_uploaded": "Đã tải lên",
"asset_uploading": "Đang tải lên…",
"asset_viewer_settings_subtitle": "Cách thư viện hiển thị",
- "asset_viewer_settings_title": "Trình xem ảnh",
- "assets": "Tệp",
- "assets_added_count": "Đã thêm {count, plural, one {# tệp} other {# tệp}}",
- "assets_added_to_album_count": "Đã thêm {count, plural, one {# tệp} other {# tệp}} vào album",
- "assets_added_to_albums_count": "Đã thêm {assetTotal, plural, one {# tệp} other {# tệp}} vào {albumTotal, plural, one {# album} other {# album}}",
- "assets_cannot_be_added_to_album_count": "{count, plural, one {Tệp} other {Tệp}} không thể thêm vào album",
- "assets_cannot_be_added_to_albums": "{count, plural, one {Tệp} other {Tệp}} không thể thêm vào bất kỳ album nào",
- "assets_count": "{count, plural, one {# tệp} other {# tệp}}",
- "assets_deleted_permanently": "Đã xóa vĩnh viễn {count} tệp",
- "assets_deleted_permanently_from_server": "Đã xóa vĩnh viễn {count} tệp khỏi máy chủ Immich",
+ "asset_viewer_settings_title": "Duyệt tài nguyên",
+ "assets": "Tài nguyên",
+ "assets_added_count": "Đã thêm {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "assets_added_to_album_count": "Đã thêm {count, plural, one {# tài nguyên} other {# tài nguyên}} vào album",
+ "assets_added_to_albums_count": "Đã thêm {assetTotal, plural, one {# tài nguyên} other {# tài nguyên}} vào {albumTotal, plural, one {# album} other {# album}}",
+ "assets_cannot_be_added_to_album_count": "{count, plural, one {Tài nguyên} other {Tài nguyên}} không thể thêm vào album",
+ "assets_cannot_be_added_to_albums": "{count, plural, one {Tài nguyên} other {Tài nguyên}} không thể thêm vào bất kỳ album nào",
+ "assets_count": "{count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "assets_deleted_permanently": "Đã xóa vĩnh viễn {count} tài nguyên",
+ "assets_deleted_permanently_from_server": "Đã xóa vĩnh viễn {count} tài nguyên khỏi máy chủ Immich",
"assets_downloaded_failed": "{count, plural, one {Đã tải xuống # tệp - {error} tệp thất bại} other {Đã tải xuống # tệp - {error} tệp thất bại}}",
"assets_downloaded_successfully": "{count, plural, one {Đã tải xuống # tệp thành công} other {Đã tải xuống # tệp thành công}}",
- "assets_moved_to_trash_count": "Đã chuyển {count, plural, one {# tệp} other {# tệp}} vào thùng rác",
- "assets_permanently_deleted_count": "Đã xóa vĩnh viễn {count, plural, one {# tệp} other {# tệp}}",
- "assets_removed_count": "Đã xóa {count, plural, one {# tệp} other {# tệp}}",
- "assets_removed_permanently_from_device": "Đã xóa vĩnh viễn {count} tệp khỏi thiết bị của bạn",
- "assets_restore_confirmation": "Bạn có chắc muốn khôi phục tất cả mục đã xóa của mình không? Bạn không thể hoàn tác hành động này! Lưu ý rằng không thể khôi phục các ảnh ngoại tuyến theo cách này.",
- "assets_restored_count": "Đã khôi phục {count, plural, one {# tệp} other {# tệp}}",
- "assets_restored_successfully": "Đã khôi phục {count} tệp thành công",
- "assets_trashed": "Đã chuyển {count} tệp vào thùng rác",
- "assets_trashed_count": "Đã chuyển {count, plural, one {# tệp} other {# tệp}} vào thùng rác",
- "assets_trashed_from_server": "Đã chuyển {count} tệp từ máy chủ Immich vào thùng rác",
- "assets_were_part_of_album_count": "{count, plural, one {Tệp đã} other {Các tệp đã}} có sẵn trong album",
- "assets_were_part_of_albums_count": "{count, plural, one {Tệp đã} other {Tệp đã}} có sẵn trong album",
+ "assets_moved_to_trash_count": "Đã chuyển {count, plural, one {# tài nguyên} other {# tài nguyên}} vào thùng rác",
+ "assets_permanently_deleted_count": "Đã xóa vĩnh viễn {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "assets_removed_count": "Đã xóa {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "assets_removed_permanently_from_device": "Đã xóa vĩnh viễn {count} tài nguyên khỏi thiết bị của bạn",
+ "assets_restore_confirmation": "Bạn có chắc muốn khôi phục tất cả tài nguyên đã xóa của mình không? Bạn không thể hoàn tác hành động này! Lưu ý rằng không thể khôi phục các tài nguyên ngoại tuyến theo cách này.",
+ "assets_restored_count": "Đã khôi phục {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "assets_restored_successfully": "Đã khôi phục {count} tài nguyên thành công",
+ "assets_trashed": "Đã chuyển {count} tài nguyên vào thùng rác",
+ "assets_trashed_count": "Đã chuyển {count, plural, one {# tài nguyên} other {# tài nguyên}} vào thùng rác",
+ "assets_trashed_from_server": "Đã chuyển {count} tài nguyên từ máy chủ Immich vào thùng rác",
+ "assets_were_part_of_album_count": "{count, plural, one {Tài nguyên đã} other {Tài nguyên đã}} có sẵn trong album",
+ "assets_were_part_of_albums_count": "{count, plural, one {Tài nguyên đã} other {Tài nguyên}} có sẵn trong album",
"authorized_devices": "Thiết bị",
"automatic_endpoint_switching_subtitle": "Kết nối nội bộ qua Wi-Fi được chỉ định khi kết nối được và sử dụng các kết nối thay thế ở nơi khác",
"automatic_endpoint_switching_title": "Tự động chuyển đổi địa chỉ máy chủ",
@@ -623,19 +650,19 @@
"backup": "Sao lưu",
"backup_album_selection_page_albums_device": "Album trên thiết bị ({count})",
"backup_album_selection_page_albums_tap": "Nhấn để chọn, nhấn đúp để bỏ qua",
- "backup_album_selection_page_assets_scatter": "Ảnh có thể có trong nhiều album khác nhau. Trong quá trình sao lưu, bạn có thể chọn để sao lưu tất cả các album hoặc chỉ một số album nhất định.",
+ "backup_album_selection_page_assets_scatter": "Tài nguyên có thể có trong nhiều album khác nhau. Trong quá trình sao lưu, bạn có thể chọn để sao lưu tất cả các album hoặc chỉ một số album nhất định.",
"backup_album_selection_page_select_albums": "Chọn album",
"backup_album_selection_page_selection_info": "Thông tin các mục đã chọn",
- "backup_album_selection_page_total_assets": "Tổng số tệp không trùng lặp",
+ "backup_album_selection_page_total_assets": "Tổng số tài nguyên không trùng lặp",
"backup_albums_sync": "Đồng bộ hóa bản sao lưu album",
"backup_all": "Tất cả",
- "backup_background_service_backup_failed_message": "Sao lưu tệp thất bại. Đang thử lại…",
- "backup_background_service_complete_notification": "Hoàn tất sao lưu tệp",
+ "backup_background_service_backup_failed_message": "Sao lưu tài nguyên thất bại. Đang thử lại…",
+ "backup_background_service_complete_notification": "Hoàn tất sao lưu tài nguyên",
"backup_background_service_connection_failed_message": "Kết nối tới máy chủ thất bại. Đang thử lại…",
"backup_background_service_current_upload_notification": "Đang tải lên {filename}",
- "backup_background_service_default_notification": "Đang kiểm tra tệp mới…",
+ "backup_background_service_default_notification": "Đang kiểm tra các tài nguyên mới…",
"backup_background_service_error_title": "Sao lưu không thành công",
- "backup_background_service_in_progress_notification": "Đang sao lưu tệp của bạn…",
+ "backup_background_service_in_progress_notification": "Đang sao lưu tài nguyên của bạn…",
"backup_background_service_upload_failure_notification": "Tải lên {filename} thất bại",
"backup_controller_page_albums": "Album sao lưu",
"backup_controller_page_background_app_refresh_disabled_content": "Bật làm mới ứng dụng trong nền tại Cài đặt > Cài đặt chung > Làm mới ứng dụng trong nền để dùng sao lưu nền.",
@@ -647,8 +674,8 @@
"backup_controller_page_background_battery_info_title": "Tiết kiệm pin",
"backup_controller_page_background_charging": "Chỉ khi đang sạc",
"backup_controller_page_background_configure_error": "Cấu hình dịch vụ nền thất bại",
- "backup_controller_page_background_delay": "Trì hoãn sao lưu tệp mới: {duration}",
- "backup_controller_page_background_description": "Bật dịch vụ nền để tự động sao lưu tệp mới mà không cần mở ứng dụng",
+ "backup_controller_page_background_delay": "Trì hoãn sao lưu tài nguyên mới: {duration}",
+ "backup_controller_page_background_description": "Bật dịch vụ nền để tự động sao lưu tài nguyên mới mà không cần mở ứng dụng",
"backup_controller_page_background_is_off": "Sao lưu tự động trong nền đang tắt",
"backup_controller_page_background_is_on": "Sao lưu tự động trong nền đang bật",
"backup_controller_page_background_turn_off": "Tắt dịch vụ nền",
@@ -658,28 +685,28 @@
"backup_controller_page_backup_selected": "Đã chọn: ",
"backup_controller_page_backup_sub": "Ảnh và video đã sao lưu",
"backup_controller_page_created": "Tạo vào: {date}",
- "backup_controller_page_desc_backup": "Bật sao lưu khi ứng dụng hoạt động để tự động sao lưu tệp mới lên máy chủ khi mở ứng dụng.",
+ "backup_controller_page_desc_backup": "Bật sao lưu khi ứng dụng hoạt động để tự động sao lưu tài nguyên mới lên máy chủ khi mở ứng dụng.",
"backup_controller_page_excluded": "Đã bỏ qua: ",
"backup_controller_page_failed": "Thất bại ({count})",
"backup_controller_page_filename": "Tên tệp: {filename} [{size}]",
"backup_controller_page_id": "ID: {id}",
"backup_controller_page_info": "Thông tin sao lưu",
- "backup_controller_page_none_selected": "Không có mục nào được chọn",
+ "backup_controller_page_none_selected": "Chưa chọn mục nào",
"backup_controller_page_remainder": "Còn lại",
"backup_controller_page_remainder_sub": "Số lượng ảnh và video đã chọn chưa được sao lưu",
"backup_controller_page_server_storage": "Dung lượng máy chủ",
"backup_controller_page_start_backup": "Bắt đầu sao lưu",
"backup_controller_page_status_off": "Sao lưu tự động khi ứng dụng hoạt động đang tắt",
"backup_controller_page_status_on": "Sao lưu tự động khi ứng dụng hoạt động đang bật",
- "backup_controller_page_storage_format": "Đã dùng {used} của {total}",
- "backup_controller_page_to_backup": "Các album cần được sao lưu",
+ "backup_controller_page_storage_format": "Đã dùng {used} trong {total}",
+ "backup_controller_page_to_backup": "Các album sẽ được sao lưu",
"backup_controller_page_total_sub": "Tất cả ảnh và video không trùng lập từ các album được chọn",
"backup_controller_page_turn_off": "Tắt sao lưu khi ứng dụng hoạt động",
"backup_controller_page_turn_on": "Bật sao lưu khi mở app",
"backup_controller_page_uploading_file_info": "Thông tin tệp đang tải lên",
"backup_err_only_album": "Không thể xóa album duy nhất",
"backup_error_sync_failed": "Đồng bộ thất bại. Không thể tiến hành sao lưu.",
- "backup_info_card_assets": "tệp",
+ "backup_info_card_assets": "tài nguyên",
"backup_manual_cancelled": "Đã hủy",
"backup_manual_in_progress": "Đang tải lên. Vui lòng thử lại sau",
"backup_manual_success": "Thành công",
@@ -690,6 +717,7 @@
"backup_settings_subtitle": "Cài đặt việc tải lên",
"backup_upload_details_page_more_details": "Nhấn để hiện chi tiết",
"backward": "Lùi lại",
+ "battery_optimization_backup_reliability": "Tắt tính năng tiết kiệm pin để đảm bảo quá trình sao lưu nền",
"biometric_auth_enabled": "Đã bật xác thực sinh trắc học",
"biometric_locked_out": "Bạn đã bị khóa xác thực bằng sinh trắc học",
"biometric_no_options": "Không có tùy chọn bằng sinh trắc học",
@@ -697,19 +725,19 @@
"birthdate_saved": "Sinh nhật đã được lưu thành công",
"birthdate_set_description": "Sinh nhật được sử dụng để tính tuổi của người này tại thời điểm chụp ảnh.",
"blurred_background": "Nền mờ",
- "browse_templates": "Xem các mẫu",
+ "browse_templates": "Xem mẫu có sẵn",
"bugs_and_feature_requests": "Báo lỗi & Đề xuất tính năng",
- "build": "Dựng",
+ "build": "Build",
"build_image": "Bản dựng",
- "bulk_delete_duplicates_confirmation": "Bạn có chắc muốn xóa hàng loạt {count, plural, one {# tệp trùng lặp} other {# tệp trùng lặp}}? Điều này sẽ giữ lại ảnh chất lượng nhất của mỗi nhóm và xóa vĩnh viễn tất cả các bản trùng lặp khác. Bạn không thể hoàn tác hành động này!",
- "bulk_keep_duplicates_confirmation": "Bạn có chắc muốn giữ lại {count, plural, one {# tệp trùng lặp} other {# tệp trùng lặp}}? Điều này sẽ xử lý tất cả các nhóm ảnh trùng lặp mà không xóa bất kỳ thứ gì.",
- "bulk_trash_duplicates_confirmation": "Bạn có chắc muốn đưa {count, plural, one {# tệp trùng lặp} other {# tệp trùng lặp}} vào thùng rác? Điều này sẽ giữ lại ảnh chất lượng nhất của mỗi nhóm và đưa tất cả các bản trùng lặp khác vào thùng rác.",
+ "bulk_delete_duplicates_confirmation": "Bạn có chắc muốn xóa hàng loạt {count, plural, one {# tài nguyên trùng lặp} other {# tài nguyên trùng lặp}}? Điều này sẽ giữ lại tài nguyên lớn nhất của mỗi nhóm và xóa vĩnh viễn tất cả các bản trùng lặp khác. Bạn không thể hoàn tác hành động này!",
+ "bulk_keep_duplicates_confirmation": "Bạn có chắc muốn giữ lại {count, plural, one {# tài nguyên trùng lặp} other {# tài nguyên trùng lặp}}? Điều này sẽ xử lý tất cả các nhóm ảnh trùng lặp mà không xóa bất kỳ thứ gì.",
+ "bulk_trash_duplicates_confirmation": "Bạn có chắc muốn đưa {count, plural, one {# tài nguyên trùng lặp} other {# tài nguyên trùng lặp}} vào thùng rác? Điều này sẽ giữ lại tài nguyên lớn nhất của mỗi nhóm và đưa tất cả các bản trùng lặp khác vào thùng rác.",
"buy": "Mua Immich",
"cache_settings_clear_cache_button": "Xóa bộ nhớ đệm",
"cache_settings_clear_cache_button_title": "Xóa bộ nhớ đệm của ứng dụng. Điều này sẽ ảnh hưởng đến hiệu suất của ứng dụng đến khi bộ nhớ đệm được tạo lại.",
"cache_settings_duplicated_assets_clear_button": "XÓA",
"cache_settings_duplicated_assets_subtitle": "Ảnh và video không được phép hiển thị trên ứng dụng",
- "cache_settings_duplicated_assets_title": "Tệp bị trùng ({count})",
+ "cache_settings_duplicated_assets_title": "Tài nguyên trùng lặp ({count})",
"cache_settings_statistics_album": "Ảnh thu nhỏ thư viện",
"cache_settings_statistics_full": "Ảnh đầy đủ",
"cache_settings_statistics_shared": "Ảnh thu nhỏ album chia sẻ",
@@ -755,26 +783,26 @@
"changed_visibility_successfully": "Đã đổi trạng thái hiển thị thành công",
"charging": "Sạc",
"charging_requirement_mobile_backup": "Sao lưu dưới nền yêu cầu thiết bị phải đang sạc",
- "check_corrupt_asset_backup": "Kiểm tra tệp bị hỏng",
+ "check_corrupt_asset_backup": "Kiểm tra tài nguyên bị hỏng",
"check_corrupt_asset_backup_button": "Tiến hành kiểm tra",
- "check_corrupt_asset_backup_description": "Chỉ chạy kiểm tra này khi có Wi-Fi và sau khi đã sao lưu toàn bộ dữ liệu. Quá trình có thể mất vài phút.",
+ "check_corrupt_asset_backup_description": "Chỉ chạy kiểm tra này khi có Wi-Fi và sau khi đã sao lưu toàn bộ tài nguyên. Quá trình có thể mất vài phút.",
"check_logs": "Kiểm tra log",
"checksum": "Checksum",
"choose": "Chọn",
"choose_matching_people_to_merge": "Chọn những người trùng khớp để hợp nhất",
"city": "Thành phố",
- "cleanup_confirm_description": "Immich phát hiện {count} tệp (được tạo ra trước {date}) được sao lưu trên máy chủ. Bạn có muốn xóa bản sao được lưu trên thiết bị này không?",
+ "cleanup_confirm_description": "Immich phát hiện {count} tài nguyên (được tạo ra trước {date}) được sao lưu trên máy chủ. Bạn có muốn xóa bản sao được lưu trên thiết bị này không?",
"cleanup_confirm_prompt_title": "Xóa khỏi thiết bị này?",
- "cleanup_deleted_assets": "Đã chuyển {count} tệp vào thùng rác",
+ "cleanup_deleted_assets": "Đã chuyển {count} tài nguyên vào thùng rác",
"cleanup_deleting": "Đang chuyển vào thùng rác...",
- "cleanup_found_assets": "Phát hiện {count} tệp được sao lưu",
- "cleanup_found_assets_with_size": "Phát hiện {count} được sao lưu ({size})",
+ "cleanup_found_assets": "Phát hiện {count} tài nguyên được sao lưu",
+ "cleanup_found_assets_with_size": "Phát hiện {count} tài nguyên đã sao lưu ({size})",
"cleanup_icloud_shared_albums_excluded": "Những album được chia sẻ trên iCloud không nằm trong phạm vi quét",
- "cleanup_no_assets_found": "Không tìm thấy tệp nào phù hợp với điều khiện trên. Tính năng Giải phóng dung lượng chỉ có thể xóa tệp đã được sao lưu lên máy chủ",
- "cleanup_preview_title": "Các tệp sẽ bị xóa ({count})",
- "cleanup_step3_description": "Tìm các tệp đã được sao lưu theo bộ lọc ngày và giữ lại cài đặt của bạn.",
- "cleanup_step4_summary": "Có {count} tệp (được tạo trước {date}) sẽ bị xóa khỏi thiết bị của bạn. Ảnh vẫn có thể được truy cập bằng ứng dụng Immich.",
- "cleanup_trash_hint": "Để giải phóng tối đa bộ nhớ, vui lòng mở ứng dụng thư viện ảnh của hệ thống và dọn sạch thùng rác",
+ "cleanup_no_assets_found": "Không tìm thấy tài nguyên nào phù hợp với điều kiện trên. Tính năng Giải phóng dung lượng chỉ có thể xóa các tài nguyên đã được sao lưu lên máy chủ",
+ "cleanup_preview_title": "Các tài nguyên sẽ bị xóa ({count})",
+ "cleanup_step3_description": "Tìm các tài nguyên đã được sao lưu theo bộ lọc ngày và giữ lại cài đặt của bạn.",
+ "cleanup_step4_summary": "Có {count} ttài nguyên (được tạo trước {date}) sẽ bị xóa khỏi thiết bị của bạn. Ảnh vẫn có thể được truy cập bằng ứng dụng Immich.",
+ "cleanup_trash_hint": "Để tiết kiệm tối đa bộ nhớ, vui lòng mở ứng dụng thư viện ảnh của hệ thống và dọn sạch thùng rác",
"clear": "Xóa",
"clear_all": "Xóa tất cả",
"clear_all_recent_searches": "Xóa tất cả tìm kiếm gần đây",
@@ -813,13 +841,13 @@
"configuration": "Cấu hình",
"confirm": "Xác nhận",
"confirm_admin_password": "Xác nhận mật khẩu quản trị viên",
- "confirm_delete_face": "Bạn có chắc muốn xóa khuôn mặt {name} khỏi tệp?",
- "confirm_delete_shared_link": "Bạn có chắc muốn xóa liên kết chia sẻ này?",
- "confirm_keep_this_delete_others": "Các ảnh còn lại trong nhóm sẽ bị xóa ngoại trừ ảnh này. Bạn có chắc muốn tiếp tục?",
+ "confirm_delete_face": "Bạn có chắc muốn xóa khuôn mặt {name} khỏi tài nguyên?",
+ "confirm_delete_shared_link": "Bạn có chắc muốn xóa link chia sẻ này?",
+ "confirm_keep_this_delete_others": "Các tài nguyên còn lại trong nhóm sẽ bị xóa ngoại trừ tài nguyên này. Bạn có chắc muốn tiếp tục?",
"confirm_new_pin_code": "Xác nhận mã PIN mới",
"confirm_password": "Xác nhận mật khẩu",
- "confirm_tag_face": "Bạn có muốn gắn thẻ gương mặt này là {name}?",
- "confirm_tag_face_unnamed": "Bạn có muốn gắn thẻ gương mặt này?",
+ "confirm_tag_face": "Bạn có muốn gắn thẻ khuôn mặt này là của {name}?",
+ "confirm_tag_face_unnamed": "Bạn có muốn gắn thẻ khuôn mặt này?",
"connected_device": "Thiết bị được kết nối",
"connected_to": "Đã kết nối tới",
"contain": "Vừa màn hình",
@@ -833,17 +861,17 @@
"control_bottom_app_bar_edit_time": "Chỉnh sửa Ngày và Giờ",
"control_bottom_app_bar_share_link": "Chia sẻ liên kết",
"control_bottom_app_bar_share_to": "Chia sẻ với",
- "control_bottom_app_bar_trash_from_immich": "Di chuyển đến Thùng rác",
- "copied_image_to_clipboard": "Đã sao chép ảnh vào bộ nhớ tạm.",
- "copied_to_clipboard": "Đã sao chép vào bộ nhớ tạm!",
+ "control_bottom_app_bar_trash_from_immich": "Di chuyển vào Thùng rác",
+ "copied_image_to_clipboard": "Đã sao chép ảnh vào clipboard.",
+ "copied_to_clipboard": "Đã sao chép vào clipboard!",
"copy_error": "Sao chép lỗi",
"copy_file_path": "Sao chép đường dẫn tệp",
"copy_image": "Sao chép ảnh",
"copy_json": "Sao chép JSON",
- "copy_link": "Sao chép liên kết",
- "copy_link_to_clipboard": "Sao chép liên kết vào bộ nhớ tạm",
+ "copy_link": "Sao chép link",
+ "copy_link_to_clipboard": "Sao chép liên kết vào clipboard",
"copy_password": "Sao chép mật khẩu",
- "copy_to_clipboard": "Sao chép vào bộ nhớ tạm",
+ "copy_to_clipboard": "Sao chép vào clipboard",
"country": "Quốc gia",
"cover": "Tối đa",
"covers": "Lưới",
@@ -853,19 +881,19 @@
"create_api_key": "Tạo khóa API",
"create_first_workflow": "Tạo workflow đầu tiên",
"create_library": "Tạo thư viện",
- "create_link": "Tạo liên kết",
+ "create_link": "Tạo link",
"create_link_to_share": "Tạo liên kết để chia sẻ",
- "create_link_to_share_description": "Ai có liên kết sẽ xem được các ảnh đã chọn",
+ "create_link_to_share_description": "Ai có link sẽ xem được các ảnh đã chọn",
"create_new": "TẠO MỚI",
"create_new_face": "Tạo khuôn mặt mới",
"create_new_person": "Tạo người mới",
- "create_new_person_hint": "Gán các ảnh đã chọn cho một người mới",
+ "create_new_person_hint": "Gán các tài nguyên đã chọn cho một người mới",
"create_new_user": "Tạo người dùng mới",
"create_person": "Tạo người",
"create_person_subtitle": "Thêm tên vào khuôn mặt đã chọn để tạo và gắn thẻ người mới",
- "create_shared_album_page_share_add_assets": "THÊM TỆP",
+ "create_shared_album_page_share_add_assets": "THÊM TÀI NGUYÊN",
"create_shared_album_page_share_select_photos": "Chọn ảnh",
- "create_shared_link": "Chia sẻ qua liên kết",
+ "create_shared_link": "Tạo link chia sẻ",
"create_tag": "Tạo thẻ",
"create_tag_description": "Tạo thẻ mới. Với các thẻ lồng nhau, vui lòng nhập đường dẫn đầy đủ của thẻ bao gồm dấu gạch chéo.",
"create_user": "Tạo người dùng",
@@ -876,7 +904,8 @@
"crop": "Cắt",
"crop_aspect_ratio_fixed": "Cố định",
"crop_aspect_ratio_free": "Tự do",
- "crop_aspect_ratio_original": "Nguyên bản",
+ "crop_aspect_ratio_original": "Gốc",
+ "crop_aspect_ratio_square": "Vuông",
"curated_object_page_title": "Đối tượng",
"current_device": "Thiết bị hiện tại",
"current_pin_code": "Mã PIN hiện tại",
@@ -894,13 +923,19 @@
"date_after": "Ngày sau",
"date_and_time": "Ngày và giờ",
"date_before": "Ngày trước",
+ "date_of_birth": "Ngày sinh",
"date_of_birth_saved": "Sinh nhật đã được lưu thành công",
"date_range": "Khoảng thời gian",
+ "date_time_original": "Ngày/Giờ gốc",
"day": "Ngày",
"days": "Ngày",
"deduplicate_all": "Xóa tất cả mục trùng lặp",
+ "default_locale": "Ngôn ngữ mặc định",
+ "default_locale_description": "Định dạng ngày tháng và số theo ngôn ngữ/vị trí trình duyệt của bạn",
+ "default_quality_subtitle": "Chất lượng khi nhấn chia sẻ. Nhấn giữ nút chia sẻ để chọn riêng từng lần.",
+ "default_share_quality": "Chất lượng chia sẻ mặc định",
"delete": "Xóa",
- "delete_action_confirmation_message": "Bạn có chắc muốn xóa tệp này? Thao tác này sẽ chuyển tệp vào thùng rác của máy chủ và sẽ hỏi bạn có muốn xóa nó cục bộ không",
+ "delete_action_confirmation_message": "Bạn có chắc muốn xóa tài nguyên này? Tài nguyên sẽ được chuyển vào thùng rác của máy chủ và sẽ hỏi bạn có muốn xóa nó trên đó không",
"delete_action_prompt": "{count} đã xóa",
"delete_album": "Xóa album",
"delete_api_key_prompt": "Bạn có chắc muốn xóa khóa API này?",
@@ -914,20 +949,20 @@
"delete_face": "Xóa khuôn mặt",
"delete_key": "Xóa khóa",
"delete_library": "Xóa Thư viện",
- "delete_link": "Xóa liên kết",
+ "delete_link": "Xóa link",
"delete_local_action_prompt": "{count} đã xóa trên thiết bị",
"delete_local_dialog_ok_backed_up_only": "Xóa ảnh đã sao lưu",
"delete_local_dialog_ok_force": "Vẫn xóa",
"delete_others": "Xóa ảnh còn lại",
"delete_permanently": "Xóa vĩnh viễn",
"delete_permanently_action_prompt": "{count} đã xóa vĩnh viễn",
- "delete_shared_link": "Xóa liên kết chia sẻ",
- "delete_shared_link_dialog_title": "Xóa liên kết đã chia sẻ",
+ "delete_shared_link": "Xóa link đã chia sẻ",
+ "delete_shared_link_dialog_title": "Xóa link đã chia sẻ",
"delete_tag": "Xóa thẻ",
"delete_tag_confirmation_prompt": "Bạn có chắc muốn xóa thẻ {tagName}?",
"delete_user": "Xóa người dùng",
- "deleted_shared_link": "Đã xóa liên kết chia sẻ",
- "deletes_missing_assets": "Xóa các ảnh không còn tồn tại trên ổ đĩa",
+ "deleted_shared_link": "Đã xóa link chia sẻ",
+ "deletes_missing_assets": "Xóa các tài nguyên không còn tồn tại trên ổ đĩa",
"description": "Mô tả",
"description_input_hint_text": "Thêm mô tả...",
"description_input_submit_error": "Cập nhật mô tả không thành công, vui lòng kiểm tra log để biết thêm chi tiết",
@@ -950,7 +985,7 @@
"documentation": "Tài liệu",
"done": "Xong",
"download": "Tải xuống",
- "download_action_prompt": "Đang tải {count} tệp",
+ "download_action_prompt": "Đang tải {count} tài nguyên",
"download_canceled": "Đã hủy tải xuống",
"download_complete": "Tải xuống hoàn tất",
"download_enqueue": "Tải xuống đang chờ",
@@ -958,23 +993,26 @@
"download_failed": "Tải xuống thất bại",
"download_finished": "Tải xuống hoàn tất",
"download_include_embedded_motion_videos": "Video nhúng",
- "download_include_embedded_motion_videos_description": "Gồm các video được nhúng trong ảnh chuyển động thành một tệp riêng",
+ "download_include_embedded_motion_videos_description": "Tách các video được nhúng trong ảnh chuyển động thành một tệp riêng",
"download_notfound": "Không tìm thấy tải xuống",
"download_original": "Tải xuống bản gốc",
"download_paused": "Đã tạm dừng tải xuống",
"download_settings": "Tải xuống",
- "download_settings_description": "Quản lý cài đặt liên quan đến việc tải ảnh xuống",
+ "download_settings_description": "Quản lý cài đặt liên quan đến việc tải xuống tài nguyên",
"download_started": "Đã bắt đầu tải xuống",
"download_sucess": "Tải xuống thành công",
"download_sucess_android": "Phương tiện đã được lưu vào DCIM/Immich",
"download_waiting_to_retry": "Đang chờ thử lại",
"downloading": "Đang tải xuống",
- "downloading_asset_filename": "Đang tải xuống tệp {filename}",
+ "downloading_asset_filename": "Đang tải xuống tài nguyên {filename}",
"downloading_from_icloud": "Đang tải xuống từ iCloud",
"downloading_media": "Đang tải xuống phương tiện",
+ "drag_to_reorder": "Kéo để sắp xếp lại",
"drop_files_to_upload": "Kéo thả các tệp để tải lên",
+ "duplicate": "Nhân bản",
+ "duplicate_workflow": "Nhân bản workflow",
"duplicates": "Tệp trùng lặp",
- "duplicates_description": "Xem lại các nhóm ảnh bị nghi ngờ trùng lặp và chọn những mục bạn muốn giữ hoặc xóa",
+ "duplicates_description": "Giải quyết từng nhóm bằng cách chỉ ra nhóm nào, nếu có, là nhóm trùng lặp.",
"duration": "Thời gian",
"edit": "Chỉnh sửa",
"edit_album": "Chỉnh sửa album",
@@ -990,7 +1028,7 @@
"edit_exclusion_pattern": "Chỉnh sửa quy tắc loại trừ",
"edit_faces": "Chỉnh sửa khuôn mặt",
"edit_key": "Chỉnh sửa khóa",
- "edit_link": "Chỉnh sửa liên kết",
+ "edit_link": "Chỉnh sửa link",
"edit_location": "Chỉnh sửa vị trí",
"edit_location_action_prompt": "{count} đã sửa vị trí",
"edit_location_dialog_title": "Vị trí",
@@ -1005,21 +1043,23 @@
"editor_close_without_save_title": "Đóng trình chỉnh sửa?",
"editor_confirm_reset_all_changes": "Bạn có chắc muốn đặt lại mọi thay đổi không?",
"editor_discard_edits_confirm": "Bỏ thay đổi",
- "editor_discard_edits_prompt": "Bạn có những thay đổi chưa được lưu. Bạn có chắc chắn muốn hủy bỏ chúng không?",
+ "editor_discard_edits_prompt": "Bạn có những sửa đổi chưa được lưu. Bạn có chắc muốn hủy bỏ chúng không?",
"editor_discard_edits_title": "Hủy thay đổi?",
"editor_edits_applied_error": "Không thể áp dụng chỉnh sửa",
"editor_edits_applied_success": "Chỉnh sửa được áp dụng thành công",
"editor_flip_horizontal": "Lật ngang",
"editor_flip_vertical": "Lật dọc",
- "editor_orientation": "Định hướng",
- "editor_reset_all_changes": "Hoàn tác tất cả thay đổi",
+ "editor_handle_corner": "{corner, select, top_left {Góc trên bên trái} top_right {Góc trên bên phải} bottom_left {Góc dưới bên trái} bottom_right {Góc dưới bên phải} other {A}} góc",
+ "editor_handle_edge": "{edge, select, top {Trên} bottom {Dưới} left {Trái} right {Phải} other {An}} cạnh",
+ "editor_orientation": "Chiều",
+ "editor_reset_all_changes": "Hủy bỏ mọi thay đổi",
"editor_rotate_left": "Xoay 90° ngược chiều kim đồng hồ",
"editor_rotate_right": "Xoay 90° theo chiều kim đồng hồ",
"email": "Email",
"email_notifications": "Thông báo qua email",
"empty_folder": "Thư mục trống",
"empty_trash": "Dọn sạch thùng rác",
- "empty_trash_confirmation": "Bạn có chắc muốn dọn sạch thùng rác? Điều này sẽ xóa vĩnh viễn tất cả các tệp trong thùng rác khỏi Immich.\nBạn không thể hoàn tác hành động này!",
+ "empty_trash_confirmation": "Bạn có chắc muốn dọn sạch thùng rác? Điều này sẽ xóa vĩnh viễn tất cả các tài nguyên trong thùng rác khỏi Immich.\nBạn không thể hoàn tác hành động này!",
"enable": "Bật",
"enable_backup": "Bật sao lưu",
"enable_biometric_auth_description": "Nhập mã PIN của bạn để bật xác thực sinh trắc học",
@@ -1031,48 +1071,49 @@
"enter_your_pin_code_subtitle": "Nhập mã PIN của bạn để truy cập thư mục Khóa",
"error": "Lỗi",
"error_change_sort_album": "Thay đổi thứ tự sắp xếp album thất bại",
- "error_delete_face": "Lỗi khi xóa khuôn mặt khỏi tệp",
+ "error_delete_face": "Lỗi khi xóa khuôn mặt khỏi tài nguyên",
"error_getting_places": "Lỗi khi lấy địa điểm",
- "error_loading_albums": "Lỗi khi tải các tập ảnh (album)",
+ "error_loading_albums": "Xảy ra lỗi khi tải các album",
"error_loading_image": "Lỗi tải ảnh",
- "error_loading_partners": "Lỗi khi lấy người thân: {error}",
- "error_retrieving_asset_information": "Không thể truy xuất thông tin tệp",
+ "error_loading_partners": "Lỗi khi tải người thân: {error}",
+ "error_retrieving_asset_information": "Không thể truy xuất thông tin tài nguyên",
"error_saving_image": "Lỗi: {error}",
"error_tag_face_bounding_box": "Lỗi gắn thẻ khuôn mặt: - không thể lấy được tọa độ khung bao",
"error_title": "Lỗi - Có điều gì đó không đúng",
- "error_while_navigating": "Không thể điều hướng đến tệp",
+ "error_while_navigating": "Không thể điều hướng đến tài nguyên",
"errors": {
- "cannot_navigate_next_asset": "Không thể chuyển đến tệp tiếp theo",
- "cannot_navigate_previous_asset": "Không thể chuyển đến tệp trước đó",
+ "cannot_navigate_next_asset": "Không thể chuyển đến tài nguyên tiếp theo",
+ "cannot_navigate_previous_asset": "Không thể chuyển đến tài nguyên trước đó",
"cant_apply_changes": "Không thể áp dụng thay đổi",
"cant_change_activity": "Không thể {enabled, select, true {disable} other {enable}} hoạt động",
- "cant_change_asset_favorite": "Không thể thay đổi việc thích tệp",
- "cant_change_metadata_assets_count": "Không thể thay đổi siêu dữ liệu của {count, plural, one {# tệp} other {# tệp}}",
+ "cant_change_asset_favorite": "Không thể thay đổi việc thích tài nguyên",
+ "cant_change_metadata_assets_count": "Không thể thay đổi siêu dữ liệu của {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"cant_get_faces": "Không thể tải khuôn mặt",
"cant_get_number_of_comments": "Không thể tải số lượng bình luận",
"cant_search_people": "Không thể tìm người",
"cant_search_places": "Không thể tìm kiếm địa điểm",
- "error_adding_assets_to_album": "Lỗi khi thêm tệp vào album",
+ "error_adding_assets_to_album": "Lỗi khi thêm tài nguyên vào album",
"error_adding_users_to_album": "Lỗi khi thêm người dùng vào album",
"error_deleting_shared_user": "Lỗi khi xóa người dùng chia sẻ",
"error_downloading": "Lỗi khi tải xuống {filename}",
"error_hiding_buy_button": "Lỗi khi ẩn nút mua",
- "error_removing_assets_from_album": "Lỗi khi xóa tệp khỏi album, kiểm tra bảng điều khiển để biết thêm chi tiết",
- "error_selecting_all_assets": "Lỗi khi chọn tất cả tệp",
+ "error_removing_assets_from_album": "Lỗi khi xóa tài nguyên khỏi album, kiểm tra bảng điều khiển để biết thêm chi tiết",
+ "error_selecting_all_assets": "Lỗi khi chọn tất cả tài nguyên",
"exclusion_pattern_already_exists": "Quy tắc loại trừ này đã tồn tại.",
"failed_to_create_album": "Tạo album thất bại",
- "failed_to_create_shared_link": "Không thể tạo liên kết chia sẻ",
- "failed_to_edit_shared_link": "Không thể chỉnh sửa liên kết chia sẻ",
+ "failed_to_create_shared_link": "Không thể tạo link chia sẻ",
+ "failed_to_edit_shared_link": "Không thể chỉnh sửa link chia sẻ",
"failed_to_get_people": "Không thể tải người",
- "failed_to_keep_this_delete_others": "Xảy ra lỗi trong quá trình xóa tệp",
- "failed_to_load_asset": "Không thể tải tệp",
- "failed_to_load_assets": "Không thể tải các tệp",
+ "failed_to_keep_this_delete_others": "Xảy ra lỗi trong quá trình xóa tài nguyên",
+ "failed_to_load_asset": "Không thể tải tài nguyên",
+ "failed_to_load_assets": "Không thể tải các tài nguyên",
"failed_to_load_notifications": "Không thể tải các thông báo",
"failed_to_load_people": "Không thể tải người",
"failed_to_remove_product_key": "Không thể xóa khóa sản phẩm",
"failed_to_reset_pin_code": "Đặt lại mã PIN không thành công",
- "failed_to_stack_assets": "Không thể xếp nhóm tệp",
- "failed_to_unstack_assets": "Không thể hủy xếp nhóm tệp",
+ "failed_to_stack_assets": "Không thể xếp nhóm tài nguyên",
+ "failed_to_tag_assets": "Không thẻ gắn thẻ tài nguyên",
+ "failed_to_unstack_assets": "Không thể hủy xếp nhóm tài nguyên",
"failed_to_update_notification_status": "Cập nhật trạng thái thông báo thất bại",
"incorrect_email_or_password": "Email hoặc mật khẩu không chính xác",
"library_folder_already_exists": "Đường dẫn nhập này đã tồn tại.",
@@ -1082,33 +1123,33 @@
"quota_higher_than_disk_size": "Bạn đã đặt hạn mức cao hơn dung lượng ổ đĩa",
"something_went_wrong": "Có gì đó không đúng",
"unable_to_add_album_users": "Không thể thêm người dùng vào album",
- "unable_to_add_assets_to_shared_link": "Không thể thêm tệp vào liên kết chia sẻ",
+ "unable_to_add_assets_to_shared_link": "Không thể thêm tài nguyên vào liên kết chia sẻ",
"unable_to_add_comment": "Không thể thêm bình luận",
"unable_to_add_exclusion_pattern": "Không thể thêm quy tắc loại trừ",
"unable_to_add_partners": "Không thể thêm người thân",
- "unable_to_add_remove_archive": "Không thể {archived, select, true {xóa tệp khỏi} other {thêm tệp vào}} Kho lưu trữ",
- "unable_to_add_remove_favorites": "Không thể {favorite, select, true {thêm tệp vào} other {xóa tệp khỏi}} Mục yêu thích",
+ "unable_to_add_remove_archive": "Không thể {archived, select, true {xóa tài nguyên khỏi} other {thêm tài nguyên vào}} Kho lưu trữ",
+ "unable_to_add_remove_favorites": "Không thể {favorite, select, true {thêm tài nguyên vào} other {xóa tài nguyên khỏi}} mục Yêu thích",
"unable_to_archive_unarchive": "Không thể {archived, select, true {lưu trữ} other {bỏ lưu trữ}}",
"unable_to_change_album_user_role": "Không thể thay đổi vai trò của người dùng album",
"unable_to_change_date": "Không thể thay đổi ngày",
"unable_to_change_description": "Không thể thay đổi mô tả",
- "unable_to_change_favorite": "Không thể thay đổi việc thích tệp",
+ "unable_to_change_favorite": "Không thể thay đổi việc thích tài nguyên",
"unable_to_change_location": "Không thể thay đổi vị trí",
"unable_to_change_password": "Không thể thay đổi mật khẩu",
"unable_to_change_visibility": "Không thể thay đổi trạng thái hiển thị cho {count, plural, one {# người} other {# người}}",
"unable_to_complete_oauth_login": "Không thể hoàn tất đăng nhập OAuth",
"unable_to_connect": "Không thể kết nối",
- "unable_to_copy_to_clipboard": "Không thể sao chép vào bộ nhớ tạm, hãy đảm bảo bạn đang truy cập trang qua https",
+ "unable_to_copy_to_clipboard": "Không thể sao chép vào clipboard, hãy đảm bảo bạn đang truy cập trang qua https",
"unable_to_create": "Không thể tạo workflow",
"unable_to_create_admin_account": "Không thể tạo tài khoản quản trị viên",
"unable_to_create_api_key": "Không thể tạo khóa API mới",
"unable_to_create_library": "Không thể tạo thư viện",
"unable_to_create_user": "Không thể tạo người dùng",
"unable_to_delete_album": "Không thể xóa album",
- "unable_to_delete_asset": "Không thể xóa tệp",
- "unable_to_delete_assets": "Lỗi khi xóa các tệp",
+ "unable_to_delete_asset": "Không thể xóa tài nguyên",
+ "unable_to_delete_assets": "Lỗi khi xóa các tài nguyên",
"unable_to_delete_exclusion_pattern": "Không thể xóa quy tắc loại trừ",
- "unable_to_delete_shared_link": "Không thể xóa liên kết chia sẻ",
+ "unable_to_delete_shared_link": "Không thể xóa link chia sẻ",
"unable_to_delete_user": "Không thể xóa người dùng",
"unable_to_delete_workflow": "Không thể xóa workflow",
"unable_to_download_files": "Không thể tải xuống tệp",
@@ -1117,7 +1158,7 @@
"unable_to_enter_fullscreen": "Không thể vào chế độ toàn màn hình",
"unable_to_exit_fullscreen": "Không thể thoát chế độ toàn màn hình",
"unable_to_get_comments_number": "Không thể lấy số lượng bình luận",
- "unable_to_get_shared_link": "Không thể lấy liên kết chia sẻ",
+ "unable_to_get_shared_link": "Không thể lấy link chia sẻ",
"unable_to_hide_person": "Không thể ẩn người",
"unable_to_link_motion_video": "Không thể liên kết video chuyển động",
"unable_to_link_oauth_account": "Không thể liên kết tài khoản OAuth",
@@ -1125,19 +1166,19 @@
"unable_to_log_out_device": "Không thể đăng xuất khỏi thiết bị",
"unable_to_login_with_oauth": "Không thể đăng nhập với OAuth",
"unable_to_play_video": "Không thể phát video",
- "unable_to_reassign_assets_existing_person": "Không thể gán lại tệp cho {name, select, null {một người hiện có} other {{name}}}",
- "unable_to_reassign_assets_new_person": "Không thể gán lại ảnh cho một người mới",
+ "unable_to_reassign_assets_existing_person": "Không thể gán lại tài nguyên cho {name, select, null {một người hiện có} other {{name}}}",
+ "unable_to_reassign_assets_new_person": "Không thể gán lại tài nguyên cho một người mới",
"unable_to_refresh_user": "Không thể làm mới người dùng",
"unable_to_remove_album_users": "Không thể xóa người dùng khỏi album",
"unable_to_remove_api_key": "Không thể xóa khóa API",
- "unable_to_remove_assets_from_shared_link": "Không thể xóa các mục đã chọn khỏi liên kết chia sẻ",
+ "unable_to_remove_assets_from_shared_link": "Không thể xóa các tài nguyên khỏi link đã chia sẻ",
"unable_to_remove_library": "Không thể xóa thư viện",
"unable_to_remove_partner": "Không thể xóa người thân",
"unable_to_remove_reaction": "Không thể xóa phản ứng",
"unable_to_reset_password": "Không thể đặt lại mật khẩu",
"unable_to_reset_pin_code": "Không thể đặt lại mã PIN",
"unable_to_resolve_duplicate": "Không thể xử lý trùng lặp",
- "unable_to_restore_assets": "Không thể khôi phục tệp",
+ "unable_to_restore_assets": "Không thể khôi phục tài nguyên",
"unable_to_restore_trash": "Không thể khôi phục thùng rác",
"unable_to_restore_user": "Không thể khôi phục người dùng",
"unable_to_save_album": "Không thể lưu album",
@@ -1150,9 +1191,9 @@
"unable_to_scan_library": "Không thể quét thư viện",
"unable_to_set_feature_photo": "Không thể đặt ảnh nổi bật",
"unable_to_set_profile_picture": "Không thể đặt ảnh đại diện",
- "unable_to_set_rating": "Không thể đặt đánh giá",
+ "unable_to_set_rating": "Không thể đặt xếp hạng",
"unable_to_submit_job": "Không thể gửi tác vụ",
- "unable_to_trash_asset": "Không thể chuyển ảnh vào thùng rác",
+ "unable_to_trash_asset": "Không thể chuyển tài nguyên vào thùng rác",
"unable_to_unlink_account": "Không thể hủy liên kết tài khoản",
"unable_to_unlink_motion_video": "Không thể hủy liên kết video chuyển động",
"unable_to_update_album_cover": "Không thể cập nhật ảnh bìa album",
@@ -1184,40 +1225,43 @@
"experimental_settings_title": "Thử nghiệm",
"expire_after": "Hết hạn sau",
"expired": "Hết hạn",
- "expires_date": "Hết hạn vào {date}",
+ "expires_date": "Hết hạn {date}",
"explore": "Khám phá",
"explorer": "Khám phá",
"export": "Xuất",
"export_as_json": "Xuất dưới dạng JSON",
"export_database": "Xuất cơ sở dữ liệu",
"export_database_description": "Xuất cơ sở dữ liệu SQLite",
+ "exposure_time": "Phơi sáng",
"extension": "Phần mở rộng",
"external": "Bên ngoài",
- "external_libraries": "Thư viện bên ngoài",
+ "external_libraries": "Thư viện ngoài",
"external_network": "Mạng bên ngoài",
"external_network_sheet_info": "Khi không ở trên mạng Wi-Fi ưu tiên, app sẽ kết nối với máy chủ thông qua URL đầu tiên bên dưới mà nó có thể truy cập, bắt đầu từ trên xuống dưới",
+ "f_number": "Khẩu độ",
"face_unassigned": "Chưa được gán",
"failed": "Thất bại",
"failed_count": "Thất bại: {count}",
"failed_to_authenticate": "Xác thực thất bại",
- "failed_to_load_assets": "Không tải được tệp",
+ "failed_to_delete_file": "Không thể xóa tệp",
+ "failed_to_load_assets": "Không tải được tài nguyên",
"failed_to_load_folder": "Không tải được thư mục",
"favorite": "Thích",
- "favorite_action_prompt": "{count} đã thêm vào Đã thích",
+ "favorite_action_prompt": "{count} đã thêm vào Yêu thích",
"favorite_or_unfavorite_photo": "Thích hoặc bỏ thích ảnh",
- "favorites": "Đã thích",
- "favorites_page_no_favorites": "Không tìm thấy tệp yêu thích",
+ "favorites": "Yêu thích",
+ "favorites_page_no_favorites": "Không tìm thấy tài nguyên yêu thích",
"feature_photo_updated": "Đã cập nhật ảnh nổi bật",
"features": "Tính năng",
"features_in_development": "Tính năng đang được phát triển",
"features_setting_description": "Quản lý các tính năng ứng dụng",
- "file_name_or_extension": "Tên hoặc phần mở rộng tập tin",
+ "file_name_or_extension": "Tên hoặc phần mở rộng tệp",
"file_name_text": "Tên tệp",
"file_size": "Kích cỡ tệp tin",
"filename": "Tên tệp",
"filetype": "Loại tệp",
"filter": "Bộ lọc",
- "filter_description": "Điều kiện để lọc tệp mục tiêu",
+ "filter_description": "Điều kiện để lọc tài nguyên mục tiêu",
"filter_people": "Lọc người",
"filter_places": "Lọc địa điểm",
"filter_tags": "Bộ lọc theo thẻ",
@@ -1225,20 +1269,22 @@
"find_them_fast": "Tìm nhanh bằng tên với tìm kiếm",
"first": "Đầu tiên",
"fix_incorrect_match": "Sửa lỗi trùng khớp không chính xác",
+ "focal_length": "Tiêu cự",
"folder": "Thư mục",
"folder_not_found": "Không tìm thấy thư mục",
"folders": "Thư mục",
"folders_feature_description": "Duyệt ảnh và video theo thư mục trên hệ thống tệp",
"forgot_pin_code_question": "Quên mã PIN?",
"forward": "Tiến tới",
- "free_up_space": "Giải phóng Bộ nhớ",
+ "free_up_space": "Giải phóng dung lượng",
"free_up_space_description": "Chuyển hình ảnh và video đã được sao lưu vào thùng rác của thiết bị để giải phóng dung lượng. Bản sao lưu trên máy chủ không bị ảnh hưởng.",
- "free_up_space_settings_subtitle": "Giải phóng bộ nhớ của thiết bị",
+ "free_up_space_settings_subtitle": "Tiết kiệm dung lượng bộ nhớ thiết bị",
"full_path": "Đường dẫn đầy đủ: {path}",
+ "full_path_or_folder": "Đường dẫn đầy đủ hoặc thư mục",
"gcast_enabled": "Google Cast",
- "gcast_enabled_description": "Tính năng này tải các tài nguyên bên ngoài từ Google để hoạt động.",
+ "gcast_enabled_description": "Tính năng này tải các tài nguyên từ Google để hoạt động.",
"general": "Chung",
- "geolocation_instruction_location": "Nhấn vào một tệp có tọa độ GPS để sử dụng vị trí của nó hoặc chọn vị trí trực tiếp từ bản đồ",
+ "geolocation_instruction_location": "Nhấn vào một tài nguyên có tọa độ GPS để sử dụng vị trí của nó hoặc chọn vị trí trực tiếp từ bản đồ",
"get_help": "Nhận trợ giúp",
"get_people_error": "Lỗi khi lấy thông tin người",
"get_wifiname_error": "Không thể lấy tên Wi-Fi. Hãy đảm bảo bạn đã cấp các quyền cần thiết và được kết nối với mạng Wi-Fi",
@@ -1256,10 +1302,10 @@
"group_places_by": "Nhóm địa điểm theo…",
"group_year": "Xếp nhóm theo năm",
"haptic_feedback_switch": "Bật phản hồi haptic",
- "haptic_feedback_title": "Phản hồi Hapic",
+ "haptic_feedback_title": "Phản hồi Haptic",
"has_quota": "Hạn mức",
- "hash_asset": "Mã hóa tệp",
- "hashed_assets": "Tệp mã hóa",
+ "hash_asset": "Mã hóa tài nguyên",
+ "hashed_assets": "Tài nguyên đã mã hóa",
"hashing": "Đang băm",
"header_settings_add_header_tip": "Thêm header",
"header_settings_field_validator_msg": "Không được để trống",
@@ -1276,22 +1322,22 @@
"hide_schema": "Ẩn lược đồ",
"hide_text_recognition": "Ẩn nhận dạng văn bản",
"hide_unnamed_people": "Ẩn những người không tên",
- "home_page_add_to_album_conflicts": "Đã thêm {added} tệp vào album {album}. {failed} tệp đã có sẵn trong album.",
- "home_page_add_to_album_err_local": "Không thể thêm tệp trên thiết bị vào album, bỏ qua",
- "home_page_add_to_album_success": "Đã thêm {added} tệp vào album {album}.",
- "home_page_album_err_partner": "Không thể thêm tệp của nguời thân vào album, bỏ qua",
- "home_page_archive_err_local": "Không thể lưu trữ tệp trên thiết bị, bỏ qua",
- "home_page_archive_err_partner": "Không thể lưu trữ tệp của người thân, bỏ qua",
+ "home_page_add_to_album_conflicts": "Đã thêm {added} tài nguyên vào album {album}. {failed} tài nguyên đã có sẵn trong album.",
+ "home_page_add_to_album_err_local": "Không thể thêm tài nguyên trên thiết bị vào album, bỏ qua",
+ "home_page_add_to_album_success": "Đã thêm {added} tài nguyên vào album {album}.",
+ "home_page_album_err_partner": "Không thể thêm tài nguyên của nguời thân vào album, bỏ qua",
+ "home_page_archive_err_local": "Không thể lưu trữ tài nguyên trên thiết bị, bỏ qua",
+ "home_page_archive_err_partner": "Không thể lưu trữ tài nguyên của người thân, bỏ qua",
"home_page_building_timeline": "Đang tạo dòng thời gian ảnh",
- "home_page_delete_err_partner": "Không thể xóa tệp của người thân, bỏ qua",
- "home_page_delete_remote_err_local": "Tệp trên thiết bị trong lựa chọn xóa từ xa, bỏ qua",
- "home_page_favorite_err_local": "Không thể thích tệp trên thiết bị, bỏ qua",
- "home_page_favorite_err_partner": "Không thể thích tệp của người thân, bỏ qua",
+ "home_page_delete_err_partner": "Không thể xóa tài nguyên của người thân, bỏ qua",
+ "home_page_delete_remote_err_local": "Tài nguyên trên thiết bị trong lựa chọn xóa từ xa, bỏ qua",
+ "home_page_favorite_err_local": "Không thể thích tài nguyên trên thiết bị, bỏ qua",
+ "home_page_favorite_err_partner": "Không thể thích tài nguyên của người thân, bỏ qua",
"home_page_first_time_notice": "Nếu đây là lần đầu bạn dùng ứng dụng, hãy chọn một album sao lưu để dòng thời gian có thể hiển thị ảnh và video của bạn",
- "home_page_locked_error_local": "Không thể di chuyển tệp trên thiết bị đến thư mục Khóa, bỏ qua",
- "home_page_locked_error_partner": "Không thể di chuyển tệp của người thân đến thư mục Khóa, bỏ qua",
- "home_page_share_err_local": "Không thể chia sẻ tệp trên thiết bị qua liên kết, bỏ qua",
- "home_page_upload_err_limit": "Chỉ có thể tải lên tối đa 30 tệp cùng lúc, bỏ qua",
+ "home_page_locked_error_local": "Không thể di chuyển tài nguyên trên thiết bị đến thư mục Khóa, bỏ qua",
+ "home_page_locked_error_partner": "Không thể di chuyển tài nguyên của người thân đến thư mục Khóa, bỏ qua",
+ "home_page_share_err_local": "Không thể chia sẻ tài nguyên trên thiết bị bằng link, bỏ qua",
+ "home_page_upload_err_limit": "Chỉ có thể tải lên tối đa 30 tài nguyên cùng lúc, bỏ qua",
"host": "Host",
"hour": "Giờ",
"hours": "Giờ",
@@ -1324,10 +1370,11 @@
"in_year_selector": "Năm",
"include_archived": "Bao gồm ảnh lưu trữ",
"include_shared_albums": "Bao gồm album chia sẻ",
- "include_shared_partner_assets": "Bao gồm ảnh người thân chia sẻ",
+ "include_shared_partner_assets": "Bao gồm tài nguyên người thân chia sẻ",
"individual_share": "Chia sẻ riêng lẻ",
"individual_shares": "Chia sẻ cá nhân",
"info": "Thông tin",
+ "integrity_checks": "Kiểm tra tính toàn vẹn",
"interval": {
"day_at_onepm": "Mỗi ngày vào lúc 1 giờ chiều",
"hours": "Mỗi {hours, plural, one {giờ} other {{hours, number} giờ}}",
@@ -1344,21 +1391,22 @@
"ios_debug_info_no_sync_yet": "Chưa có tác vụ đồng bộ nền chạy",
"ios_debug_info_processes_queued": "{count, plural, one {{count} tiến trình nền đã được đưa vào hàng đợi} other {{count} tiến trình nền đã được đưa vào hàng đợi}}",
"ios_debug_info_processing_ran_at": "Quá trình xử lý đã chạy vào {dateTime}",
+ "iso": "ISO",
"items_count": "{count, plural, one {# mục} other {# mục}}",
"jobs": "Tác vụ",
"json_editor": "Biên tập JSON",
"json_error": "Lỗi JSON",
"keep": "Giữ",
"keep_albums": "Giữ lại các tập ảnh",
- "keep_albums_count": "Giữ lại {count} {count, plural, one {tập ảnh} other {tập ảnh}}",
+ "keep_albums_count": "Giữ lại {count} {count, plural, one {album} other {album}}",
"keep_all": "Giữ tất cả",
- "keep_description": "Chọn những gì sẽ được giữ lại trên thiết bị khi giải phóng bộ nhớ.",
+ "keep_description": "Chọn giữ lại những gì trên thiết bị khi giải phóng dung lượng.",
"keep_favorites": "Giữ lại các mục yêu thích",
"keep_on_device": "Giữ lại trên thiết bị",
"keep_on_device_hint": "Chọn các tệp sẽ được giữ lại trên thiết bị",
"keep_this_delete_others": "Giữ tệp này, xóa các tệp khác",
"keeping": "Giữ lại: {items}",
- "kept_this_deleted_others": "Đã giữ lại tệp này và xóa {count, plural, one {# tệp} other {# tệp}}",
+ "kept_this_deleted_others": "Đã giữ lại tài nguyên này và xóa {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"keyboard_shortcuts": "Phím tắt",
"language": "Ngôn ngữ",
"language_no_results_subtitle": "Thử điều chỉnh quy tắc tìm kiếm",
@@ -1374,6 +1422,7 @@
"leave": "Rời khỏi",
"leave_album": "Rời khỏi album",
"lens_model": "Lens",
+ "less": "Ít",
"let_others_respond": "Cho phép bình luận",
"level": "Mức độ",
"library": "Thư viện",
@@ -1382,23 +1431,28 @@
"library_options": "Tùy chọn thư viện",
"library_page_device_albums": "Album trên thiết bị",
"library_page_new_album": "Album mới",
- "library_page_sort_asset_count": "Số lượng tệp",
+ "library_page_sort_asset_count": "Số lượng tài nguyên",
"library_page_sort_created": "Mới tạo gần đây",
"library_page_sort_last_modified": "Sửa đổi lần cuối",
"library_page_sort_title": "Tên album",
"licenses": "Giấy phép",
"light": "Sáng",
+ "light_theme": "Chuyển sang chế độ sáng",
"like": "Thích",
"like_deleted": "Đã bỏ thích",
+ "link": "Link",
"link_motion_video": "Liên kết video chuyển động",
+ "link_to_docs": "Để biết thêm thông tin, tham khảo tài liệu.",
"link_to_oauth": "Liên kết đến OAuth",
"linked_oauth_account": "Tài khoản OAuth đã liên kết",
"list": "Danh sách",
+ "live": "Động",
+ "load_more": "Tải Thêm",
"loading": "Đang tải",
"loading_search_results_failed": "Tải kết quả tìm kiếm không thành công",
"local": "Trên thiết bị",
- "local_asset_cast_failed": "Không thể chiếu nội dung chưa được tải lên máy chủ",
- "local_assets": "Tệp trên thiết bị",
+ "local_asset_cast_failed": "Không thể chiếu một tài nguyên chưa được tải lên máy chủ",
+ "local_assets": "Tài nguyên trên thiết bị",
"local_id": "ID cục bộ",
"local_media_summary": "Mô tả phương tiện trên thiết bị",
"local_network": "Mạng nội bộ",
@@ -1476,11 +1530,11 @@
"maintenance_title": "Tạm thời không khả dụng",
"make": "Thương hiệu",
"manage_geolocation": "Quản lý địa điểm",
- "manage_media_access_rationale": "Để có thể di chuyển tệp vào thùng rác và khôi phục chúng từ đó.",
+ "manage_media_access_rationale": "Để có thể di chuyển tài nguyên vào thùng rác và khôi phục chúng từ đó.",
"manage_media_access_settings": "Mở cài đặt",
"manage_media_access_subtitle": "Cho phép ứng dụng [Immich] quản lý và di chuyển tệp.",
"manage_media_access_title": "Quản lý phương tiện",
- "manage_shared_links": "Quản lý liên kết chia sẻ",
+ "manage_shared_links": "Quản lý những liên kết đã chia sẻ",
"manage_sharing_with_partners": "Quản lý chia sẻ với người thân",
"manage_the_app_settings": "Quản lý cài đặt ứng dụng",
"manage_your_account": "Quản lý tài khoản của bạn",
@@ -1492,11 +1546,11 @@
"map_cannot_get_user_location": "Không thể xác định vị trí của bạn",
"map_location_dialog_yes": "Có",
"map_location_picker_page_use_location": "Dùng vị trí này",
- "map_location_service_disabled_content": "Cần bật dịch vụ định vị để hiển thị ảnh hoặc video từ vị trí hiện tại của bạn. Bạn có muốn bật nó ngay bây giờ không?",
+ "map_location_service_disabled_content": "Cần bật dịch vụ định vị để hiển thị tài nguyên từ vị trí hiện tại của bạn. Bạn có muốn bật nó ngay bây giờ không?",
"map_location_service_disabled_title": "Dịch vụ vị trí bị vô hiệu hoá",
- "map_marker_for_images": "Đánh dấu bản đồ cho ảnh chụp tại {city}, {country}",
+ "map_marker_for_image": "Đánh dấu điểm trên bản đồ cho hình ảnh được chụp tại {city}, {country}",
"map_marker_with_image": "Đánh dấu bản đồ với ảnh",
- "map_no_location_permission_content": "Cần quyền truy cập vị trí để hiển thị tệp từ vị trí hiện tại của bạn. Bạn có muốn cho phép ngay bây giờ không?",
+ "map_no_location_permission_content": "Cần quyền truy cập vị trí để hiển thị tài nguyên từ vị trí hiện tại của bạn. Bạn có muốn cho phép ngay bây giờ không?",
"map_no_location_permission_title": "Ứng dụng không được phép truy cập vị trí",
"map_settings": "Cài đặt bản đồ",
"map_settings_dark_mode": "Chế độ tối",
@@ -1507,14 +1561,46 @@
"map_settings_dialog_title": "Cài đặt bản đồ",
"map_settings_include_show_archived": "Bao gồm ảnh đã lưu trữ",
"map_settings_include_show_partners": "Bao gồm người thân",
- "map_settings_only_show_favorites": "Chỉ hiển thị mục yêu thích",
+ "map_settings_only_show_favorites": "Chỉ hiển thị mục Yêu thích",
"map_settings_theme_settings": "Giao diện bản đồ",
"map_zoom_to_see_photos": "Thu nhỏ để xem ảnh",
"mark_all_as_read": "Đánh dấu đã đọc tất cả",
"mark_as_read": "Đánh dấu đã đọc",
"marked_all_as_read": "Đã đánh dấu tất cả đã đọc",
"matches": "Khớp",
- "matching_assets": "Tệp trùng khớp",
+ "matching_assets": "Tài nguyên trùng khớp",
+ "media_chrome": {
+ "auto": "Tự động",
+ "captions": "Chú thích",
+ "captions_off": "Tắt",
+ "closed_captions": "đã đóng chú thích",
+ "decode_error": "Lỗi giải mã",
+ "disable_captions": "Tắt chú thích",
+ "enable_captions": "Bật chú thích",
+ "enter_fullscreen_mode": "Chế độ toàn màn hình",
+ "exit_fullscreen_mode": "Thoát chế độ toàn màn hình",
+ "loop": "Lặp lại",
+ "media_error_description": "Lỗi phương tiện đã khiến quá trình phát lại bị gián đoạn. Phương tiện có thể bị hỏng hoặc trình duyệt của bạn không hỗ trợ định dạng này.",
+ "media_loading": "đang tải phương tiện",
+ "mute": "Tắt tiếng",
+ "network_error": "Lỗi kết nối mạng",
+ "network_error_description": "Lỗi kết nối mạng đã khiến quá trình tải xuống phương tiện không thành công.",
+ "not_supported_error": "Nguồn không được hỗ trợ",
+ "playback_rate": "Tốc độ phát lại",
+ "playback_rate_current": "tốc độ phát lại hiện tại",
+ "playback_rate_value": "Tốc độ phát lại {playbackRate}",
+ "playback_time": "thời gian phát lại",
+ "quality": "Chất lượng",
+ "second": "giây",
+ "seconds": "giây",
+ "time_value_of_total_time": "{currentTime} trong {totalTime}",
+ "time_value_remaining": "{time} còn lại",
+ "unmute": "Bật tiếng",
+ "unsupported_error_description": "Đã xảy ra lỗi không được hỗ trợ. Máy chủ hoặc mạng gặp sự cố, hoặc trình duyệt của bạn không hỗ trợ định dạng này.",
+ "video_not_loaded_unknown_time": "video không tải được, thời gian không xác định.",
+ "video_player": "trình phát video",
+ "volume": "âm lượng"
+ },
"media_type": "Loại phương tiện",
"memories": "Kỷ niệm",
"memories_all_caught_up": "Bạn đã xem hết rồi",
@@ -1531,6 +1617,8 @@
"merge_people_prompt": "Bạn có muốn hợp nhất những người này? Hành động này không thể hoàn tác.",
"merge_people_successfully": "Hợp nhất người thành công",
"merged_people_count": "Đã hợp nhất {count, plural, one {# người} other {# người}}",
+ "minFaces": "Số khuôn mặt tối thiểu",
+ "minFaces_description": "Số lượng khuôn mặt được nhận diện tối thiểu để một người được hiển thị",
"minimize": "Thu nhỏ",
"minute": "Phút",
"minutes": "Phút",
@@ -1540,24 +1628,28 @@
"mobile_app": "Ứng dụng di động",
"mobile_app_download_onboarding_note": "Tải xuống app đồng hành bằng các tùy chọn sau",
"model": "Dòng",
+ "modify_date": "Ngày sửa đổi",
"month": "Tháng",
"more": "Thêm",
+ "motion": "Hoạt ảnh",
"move": "Di chuyển",
"move_down": "Di chuyển xuống",
"move_off_locked_folder": "Di chuyển ra khỏi thư mục Khóa",
- "move_to": "Chuyển đến",
- "move_to_device_trash": "Chuyển đến thùng rác của thiết bị",
+ "move_to": "Di chuyển đến",
+ "move_to_device_trash": "Chuyển vào thùng rác thiết bị",
"move_to_lock_folder_action_prompt": "{count} đã được thêm vào thư mục Khóa",
"move_to_locked_folder": "Di chuyển đến thư mục Khóa",
"move_to_locked_folder_confirmation": "Ảnh và video này sẽ bị xóa khỏi các album, chỉ có thể xem được trong thư mục Khóa",
"move_up": "Di chuyển lên",
- "moved_to_archive": "Đã di chuyển {count, plural, one {# tệp} other {# tệp}} đến lưu trữ",
- "moved_to_library": "Đã di chuyển {count, plural, one {# tệp} other {# tệp}} đến thư viện",
+ "moved_to_archive": "Đã di chuyển {count, plural, one {# tài nguyên} other {# tài nguyên}} đến lưu trữ",
+ "moved_to_library": "Đã di chuyển {count, plural, one {# tài nguyên} other {# tài nguyên}} đến thư viện",
"moved_to_trash": "Đã chuyển vào thùng rác",
- "multiselect_grid_edit_date_time_err_read_only": "Không thể chỉnh sửa ngày của tệp chỉ có quyền đọc, bỏ qua",
- "multiselect_grid_edit_gps_err_read_only": "Không thể chỉnh sửa vị trí của tệp chỉ có quyền đọc, bỏ qua",
+ "multiselect_grid_edit_date_time_err_read_only": "Không thể chỉnh sửa ngày của tài nguyên chỉ có quyền đọc, bỏ qua",
+ "multiselect_grid_edit_gps_err_read_only": "Không thể chỉnh sửa vị trí của tài nguyên chỉ có quyền đọc, bỏ qua",
"mute_memories": "Tắt tiếng Kỷ niệm",
"my_albums": "Album của tôi",
+ "my_immich_description": "Sao chép trang hiện tại dưới dạng link My Immich",
+ "my_immich_title": "Liên kết My Immich",
"name": "Tên",
"name_or_nickname": "Tên hoặc biệt danh",
"name_required": "Bắt buộc nhập tên",
@@ -1567,7 +1659,7 @@
"network_requirement_videos_upload": "Dùng dữ liệu di động sao lưu video",
"network_requirements": "Kết nối mạng",
"network_requirements_updated": "Kết nối mạng đã thay đổi, đang đặt lại hàng đợi sao lưu",
- "networking_settings": "Mạng",
+ "networking_settings": "Kết nối mạng",
"networking_subtitle": "Các địa chỉ máy chủ",
"never": "Không bao giờ",
"new_album": "Album mới",
@@ -1585,34 +1677,35 @@
"next": "Tiếp theo",
"next_memory": "Kỷ niệm tiếp theo",
"no": "Không",
- "no_albums_found": "Không phát hiện tập ảnh nào",
+ "no_albums_found": "Không tìm thấy album nào",
"no_albums_message": "Tạo album để sắp xếp ảnh và video của bạn",
"no_albums_with_name_yet": "Có vẻ như bạn chưa có bất kỳ album nào với tên này.",
"no_albums_yet": "Có vẻ như bạn chưa có bất kỳ album nào.",
"no_archived_assets_message": "Lưu trữ ảnh và video để ẩn chúng khỏi thư viện Ảnh của bạn",
- "no_assets_message": "Nhấn vào để tải lên ảnh của bạn lần đầu tiên",
- "no_assets_to_show": "Không có gì để hiển thị",
+ "no_assets_message": "Nhấn vào đây để tải ảnh đầu tiên của bạn lên",
+ "no_assets_to_show": "Không có tài nguyên để hiển thị",
"no_cast_devices_found": "Không tìm thấy thiết bị chiếu",
- "no_checksum_local": "Không có checksum khả dụng - không thể truy xuất tệp trên thiết bị",
- "no_checksum_remote": "Không có checksum khả dụng - không thể truy xuất tệp trên mây",
+ "no_checksum_local": "Không có checksum khả dụng - không thể truy xuất tài nguyên trên thiết bị",
+ "no_checksum_remote": "Không có checksum khả dụng - không thể truy xuất tài nguyên trên mây",
"no_configuration_needed": "Không cần cấu hình",
"no_devices": "Không có thiết bị được cấp quyền",
"no_duplicates_found": "Không tìm thấy các mục trùng lặp.",
"no_exif_info_available": "Không có thông tin exif",
"no_explore_results_message": "Tải thêm ảnh lên để khám phá bộ sưu tập của bạn.",
"no_favorites_message": "Thêm ảnh yêu thích để nhanh chóng tìm thấy những bức ảnh và video đẹp nhất của bạn",
- "no_libraries_message": "Tạo một thư viện bên ngoài để xem ảnh và video của bạn",
- "no_local_assets_found": "Không tìm thấy tệp trên thiết bị nào với checksum này",
+ "no_libraries_message": "Tạo một thư viện ngoài để xem ảnh và video của bạn",
+ "no_local_assets_found": "Không tìm thấy tài nguyên trên thiết bị nào với checksum này",
"no_location_set": "Chưa có địa điểm được đặt",
"no_locked_photos_message": "Ảnh và video trong thư mục Khóa sẽ được ẩn đi và không hiển thị khi bạn duyệt hay tìm kiếm trong thư viện.",
"no_name": "Không có tên",
"no_notifications": "Không có thông báo",
"no_people_found": "Không có người nào khớp với tìm kiếm",
"no_places": "Không có địa điểm",
- "no_remote_assets_found": "Không tìm thấy tệp trên mây nào với checksum này",
+ "no_remote_assets_found": "Không tìm thấy tài nguyên trên mây nào với checksum này",
"no_results": "Không có kết quả",
"no_results_description": "Thử một từ đồng nghĩa hoặc từ khóa tổng quát hơn",
"no_shared_albums_message": "Tạo một album để chia sẻ ảnh và video với mọi người trong mạng của bạn",
+ "no_steps": "Chưa có bước nào được thêm vào",
"no_uploads_in_progress": "Không có tải lên nào đang tiến hành",
"none": "Trống",
"not_allowed": "Không cho phép",
@@ -1621,6 +1714,7 @@
"not_selected": "Không được chọn",
"notes": "Lưu ý",
"nothing_here_yet": "Chưa có nội dung nào",
+ "notification_backup_reliability": "Bật thông báo để đảm bảo quá trình sao lưu nền",
"notification_permission_dialog_content": "Để bật thông báo, chuyển tới Cài đặt và chọn cho phép.",
"notification_permission_list_tile_content": "Cấp quyền để bật thông báo.",
"notification_permission_list_tile_enable_button": "Bật thông báo",
@@ -1648,7 +1742,7 @@
"online": "Trực tuyến",
"only_favorites": "Chỉ lượt thích",
"open": "Mở",
- "open_calendar": "Hiện thị lịch",
+ "open_calendar": "Mở lịch",
"open_in_browser": "Mở trong trình duyệt",
"open_in_map_view": "Mở trong bản đồ",
"open_in_openstreetmap": "Mở trong OpenStreetMap",
@@ -1658,6 +1752,7 @@
"organize_into_albums": "Sắp xếp thành album",
"organize_into_albums_description": "Đưa ảnh hiện có vào album bằng cách sử dụng cài đặt đồng bộ hiện tại",
"organize_your_library": "Sắp xếp thư viện của bạn",
+ "orientation": "Hướng",
"original": "gốc",
"other": "Khác",
"other_devices": "Thiết bị khác",
@@ -1672,8 +1767,8 @@
"partner_can_access_location": "Vị trí nơi ảnh của bạn được chụp",
"partner_list_user_photos": "Ảnh của {user}",
"partner_list_view_all": "Xem tất cả",
- "partner_page_empty_message": "Ảnh của bạn chưa được chia sẻ với bất kỳ ai.",
- "partner_page_no_more_users": "Không còn người dùng nào để thêm",
+ "partner_page_empty_message": "Ảnh của bạn chưa được chia sẻ với người thân nào.",
+ "partner_page_no_more_users": "Không còn người thân nào để thêm",
"partner_page_partner_add_failed": "Thêm người thân thất bại",
"partner_page_select_partner": "Chọn người thân",
"partner_page_shared_to_title": "Chia sẻ với",
@@ -1697,16 +1792,16 @@
"pending": "Đang chờ xử lý",
"people": "Mọi người",
"people_edits_count": "Đã chỉnh sửa {count, plural, one {# người} other {# người}}",
- "people_feature_description": "Duyệt ảnh và video được xếp nhóm theo người",
+ "people_feature_description": "Duyệt ảnh và video được phân loại theo người",
"people_selected": "{count, plural, one {# người đã chọn} other {# người đã chọn}}",
"people_sidebar_description": "Hiển thị mục Mọi người trong thanh bên",
"permanent_deletion_warning": "Cảnh báo xóa vĩnh viễn",
- "permanent_deletion_warning_setting_description": "Hiển thị cảnh báo khi xóa vĩnh viễn ảnh",
+ "permanent_deletion_warning_setting_description": "Hiển thị cảnh báo khi xóa vĩnh viễn tài nguyên",
"permanently_delete": "Xóa vĩnh viễn",
- "permanently_delete_assets_count": "Xóa vĩnh viễn {count, plural, one {tệp} other {tệp}}",
- "permanently_delete_assets_prompt": "Bạn có chắc muốn xóa vĩnh viễn {count, plural, one {tệp này?} other {# tệp này?}} Điều này cũng sẽ xóa {count, plural, one {nó khỏi} other {chúng khỏi}} các album.",
- "permanently_deleted_asset": "Tệp đã bị xóa vĩnh viễn",
- "permanently_deleted_assets_count": "Đã xóa vĩnh viễn {count, plural, one {# tệp} other {# tệp}}",
+ "permanently_delete_assets_count": "Xóa vĩnh viễn {count, plural, one {tài nguyên} other {tài nguyên}}",
+ "permanently_delete_assets_prompt": "Bạn có chắc muốn xóa vĩnh viễn {count, plural, one {tài nguyên này?} other {#tài nguyên này?}} Điều này cũng sẽ xóa {count, plural, one {nó khỏi} other {chúng khỏi}} các album.",
+ "permanently_deleted_asset": "Tài nguyên đã bị xóa vĩnh viễn",
+ "permanently_deleted_assets_count": "Đã xóa vĩnh viễn {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"permission": "Quyền",
"permission_empty": "Quyền của bạn không được để trống",
"permission_onboarding_back": "Quay lại",
@@ -1746,9 +1841,11 @@
"play_motion_photo": "Phát ảnh chuyển động",
"play_or_pause_video": "Phát hoặc dừng video",
"play_original_video": "Phát video gốc",
- "play_original_video_setting_description": "Nên phát video gốc thay vì video đã chuyển mã. Nếu tệp gốc không tương thích, video có thể không phát được.",
+ "play_original_video_setting_description": "Nên phát video gốc thay vì video đã chuyển mã. Nếu tài nguyên gốc không tương thích, video có thể không phát được.",
"play_transcoded_video": "Phát video đã chuyển mã",
"please_auth_to_access": "Vui lòng xác thực để truy cập",
+ "plugin_method_filter_type": "Bộ lọc",
+ "plugin_method_filter_type_description": "Phương pháp này có thể lọc các sự kiện và ngăn chặn có điều kiện các bước tiếp theo không cho chạy",
"port": "Cổng",
"preferences_settings_subtitle": "Tùy chỉnh trải nghiệm ứng dụng",
"preferences_settings_title": "Cá nhân hóa",
@@ -1770,6 +1867,7 @@
"profile_drawer_readonly_mode": "Đã bật chế độ chỉ-xem. Nhấn giữ ảnh đại diện người dùng để tắt.",
"profile_image_of_user": "Ảnh đại diện của {user}",
"profile_picture_set": "Ảnh đại diện đã được đặt.",
+ "projection_type": "Loại chiếu",
"public_album": "Album công khai",
"public_share": "Chia sẻ công khai",
"purchase_account_info": "Người hỗ trợ",
@@ -1797,34 +1895,34 @@
"purchase_per_server": "Mỗi máy chủ",
"purchase_per_user": "Mỗi người dùng",
"purchase_remove_product_key": "Xóa khóa sản phẩm",
- "purchase_remove_product_key_prompt": "Bạn có chắc muốn xoá khóa sản phẩm?",
+ "purchase_remove_product_key_prompt": "Bạn có chắc muốn xóa khóa sản phẩm?",
"purchase_remove_server_product_key": "Xóa khóa sản phẩm máy chủ",
- "purchase_remove_server_product_key_prompt": "Bạn có chắc muốn xoá khóa sản phẩm máy chủ?",
+ "purchase_remove_server_product_key_prompt": "Bạn có chắc muốn xóa khóa sản phẩm Máy chủ?",
"purchase_server_description_1": "Dành cho toàn bộ máy chủ",
"purchase_server_description_2": "Trạng thái người hỗ trợ",
"purchase_server_title": "Máy chủ",
"purchase_settings_server_activated": "Khóa sản phẩm máy chủ được quản lý bởi quản trị viên",
- "query_asset_id": "Truy vấn ID tệp",
+ "query_asset_id": "ID tài nguyên truy vấn",
"queue_status": "Xếp hàng {count}/{total}",
- "rate_asset": "Asset Đánh giá",
+ "rate_asset": "Xếp hạng tài nguyên",
"rating": "Xếp hạng sao",
"rating_clear": "Xóa xếp hạng",
"rating_count": "{count, plural, =0 {Chưa xếp hạng} one {# sao} other {# sao}}",
"rating_description": "Hiển thị xếp hạng EXIF trong bảng thông tin",
"reaction_options": "Tùy chọn phản ứng",
- "read_changelog": "Đọc nhật ký thay đổi",
+ "read_changelog": "Đọc Ghi chú Phát hành",
"readonly_mode_disabled": "Đã tắt chế độ chỉ-xem",
"readonly_mode_enabled": "Đã bật chế độ chỉ-xem",
"ready_for_upload": "Sẵn sàng tải lên",
"reassign": "Gán lại",
- "reassigned_assets_to_existing_person": "Đã gán lại {count, plural, one {# ảnh} other {# ảnh}} cho {name, select, null {một người hiện có} other {{name}}}",
- "reassigned_assets_to_new_person": "Đã gán lại {count, plural, one {# ảnh} other {# ảnh}} cho một người mới",
- "reassing_hint": "Gán các ảnh đã chọn cho một người hiện có",
+ "reassigned_assets_to_existing_person": "Đã gán lại {count, plural, one {# tài nguyên} other {# tài nguyên}} cho {name, select, null {một người hiện có} other {{name}}}",
+ "reassigned_assets_to_new_person": "Đã gán lại {count, plural, one {# tài nguyên} other {# tài nguyên}} cho một người mới",
+ "reassing_hint": "Gán các tài nguyên đã chọn cho một người hiện có",
"recent": "Gần đây",
"recent_albums": "Album gần đây",
"recent_searches": "Tìm kiếm gần đây",
- "recently_added": "Thêm gần đây",
- "recently_added_page_title": "Mới thêm gần đây",
+ "recently_added": "Được thêm gần đây",
+ "recently_added_page_title": "Được thêm gần đây",
"recently_taken": "Chụp gần đây",
"recently_taken_page_title": "Chụp Gần đây",
"refresh": "Làm mới",
@@ -1834,26 +1932,27 @@
"refresh_thumbnails": "Làm mới ảnh thu nhỏ",
"refreshed": "Đã làm mới",
"refreshes_every_file": "Đọc lại tất cả tệp mới và hiện có",
- "refreshing_encoded_video": "Đang làm mới video đã mã hóa",
- "refreshing_faces": "Đang làm mới khuôn mặt",
- "refreshing_metadata": "Đang làm mới metadata",
+ "refreshing_encoded_video": "Đã làm mới video được chuyển mã",
+ "refreshing_faces": "Đã làm mới các khuôn mặt",
+ "refreshing_metadata": "Đã làm mới metadata",
"regenerating_thumbnails": "Đang tạo lại ảnh thu nhỏ",
"remote": "Trên mây",
- "remote_assets": "Tệp trên mây",
+ "remote_assets": "Tài nguyên trên mây",
"remote_media_summary": "Mô tả phương tiện trên máy chủ",
"remove": "Xóa",
- "remove_assets_album_confirmation": "Bạn có chắc muốn xóa {count, plural, one {# tệp} other {# tệp}} khỏi album?",
- "remove_assets_shared_link_confirmation": "Bạn có chắc muốn xóa {count, plural, one {# tệp} other {# tệp}} khỏi liên kết chia sẻ này?",
- "remove_assets_title": "Xóa tệp?",
+ "remove_assets_album_confirmation": "Bạn có chắc muốn xóa {count, plural, one {# tài nguyên} other {# tài nguyên}} khỏi album?",
+ "remove_assets_shared_link_confirmation": "Bạn có chắc muốn xóa {count, plural, one {# tài nguyên} other {# tài nguyên}} khỏi liên kết chia sẻ này?",
+ "remove_assets_title": "Xóa tài nguyên?",
"remove_custom_date_range": "Bỏ chọn khoảng ngày tùy chỉnh",
- "remove_deleted_assets": "Loại bỏ tệp ngoại tuyến",
+ "remove_deleted_assets": "Loại bỏ tài nguyên đã bị xóa",
+ "remove_filter": "Xóa bộ lọc",
"remove_from_album": "Xóa khỏi album",
"remove_from_album_action_prompt": "{count} đã gỡ khỏi album",
- "remove_from_favorites": "Xóa khỏi Mục yêu thích",
+ "remove_from_favorites": "Xóa khỏi mục Yêu thích",
"remove_from_lock_folder_action_prompt": "{count} đã được xóa khỏi thư mục Khóa",
"remove_from_locked_folder": "Xóa khỏi thư mục Khóa",
"remove_from_locked_folder_confirmation": "Bạn có chắc muốn di chuyển ảnh và video này khỏi thư mục Khóa? Chúng sẽ hiện trong thư viện của bạn.",
- "remove_from_shared_link": "Xóa khỏi liên kết chia sẻ",
+ "remove_from_shared_link": "Xóa khỏi link chia sẻ",
"remove_memory": "Xóa kỷ niệm",
"remove_photo_from_memory": "Xóa ảnh khỏi kỷ niệm này",
"remove_tag": "Gỡ thẻ",
@@ -1861,16 +1960,16 @@
"remove_user": "Xóa người dùng",
"removed_api_key": "Khóa API đã xóa: {name}",
"removed_from_archive": "Đã xóa khỏi Kho lưu trữ",
- "removed_from_favorites": "Đã xóa khỏi Mục yêu thích",
- "removed_from_favorites_count": "{count, plural, other {Đã xóa #}} khỏi Mục yêu thích",
+ "removed_from_favorites": "Đã xóa khỏi mục Yêu thích",
+ "removed_from_favorites_count": "{count, plural, other {Đã xóa #}} khỏi mục Yêu thích",
"removed_memory": "Đã xóa kỷ niệm",
"removed_photo_from_memory": "Đã xóa ảnh khỏi kỷ niệm",
- "removed_tagged_assets": "Đã xóa thẻ khỏi {count, plural, one {# tệp} other {# tệp}}",
+ "removed_tagged_assets": "Đã xóa thẻ khỏi {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"rename": "Đổi tên",
"repair": "Sửa chữa",
"repair_no_results_message": "Các tệp không được theo dõi và bị thiếu sẽ xuất hiện ở đây",
"replace_with_upload": "Thay thế tệp khác",
- "repository": "Kho lưu trữ",
+ "repository": "Kho mã nguồn",
"require_password": "Yêu cầu mật khẩu",
"require_user_to_change_password_on_first_login": "Yêu cầu người dùng thay đổi mật khẩu ở lần đầu đăng nhập",
"rescan": "Quét lại",
@@ -1895,12 +1994,12 @@
"restore_all": "Khôi phục tất cả",
"restore_trash_action_prompt": "{count} đã khôi phục từ thùng rác",
"restore_user": "Khôi phục người dùng",
- "restored_asset": "Tệp đã được khôi phục",
+ "restored_asset": "Tài nguyên đã được khôi phục",
"resume": "Tiếp tục",
"resume_paused_jobs": "Tiếp tục {count, plural, one {# tác vụ đã dừng} other {# tác vụ đã dừng}}",
"retry_upload": "Thử tải lên lại",
"review_duplicates": "Xem lại các mục trùng lặp",
- "review_large_files": "Xem lại tệp dung lượng lớn",
+ "review_large_files": "Xem lại các tệp dung lượng lớn",
"role": "Vai trò",
"role_editor": "Người chỉnh sửa",
"role_viewer": "Người xem",
@@ -1908,25 +2007,30 @@
"save": "Lưu",
"save_to_gallery": "Lưu vào thư viện",
"saved": "Đã lưu",
- "saved_api_key": "Khóa API đã lưu",
- "saved_profile": "Hồ sơ đã lưu",
- "saved_settings": "Cài đặt đã lưu",
+ "saved_api_key": "Đã lưu Khóa API",
+ "saved_profile": "Đã lưu hồ sơ",
+ "saved_settings": "Đã lưu cài đặt",
"say_something": "Nói điều gì đó",
"scaffold_body_error_occurred": "Xảy ra lỗi",
+ "scaffold_body_error_unrecoverable": "Đã xảy ra lỗi không thể khắc phục. Vui lòng chia sẻ lỗi và dấu vết ngăn xếp trên Discord hoặc GitHub để chúng tôi có thể trợ giúp. Nếu được yêu cầu, bạn có thể xóa dữ liệu ứng dụng bên dưới.",
"scan": "Quét",
"scan_all_libraries": "Quét tất cả thư viện",
"scan_library": "Quét",
"scan_settings": "Cài đặt quét",
"scanning": "Đang quét",
"scanning_for_album": "Đang quét album...",
+ "screencast_mode_description": "Hiển thị chỉ báo sự kiện bàn phím và chuột trên màn hình",
+ "screencast_mode_title": "Bật/tắt chế độ quay màn hình",
"search": "Tìm kiếm",
"search_albums": "Tìm album",
"search_by_context": "Tìm theo ngữ cảnh",
"search_by_description": "Tìm theo mô tả",
- "search_by_description_example": "Dạo chơi Sa Pa",
+ "search_by_description_example": "Leo núi ở Sa Pa",
"search_by_filename": "Tìm theo tên hoặc định dạng tệp",
"search_by_filename_example": "Ví dụ: IMG_1234.JPG hoặc PNG",
- "search_by_ocr": "Tìm bằng OCR",
+ "search_by_full_path": "Tìm kiếm theo đường dẫn đầy đủ hoặc thư mục",
+ "search_by_full_path_example": "/John/Projects/3D_Printing/2026-07-01 - bạn có thể tìm Projects, 3D, Printing, 2026...",
+ "search_by_ocr": "Tìm theo OCR",
"search_by_ocr_example": "Latte",
"search_camera_lens_model": "Tìm dòng lens...",
"search_camera_make": "Tìm thương hiệu máy ảnh...",
@@ -1945,13 +2049,13 @@
"search_filter_location_title": "Chọn vị trí",
"search_filter_media_type": "Phương tiện",
"search_filter_media_type_title": "Chọn loại phương tiện",
- "search_filter_ocr": "Tìm bằng OCR",
+ "search_filter_ocr": "Tìm theo OCR",
"search_filter_people_title": "Chọn người",
"search_filter_star_rating": "Xếp hạng sao",
"search_filter_tags_title": "Chọn các thẻ",
"search_for": "Tìm kiếm",
"search_for_existing_person": "Tìm người hiện có",
- "search_no_more_result": "Không còn kết quả",
+ "search_no_more_result": "Không còn kết quả nào",
"search_no_people": "Không có người",
"search_no_people_named": "Không có người tên \"{name}\"",
"search_no_result": "Không tìm thấy kết quả, hãy thử một cụm từ hoặc kết hợp với tìm kiếm khác",
@@ -1972,7 +2076,7 @@
"search_rating": "Tìm kiếm theo xếp hạng…",
"search_result_page_new_search_hint": "Tìm kiếm mới",
"search_settings": "Tìm kiếm cài đặt",
- "search_state": "Tìm tỉnh...",
+ "search_state": "Tìm tiểu bang...",
"search_suggestion_list_smart_search_hint_1": "Tìm kiếm thông minh được bật mặc định, để tìm kiếm metadata hãy sử dụng cú pháp ",
"search_suggestion_list_smart_search_hint_2": "m:cụm-từ-tìm-kiếm-của-bạn",
"search_tags": "Tìm thẻ...",
@@ -2002,6 +2106,7 @@
"select_person": "Chọn người",
"select_person_to_tag": "Chọn người để gắn thẻ",
"select_photos": "Chọn ảnh",
+ "select_quality": "Chọn chất lượng",
"select_trash_all": "Chọn xóa tất cả",
"select_user_for_sharing_page_err_album": "Tạo album thất bại",
"selected": "Đã chọn",
@@ -2027,15 +2132,15 @@
"set_date_of_birth": "Đặt sinh nhật",
"set_profile_picture": "Đặt ảnh đại diện",
"set_slideshow_to_fullscreen": "Đặt trình chiếu ở chế độ toàn màn hình",
- "set_stack_primary_asset": "Đặt làm tài sản chính",
- "setting_image_navigation_enable_subtitle": "Nếu được bật, bạn có thể điều hướng đến ảnh phía trước/kế tiếp bằng cách chạm vào phần tư bên trái/phải màn hình.",
+ "set_stack_primary_asset": "Đặt làm tài nguyên chính",
+ "setting_image_navigation_enable_subtitle": "Bật để chuyển sang ảnh trước/ảnh sau bằng cách nhấn mép trái/phải màn hình.",
"setting_image_navigation_enable_title": "Chạm để điều hướng",
"setting_image_navigation_title": "Điều hướng hình ảnh",
- "setting_image_viewer_help": "Trình xem ảnh tải ảnh thu nhỏ cỡ nhỏ trước, sau đó tải cỡ trung bình (nếu được bật), cuối cùng tải bản gốc (nếu được bật).",
+ "setting_image_viewer_help": "Khi xem chi tiết, thứ tự nạp sẽ là: ảnh thu nhỏ (cỡ nhỏ) → ảnh xem trước (cỡ trung bình) (nếu bật) → ảnh gốc (nếu bật).",
"setting_image_viewer_original_subtitle": "Bật để tải ảnh gốc ở độ phân giải đầy đủ (dung lượng lớn). Tắt để giảm mức sử dụng dữ liệu (mức sử dụng mạng và bộ nhớ đệm trên thiết bị).",
- "setting_image_viewer_original_title": "Tải ảnh gốc",
- "setting_image_viewer_preview_subtitle": "Bật để tải ảnh độ phân giải trung bình. Tắt để tải trực tiếp ảnh gốc hoặc chỉ sử dụng ảnh thu nhỏ.",
- "setting_image_viewer_preview_title": "Tải ảnh xem trước",
+ "setting_image_viewer_original_title": "Ưu tiên chất lượng gốc",
+ "setting_image_viewer_preview_subtitle": "Bật để nạp ảnh chất lượng trung bình. Tắt để nạp thẳng ảnh gốc hoặc chỉ xem ảnh thu nhỏ.",
+ "setting_image_viewer_preview_title": "Nạp ảnh xem trước",
"setting_image_viewer_title": "Ảnh",
"setting_languages_apply": "Áp dụng",
"setting_languages_subtitle": "Thay đổi ngôn ngữ ứng dụng",
@@ -2045,26 +2150,28 @@
"setting_notifications_notify_minutes": "{count} phút",
"setting_notifications_notify_never": "không bao giờ",
"setting_notifications_notify_seconds": "{count} giây",
- "setting_notifications_single_progress_subtitle": "Thông tin chi tiết của từng ảnh đang tải lên",
+ "setting_notifications_single_progress_subtitle": "Thông tin chi tiết của từng tài nguyên đang tải lên",
"setting_notifications_single_progress_title": "Hiện chi tiết sao lưu nền đang thực hiện",
"setting_notifications_subtitle": "Các loại thông báo",
- "setting_notifications_total_progress_subtitle": "Toàn bộ quá trình tải lên (hoàn thành/tổng số tệp)",
+ "setting_notifications_total_progress_subtitle": "Toàn bộ quá trình tải lên (hoàn thành/tổng số tài nguyên)",
"setting_notifications_total_progress_title": "Hiện quá trình sao lưu nền đang thực hiện",
"setting_video_viewer_auto_play_subtitle": "Khi mở video",
"setting_video_viewer_auto_play_title": "Tự động phát video",
"setting_video_viewer_looping_title": "Lặp lại",
- "setting_video_viewer_original_video_subtitle": "Khi phát trực tuyến video từ máy chủ, hãy phát video gốc ngay cả khi có bản chuyển mã. Có thể dẫn đến tình trạng chờ. Video có sẵn trên máy được phát ở chất lượng gốc bất kể cài đặt này.",
- "setting_video_viewer_original_video_title": "Dùng video gốc",
+ "setting_video_viewer_original_video_subtitle": "Khi phát trực tuyến một video từ máy chủ, hệ thống sẽ luôn dùng video gốc thay vì bản chuyển mã (có thể gây hiện tượng giật/chờ tải). Video lưu trên thiết bị luôn được phát ở chất lượng gốc.",
+ "setting_video_viewer_original_video_title": "Ưu tiên chất lượng gốc",
"settings": "Cài đặt",
"settings_require_restart": "Vui lòng khởi động lại Immich để áp dụng cài đặt này",
"settings_saved": "Đã lưu cài đặt",
"setup_pin_code": "Thiết lập mã PIN",
"share": "Chia sẻ",
- "share_action_prompt": "Đã chia sẻ {count} tệp",
+ "share_action_prompt": "Đã chia sẻ {count} tài nguyên",
"share_add_photos": "Thêm ảnh",
"share_assets_selected": "{count} đã chọn",
"share_dialog_preparing": "Đang xử lý...",
- "share_link": "Liên kết chia sẻ",
+ "share_link": "Link chia sẻ",
+ "share_original": "Chất lượng gốc (lớn)",
+ "share_preview": "Dùng ảnh thu nhỏ (nhỏ)",
"shared": "Đã chia sẻ",
"shared_album_activities_input_disable": "Nhận xét hiện đã tắt",
"shared_album_activity_remove_content": "Bạn có muốn xóa hoạt động này?",
@@ -2079,10 +2186,10 @@
"shared_from_partner": "Ảnh từ {partner}",
"shared_intent_upload_button_progress_text": "{current} / {total} Đã tải lên",
"shared_link_app_bar_title": "Liên kết đã chia sẻ",
- "shared_link_clipboard_copied_massage": "Đã sao chép vào bộ nhớ tạm",
+ "shared_link_clipboard_copied_massage": "Đã sao chép vào clipboard",
"shared_link_clipboard_text": "Liên kết: {link}\nMật khẩu: {password}",
"shared_link_create_error": "Tạo liên kết chia sẻ không thành công",
- "shared_link_custom_url_description": "Truy cập liên kết chia sẻ với một URL tùy chỉnh",
+ "shared_link_custom_url_description": "Truy cập link đã chia sẻ với một URL tùy chỉnh",
"shared_link_edit_description_hint": "Nhập mô tả chia sẻ",
"shared_link_edit_expire_after_option_day": "1 ngày",
"shared_link_edit_expire_after_option_days": "{count} ngày",
@@ -2106,11 +2213,11 @@
"shared_link_expires_seconds": "Hết hạn sau {count} giây",
"shared_link_individual_shared": "Chia sẻ riêng tư",
"shared_link_info_chip_metadata": "Dữ liệu EXIF",
- "shared_link_manage_links": "Quản lý liên kết đã chia sẻ",
- "shared_link_options": "Tùy chọn liên kết chia sẻ",
- "shared_link_password_description": "Bắt buộc để truy cập liên kết chia sẻ này",
- "shared_links": "Liên kết chia sẻ",
- "shared_links_description": "Chia sẻ ảnh và video bằng liên kết",
+ "shared_link_manage_links": "Quản lý các link đã chia sẻ",
+ "shared_link_options": "Tùy chọn chia sẻ link",
+ "shared_link_password_description": "Bắt buộc để truy cập link chia sẻ này",
+ "shared_links": "Chia sẻ link",
+ "shared_links_description": "Chia sẻ ảnh và video bằng link",
"shared_photos_and_videos_count": "{assetCount, plural, other {# ảnh & video đã chia sẻ.}}",
"shared_with_me": "Chia sẻ với tôi",
"shared_with_partner": "Đã chia sẻ với {partner}",
@@ -2122,25 +2229,28 @@
"sharing_sidebar_description": "Hiển thị mục Chia sẻ trong thanh bên",
"sharing_silver_appbar_create_shared_album": "Tạo album chia sẻ",
"sharing_silver_appbar_share_partner": "Chia sẻ với người thân",
- "shift_to_permanent_delete": "nhấn ⇧ để xóa vĩnh viễn tệp",
+ "shift_to_permanent_delete": "nhấn ⇧ để xóa vĩnh viễn tài nguyên",
"show_album_options": "Hiện tùy chọn album",
"show_albums": "Hiện album",
"show_all_people": "Hiển thị tất cả mọi người",
"show_and_hide_people": "Hiển thị & ẩn người",
- "show_file_location": "Hiển thị vị trí tập tin",
+ "show_file_location": "Hiển thị vị trí tệp",
"show_gallery": "Hiển thị thư viện ảnh",
"show_hidden_people": "Hiển thị người bị ẩn",
"show_in_timeline": "Hiển thị trên dòng thời gian",
"show_in_timeline_setting_description": "Hiển thị ảnh và video từ người dùng này trong dòng thời gian của bạn",
"show_keyboard_shortcuts": "Hiện phím tắt",
+ "show_less": "Hiện ít hơn",
"show_metadata": "Hiển thị metadata",
+ "show_more_fields": "{count, plural, one {Hiện thêm # trường} other {Hiện thêm # trường}}",
"show_or_hide_info": "Hiển thị hoặc ẩn thông tin",
"show_password": "Hiển thị mật khẩu",
"show_person_options": "Hiện tùy chọn người",
"show_progress_bar": "Hiển thị thanh tiến trình",
"show_schema": "Hiện lược đồ",
"show_search_options": "Hiện tùy chọn tìm kiếm",
- "show_shared_links": "Hiển thị các liên kết được chia sẻ",
+ "show_shared_links": "Hiển thị các link được chia sẻ",
+ "show_slideshow_metadata_overlay": "Hiển thị lớp phủ thông tin hình ảnh",
"show_slideshow_transition": "Hiển thị hiệu ứng chuyển tiếp",
"show_supporter_badge": "Huy hiệu người ủng hộ",
"show_supporter_badge_description": "Hiển thị huy hiệu người ủng hộ",
@@ -2148,7 +2258,7 @@
"show_text_search_menu": "Hiển thị menu tìm kiếm văn bản",
"shuffle": "Ngẫu nhiên",
"sidebar": "Thanh bên",
- "sidebar_display_description": "Hiển thị liên kết đến chế độ xem trong thanh bên",
+ "sidebar_display_description": "Hiển thị link đến chế độ xem trong thanh bên",
"sign_out": "Đăng xuất",
"sign_up": "Đăng ký",
"size": "Kích thước",
@@ -2156,9 +2266,14 @@
"skip_to_folders": "Chuyển đến thư mục",
"skip_to_tags": "Chuyển đến thẻ",
"slideshow": "Trình chiếu",
+ "slideshow_metadata_overlay_mode": "Lớp phủ nội dung",
+ "slideshow_metadata_overlay_mode_description_only": "Chỉ mô tả",
+ "slideshow_metadata_overlay_mode_full": "Đầy đủ",
"slideshow_repeat": "Trình chiếu lại",
"slideshow_repeat_description": "Phát lại từ đầu khi trình chiếu kết thúc",
"slideshow_settings": "Cài đặt trình chiếu",
+ "smart_album": "Album thông minh",
+ "some_assets_already_have_a_location_warning": "Một số tài nguyên được lựa chọn đã có vị trí",
"sort_albums_by": "Sắp xếp album theo...",
"sort_created": "Ngày tạo",
"sort_items": "Số lượng mục",
@@ -2168,19 +2283,24 @@
"sort_people_by_similarity": "Sắp xếp người theo độ tương đồng",
"sort_recent": "Ảnh gần đây nhất",
"sort_title": "Tiêu đề",
- "source": "Nguồn",
+ "source": "Mã nguồn",
"stack": "Nhóm ảnh",
"stack_action_prompt": "{count} đã được nhóm",
"stack_duplicates": "Nhóm mục trùng lặp",
"stack_select_one_photo": "Chọn ảnh chính cho nhóm ảnh",
"stack_selected_photos": "Nhóm các ảnh đã chọn",
- "stacked_assets_count": "Đã nhóm {count, plural, one {# tệp} other {# tệp}}",
+ "stacked_assets_count": "Đã nhóm {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"stacktrace": "Thông tin chi tiết lỗi",
"start": "Bắt đầu",
"start_date": "Ngày bắt đầu",
"start_date_before_end_date": "Ngày bắt đầu phải trước ngày kết thúc",
- "state": "Tỉnh",
+ "state": "Tiểu bang",
"status": "Trạng thái",
+ "step_delete": "Xóa bước",
+ "step_delete_confirm": "Bạn có chắc muốn xóa bước này?",
+ "step_details": "Chi tiết bước",
+ "steps": "Các bước",
+ "steps_count": "{count, plural, one {# bước} other {# bước}}",
"stop_casting": "Dừng chiếu",
"stop_motion_photo": "Dừng ảnh chuyển động",
"stop_photo_sharing": "Dừng chia sẻ ảnh của bạn?",
@@ -2189,7 +2309,7 @@
"storage": "Bộ nhớ",
"storage_label": "Nhãn lưu trữ",
"storage_quota": "Hạn mức dung lượng",
- "storage_usage": "Đã dùng {used} của {available}",
+ "storage_usage": "{used} trong {available}",
"submit": "Gửi",
"success": "Thành công",
"suggestions": "Gợi ý",
@@ -2207,15 +2327,18 @@
"sync_status": "Trạng thái đồng bộ",
"sync_status_subtitle": "Thống kê về việc đồng bộ",
"sync_upload_album_setting_subtitle": "Tạo và tải lên ảnh và video của bạn vào album đã chọn trên Immich",
+ "system_theme": "Chủ đề hệ thống",
+ "system_theme_command_description": "Giống chủ đề hệ thống ({value})",
"tag": "Thẻ",
- "tag_assets": "Gắn thẻ",
+ "tag_assets": "Gắn thẻ tài nguyên",
"tag_created": "Đã tạo thẻ: {tag}",
- "tag_feature_description": "Duyệt ảnh và video được nhóm theo chủ đề thẻ hợp lý",
+ "tag_face": "Gắn thẻ khuôn mặt",
+ "tag_feature_description": "Duyệt ảnh và video được phân loại theo chủ đề thẻ",
"tag_not_found_question": "Không tìm thấy thẻ? Create a new tag. (Tạo một thẻ mới)",
"tag_people": "Gắn thẻ Mọi người",
"tag_updated": "Đã cập nhật thẻ: {tag}",
- "tagged_assets": "Đã gắn thẻ {count, plural, one {# tệp} other {# tệp}}",
- "tags": "Thẻ",
+ "tagged_assets": "Đã gắn thẻ {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "tags": "Gắn thẻ",
"tap_to_run_job": "Nhấn để chạy tác vụ",
"template": "Mẫu",
"text_recognition": "Nhận dạng văn bản",
@@ -2223,13 +2346,13 @@
"theme_selection": "Chủ đề",
"theme_selection_description": "Dựa theo trình duyệt của bạn",
"theme_setting_asset_list_storage_indicator_title": "Hiện trạng thái sao lưu trên ảnh thu nhỏ",
- "theme_setting_asset_list_tiles_per_row_title": "Số lượng tệp trên mỗi hàng ({count})",
- "theme_setting_colorful_interface_subtitle": "Áp dụng màu chủ đạo cho nền app.",
+ "theme_setting_asset_list_tiles_per_row_title": "Số lượng tài nguyên trên mỗi hàng ({count})",
+ "theme_setting_colorful_interface_subtitle": "Áp dụng màu chủ đề cho nền app.",
"theme_setting_colorful_interface_title": "Giao diện sinh động",
"theme_setting_image_viewer_quality_subtitle": "Điều chỉnh chất lượng của trình xem ảnh",
"theme_setting_image_viewer_quality_title": "Chất lượng trình xem ảnh",
"theme_setting_primary_color_subtitle": "Chọn màu cho các hành động chính và điểm nhấn.",
- "theme_setting_primary_color_title": "Màu chủ đạo",
+ "theme_setting_primary_color_title": "Màu chủ đề",
"theme_setting_system_primary_color_title": "Dùng màu hệ thống",
"theme_setting_system_theme_switch": "Tự động (Giống thiết bị)",
"theme_setting_theme_subtitle": "Chọn cài đặt giao diện ứng dụng",
@@ -2247,11 +2370,11 @@
"to_change_password": "Đổi mật khẩu",
"to_favorite": "Thích",
"to_login": "Đăng nhập",
- "to_multi_select": "để chọn-nhiều",
+ "to_multi_select": "chọn nhiều mục",
"to_parent": "Về thư mục gốc",
- "to_select": "để chọn",
+ "to_select": "chọn",
"to_trash": "Xóa",
- "toggle_settings": "Chuyển đổi cài đặt",
+ "toggle_settings": "Đổi cài đặt",
"toggle_theme_description": "Đổi chủ đề",
"total": "Tổng cộng",
"total_usage": "Dung lượng đã dùng",
@@ -2259,22 +2382,24 @@
"trash_action_prompt": "{count} đã chuyển vào thùng rác",
"trash_all": "Xóa hết",
"trash_count": "Xóa {count, number} mục",
- "trash_delete_asset": "Chuyển vào thùng rác/Xóa vĩnh viễn",
+ "trash_delete_asset": "Chuyển vào thùng rác/Xóa tài nguyên",
"trash_emptied": "Đã dọn sạch thùng rác",
"trash_no_results_message": "Ảnh và video đã bị xóa sẽ hiển thị ở đây.",
"trash_page_delete_all": "Xóa tất cả",
"trash_page_empty_trash_dialog_content": "Bạn có muốn dọn sạch thùng rác của mình không? Những mục này sẽ bị xóa vĩnh viễn khỏi Immich",
"trash_page_info": "Những mục này sẽ bị xóa sau {days} ngày",
- "trash_page_no_assets": "Không có tệp nào",
+ "trash_page_no_assets": "Không có tài nguyên nào",
"trash_page_restore_all": "Khôi phục tất cả",
- "trash_page_select_assets_btn": "Chọn tệp",
+ "trash_page_select_assets_btn": "Chọn tài nguyên",
"trash_page_title": "Thùng rác ({count})",
"trashed_items_will_be_permanently_deleted_after": "Các mục đã xóa sẽ bị xóa vĩnh viễn sau {days, plural, one {# ngày} other {# ngày}}.",
"trigger": "Kích hoạt",
- "trigger_asset_uploaded": "Tệp đã được tải lên",
- "trigger_asset_uploaded_description": "Sự kiện này được kích hoạt khi một tệp mới được tải lên",
+ "trigger_asset_metadata_extraction": "Trích xuất metadata tài nguyên",
+ "trigger_asset_metadata_extraction_description": "Sự kiện này được kích hoạt khi metadata EXIF của một tài nguyên được trích xuất",
+ "trigger_asset_uploaded": "Đã tải lên tài nguyên",
+ "trigger_asset_uploaded_description": "Được kích hoạt khi một tài nguyên mới được tải lên",
"trigger_description": "Một sự kiện khởi đầu workflow",
- "trigger_person_recognized": "Người được nhận diện",
+ "trigger_person_recognized": "Đã nhận diện người",
"trigger_person_recognized_description": "Được kích hoạt khi phát hiện thấy một người",
"trigger_type": "Kiểu kích hoạt",
"troubleshoot": "Khắc phục sự cố",
@@ -2287,7 +2412,7 @@
"unarchived_count": "{count, plural, other {Đã bỏ lưu trữ # mục}}",
"undo": "Hoàn tác",
"unfavorite": "Bỏ thích",
- "unfavorite_action_prompt": "{count} đã bỏ khỏi Đã thích",
+ "unfavorite_action_prompt": "{count} đã bỏ khỏi Yêu thích",
"unhide_person": "Hiện người",
"unknown": "Không xác định",
"unknown_country": "Quốc gia chưa rõ",
@@ -2307,31 +2432,34 @@
"unselect_all_in": "Bỏ chọn tất cả trong {group}",
"unstack": "Hủy xếp nhóm",
"unstack_action_prompt": "{count} đã bỏ nhóm",
- "unstacked_assets_count": "Đã hủy xếp nhóm {count, plural, one {# tệp} other {# tệp}}",
+ "unstacked_assets_count": "Đã hủy xếp nhóm {count, plural, one {# tài nguyên} other {# tài nguyên}}",
"unsupported_field_type": "Loại trường không được hỗ trợ",
"unsupported_file_type": "Tệp {file} không thể được tải lên vì loại tệp {type} không được hỗ trợ.",
"untagged": "Chưa gắn thẻ",
"up_next": "Tiếp theo",
- "update_location_action_prompt": "Cập nhật địa điểm của {count} tệp đã chọn với:",
+ "update_location_action_prompt": "Cập nhật vị trí của {count} tài nguyên đã chọn với:",
"updated_at": "Đã cập nhật",
"updated_password": "Đã cập nhật mật khẩu",
"upload": "Tải lên",
"upload_concurrency": "Tải lên đồng thời",
+ "upload_day_count": "{date}: {count, plural, one {# tải lên} other {# tải lên}}",
"upload_details": "Chi tiết tải lên",
- "upload_dialog_info": "Bạn có muốn sao lưu những tệp đã chọn lên máy chủ không?",
- "upload_dialog_title": "Tải lên tệp",
- "upload_error_with_count": "Không thể tải lên {count, plural, one {# tệp} other {# tệp}}",
- "upload_errors": "Đã hoàn tất tải lên với {count, plural, one {# lỗi} other {# lỗi}}, làm mới trang để xem các tệp vừa tải lên.",
+ "upload_dialog_info": "Bạn có muốn sao lưu những tài nguyên đã chọn lên máy chủ không?",
+ "upload_dialog_title": "Tải lên tài nguyên",
+ "upload_error_with_count": "Không thể tải lên {count, plural, one {# tài nguyên} other {# tài nguyên}}",
+ "upload_errors": "Đã hoàn tất tải lên với {count, plural, one {# lỗi} other {# lỗi}}, làm mới trang để xem các tài nguyên mới tải lên.",
"upload_finished": "Đã hoàn tất tải lên",
"upload_progress": "Còn lại {remaining, number} - Đã xử lý {processed, number}/{total, number}",
- "upload_skipped_duplicates": "Đã bỏ qua {count, plural, one {# tệp trùng lặp} other {# tệp trùng lặp}}",
- "upload_status_duplicates": "Tệp trùng lặp",
+ "upload_skipped_duplicates": "Đã bỏ qua {count, plural, one {# tài nguyên trùng lặp} other {# tài nguyên trùng lặp}}",
+ "upload_status_duplicates": "Trùng lặp",
"upload_status_errors": "Lỗi",
"upload_status_uploaded": "Đã tải lên",
- "upload_success": "Tải lên thành công, làm mới trang để xem các tệp vừa tải lên.",
+ "upload_success": "Tải lên thành công, làm mới trang để xem các tài nguyên mới tải lên.",
"upload_to_immich": "Tải lên Immich ({count})",
"uploading": "Đang tải lên",
"uploading_media": "Đang tải lên phương tiện",
+ "uploads": "Tải lên",
+ "uploads_count": "{count, plural, one {# tải lên} other {# tải lên}}",
"url": "URL",
"usage": "Sử dụng",
"use_biometric": "Dùng sinh trắc học",
@@ -2339,10 +2467,11 @@
"use_browser_locale_description": "Định dạng ngày, thời gian và số dựa trên ngôn ngữ trình duyệt",
"use_current_connection": "Dùng kết nối hiện tại",
"use_custom_date_range": "Chọn khoảng thời gian tùy chỉnh",
+ "use_template": "Dùng mẫu có sẵn",
"user": "Người dùng",
"user_has_been_deleted": "Người dùng này đã bị xóa.",
"user_id": "ID người dùng",
- "user_liked": "{user} đã thích {type, select, photo {ảnh này} video {video này} asset {tệp này} other {nó}}",
+ "user_liked": "{user} đã thích {type, select, photo {ảnh này} video {video này} asset {tài nguyên này} other {nó}}",
"user_pin_code_settings": "Mã PIN",
"user_pin_code_settings_description": "Quản lý mã PIN của bạn",
"user_privacy": "Quyền riêng tư người dùng",
@@ -2362,12 +2491,13 @@
"variables": "Các tham số",
"version": "Phiên bản",
"version_announcement_closing": "Bạn của bạn, Alex",
- "version_announcement_message": "Chào bạn! Một phiên bản mới của Immich đã ra mắt. Vui lòng dành thời gian để xem danh sách thay đổi để đảm bảo cấu hình của bạn được cập nhật để tránh lỗi cấu hình sai, đặc biệt nếu bạn sử dụng WatchTower hoặc bất kỳ cơ chế tự động cập nhật Immich của bạn.",
+ "version_announcement_message": "Chào bạn! Immich đã ra mắt phiên bản mới. Vui lòng dành thời gian để xem ghi chú phát hành để đảm bảo cấu hình của bạn được cập nhật nhằm tránh cấu hình sai, đặc biệt nếu bạn sử dụng WatchTower hoặc bất kỳ cơ chế tự động cập nhật Immich nào.",
"version_history": "Lịch sử phiên bản",
"version_history_item": "Đã cài đặt {version} vào {date}",
"video": "Video",
"video_hover_setting": "Xem trước video khi di chuột lên",
- "video_hover_setting_description": "Phát đoạn video xem trước khi di chuột qua mục. Ngay cả khi tắt chức năng này, vẫn có thể bắt đầu phát video bằng cách di chuột qua biểu tượng phát.",
+ "video_hover_setting_description": "Phát đoạn video xem trước khi di chuột qua mục. Nếu tắt, vẫn có thể bắt đầu phát video bằng cách di chuột qua biểu tượng phát.",
+ "video_quality": "Chất lượng video",
"videos": "Video",
"videos_count": "{count, plural, one {# Video} other {# Video}}",
"videos_only": "Chỉ video",
@@ -2375,21 +2505,22 @@
"view_album": "Xem Album",
"view_all": "Xem tất cả",
"view_all_users": "Xem tất cả người dùng",
- "view_asset_owners": "Xem chủ sở hữu tệp",
+ "view_asset_owners": "Xem chủ sở hữu tài nguyên",
"view_details": "Xem thông tin chi tiết",
"view_in_timeline": "Xem trong dòng thời gian",
"view_link": "Xem liên kết",
"view_links": "Xem các liên kết",
"view_name": "Giao diện",
- "view_next_asset": "Xem tệp tiếp theo",
- "view_previous_asset": "Xem tệp trước đó",
+ "view_next_asset": "Xem tài nguyên tiếp theo",
+ "view_previous_asset": "Xem tài nguyên trước đó",
"view_qr_code": "Xem mã QR",
"view_similar_photos": "Xem ảnh tương tự",
"view_stack": "Xem nhóm ảnh",
"view_user": "Xem Người dùng",
"viewer_remove_from_stack": "Xóa khỏi nhóm",
- "viewer_stack_use_as_main_asset": "Đặt làm ảnh nổi bật",
+ "viewer_stack_use_as_main_asset": "Đặt làm tài nguyên chính",
"viewer_unstack": "Hủy xếp nhóm",
+ "visibility": "Khả năng hiển thị",
"visibility_changed": "Đã thay đổi trạng thái hiển thị cho {count, plural, one {# người} other {# người}}",
"visual": "Trực quan",
"visual_builder": "Tạo trực quan",
@@ -2399,8 +2530,10 @@
"week": "Tuần",
"welcome": "Chào mừng",
"welcome_to_immich": "Chào mừng đến với Immich",
+ "when": "Khi nào",
"width": "Chiều rộng",
"wifi_name": "Tên Wi-Fi",
+ "workflow": "Workflow",
"workflow_delete_prompt": "Bạn có chắc muốn xóa luồng công việc này?",
"workflow_deleted": "Đã xóa luồng công việc",
"workflow_description": "Mô tả luồng công việc",
@@ -2410,17 +2543,19 @@
"workflow_name": "Tên luồng công việc",
"workflow_navigation_prompt": "Bạn có chắc muốn rời đi mà không lưu lại các thay đổi của mình?",
"workflow_summary": "Mô tả luồng công việc",
+ "workflow_templates": "Mẫu workflow có sẵn",
"workflow_update_success": "Đã cập nhật luồng công việc thành công",
"workflow_updated": "Đã cập nhật Luồng công việc",
"workflows": "Luồng công việc",
- "workflows_help_text": "Luồng công việc tự động hóa các hành động trên tập tin của bạn dựa trên các trình kích hoạt và bộ lọc",
+ "workflows_help_text": "Luồng công việc tự động hóa các hành động trên tài nguyên của bạn dựa trên các trình kích hoạt và bộ lọc",
"wrong_pin_code": "Mã PIN không đúng",
+ "x_of_total": "{x}/{total}",
"year": "Năm",
"years_ago": "{years, plural, one {# năm} other {# năm}} trước",
"yes": "Đồng ý",
"you_dont_have_any_shared_links": "Bạn không có liên kết chia sẻ nào",
"your_wifi_name": "Tên Wi-Fi của bạn",
- "zero_to_clear_rating": "nhấn 0 để xóa đánh giá ảnh",
+ "zero_to_clear_rating": "nhấn 0 để xóa xếp hạng tài nguyên",
"zoom_image": "Thu phóng ảnh",
"zoom_to_bounds": "Thu phóng vừa khung"
}
diff --git a/i18n/yue_Hant.json b/i18n/yue_Hant.json
index 134c0ddfa0..0db0b76296 100644
--- a/i18n/yue_Hant.json
+++ b/i18n/yue_Hant.json
@@ -304,6 +304,12 @@
"oauth_storage_label_claim": "儲存標籤宣告",
"oauth_storage_label_claim_description": "自動將使用者嘅儲存標籤設定為呢個宣告值。",
"oauth_storage_quota_claim": "儲存限額宣告",
+ "oauth_storage_quota_claim_description": "自動將使用者嘅儲存限額設定為呢個宣告之值。",
+ "oauth_storage_quota_default": "預設儲存限額(GiB)",
+ "oauth_storage_quota_default_description": "未提供宣告時所使用嘅限額(GiB)。",
+ "oauth_timeout": "請求超時",
+ "oauth_timeout_description": "請求超時(毫秒)",
+ "ocr_job_description": "用機械學習辨識影像中嘅文字",
"queue_details": "隊列資訊",
"queues": "任務隊列",
"queues_page_description": "管理員任務隊列頁面",
diff --git a/i18n/zh_Hans.json b/i18n/zh_Hans.json
index a2e5ce1431..7081e73805 100644
--- a/i18n/zh_Hans.json
+++ b/i18n/zh_Hans.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "使用此位置",
"map_location_service_disabled_content": "需要启用定位服务才能显示您当前位置的媒体文件。是否现在启用它?",
"map_location_service_disabled_title": "定位服务已禁用",
- "map_marker_for_images": "标记{city}、{country}拍摄照片的地图图标",
"map_marker_with_image": "带预览图的地图标记",
"map_no_location_permission_content": "需要位置权限才能显示您当前位置的照片/视频。现在要允许吗?",
"map_no_location_permission_title": "位置权限被拒绝",
diff --git a/i18n/zh_Hant.json b/i18n/zh_Hant.json
index 039f2e3631..49b30a0058 100644
--- a/i18n/zh_Hant.json
+++ b/i18n/zh_Hant.json
@@ -1548,7 +1548,6 @@
"map_location_picker_page_use_location": "使用此位置",
"map_location_service_disabled_content": "需要啟用定位服務才能顯示您目前位置相關的項目。要現在啟用嗎?",
"map_location_service_disabled_title": "定位服務已停用",
- "map_marker_for_images": "在 {city}、{country} 拍攝影像的地圖標記",
"map_marker_with_image": "帶有影像的地圖標記",
"map_no_location_permission_content": "需要位置權限才能顯示與您目前位置相關的項目。要現在就授予位置權限嗎?",
"map_no_location_permission_title": "沒有位置權限",
From 22ec449e43a4d3532bca6337ca041c9349777238 Mon Sep 17 00:00:00 2001
From: Mees Frensel <33722705+meesfrensel@users.noreply.github.com>
Date: Tue, 23 Jun 2026 18:02:29 +0200
Subject: [PATCH 026/435] chore: remove unused i18n strings (#29288)
---
i18n/en.json | 313 +--------------------------------------------------
1 file changed, 1 insertion(+), 312 deletions(-)
diff --git a/i18n/en.json b/i18n/en.json
index 2b124c276e..6bcb88d2c5 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -10,22 +10,18 @@
"active": "Active",
"active_count": "Active: {count}",
"activity": "Activity",
- "activity_changed": "Activity is {enabled, select, true {enabled} other {disabled}}",
"add": "Add",
"add_a_description": "Add a description",
"add_a_location": "Add a location",
"add_a_name": "Add a name",
"add_a_title": "Add a title",
"add_action": "Add action",
- "add_action_description": "Click to add an action to perform",
"add_assets": "Add assets",
"add_birthday": "Add a birthday",
"add_endpoint": "Add endpoint",
"add_exclusion_pattern": "Add exclusion pattern",
"add_location": "Add location",
- "add_more_users": "Add more users",
"add_partner": "Add partner",
- "add_path": "Add path",
"add_photos": "Add photos",
"add_step": "Add step",
"add_tag": "Add tag",
@@ -34,11 +30,9 @@
"add_to_album_bottom_sheet_added": "Added to {album}",
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
"add_to_album_bottom_sheet_some_local_assets": "Some local assets could not be added to album",
- "add_to_album_toggle": "Toggle selection for {album}",
"add_to_albums": "Add to albums",
"add_to_albums_count": "Add to albums ({count})",
"add_to_bottom_bar": "Add to",
- "add_to_shared_album": "Add to shared album",
"add_upload_to_stack": "Add upload to stack",
"add_url": "Add URL",
"added_to_archive": "Added to archive",
@@ -481,8 +475,6 @@
"advanced_settings_clear_image_cache": "Clear Image Cache",
"advanced_settings_clear_image_cache_error": "Failed to clear image cache",
"advanced_settings_clear_image_cache_success": "Successfully cleared {size}",
- "advanced_settings_enable_alternate_media_filter_subtitle": "Use this option to filter media during sync based on alternate criteria. Only try this if you have issues with the app detecting all albums.",
- "advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Use alternate device album sync filter",
"advanced_settings_log_level_title": "Log level: {level}",
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from local assets. Activate this setting to load remote images instead.",
"advanced_settings_prefer_remote_title": "Prefer remote images",
@@ -490,8 +482,6 @@
"advanced_settings_proxy_headers_title": "Custom proxy headers [EXPERIMENTAL]",
"advanced_settings_readonly_mode_subtitle": "Enables the read-only mode where the photos can be only viewed, things like selecting multiple images, sharing, casting, delete are all disabled. Enable/Disable read-only via user avatar from the main screen",
"advanced_settings_readonly_mode_title": "Read-only mode",
- "advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
- "advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates [EXPERIMENTAL]",
"advanced_settings_sync_remote_deletions_subtitle": "Automatically delete or restore an asset on this device when that action is taken on the web",
"advanced_settings_sync_remote_deletions_title": "Sync remote deletions [EXPERIMENTAL]",
"advanced_settings_tile_subtitle": "Advanced user's settings",
@@ -507,31 +497,18 @@
"album_delete_confirmation": "Are you sure you want to delete the album {album}?",
"album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.",
"album_deleted": "Album deleted",
- "album_info_card_backup_album_excluded": "EXCLUDED",
- "album_info_card_backup_album_included": "INCLUDED",
"album_info_updated": "Album info updated",
- "album_leave": "Leave album?",
- "album_leave_confirmation": "Are you sure you want to leave {album}?",
"album_name": "Album Name",
"album_options": "Album options",
"album_remove_user": "Remove user?",
"album_remove_user_confirmation": "Are you sure you want to remove {user}?",
"album_search_not_found": "No albums found matching your search",
- "album_selected": "Album selected",
"album_share_no_users": "Looks like you have shared this album with all users or you don't have any user to share with.",
"album_summary": "Album summary",
"album_updated": "Album updated",
"album_updated_setting_description": "Receive an email notification when a shared album has new assets",
"album_upload_assets": "Upload assets from your computer and add to album",
- "album_user_left": "Left {album}",
- "album_user_removed": "Removed {user}",
- "album_viewer_appbar_delete_confirm": "Are you sure you want to delete this album from your account?",
"album_viewer_appbar_share_err_delete": "Failed to delete album",
- "album_viewer_appbar_share_err_leave": "Failed to leave album",
- "album_viewer_appbar_share_err_remove": "There are problems in removing assets from album",
- "album_viewer_appbar_share_err_title": "Failed to change album title",
- "album_viewer_appbar_share_leave": "Leave album",
- "album_viewer_appbar_share_to": "Share To",
"album_viewer_page_share_add_users": "Add users",
"album_with_link_access": "Let anyone with the link see photos and people in this album.",
"albums": "Albums",
@@ -540,14 +517,12 @@
"albums_default_sort_order_description": "Initial asset sort order when creating new albums.",
"albums_feature_description": "Collections of assets that can be shared with other users.",
"albums_on_device_count": "Albums on device ({count})",
- "albums_selected": "{count, plural, one {# album selected} other {# albums selected}}",
"all": "All",
"all_albums": "All albums",
"all_people": "All people",
"all_photos": "All photos",
"all_videos": "All videos",
"allow_dark_mode": "Allow dark mode",
- "allow_edits": "Allow edits",
"allow_public_user_to_download": "Allow public user to download",
"allow_public_user_to_upload": "Allow public user to upload",
"allowed": "Allowed",
@@ -555,14 +530,12 @@
"always_keep": "Always keep",
"always_keep_photos_hint": "Free Up Space will keep all photos on this device.",
"always_keep_videos_hint": "Free Up Space will keep all videos on this device.",
- "anti_clockwise": "Anti-clockwise",
"api_key": "API Key",
"api_key_description": "This value will only be shown once. Please be sure to copy it before closing the window.",
"api_key_empty": "Your API Key name shouldn't be empty",
"api_keys": "API Keys",
"app_architecture_variant": "Variant (Architecture)",
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
- "app_bar_signout_dialog_ok": "Yes",
"app_bar_signout_dialog_title": "Sign out",
"app_download_links": "App Download Links",
"app_settings": "App Settings",
@@ -573,28 +546,19 @@
"archive": "Archive",
"archive_action_prompt": "{count} added to Archive",
"archive_or_unarchive_photo": "Archive or unarchive photo",
- "archive_page_no_archived_assets": "No archived assets found",
- "archive_page_title": "Archive ({count})",
"archive_size": "Archive size",
"archive_size_description": "Configure the archive size for downloads (in GiB)",
"archived": "Archived",
"archived_count": "{count, plural, other {Archived #}}",
"are_these_the_same_person": "Are these the same person?",
"are_you_sure_to_do_this": "Are you sure you want to do this?",
- "array_field_not_fully_supported": "Array fields require manual JSON editing",
- "asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
- "asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
"asset_added_to_album": "Added to album",
"asset_adding_to_album": "Adding to album…",
"asset_created": "Asset created",
"asset_day_count": "{date}: {count, plural, one {# asset} other {# assets}}",
"asset_description_updated": "Asset description has been updated",
- "asset_filename_is_offline": "Asset {filename} is offline",
- "asset_has_unassigned_faces": "Asset has unassigned faces",
"asset_hashing": "Hashing…",
"asset_list_group_by_sub_title": "Group by",
- "asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
- "asset_list_layout_settings_group_automatically": "Automatic",
"asset_list_layout_settings_group_by": "Group assets by",
"asset_list_layout_settings_group_by_month_day": "Month + day",
"asset_list_layout_sub_title": "Layout",
@@ -605,36 +569,26 @@
"asset_not_found_on_icloud": "Asset not found on iCloud. the asset may be inaccessible due to bad file stored on iCloud",
"asset_offline": "Asset Offline",
"asset_offline_description": "This external asset is no longer found on disk. Please contact your Immich administrator for help.",
- "asset_restored_successfully": "Asset restored successfully",
"asset_skipped": "Skipped",
"asset_skipped_in_trash": "In trash",
- "asset_trashed": "Asset trashed",
"asset_troubleshoot": "Asset Troubleshoot",
"asset_uploaded": "Uploaded",
"asset_uploading": "Uploading…",
"asset_viewer_settings_subtitle": "Manage your gallery viewer settings",
"asset_viewer_settings_title": "Asset Viewer",
"assets": "Assets",
- "assets_added_count": "Added {count, plural, one {# asset} other {# assets}}",
"assets_added_to_album_count": "Added {count, plural, one {# asset} other {# assets}} to the album",
"assets_added_to_albums_count": "Added {assetTotal, plural, one {# asset} other {# assets}} to {albumTotal, plural, one {# album} other {# albums}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
"assets_cannot_be_added_to_albums": "{count, plural, one {Asset} other {Assets}} cannot be added to any of the albums",
"assets_count": "{count, plural, one {# asset} other {# assets}}",
- "assets_deleted_permanently": "{count} asset(s) deleted permanently",
- "assets_deleted_permanently_from_server": "{count} asset(s) deleted permanently from the Immich server",
- "assets_downloaded_failed": "{count, plural, one {Downloaded # file - {error} file failed} other {Downloaded # files - {error} files failed}}",
- "assets_downloaded_successfully": "{count, plural, one {Downloaded # file successfully} other {Downloaded # files successfully}}",
"assets_moved_to_trash_count": "Moved {count, plural, one {# asset} other {# assets}} to trash",
"assets_permanently_deleted_count": "Permanently deleted {count, plural, one {# asset} other {# assets}}",
"assets_removed_count": "Removed {count, plural, one {# asset} other {# assets}}",
- "assets_removed_permanently_from_device": "{count} asset(s) removed permanently from your device",
"assets_restore_confirmation": "Are you sure you want to restore all your trashed assets? You cannot undo this action! Note that any offline assets cannot be restored this way.",
"assets_restored_count": "Restored {count, plural, one {# asset} other {# assets}}",
- "assets_restored_successfully": "{count} asset(s) restored successfully",
"assets_trashed": "{count} asset(s) trashed",
"assets_trashed_count": "Trashed {count, plural, one {# asset} other {# assets}}",
- "assets_trashed_from_server": "{count} asset(s) trashed from the Immich server",
"assets_were_part_of_album_count": "{count, plural, one {Asset was} other {Assets were}} already part of the album",
"assets_were_part_of_albums_count": "{count, plural, one {Asset was} other {Assets were}} already part of the albums",
"authorized_devices": "Authorized Devices",
@@ -643,86 +597,45 @@
"autoplay_slideshow": "Autoplay slideshow",
"back": "Back",
"back_close_deselect": "Back, close, or deselect",
- "background_backup_running_error": "Background backup is currently running, cannot start manual backup",
"background_location_permission": "Background location permission",
"background_location_permission_content": "In order to switch networks when running in the background, Immich must *always* have precise location access so the app can read the Wi-Fi network's name",
"background_options": "Background Options",
"backup": "Backup",
- "backup_album_selection_page_albums_device": "Albums on device ({count})",
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
"backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
"backup_album_selection_page_select_albums": "Select albums",
"backup_album_selection_page_selection_info": "Selection Info",
- "backup_album_selection_page_total_assets": "Total unique assets",
"backup_albums_sync": "Backup Albums Synchronization",
- "backup_all": "All",
- "backup_background_service_backup_failed_message": "Failed to backup assets. Retrying…",
"backup_background_service_complete_notification": "Asset backup complete",
- "backup_background_service_connection_failed_message": "Failed to connect to the server. Retrying…",
- "backup_background_service_current_upload_notification": "Uploading {filename}",
"backup_background_service_default_notification": "Checking for new assets…",
- "backup_background_service_error_title": "Backup error",
"backup_background_service_in_progress_notification": "Backing up your assets…",
- "backup_background_service_upload_failure_notification": "Failed to upload {filename}",
"backup_controller_page_albums": "Backup Albums",
- "backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
- "backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
- "backup_controller_page_background_app_refresh_enable_button_text": "Go to settings",
"backup_controller_page_background_battery_info_link": "Show me how",
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
"backup_controller_page_background_battery_info_ok": "OK",
"backup_controller_page_background_battery_info_title": "Battery optimizations",
- "backup_controller_page_background_charging": "Only while charging",
- "backup_controller_page_background_configure_error": "Failed to configure the background service",
"backup_controller_page_background_delay": "Delay new assets backup: {duration}",
- "backup_controller_page_background_description": "Turn on the background service to automatically backup any new assets without needing to open the app",
- "backup_controller_page_background_is_off": "Automatic background backup is off",
- "backup_controller_page_background_is_on": "Automatic background backup is on",
- "backup_controller_page_background_turn_off": "Turn off background service",
- "backup_controller_page_background_turn_on": "Turn on background service",
- "backup_controller_page_background_wifi": "Only on Wi-Fi",
"backup_controller_page_backup": "Backup",
"backup_controller_page_backup_selected": "Selected: ",
"backup_controller_page_backup_sub": "Backed up photos and videos",
- "backup_controller_page_created": "Created on: {date}",
- "backup_controller_page_desc_backup": "Turn on foreground backup to automatically upload new assets to the server when opening the app.",
"backup_controller_page_excluded": "Excluded: ",
- "backup_controller_page_failed": "Failed ({count})",
- "backup_controller_page_filename": "File name: {filename} [{size}]",
- "backup_controller_page_id": "ID: {id}",
- "backup_controller_page_info": "Backup Information",
"backup_controller_page_none_selected": "None selected",
"backup_controller_page_remainder": "Remainder",
"backup_controller_page_remainder_sub": "Remaining photos and videos to back up from selection",
"backup_controller_page_server_storage": "Server Storage",
- "backup_controller_page_start_backup": "Start Backup",
- "backup_controller_page_status_off": "Automatic foreground backup is off",
- "backup_controller_page_status_on": "Automatic foreground backup is on",
"backup_controller_page_storage_format": "{used} of {total} used",
"backup_controller_page_to_backup": "Albums to be backed up",
"backup_controller_page_total_sub": "All unique photos and videos from selected albums",
- "backup_controller_page_turn_off": "Turn off foreground backup",
- "backup_controller_page_turn_on": "Turn on foreground backup",
- "backup_controller_page_uploading_file_info": "Uploading file info",
- "backup_err_only_album": "Cannot remove the only album",
"backup_error_sync_failed": "Sync failed. Cannot process backup.",
"backup_info_card_assets": "assets",
- "backup_manual_cancelled": "Cancelled",
- "backup_manual_in_progress": "Upload already in progress. Try after sometime",
- "backup_manual_success": "Success",
- "backup_manual_title": "Upload status",
"backup_options": "Backup Options",
- "backup_options_page_title": "Backup options",
- "backup_setting_subtitle": "Manage background and foreground upload settings",
"backup_settings_subtitle": "Manage upload settings",
- "backup_upload_details_page_more_details": "Tap for more details",
"backward": "Backward",
"battery_optimization_backup_reliability": "Disabling battery optimizations can improve the reliability of background backup",
"biometric_auth_enabled": "Biometric authentication enabled",
"biometric_locked_out": "You are locked out of biometric authentication",
"biometric_no_options": "No biometric options available",
"biometric_not_available": "Biometric authentication is not available on this device",
- "birthdate_saved": "Date of birth saved successfully",
"birthdate_set_description": "Date of birth is used to calculate the age of this person at the time of a photo.",
"blurred_background": "Blurred background",
"browse_templates": "Browse templates",
@@ -733,20 +646,6 @@
"bulk_keep_duplicates_confirmation": "Are you sure you want to keep {count, plural, one {# duplicate asset} other {# duplicate assets}}? This will resolve all duplicate groups without deleting anything.",
"bulk_trash_duplicates_confirmation": "Are you sure you want to bulk trash {count, plural, one {# duplicate asset} other {# duplicate assets}}? This will keep the largest asset of each group and trash all other duplicates.",
"buy": "Purchase Immich",
- "cache_settings_clear_cache_button": "Clear cache",
- "cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
- "cache_settings_duplicated_assets_clear_button": "CLEAR",
- "cache_settings_duplicated_assets_subtitle": "Photos and videos that are ignore listed by the app",
- "cache_settings_duplicated_assets_title": "Duplicated Assets ({count})",
- "cache_settings_statistics_album": "Library thumbnails",
- "cache_settings_statistics_full": "Full images",
- "cache_settings_statistics_shared": "Shared album thumbnails",
- "cache_settings_statistics_thumbnail": "Thumbnails",
- "cache_settings_statistics_title": "Cache usage",
- "cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
- "cache_settings_tile_subtitle": "Control the local storage behaviour",
- "cache_settings_tile_title": "Local Storage",
- "cache_settings_title": "Caching Settings",
"camera": "Camera",
"camera_brand": "Camera brand",
"camera_model": "Camera model",
@@ -763,7 +662,6 @@
"change_date": "Change date",
"change_description": "Change description",
"change_display_order": "Change display order",
- "change_expiration_time": "Change expiration time",
"change_location": "Change location",
"change_name": "Change name",
"change_name_successfully": "Changed name successfully",
@@ -777,15 +675,10 @@
"change_password_form_password_mismatch": "Passwords do not match",
"change_password_form_reenter_new_password": "Re-enter New Password",
"change_pin_code": "Change PIN code",
- "change_trigger": "Change trigger",
- "change_trigger_prompt": "Are you sure you want to change the trigger? This will remove all existing actions and filters.",
"change_your_password": "Change your password",
"changed_visibility_successfully": "Changed visibility successfully",
"charging": "Charging",
"charging_requirement_mobile_backup": "Background backup requires the device to be charging",
- "check_corrupt_asset_backup": "Check for corrupt asset backups",
- "check_corrupt_asset_backup_button": "Perform check",
- "check_corrupt_asset_backup_description": "Run this check only over Wi-Fi and once all assets have been backed-up. The procedure might take a few minutes.",
"check_logs": "Check Logs",
"checksum": "Checksum",
"choose": "Choose",
@@ -810,8 +703,6 @@
"clear_file_cache": "Clear File Cache",
"clear_message": "Clear message",
"clear_value": "Clear value",
- "client_cert_dialog_msg_confirm": "OK",
- "client_cert_enter_password": "Enter Password",
"client_cert_import": "Import",
"client_cert_import_success_msg": "Client certificate is imported",
"client_cert_invalid_msg": "Invalid certificate file or wrong password",
@@ -820,12 +711,10 @@
"client_cert_remove_msg": "Client certificate is removed",
"client_cert_subtitle": "Supports PKCS12 (.p12, .pfx) format only. Certificate import/removal is available only before login",
"client_cert_title": "SSL client certificate [EXPERIMENTAL]",
- "clockwise": "Сlockwise",
"close": "Close",
"collapse": "Collapse",
"collapse_all": "Collapse all",
"color": "Color",
- "color_theme": "Color theme",
"command": "Command",
"command_palette_prompt": "Quickly find pages, actions, or commands",
"command_palette_to_close": "to close",
@@ -854,18 +743,13 @@
"context": "Context",
"continue": "Continue",
"control_bottom_app_bar_add_tags": "Add Tags",
- "control_bottom_app_bar_create_new_album": "Create new album",
- "control_bottom_app_bar_delete_from_immich": "Delete from Immich",
"control_bottom_app_bar_delete_from_local": "Delete from device",
"control_bottom_app_bar_edit_location": "Edit Location",
"control_bottom_app_bar_edit_time": "Edit Date & Time",
- "control_bottom_app_bar_share_link": "Share Link",
- "control_bottom_app_bar_share_to": "Share To",
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
"copied_image_to_clipboard": "Copied image to clipboard.",
"copied_to_clipboard": "Copied to clipboard!",
"copy_error": "Copy error",
- "copy_file_path": "Copy file path",
"copy_image": "Copy Image",
"copy_json": "Copy JSON",
"copy_link": "Copy link",
@@ -885,7 +769,6 @@
"create_link_to_share": "Create link to share",
"create_link_to_share_description": "Let anyone with the link see the selected photo(s)",
"create_new": "CREATE NEW",
- "create_new_face": "Create new face",
"create_new_person": "Create new person",
"create_new_person_hint": "Assign selected assets to a new person",
"create_new_user": "Create new user",
@@ -902,11 +785,9 @@
"created_at": "Created",
"creating_linked_albums": "Creating linked albums...",
"crop": "Crop",
- "crop_aspect_ratio_fixed": "Fixed",
"crop_aspect_ratio_free": "Free",
"crop_aspect_ratio_original": "Original",
"crop_aspect_ratio_square": "Square",
- "curated_object_page_title": "Things",
"current_device": "Current device",
"current_pin_code": "Current PIN code",
"current_server_address": "Current server address",
@@ -930,8 +811,6 @@
"day": "Day",
"days": "Days",
"deduplicate_all": "Deduplicate All",
- "default_locale": "Default Locale",
- "default_locale_description": "Format dates and numbers based on your browser locale",
"default_quality_subtitle": "Quality used when tapping share. Long press the share button to choose each time.",
"default_share_quality": "Default share quality",
"delete": "Delete",
@@ -942,8 +821,6 @@
"delete_dialog_alert": "These items will be permanently deleted from Immich and from your device",
"delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server",
"delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device",
- "delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server",
- "delete_dialog_ok_force": "Delete Anyway",
"delete_dialog_title": "Delete Permanently",
"delete_duplicates_confirmation": "Are you sure you want to permanently delete these duplicates?",
"delete_face": "Delete face",
@@ -962,21 +839,16 @@
"delete_tag_confirmation_prompt": "Are you sure you want to delete {tagName} tag?",
"delete_user": "Delete user",
"deleted_shared_link": "Deleted shared link",
- "deletes_missing_assets": "Deletes assets missing from disk",
"description": "Description",
- "description_input_hint_text": "Add description...",
- "description_input_submit_error": "Error updating description, check the log for more details",
"deselect_all": "Deselect All",
"details": "Details",
"direction": "Direction",
"disable": "Disable",
"disabled": "Disabled",
- "disallow_edits": "Disallow edits",
"discord": "Discord",
"discover": "Discover",
"discovered_devices": "Discovered devices",
"dismiss_all_errors": "Dismiss all errors",
- "dismiss_error": "Dismiss error",
"display_options": "Display options",
"display_order": "Display order",
"display_original_photos": "Display original photos",
@@ -985,11 +857,9 @@
"documentation": "Documentation",
"done": "Done",
"download": "Download",
- "download_action_prompt": "Downloading {count} assets",
"download_canceled": "Download canceled",
"download_complete": "Download complete",
"download_enqueue": "Download enqueued",
- "download_error": "Download Error",
"download_failed": "Download failed",
"download_finished": "Download finished",
"download_include_embedded_motion_videos": "Embedded videos",
@@ -999,9 +869,6 @@
"download_paused": "Download paused",
"download_settings": "Download",
"download_settings_description": "Manage settings related to asset download",
- "download_started": "Download started",
- "download_sucess": "Download success",
- "download_sucess_android": "The media has been downloaded to DCIM/Immich",
"download_waiting_to_retry": "Waiting to retry",
"downloading": "Downloading",
"downloading_asset_filename": "Downloading asset {filename}",
@@ -1022,9 +889,7 @@
"edit_date_and_time": "Edit date and time",
"edit_date_and_time_action_prompt": "{count} date and time edited",
"edit_date_and_time_by_offset": "Change date by offset",
- "edit_date_and_time_by_offset_interval": "New date range: {from} - {to}",
"edit_description": "Edit description",
- "edit_description_prompt": "Please select a new description:",
"edit_exclusion_pattern": "Edit exclusion pattern",
"edit_faces": "Edit faces",
"edit_key": "Edit key",
@@ -1039,9 +904,6 @@
"edit_user": "Edit user",
"edit_workflow": "Edit workflow",
"editor": "Editor",
- "editor_close_without_save_prompt": "The changes will not be saved",
- "editor_close_without_save_title": "Close editor?",
- "editor_confirm_reset_all_changes": "Are you sure you want to reset all changes?",
"editor_discard_edits_confirm": "Discard edits",
"editor_discard_edits_prompt": "You have unsaved edits. Are you sure you want to discard them?",
"editor_discard_edits_title": "Discard edits?",
@@ -1070,9 +932,7 @@
"enter_your_pin_code": "Enter your PIN code",
"enter_your_pin_code_subtitle": "Enter your PIN code to access the locked folder",
"error": "Error",
- "error_change_sort_album": "Failed to change album sort order",
"error_delete_face": "Error deleting face from asset",
- "error_getting_places": "Error getting places",
"error_loading_albums": "Error loading albums",
"error_loading_image": "Error loading image",
"error_loading_partners": "Error loading partners: {error}",
@@ -1211,18 +1071,10 @@
"exif": "Exif",
"exif_bottom_sheet_description": "Add Description...",
"exif_bottom_sheet_description_error": "Error updating description",
- "exif_bottom_sheet_details": "DETAILS",
- "exif_bottom_sheet_location": "LOCATION",
"exif_bottom_sheet_no_description": "No description",
- "exif_bottom_sheet_people": "PEOPLE",
- "exif_bottom_sheet_person_add_person": "Add name",
"exit_slideshow": "Exit Slideshow",
"expand": "Expand",
"expand_all": "Expand all",
- "experimental_settings_new_asset_list_subtitle": "Work in progress",
- "experimental_settings_new_asset_list_title": "Enable experimental photo grid",
- "experimental_settings_subtitle": "Use at your own risk!",
- "experimental_settings_title": "Experimental",
"expire_after": "Expire after",
"expired": "Expired",
"expires_date": "Expires {date}",
@@ -1250,10 +1102,8 @@
"favorite_action_prompt": "{count} added to Favorites",
"favorite_or_unfavorite_photo": "Favorite or unfavorite photo",
"favorites": "Favorites",
- "favorites_page_no_favorites": "No favorite assets found",
"feature_photo_updated": "Feature photo updated",
"features": "Features",
- "features_in_development": "Features in Development",
"features_setting_description": "Manage the app features",
"file_name_or_extension": "File name or extension",
"file_name_text": "File name",
@@ -1261,12 +1111,10 @@
"filename": "Filename",
"filetype": "Filetype",
"filter": "Filter",
- "filter_description": "Conditions to filter the target assets",
"filter_people": "Filter people",
"filter_places": "Filter places",
"filter_tags": "Filter tags",
"filters": "Filters",
- "find_them_fast": "Find them fast by name with search",
"first": "First",
"fix_incorrect_match": "Fix incorrect match",
"focal_length": "Focal Length",
@@ -1301,7 +1149,6 @@
"group_owner": "Group by owner",
"group_places_by": "Group places by...",
"group_year": "Group by year",
- "haptic_feedback_switch": "Enable haptic feedback",
"haptic_feedback_title": "Haptic Feedback",
"has_quota": "Has quota",
"hash_asset": "Hash asset",
@@ -1322,29 +1169,12 @@
"hide_schema": "Hide schema",
"hide_text_recognition": "Hide text recognition",
"hide_unnamed_people": "Hide unnamed people",
- "home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
- "home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
- "home_page_add_to_album_success": "Added {added} assets to album {album}.",
- "home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
- "home_page_archive_err_local": "Can not archive local assets yet, skipping",
- "home_page_archive_err_partner": "Can not archive partner assets, skipping",
"home_page_building_timeline": "Building the timeline",
- "home_page_delete_err_partner": "Can not delete partner assets, skipping",
- "home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
- "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
- "home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
- "home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album so that the timeline can populate photos and videos in it",
- "home_page_locked_error_local": "Can not move local assets to locked folder, skipping",
- "home_page_locked_error_partner": "Can not move partner assets to locked folder, skipping",
- "home_page_share_err_local": "Can not share local assets via link, skipping",
- "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"host": "Host",
"hour": "Hour",
"hours": "Hours",
"id": "ID",
"idle": "Idle",
- "ignore_icloud_photos": "Ignore iCloud photos",
- "ignore_icloud_photos_description": "Photos that are stored on iCloud will not be uploaded to the Immich server",
"image": "Image",
"image_alt_text_date": "{isVideo, select, true {Video} other {Image}} taken on {date}",
"image_alt_text_date_1_person": "{isVideo, select, true {Video} other {Image}} taken with {person1} on {date}",
@@ -1356,10 +1186,6 @@
"image_alt_text_date_place_2_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1} and {person2} on {date}",
"image_alt_text_date_place_3_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1}, {person2}, and {person3} on {date}",
"image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1}, {person2}, and {additionalCount, number} others on {date}",
- "image_saved_successfully": "Image saved",
- "image_viewer_page_state_provider_download_started": "Download Started",
- "image_viewer_page_state_provider_download_success": "Download Success",
- "image_viewer_page_state_provider_share_error": "Share Error",
"immich_logo": "Immich Logo",
"immich_web_interface": "Immich Web Interface",
"import_from_json": "Import from JSON",
@@ -1385,17 +1211,9 @@
"invalid_date_format": "Invalid date format",
"invite_people": "Invite People",
"invite_to_album": "Invite to album",
- "ios_debug_info_fetch_ran_at": "Fetch ran {dateTime}",
- "ios_debug_info_last_sync_at": "Last sync {dateTime}",
- "ios_debug_info_no_processes_queued": "No background processes queued",
- "ios_debug_info_no_sync_yet": "No background sync job has run yet",
- "ios_debug_info_processes_queued": "{count, plural, one {{count} background process queued} other {{count} background processes queued}}",
- "ios_debug_info_processing_ran_at": "Processing ran {dateTime}",
"iso": "ISO",
"items_count": "{count, plural, one {# item} other {# items}}",
"jobs": "Jobs",
- "json_editor": "JSON editor",
- "json_error": "JSON error",
"keep": "Keep",
"keep_albums": "Keep albums",
"keep_albums_count": "Keeping {count} {count, plural, one {album} other {albums}}",
@@ -1428,9 +1246,6 @@
"library": "Library",
"library_add_folder": "Add folder",
"library_edit_folder": "Edit folder",
- "library_options": "Library options",
- "library_page_device_albums": "Albums on Device",
- "library_page_new_album": "New album",
"library_page_sort_asset_count": "Number of assets",
"library_page_sort_created": "Created date",
"library_page_sort_last_modified": "Last modified",
@@ -1476,11 +1291,9 @@
"login": "Login",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
- "login_form_back_button_text": "Back",
"login_form_email_hint": "youremail@email.com",
"login_form_endpoint_hint": "http://your-server-ip:port",
"login_form_endpoint_url": "Server Endpoint URL",
- "login_form_err_http": "Please specify http:// or https://",
"login_form_err_invalid_email": "Invalid Email",
"login_form_err_invalid_url": "Invalid URL",
"login_form_err_leading_whitespace": "Leading whitespace",
@@ -1490,7 +1303,6 @@
"login_form_failed_login": "Error logging you in, check server URL, email and password",
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
"login_form_password_hint": "password",
- "login_form_save_login": "Stay logged in",
"login_form_server_empty": "Enter a server URL.",
"login_form_server_error": "Could not connect to server.",
"login_has_been_disabled": "Login has been disabled.",
@@ -1508,7 +1320,6 @@
"maintenance_action_restore": "Restoring Database",
"maintenance_description": "Immich has been put into maintenance mode.",
"maintenance_end": "End maintenance mode",
- "maintenance_end_error": "Failed to end maintenance mode.",
"maintenance_logged_in_as": "Currently logged in as {user}",
"maintenance_restore_from_backup": "Restore From Backup",
"maintenance_restore_library": "Restore Your Library",
@@ -1534,7 +1345,6 @@
"manage_media_access_settings": "Open settings",
"manage_media_access_subtitle": "Allow the Immich app to manage and move media files.",
"manage_media_access_title": "Media Management Access",
- "manage_shared_links": "Manage shared links",
"manage_sharing_with_partners": "Manage sharing with partners",
"manage_the_app_settings": "Manage the app settings",
"manage_your_account": "Manage your account",
@@ -1542,9 +1352,7 @@
"manage_your_devices": "Manage your logged-in devices",
"manage_your_oauth_connection": "Manage your OAuth connection",
"map": "Map",
- "map_assets_in_bounds": "{count, plural, =0 {No photos in this area} one {# photo} other {# photos}}",
"map_cannot_get_user_location": "Cannot get user's location",
- "map_location_dialog_yes": "Yes",
"map_location_picker_page_use_location": "Use this location",
"map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?",
"map_location_service_disabled_title": "Location Service disabled",
@@ -1558,14 +1366,11 @@
"map_settings_date_range_option_days": "Past {days} days",
"map_settings_date_range_option_year": "Past year",
"map_settings_date_range_option_years": "Past {years} years",
- "map_settings_dialog_title": "Map Settings",
"map_settings_include_show_archived": "Include Archived",
"map_settings_include_show_partners": "Include Partners",
"map_settings_only_show_favorites": "Show Favorite Only",
"map_settings_theme_settings": "Map Theme",
- "map_zoom_to_see_photos": "Zoom out to see photos",
"mark_all_as_read": "Mark all as read",
- "mark_as_read": "Mark as read",
"marked_all_as_read": "Marked all as read",
"matches": "Matches",
"matching_assets": "Matching Assets",
@@ -1622,8 +1427,6 @@
"minimize": "Minimize",
"minute": "Minute",
"minutes": "Minutes",
- "mirror_horizontal": "Horizontal",
- "mirror_vertical": "Vertical",
"missing": "Missing",
"mobile_app": "Mobile App",
"mobile_app_download_onboarding_note": "Download the companion mobile app using the following options",
@@ -1633,19 +1436,13 @@
"more": "More",
"motion": "Motion",
"move": "Move",
- "move_down": "Move down",
"move_off_locked_folder": "Move out of locked folder",
"move_to": "Move to",
"move_to_device_trash": "Move to device trash",
"move_to_lock_folder_action_prompt": "{count} added to the locked folder",
"move_to_locked_folder": "Move to locked folder",
"move_to_locked_folder_confirmation": "These photos and video will be removed from all albums, and only viewable from the locked folder",
- "move_up": "Move up",
- "moved_to_archive": "Moved {count, plural, one {# asset} other {# assets}} to archive",
- "moved_to_library": "Moved {count, plural, one {# asset} other {# assets}} to library",
"moved_to_trash": "Moved to trash",
- "multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
- "multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
"mute_memories": "Mute Memories",
"my_albums": "My albums",
"my_immich_description": "Copy current page as a My Immich link",
@@ -1664,12 +1461,10 @@
"never": "Never",
"new_album": "New Album",
"new_api_key": "New API Key",
- "new_date_range": "New date range",
"new_password": "New password",
"new_person": "New person",
"new_pin_code": "New PIN code",
"new_pin_code_subtitle": "This is your first time accessing the locked folder. Create a PIN code to securely access this page",
- "new_timeline": "New Timeline",
"new_update": "New update",
"new_user_created": "New user created",
"new_version_available": "NEW VERSION AVAILABLE",
@@ -1687,7 +1482,6 @@
"no_cast_devices_found": "No cast devices found",
"no_checksum_local": "No checksum available - cannot fetch local assets",
"no_checksum_remote": "No checksum available - cannot fetch remote asset",
- "no_configuration_needed": "No configuration needed",
"no_devices": "No authorized devices",
"no_duplicates_found": "No duplicates were found.",
"no_exif_info_available": "No exif info available",
@@ -1695,7 +1489,6 @@
"no_favorites_message": "Add favorites to quickly find your best pictures and videos",
"no_libraries_message": "Create an external library to view your photos and videos",
"no_local_assets_found": "No local assets found with this checksum",
- "no_location_set": "No location set",
"no_locked_photos_message": "Photos and videos in the locked folder are hidden and won't show up as you browse or search your library.",
"no_name": "No Name",
"no_notifications": "No notifications",
@@ -1706,7 +1499,6 @@
"no_results_description": "Try a synonym or more general keyword",
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
"no_steps": "No steps added yet",
- "no_uploads_in_progress": "No uploads in progress",
"none": "None",
"not_allowed": "Not allowed",
"not_available": "N/A",
@@ -1756,7 +1548,6 @@
"original": "original",
"other": "Other",
"other_devices": "Other devices",
- "other_entities": "Other entities",
"other_variables": "Other variables",
"owned": "Owned",
"owner": "Owner",
@@ -1766,12 +1557,9 @@
"partner_can_access_assets": "All your photos and videos except those in Archived and Deleted",
"partner_can_access_location": "The location where your photos were taken",
"partner_list_user_photos": "{user}'s photos",
- "partner_list_view_all": "View all",
"partner_page_empty_message": "Your photos are not yet shared with any partner.",
"partner_page_no_more_users": "No more users to add",
- "partner_page_partner_add_failed": "Failed to add partner",
"partner_page_select_partner": "Select partner",
- "partner_page_shared_to_title": "Shared to",
"partner_page_stop_sharing_content": "{partner} will no longer be able to access your photos.",
"partner_sharing": "Partner Sharing",
"partners": "Partners",
@@ -1793,8 +1581,6 @@
"people": "People",
"people_edits_count": "Edited {count, plural, one {# person} other {# people}}",
"people_feature_description": "Browsing photos and videos grouped by people",
- "people_selected": "{count, plural, one {# person selected} other {# people selected}}",
- "people_sidebar_description": "Display a link to People in the sidebar",
"permanent_deletion_warning": "Permanent deletion warning",
"permanent_deletion_warning_setting_description": "Show a warning when permanently deleting assets",
"permanently_delete": "Permanently delete",
@@ -1804,14 +1590,6 @@
"permanently_deleted_assets_count": "Permanently deleted {count, plural, one {# asset} other {# assets}}",
"permission": "Permission",
"permission_empty": "Your permission shouldn't be empty",
- "permission_onboarding_back": "Back",
- "permission_onboarding_continue_anyway": "Continue anyway",
- "permission_onboarding_get_started": "Get started",
- "permission_onboarding_go_to_settings": "Go to settings",
- "permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
- "permission_onboarding_permission_granted": "Permission granted! You are all set.",
- "permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
- "permission_onboarding_request": "Immich requires permission to view your photos and videos.",
"person": "Person",
"person_age_months": "{months, plural, one {# month} other {# months}} old",
"person_age_year_months": "1 year, {months, plural, one {# month} other {# months}} old",
@@ -1819,13 +1597,10 @@
"person_birthdate": "Born on {date}",
"person_hidden": "{name}{hidden, select, true { (hidden)} other {}}",
"person_recognized": "Person recognized",
- "person_selected": "Person selected",
"photo_shared_all_users": "Looks like you shared your photos with all users or you don't have any user to share with.",
"photos": "Photos",
"photos_and_videos": "Photos & Videos",
- "photos_count": "{count, plural, one {{count, number} Photo} other {{count, number} Photos}}",
"photos_from_previous_years": "Photos from previous years",
- "photos_only": "Photos only",
"pick_a_location": "Pick a location",
"pick_custom_range": "Custom range",
"pick_date_range": "Select a date range",
@@ -1862,7 +1637,6 @@
"privacy": "Privacy",
"profile": "Profile",
"profile_drawer_app_logs": "Logs",
- "profile_drawer_client_server_up_to_date": "Client and Server are up-to-date",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Read-only mode enabled. Long-press the user avatar icon to exit.",
"profile_image_of_user": "Profile image of {user}",
@@ -1886,7 +1660,6 @@
"purchase_individual_description_2": "Supporter status",
"purchase_individual_title": "Individual",
"purchase_input_suggestion": "Have a product key? Enter the key below",
- "purchase_license_subtitle": "Buy Immich to support the continued development of the service",
"purchase_lifetime_description": "Lifetime purchase",
"purchase_option_title": "PURCHASE OPTIONS",
"purchase_panel_info_1": "Building Immich takes a lot of time and effort, and we have full-time engineers working on it to make it as good as we possibly can. Our mission is for open-source software and ethical business practices to become a sustainable income source for developers and to create a privacy-respecting ecosystem with real alternatives to exploitative cloud services.",
@@ -1919,19 +1692,16 @@
"reassigned_assets_to_new_person": "Re-assigned {count, plural, one {# asset} other {# assets}} to a new person",
"reassing_hint": "Assign selected assets to an existing person",
"recent": "Recent",
- "recent_albums": "Recent albums",
"recent_searches": "Recent searches",
"recently_added": "Recently added",
"recently_added_page_title": "Recently Added",
"recently_taken": "Recently taken",
- "recently_taken_page_title": "Recently Taken",
"refresh": "Refresh",
"refresh_encoded_videos": "Refresh encoded videos",
"refresh_faces": "Refresh faces",
"refresh_metadata": "Refresh metadata",
"refresh_thumbnails": "Refresh thumbnails",
"refreshed": "Refreshed",
- "refreshes_every_file": "Re-reads all existing and new files",
"refreshing_encoded_video": "Refreshing encoded video",
"refreshing_faces": "Refreshing faces",
"refreshing_metadata": "Refreshing metadata",
@@ -1944,7 +1714,6 @@
"remove_assets_shared_link_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from this shared link?",
"remove_assets_title": "Remove assets?",
"remove_custom_date_range": "Remove custom date range",
- "remove_deleted_assets": "Remove Deleted Assets",
"remove_filter": "Remove filter",
"remove_from_album": "Remove from album",
"remove_from_album_action_prompt": "{count} removed from the album",
@@ -1956,29 +1725,22 @@
"remove_memory": "Remove memory",
"remove_photo_from_memory": "Remove photo from this memory",
"remove_tag": "Remove tag",
- "remove_url": "Remove URL",
"remove_user": "Remove user",
"removed_api_key": "Removed API Key: {name}",
"removed_from_archive": "Removed from archive",
"removed_from_favorites": "Removed from favorites",
"removed_from_favorites_count": "{count, plural, other {Removed #}} from favorites",
"removed_memory": "Removed memory",
- "removed_photo_from_memory": "Removed photo from memory",
"removed_tagged_assets": "Removed tag from {count, plural, one {# asset} other {# assets}}",
"rename": "Rename",
- "repair": "Repair",
- "repair_no_results_message": "Untracked and missing files will show up here",
- "replace_with_upload": "Replace with upload",
"repository": "Repository",
"require_password": "Require password",
- "require_user_to_change_password_on_first_login": "Require user to change password on first login",
"rescan": "Rescan",
"reset": "Reset",
"reset_password": "Reset password",
"reset_people_visibility": "Reset people visibility",
"reset_pin_code": "Reset PIN code",
"reset_pin_code_description": "If you forgot your PIN code, you can contact the server administrator to reset it",
- "reset_pin_code_success": "Successfully reset PIN code",
"reset_pin_code_with_password": "You can always reset your PIN code with your password",
"reset_sqlite": "Reset SQLite Database",
"reset_sqlite_clear_app_data": "Clear Data",
@@ -1992,12 +1754,10 @@
"resolved_all_duplicates": "Resolved all duplicates",
"restore": "Restore",
"restore_all": "Restore all",
- "restore_trash_action_prompt": "{count} restored from trash",
"restore_user": "Restore user",
"restored_asset": "Restored asset",
"resume": "Resume",
"resume_paused_jobs": "Resume {count, plural, one {# paused job} other {# paused jobs}}",
- "retry_upload": "Retry upload",
"review_duplicates": "Review duplicates",
"review_large_files": "Review large files",
"role": "Role",
@@ -2005,7 +1765,6 @@
"role_viewer": "Viewer",
"running": "Running",
"save": "Save",
- "save_to_gallery": "Save to gallery",
"saved": "Saved",
"saved_api_key": "Saved API Key",
"saved_profile": "Saved profile",
@@ -2016,7 +1775,6 @@
"scan": "Scan",
"scan_all_libraries": "Scan All Libraries",
"scan_library": "Scan",
- "scan_settings": "Scan Settings",
"scanning": "Scanning",
"scanning_for_album": "Scanning for album...",
"screencast_mode_description": "Show keyboard and mouse event indicators on the screen",
@@ -2049,7 +1807,6 @@
"search_filter_location_title": "Select location",
"search_filter_media_type": "Media Type",
"search_filter_media_type_title": "Select media type",
- "search_filter_ocr": "Search by OCR",
"search_filter_people_title": "Select people",
"search_filter_star_rating": "Star Rating",
"search_filter_tags_title": "Select tags",
@@ -2060,25 +1817,13 @@
"search_no_people_named": "No people named \"{name}\"",
"search_no_result": "No results found, try a different search term or combination",
"search_options": "Search options",
- "search_page_categories": "Categories",
- "search_page_motion_photos": "Motion Photos",
- "search_page_no_objects": "No Objects Info Available",
- "search_page_no_places": "No Places Info Available",
- "search_page_screenshots": "Screenshots",
"search_page_search_photos_videos": "Search for your photos and videos",
- "search_page_selfies": "Selfies",
- "search_page_things": "Things",
"search_page_view_all_button": "View all",
- "search_page_your_activity": "Your activity",
- "search_page_your_map": "Your Map",
"search_people": "Search people",
"search_places": "Search places",
"search_rating": "Search by rating...",
- "search_result_page_new_search_hint": "New Search",
"search_settings": "Search settings",
"search_state": "Search state...",
- "search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
- "search_suggestion_list_smart_search_hint_2": "m:your-search-term",
"search_tags": "Search tags...",
"search_timezone": "Search timezone...",
"search_type": "Search type",
@@ -2092,7 +1837,6 @@
"select_albums": "Select albums",
"select_all": "Select all",
"select_all_duplicates": "Select all duplicates",
- "select_all_in": "Select all in {group}",
"select_avatar_color": "Select avatar color",
"select_count": "{count, plural, one {Select #} other {Select #}}",
"select_cutoff_date": "Select cutoff date",
@@ -2100,7 +1844,6 @@
"select_featured_photo": "Select featured photo",
"select_from_computer": "Select from computer",
"select_keep_all": "Select keep all",
- "select_library_owner": "Select library owner",
"select_new_face": "Select new face",
"select_people": "Select people",
"select_person": "Select person",
@@ -2108,7 +1851,6 @@
"select_photos": "Select photos",
"select_quality": "Select quality",
"select_trash_all": "Select trash all",
- "select_user_for_sharing_page_err_album": "Failed to create album",
"selected": "Selected",
"selected_count": "{count, plural, other {# selected}}",
"selected_gps_coordinates": "Selected GPS Coordinates",
@@ -2141,33 +1883,20 @@
"setting_image_viewer_original_title": "Load original image",
"setting_image_viewer_preview_subtitle": "Enable to load a medium-resolution image. Disable to either directly load the original or only use the thumbnail.",
"setting_image_viewer_preview_title": "Load preview image",
- "setting_image_viewer_title": "Images",
"setting_languages_apply": "Apply",
"setting_languages_subtitle": "Change the app's language",
- "setting_notifications_notify_failures_grace_period": "Notify background backup failures: {duration}",
- "setting_notifications_notify_hours": "{count} hours",
- "setting_notifications_notify_immediately": "immediately",
"setting_notifications_notify_minutes": "{count} minutes",
- "setting_notifications_notify_never": "never",
"setting_notifications_notify_seconds": "{count} seconds",
- "setting_notifications_single_progress_subtitle": "Detailed upload progress information per asset",
- "setting_notifications_single_progress_title": "Show background backup detail progress",
"setting_notifications_subtitle": "Adjust your notification preferences",
- "setting_notifications_total_progress_subtitle": "Overall upload progress (done/total assets)",
- "setting_notifications_total_progress_title": "Show background backup total progress",
"setting_video_viewer_auto_play_subtitle": "Automatically start playing videos when they are opened",
"setting_video_viewer_auto_play_title": "Auto play videos",
"setting_video_viewer_looping_title": "Looping",
"setting_video_viewer_original_video_subtitle": "When streaming a video from the server, play the original even when a transcode is available. May lead to buffering. Videos available locally are played in original quality regardless of this setting.",
"setting_video_viewer_original_video_title": "Force original video",
"settings": "Settings",
- "settings_require_restart": "Please restart Immich to apply this setting",
"settings_saved": "Settings saved",
"setup_pin_code": "Setup a PIN code",
"share": "Share",
- "share_action_prompt": "Shared {count} assets",
- "share_add_photos": "Add photos",
- "share_assets_selected": "{count} selected",
"share_dialog_preparing": "Preparing...",
"share_link": "Share Link",
"share_original": "Use original (large)",
@@ -2177,8 +1906,6 @@
"shared_album_activity_remove_content": "Do you want to delete this activity?",
"shared_album_activity_remove_title": "Delete Activity",
"shared_album_section_people_action_error": "Error leaving/removing from album",
- "shared_album_section_people_action_leave": "Remove user from album",
- "shared_album_section_people_action_remove_user": "Remove user from album",
"shared_album_section_people_title": "PEOPLE",
"shared_by": "Shared by",
"shared_by_user": "Shared by {user}",
@@ -2187,7 +1914,6 @@
"shared_intent_upload_button_progress_text": "{current} / {total} Uploaded",
"shared_link_app_bar_title": "Shared Links",
"shared_link_clipboard_copied_massage": "Copied to clipboard",
- "shared_link_clipboard_text": "Link: {link}\nPassword: {password}",
"shared_link_create_error": "Error while creating shared link",
"shared_link_custom_url_description": "Access this shared link with a custom URL",
"shared_link_edit_description_hint": "Enter the share description",
@@ -2223,12 +1949,6 @@
"shared_with_partner": "Shared with {partner}",
"sharing": "Sharing",
"sharing_enter_password": "Please enter the password to view this page.",
- "sharing_page_album": "Shared albums",
- "sharing_page_description": "Create shared albums to share photos and videos with people in your network.",
- "sharing_page_empty_list": "EMPTY LIST",
- "sharing_sidebar_description": "Display a link to Sharing in the sidebar",
- "sharing_silver_appbar_create_shared_album": "New shared album",
- "sharing_silver_appbar_share_partner": "Share with partner",
"shift_to_permanent_delete": "press ⇧ to permanently delete asset",
"show_album_options": "Show album options",
"show_albums": "Show albums",
@@ -2278,7 +1998,6 @@
"sort_created": "Date created",
"sort_items": "Number of items",
"sort_modified": "Date modified",
- "sort_newest": "Newest photo",
"sort_oldest": "Oldest photo",
"sort_people_by_similarity": "Sort people by similarity",
"sort_recent": "Most recent photo",
@@ -2287,7 +2006,6 @@
"stack": "Stack",
"stack_action_prompt": "{count} stacked",
"stack_duplicates": "Stack duplicates",
- "stack_select_one_photo": "Select one main photo for the stack",
"stack_selected_photos": "Stack selected photos",
"stacked_assets_count": "Stacked {count, plural, one {# asset} other {# assets}}",
"stacktrace": "Stacktrace",
@@ -2300,7 +2018,6 @@
"step_delete_confirm": "Are you sure you want to delete this step?",
"step_details": "Step details",
"steps": "Steps",
- "steps_count": "{count, plural, one {# step} other {# steps}}",
"stop_casting": "Stop casting",
"stop_motion_photo": "Stop Motion Photo",
"stop_photo_sharing": "Stop sharing your photos?",
@@ -2321,7 +2038,6 @@
"swap_merge_direction": "Swap merge direction",
"sync": "Sync",
"sync_albums": "Sync albums",
- "sync_albums_manual_subtitle": "Sync all uploaded videos and photos to the selected backup albums",
"sync_local": "Sync Local",
"sync_remote": "Sync Remote",
"sync_status": "Sync Status",
@@ -2334,7 +2050,6 @@
"tag_created": "Created tag: {tag}",
"tag_face": "Tag face",
"tag_feature_description": "Browsing photos and videos grouped by logical tag topics",
- "tag_not_found_question": "Cannot find a tag? Create a new tag.",
"tag_people": "Tag People",
"tag_updated": "Updated tag: {tag}",
"tagged_assets": "Tagged {count, plural, one {# asset} other {# assets}}",
@@ -2349,15 +2064,10 @@
"theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({count})",
"theme_setting_colorful_interface_subtitle": "Apply primary color to background surfaces.",
"theme_setting_colorful_interface_title": "Colorful interface",
- "theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer",
- "theme_setting_image_viewer_quality_title": "Image viewer quality",
"theme_setting_primary_color_subtitle": "Pick a color for primary actions and accents.",
"theme_setting_primary_color_title": "Primary color",
"theme_setting_system_primary_color_title": "Use system color",
"theme_setting_system_theme_switch": "Automatic (Follow system setting)",
- "theme_setting_theme_subtitle": "Choose the app's theme setting",
- "theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
- "theme_setting_three_stage_loading_title": "Enable three-stage loading",
"then": "Then",
"they_will_be_merged_together": "They will be merged together",
"third_party_resources": "Third-Party Resources",
@@ -2383,25 +2093,17 @@
"trash_all": "Trash All",
"trash_count": "Trash {count, number}",
"trash_delete_asset": "Trash/Delete Asset",
- "trash_emptied": "Emptied trash",
"trash_no_results_message": "Trashed photos and videos will show up here.",
"trash_page_delete_all": "Delete All",
- "trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich",
"trash_page_info": "Trashed items will be permanently deleted after {days} days",
- "trash_page_no_assets": "No trashed assets",
- "trash_page_restore_all": "Restore All",
- "trash_page_select_assets_btn": "Select assets",
- "trash_page_title": "Trash ({count})",
"trashed_items_will_be_permanently_deleted_after": "Trashed items will be permanently deleted after {days, plural, one {# day} other {# days}}.",
"trigger": "Trigger",
"trigger_asset_metadata_extraction": "Asset Metadata Extraction",
"trigger_asset_metadata_extraction_description": "Triggered when the EXIF metadata of an asset is extracted",
"trigger_asset_uploaded": "Asset Upload",
"trigger_asset_uploaded_description": "Triggered when a new asset is uploaded",
- "trigger_description": "An event that kicks off the workflow",
"trigger_person_recognized": "Person Recognized",
"trigger_person_recognized_description": "Triggered when a person is recognized",
- "trigger_type": "Trigger type",
"troubleshoot": "Troubleshoot",
"type": "Type",
"unable_to_change_pin_code": "Unable to change PIN code",
@@ -2429,7 +2131,6 @@
"unsaved_change": "Unsaved change",
"unselect_all": "Unselect all",
"unselect_all_duplicates": "Unselect all duplicates",
- "unselect_all_in": "Unselect all in {group}",
"unstack": "Un-stack",
"unstack_action_prompt": "{count} unstacked",
"unstacked_assets_count": "Un-stacked {count, plural, one {# asset} other {# assets}}",
@@ -2444,8 +2145,6 @@
"upload_concurrency": "Upload concurrency",
"upload_day_count": "{date}: {count, plural, one {# upload} other {# uploads}}",
"upload_details": "Upload Details",
- "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
- "upload_dialog_title": "Upload Asset",
"upload_error_with_count": "Upload error for {count, plural, one {# asset} other {# assets}}",
"upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.",
"upload_finished": "Upload finished",
@@ -2477,7 +2176,6 @@
"user_privacy": "User Privacy",
"user_purchase_settings": "Purchase",
"user_purchase_settings_description": "Manage your purchase",
- "user_role_set": "Set {user} as {role}",
"user_usage_detail": "User usage detail",
"user_usage_stats": "Account usage statistics",
"user_usage_stats_description": "View account usage statistics",
@@ -2487,7 +2185,6 @@
"utilities": "Utilities",
"validate": "Validate",
"validate_endpoint_error": "Please enter a valid URL",
- "validation_error": "Validation error",
"variables": "Variables",
"version": "Version",
"version_announcement_closing": "Your friend, Alex",
@@ -2500,7 +2197,6 @@
"video_quality": "Video quality",
"videos": "Videos",
"videos_count": "{count, plural, one {# Video} other {# Videos}}",
- "videos_only": "Videos only",
"view": "View",
"view_album": "View Album",
"view_all": "View All",
@@ -2509,21 +2205,16 @@
"view_details": "View Details",
"view_in_timeline": "View in timeline",
"view_link": "View link",
- "view_links": "View links",
"view_name": "View",
"view_next_asset": "View next asset",
"view_previous_asset": "View previous asset",
"view_qr_code": "View QR code",
"view_similar_photos": "View similar photos",
"view_stack": "View Stack",
- "view_user": "View User",
"viewer_remove_from_stack": "Remove from Stack",
- "viewer_stack_use_as_main_asset": "Use as Main Asset",
- "viewer_unstack": "Un-Stack",
"visibility": "Visibility",
"visibility_changed": "Visibility changed for {count, plural, one {# person} other {# people}}",
"visual": "Visual",
- "visual_builder": "Visual builder",
"waiting": "Waiting",
"waiting_count": "Waiting: {count}",
"warning": "Warning",
@@ -2545,7 +2236,6 @@
"workflow_summary": "Workflow summary",
"workflow_templates": "Workflow templates",
"workflow_update_success": "Workflow updated successfully",
- "workflow_updated": "Workflow updated",
"workflows": "Workflows",
"workflows_help_text": "Workflows automate actions on your assets based on triggers and filters",
"wrong_pin_code": "Wrong PIN code",
@@ -2556,6 +2246,5 @@
"you_dont_have_any_shared_links": "You don't have any shared links",
"your_wifi_name": "Your Wi-Fi name",
"zero_to_clear_rating": "press 0 to clear asset rating",
- "zoom_image": "Zoom Image",
- "zoom_to_bounds": "Zoom to bounds"
+ "zoom_image": "Zoom Image"
}
From f4c8459484f4548f6db38bdd6b646922bd0dfaf5 Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Tue, 23 Jun 2026 22:20:57 +0530
Subject: [PATCH 027/435] feat: mobile actions (#29280)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
mobile/lib/presentation/actions/action.dart | 14 ++++
.../presentation/actions/action.widget.dart | 81 +++++++++++++++++++
mobile/lib/utils/error_handler.dart | 61 ++++++++++++++
3 files changed, 156 insertions(+)
create mode 100644 mobile/lib/presentation/actions/action.dart
create mode 100644 mobile/lib/presentation/actions/action.widget.dart
create mode 100644 mobile/lib/utils/error_handler.dart
diff --git a/mobile/lib/presentation/actions/action.dart b/mobile/lib/presentation/actions/action.dart
new file mode 100644
index 0000000000..419f97e9cb
--- /dev/null
+++ b/mobile/lib/presentation/actions/action.dart
@@ -0,0 +1,14 @@
+import 'package:flutter/material.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+
+abstract class BaseAction {
+ final IconData icon;
+
+ const BaseAction({required this.icon});
+
+ String label(BuildContext context);
+
+ bool isVisible(BuildContext context, WidgetRef ref);
+
+ Future onAction(BuildContext context, WidgetRef ref);
+}
diff --git a/mobile/lib/presentation/actions/action.widget.dart b/mobile/lib/presentation/actions/action.widget.dart
new file mode 100644
index 0000000000..6c0f513808
--- /dev/null
+++ b/mobile/lib/presentation/actions/action.widget.dart
@@ -0,0 +1,81 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/utils/error_handler.dart';
+import 'package:immich_ui/immich_ui.dart';
+
+class _ActionWidget extends ConsumerWidget {
+ final BaseAction action;
+ final Widget Function(Future Function() onAction) builder;
+
+ const _ActionWidget({required this.action, required this.builder});
+
+ Future _onAction(BuildContext context, WidgetRef ref) async {
+ try {
+ await action.onAction(context, ref);
+ } catch (error, stackTrace) {
+ handleError(context, error, stack: stackTrace, description: 'Action failed: ${action.runtimeType}');
+ }
+ }
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ if (!action.isVisible(context, ref)) {
+ return const SizedBox.shrink();
+ }
+
+ return builder(() => _onAction(context, ref));
+ }
+}
+
+class ActionIconButtonWidget extends StatelessWidget {
+ final BaseAction action;
+ final ImmichVariant variant;
+
+ const ActionIconButtonWidget({super.key, required this.action, this.variant = .ghost});
+
+ @override
+ Widget build(BuildContext context) => _ActionWidget(
+ action: action,
+ builder: (onAction) => ImmichIconButton(icon: action.icon, onPressed: onAction, variant: variant),
+ );
+}
+
+class ActionButtonWidget extends StatelessWidget {
+ final BaseAction action;
+ final ImmichVariant variant;
+
+ const ActionButtonWidget({super.key, required this.action, this.variant = .ghost});
+
+ @override
+ Widget build(BuildContext context) => _ActionWidget(
+ action: action,
+ builder: (onAction) =>
+ ImmichTextButton(labelText: action.label(context), icon: action.icon, onPressed: onAction, variant: variant),
+ );
+}
+
+class ActionColumnButtonWidget extends StatelessWidget {
+ final BaseAction action;
+
+ const ActionColumnButtonWidget({super.key, required this.action});
+
+ @override
+ Widget build(BuildContext context) => _ActionWidget(
+ action: action,
+ builder: (onAction) => ImmichColumnButton(icon: action.icon, label: action.label(context), onPressed: onAction),
+ );
+}
+
+class ActionMenuItemWidget extends StatelessWidget {
+ final BaseAction action;
+
+ const ActionMenuItemWidget({super.key, required this.action});
+
+ @override
+ Widget build(BuildContext context) => _ActionWidget(
+ action: action,
+ builder: (onAction) => ImmichMenuItem(icon: action.icon, label: action.label(context), onPressed: onAction),
+ );
+}
diff --git a/mobile/lib/utils/error_handler.dart b/mobile/lib/utils/error_handler.dart
new file mode 100644
index 0000000000..24387b8002
--- /dev/null
+++ b/mobile/lib/utils/error_handler.dart
@@ -0,0 +1,61 @@
+import 'dart:convert';
+
+import 'package:flutter/widgets.dart';
+import 'package:immich_mobile/generated/translations.g.dart';
+import 'package:immich_mobile/utils/debug_print.dart';
+import 'package:immich_ui/immich_ui.dart';
+import 'package:openapi/api.dart';
+// ignore: depend_on_referenced_packages
+import 'package:stack_trace/stack_trace.dart';
+
+void handleError(BuildContext context, Object error, {StackTrace? stack, String? description}) {
+ String? stackTrace;
+ if (stack != null) {
+ final trace = Trace.from(stack);
+ final clean = trace.foldFrames(
+ (frame) => frame.package == 'flutter' || frame.package == 'flutter_test' || frame.isCore,
+ terse: true,
+ );
+ stackTrace = clean.toString();
+ }
+
+ dPrint(
+ () => 'Error${description != null ? ' ($description)' : ''}: $error${stackTrace != null ? '\n$stackTrace' : ''}',
+ );
+
+ if (!context.mounted) {
+ return;
+ }
+
+ final String message;
+ if (serverErrorMessage(error) case String serverMessage) {
+ message = serverMessage;
+ } else if (isConnectionError(error)) {
+ message = context.t.login_form_server_error;
+ } else {
+ message = context.t.scaffold_body_error_occurred;
+ }
+
+ snackbar.error(message);
+}
+
+@visibleForTesting
+String? serverErrorMessage(Object error) {
+ if (error is! ApiException || error.innerException != null || error.message == null) {
+ return null;
+ }
+
+ try {
+ final body = jsonDecode(error.message!);
+ if (body is Map && body['message'] != null) {
+ final message = body['message'];
+ return message is List ? message.join(', ') : message.toString();
+ }
+ } catch (_) {
+ // The body was not JSON; fall back to the raw payload below.
+ }
+ return error.message;
+}
+
+@visibleForTesting
+bool isConnectionError(Object error) => error is ApiException && error.innerException != null;
From 5165cf1d2f37c4eabe306337f0a8a251be5f88fa Mon Sep 17 00:00:00 2001
From: okxint <130782884+okxint@users.noreply.github.com>
Date: Tue, 23 Jun 2026 23:13:56 +0530
Subject: [PATCH 028/435] fix(mobile): force AssetViewerPage recreation on
repeated view intents (#29235)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix(mobile): force AssetViewerPage recreation on repeated view intents
When View in Immich is triggered a second time while the viewer is
already open, auto_route's replaceAll reuses the existing route (same
type, null key) and Flutter keeps the old ConsumerState alive. The
PageController and preloader inside _AssetViewerState are late final,
so they never reset — the viewer stays frozen on the previous asset.
Passing UniqueKey() to AssetViewerRoute ensures each view intent
creates a fresh widget element, so initState runs, the PageController
is initialised from scratch, and the new TimelineService from the
updated ProviderScope override is picked up correctly.
Fixes #29230
* clean up
---------
Co-authored-by: Alex Tran
---
.../lib/providers/view_intent/view_intent_handler_android.dart | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mobile/lib/providers/view_intent/view_intent_handler_android.dart b/mobile/lib/providers/view_intent/view_intent_handler_android.dart
index c00ff38648..51415af7b1 100644
--- a/mobile/lib/providers/view_intent/view_intent_handler_android.dart
+++ b/mobile/lib/providers/view_intent/view_intent_handler_android.dart
@@ -1,5 +1,6 @@
import 'dart:async';
+import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
@@ -97,7 +98,7 @@ class AndroidViewIntentHandler implements ViewIntentHandler {
await _router.replaceAll([
const TabShellRoute(),
- AssetViewerRoute(initialIndex: 0, timelineService: timelineService),
+ AssetViewerRoute(key: UniqueKey(), initialIndex: 0, timelineService: timelineService),
]);
}
}
From f29f86542ce0c38b50de625db81fc590e56f6b69 Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Tue, 23 Jun 2026 23:50:59 +0530
Subject: [PATCH 029/435] feat: partner actions (#29281)
* feat: partner actions
# Conflicts:
# i18n/en.json
* cleanup
* fix tests
* ci fix
---------
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
i18n/en.json | 6 +-
.../pages/library/partner/partner.page.dart | 126 ++----------------
mobile/lib/presentation/actions/action.dart | 19 ++-
.../presentation/actions/action.widget.dart | 36 +++--
.../presentation/actions/partner.action.dart | 125 +++++++++++++++++
mobile/lib/widgets/common/confirm_dialog.dart | 6 +-
mobile/test/domain/service.mock.dart | 3 +
mobile/test/unit/factories/user_factory.dart | 19 +++
mobile/test/unit/mocks.dart | 125 +++++++++++++----
.../actions/partner_action_test.dart | 83 ++++++++++++
.../unit/presentation/partner_page_test.dart | 24 ++--
mobile/test/unit/presentation_context.dart | 39 +++++-
.../test/unit/services/hash_service_test.dart | 2 +-
13 files changed, 433 insertions(+), 180 deletions(-)
create mode 100644 mobile/lib/presentation/actions/partner.action.dart
create mode 100644 mobile/test/unit/presentation/actions/partner_action_test.dart
diff --git a/i18n/en.json b/i18n/en.json
index 6bcb88d2c5..830b5f915b 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1303,9 +1303,9 @@
"login_form_failed_login": "Error logging you in, check server URL, email and password",
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
"login_form_password_hint": "password",
- "login_form_server_empty": "Enter a server URL.",
- "login_form_server_error": "Could not connect to server.",
- "login_has_been_disabled": "Login has been disabled.",
+ "login_form_server_empty": "Enter a server URL",
+ "login_form_server_error": "Could not connect to server",
+ "login_has_been_disabled": "Login has been disabled",
"login_password_changed_error": "There was an error updating your password",
"login_password_changed_success": "Password updated successfully",
"logout_all_device_confirmation": "Are you sure you want to log out all devices?",
diff --git a/mobile/lib/pages/library/partner/partner.page.dart b/mobile/lib/pages/library/partner/partner.page.dart
index 0d9e8f95bd..7274b8a14e 100644
--- a/mobile/lib/pages/library/partner/partner.page.dart
+++ b/mobile/lib/pages/library/partner/partner.page.dart
@@ -1,23 +1,13 @@
import 'package:auto_route/auto_route.dart';
-import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/generated/translations.g.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/partner.action.dart';
import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
-import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
-
-@visibleForTesting
-final candidatesStateProvider = StreamProvider.autoDispose>((ref) {
- final currentUser = ref.watch(currentUserProvider);
- // TODO: Refactor with a route guard to avoid this check in every provider
- if (currentUser == null) {
- return const Stream.empty();
- }
- return ref.watch(partnerServiceProvider).getCandidates(currentUser.id);
-});
@visibleForTesting
final partnersStateProvider = StreamProvider.autoDispose>((ref) {
@@ -30,28 +20,6 @@ final partnersStateProvider = StreamProvider.autoDispose>((ref
return ref.watch(partnerServiceProvider).search(currentUser.id, .sharedBy);
});
-Future _addPartner(BuildContext context, WidgetRef ref) async {
- final selected = await showDialog(context: context, builder: (_) => const PartnerSelectionDialog());
- final currentUser = ref.read(currentUserProvider);
- if (selected != null && currentUser != null) {
- await ref.read(partnerServiceProvider).create(sharedById: currentUser.id, sharedWithId: selected.id);
- }
-}
-
-Future _removePartner(BuildContext context, WidgetRef ref, Partner partner) => showDialog(
- context: context,
- builder: (_) => ConfirmDialog(
- title: "stop_photo_sharing",
- content: context.t.partner_page_stop_sharing_content(partner: partner.name),
- onOk: () {
- final currentUser = ref.read(currentUserProvider);
- if (currentUser != null) {
- ref.read(partnerServiceProvider).delete(sharedById: currentUser.id, sharedWithId: partner.id);
- }
- },
- ),
-);
-
@RoutePage()
class PartnerPage extends ConsumerWidget {
const PartnerPage({super.key});
@@ -65,20 +33,10 @@ class PartnerPage extends ConsumerWidget {
title: Text(context.t.partners),
elevation: 0,
centerTitle: false,
- actions: [
- IconButton(
- onPressed: () => _addPartner(context, ref),
- icon: const Icon(Icons.person_add),
- tooltip: context.t.add_partner,
- ),
- ],
+ actions: const [ActionIconButtonWidget(action: PartnerAddAction())],
),
body: sharedByAsync.when(
- data: (partners) => PartnerSharedByList(
- partners: partners.toList(growable: false),
- onAdd: () => _addPartner(context, ref),
- onRemove: (partner) => _removePartner(context, ref, partner),
- ),
+ data: (partners) => PartnerSharedByList(partners: partners.toList(growable: false)),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => Center(child: Text(context.t.error_loading_partners(error: error))),
),
@@ -87,9 +45,7 @@ class PartnerPage extends ConsumerWidget {
}
class _EmptyPartners extends StatelessWidget {
- const _EmptyPartners({required this.onAdd});
-
- final VoidCallback onAdd;
+ const _EmptyPartners();
@override
Widget build(BuildContext context) {
@@ -102,13 +58,9 @@ class _EmptyPartners extends StatelessWidget {
padding: const .symmetric(vertical: 8),
child: Text(context.t.partner_page_empty_message, style: const TextStyle(fontSize: 14)),
),
- Align(
+ const Align(
alignment: .center,
- child: ElevatedButton.icon(
- onPressed: onAdd,
- icon: const Icon(Icons.person_add),
- label: Text(context.t.add_partner),
- ),
+ child: ActionButtonWidget(action: PartnerAddAction()),
),
],
),
@@ -118,16 +70,14 @@ class _EmptyPartners extends StatelessWidget {
@visibleForTesting
class PartnerSharedByList extends StatelessWidget {
- const PartnerSharedByList({super.key, required this.partners, required this.onAdd, required this.onRemove});
+ const PartnerSharedByList({super.key, required this.partners});
final List partners;
- final VoidCallback onAdd;
- final ValueChanged onRemove;
@override
Widget build(BuildContext context) {
if (partners.isEmpty) {
- return _EmptyPartners(onAdd: onAdd);
+ return const _EmptyPartners();
}
return ListView.builder(
@@ -138,63 +88,11 @@ class PartnerSharedByList extends StatelessWidget {
leading: PartnerUserAvatar(userId: partner.id, name: partner.name),
title: Text(partner.name),
subtitle: Text(partner.email),
- trailing: IconButton(icon: const Icon(Icons.person_remove), onPressed: () => onRemove(partner)),
+ trailing: ActionIconButtonWidget(
+ action: PartnerRemoveAction(sharedWithId: partner.id, partnerName: partner.name),
+ ),
);
},
);
}
}
-
-@visibleForTesting
-class PartnerSelectionDialog extends ConsumerWidget {
- const PartnerSelectionDialog({super.key});
-
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final candidatesAsync = ref.watch(candidatesStateProvider);
-
- return SimpleDialog(
- title: const Text("partner_page_select_partner").tr(),
- children: candidatesAsync.when(
- data: (candidates) {
- final users = candidates.toList();
- if (users.isEmpty) {
- return [
- Padding(
- padding: const .symmetric(horizontal: 24, vertical: 8),
- child: const Text("partner_page_no_more_users").tr(),
- ),
- ];
- }
- return [
- for (final candidate in users)
- SimpleDialogOption(
- onPressed: () => Navigator.of(context).pop(candidate),
- child: Row(
- children: [
- Padding(
- padding: const .only(right: 8),
- child: PartnerUserAvatar(userId: candidate.id, name: candidate.name),
- ),
- Text(candidate.name),
- ],
- ),
- ),
- ];
- },
- loading: () => const [
- Padding(
- padding: .all(24),
- child: Center(child: CircularProgressIndicator()),
- ),
- ],
- error: (error, _) => [
- Padding(
- padding: const .symmetric(horizontal: 24, vertical: 8),
- child: Text(context.t.error_loading_partners(error: error)),
- ),
- ],
- ),
- );
- }
-}
diff --git a/mobile/lib/presentation/actions/action.dart b/mobile/lib/presentation/actions/action.dart
index 419f97e9cb..5d37706aaa 100644
--- a/mobile/lib/presentation/actions/action.dart
+++ b/mobile/lib/presentation/actions/action.dart
@@ -1,14 +1,23 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/user.model.dart';
+
+class ActionScope {
+ final BuildContext context;
+ final WidgetRef ref;
+ final UserDto authUser;
+
+ const ActionScope({required this.context, required this.ref, required this.authUser});
+}
abstract class BaseAction {
- final IconData icon;
+ const BaseAction();
- const BaseAction({required this.icon});
+ IconData get icon;
- String label(BuildContext context);
+ String label(ActionScope scope);
- bool isVisible(BuildContext context, WidgetRef ref);
+ bool isVisible(ActionScope scope) => true;
- Future onAction(BuildContext context, WidgetRef ref);
+ Future onAction(ActionScope scope);
}
diff --git a/mobile/lib/presentation/actions/action.widget.dart b/mobile/lib/presentation/actions/action.widget.dart
index 6c0f513808..0f891abde6 100644
--- a/mobile/lib/presentation/actions/action.widget.dart
+++ b/mobile/lib/presentation/actions/action.widget.dart
@@ -2,30 +2,44 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/utils/error_handler.dart';
import 'package:immich_ui/immich_ui.dart';
+class _ActionWidgetScope {
+ final String label;
+ final VoidCallback onAction;
+
+ const _ActionWidgetScope({required this.label, required this.onAction});
+}
+
class _ActionWidget extends ConsumerWidget {
final BaseAction action;
- final Widget Function(Future Function() onAction) builder;
+ final Widget Function(_ActionWidgetScope context) builder;
const _ActionWidget({required this.action, required this.builder});
- Future _onAction(BuildContext context, WidgetRef ref) async {
+ Future _onAction(ActionScope scope) async {
try {
- await action.onAction(context, ref);
+ await action.onAction(scope);
} catch (error, stackTrace) {
- handleError(context, error, stack: stackTrace, description: 'Action failed: ${action.runtimeType}');
+ handleError(scope.context, error, stack: stackTrace, description: 'Action failed: ${action.runtimeType}');
}
}
@override
Widget build(BuildContext context, WidgetRef ref) {
- if (!action.isVisible(context, ref)) {
+ final authUser = ref.watch(currentUserProvider);
+ if (authUser == null) {
return const SizedBox.shrink();
}
- return builder(() => _onAction(context, ref));
+ final scope = ActionScope(context: context, ref: ref, authUser: authUser);
+ if (!action.isVisible(scope)) {
+ return const SizedBox.shrink();
+ }
+
+ return builder(.new(label: action.label(scope), onAction: () => _onAction(scope)));
}
}
@@ -38,7 +52,7 @@ class ActionIconButtonWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => _ActionWidget(
action: action,
- builder: (onAction) => ImmichIconButton(icon: action.icon, onPressed: onAction, variant: variant),
+ builder: (ctx) => ImmichIconButton(icon: action.icon, onPressed: ctx.onAction, variant: variant),
);
}
@@ -51,8 +65,8 @@ class ActionButtonWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => _ActionWidget(
action: action,
- builder: (onAction) =>
- ImmichTextButton(labelText: action.label(context), icon: action.icon, onPressed: onAction, variant: variant),
+ builder: (ctx) =>
+ ImmichTextButton(labelText: ctx.label, icon: action.icon, onPressed: ctx.onAction, variant: variant),
);
}
@@ -64,7 +78,7 @@ class ActionColumnButtonWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => _ActionWidget(
action: action,
- builder: (onAction) => ImmichColumnButton(icon: action.icon, label: action.label(context), onPressed: onAction),
+ builder: (ctx) => ImmichColumnButton(icon: action.icon, label: ctx.label, onPressed: ctx.onAction),
);
}
@@ -76,6 +90,6 @@ class ActionMenuItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => _ActionWidget(
action: action,
- builder: (onAction) => ImmichMenuItem(icon: action.icon, label: action.label(context), onPressed: onAction),
+ builder: (ctx) => ImmichMenuItem(icon: action.icon, label: ctx.label, onPressed: ctx.onAction),
);
}
diff --git a/mobile/lib/presentation/actions/partner.action.dart b/mobile/lib/presentation/actions/partner.action.dart
new file mode 100644
index 0000000000..11fb69ee75
--- /dev/null
+++ b/mobile/lib/presentation/actions/partner.action.dart
@@ -0,0 +1,125 @@
+import 'package:flutter/material.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/user.model.dart';
+import 'package:immich_mobile/generated/translations.g.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart';
+import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
+import 'package:immich_mobile/providers/user.provider.dart';
+import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
+
+class PartnerAddAction extends BaseAction {
+ const PartnerAddAction();
+
+ @override
+ IconData get icon => Icons.person_add_rounded;
+
+ @override
+ String label(ActionScope scope) => scope.context.t.add_partner;
+
+ @override
+ Future onAction(ActionScope scope) async {
+ final ActionScope(:context, :ref, :authUser) = scope;
+ final selected = await showDialog(context: context, builder: (_) => const PartnerSelectionDialog());
+ if (selected == null) {
+ return;
+ }
+
+ await ref.read(partnerServiceProvider).create(sharedById: authUser.id, sharedWithId: selected.id);
+ }
+}
+
+class PartnerRemoveAction extends BaseAction {
+ const PartnerRemoveAction({required this.sharedWithId, required this.partnerName});
+
+ final String sharedWithId;
+ final String partnerName;
+
+ @override
+ IconData get icon => Icons.person_remove_rounded;
+
+ @override
+ String label(ActionScope scope) => scope.context.t.remove;
+
+ @override
+ Future onAction(ActionScope scope) async {
+ final ActionScope(:context, :ref, :authUser) = scope;
+
+ final confirmed = await showDialog(
+ context: context,
+ builder: (_) => ConfirmDialog(
+ title: context.t.stop_photo_sharing,
+ content: context.t.partner_page_stop_sharing_content(partner: partnerName),
+ ),
+ );
+ if (confirmed != true) {
+ return;
+ }
+
+ await ref.read(partnerServiceProvider).delete(sharedById: authUser.id, sharedWithId: sharedWithId);
+ }
+}
+
+@visibleForTesting
+final candidatesStateProvider = StreamProvider.autoDispose>((ref) {
+ final currentUser = ref.watch(currentUserProvider);
+ // TODO: Refactor with a route guard to avoid this check in every provider
+ if (currentUser == null) {
+ return const Stream.empty();
+ }
+ return ref.watch(partnerServiceProvider).getCandidates(currentUser.id);
+});
+
+@visibleForTesting
+class PartnerSelectionDialog extends ConsumerWidget {
+ const PartnerSelectionDialog({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final candidatesAsync = ref.watch(candidatesStateProvider);
+
+ return SimpleDialog(
+ title: Text(context.t.partner_page_select_partner),
+ children: candidatesAsync.when(
+ data: (candidates) {
+ final users = candidates.toList();
+ if (users.isEmpty) {
+ return [
+ Padding(
+ padding: const .symmetric(horizontal: 24, vertical: 8),
+ child: Text(context.t.partner_page_no_more_users),
+ ),
+ ];
+ }
+ return [
+ for (final candidate in users)
+ SimpleDialogOption(
+ onPressed: () => Navigator.of(context).pop(candidate),
+ child: Row(
+ children: [
+ Padding(
+ padding: const .only(right: 8),
+ child: PartnerUserAvatar(userId: candidate.id, name: candidate.name),
+ ),
+ Text(candidate.name),
+ ],
+ ),
+ ),
+ ];
+ },
+ loading: () => const [
+ Padding(
+ padding: .all(24),
+ child: Center(child: CircularProgressIndicator()),
+ ),
+ ],
+ error: (error, _) => [
+ Padding(
+ padding: const .symmetric(horizontal: 24, vertical: 8),
+ child: Text(context.t.error_loading_partners(error: error)),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/mobile/lib/widgets/common/confirm_dialog.dart b/mobile/lib/widgets/common/confirm_dialog.dart
index 153c124595..9c3f4344c6 100644
--- a/mobile/lib/widgets/common/confirm_dialog.dart
+++ b/mobile/lib/widgets/common/confirm_dialog.dart
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
class ConfirmDialog extends StatelessWidget {
- final Function onOk;
+ final Function? onOk;
final String title;
final String content;
final String cancel;
@@ -11,7 +11,7 @@ class ConfirmDialog extends StatelessWidget {
const ConfirmDialog({
super.key,
- required this.onOk,
+ this.onOk,
required this.title,
required this.content,
this.cancel = "cancel",
@@ -21,7 +21,7 @@ class ConfirmDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
void onOkPressed() {
- onOk();
+ onOk?.call();
context.pop(true);
}
diff --git a/mobile/test/domain/service.mock.dart b/mobile/test/domain/service.mock.dart
index 743d75f1bf..d5feb56563 100644
--- a/mobile/test/domain/service.mock.dart
+++ b/mobile/test/domain/service.mock.dart
@@ -1,5 +1,6 @@
import 'package:immich_mobile/domain/services/partner.service.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
+import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/domain/utils/background_sync.dart';
import 'package:immich_mobile/platform/native_sync_api.g.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
@@ -14,3 +15,5 @@ class MockNativeSyncApi extends Mock implements NativeSyncApi {}
class MockAppSettingsService extends Mock implements AppSettingsService {}
class MockPartnerService extends Mock implements PartnerService {}
+
+class MockUserService extends Mock implements UserService {}
diff --git a/mobile/test/unit/factories/user_factory.dart b/mobile/test/unit/factories/user_factory.dart
index c89b03abfe..248e98dc69 100644
--- a/mobile/test/unit/factories/user_factory.dart
+++ b/mobile/test/unit/factories/user_factory.dart
@@ -23,4 +23,23 @@ class UserFactory {
avatarColor: avatarColor ?? .primary,
);
}
+
+ static UserDto createDto({
+ String? id,
+ String? name,
+ String? email,
+ DateTime? profileChangedAt,
+ bool? hasProfileImage,
+ AvatarColor? avatarColor,
+ }) {
+ id = TestUtils.uuid(id);
+ return UserDto(
+ id: id,
+ name: name ?? 'user_$id',
+ email: email ?? '$id@test.com',
+ profileChangedAt: TestUtils.date(profileChangedAt),
+ hasProfileImage: hasProfileImage ?? false,
+ avatarColor: avatarColor ?? .primary,
+ );
+ }
}
diff --git a/mobile/test/unit/mocks.dart b/mobile/test/unit/mocks.dart
index 4f8e608caa..69260d343d 100644
--- a/mobile/test/unit/mocks.dart
+++ b/mobile/test/unit/mocks.dart
@@ -1,24 +1,15 @@
-import 'package:immich_mobile/domain/models/album/local_album.model.dart';
-import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
-import 'package:mocktail/mocktail.dart' as mocktail;
+import 'dart:typed_data';
+
+import 'package:immich_mobile/constants/enums.dart';
+import 'package:immich_mobile/domain/models/user.model.dart';
+import 'package:mocktail/mocktail.dart' as mock;
+import 'package:mocktail/mocktail.dart';
import '../domain/service.mock.dart';
import '../infrastructure/repository.mock.dart';
-
-void _registerFallbacks() {
- mocktail.registerFallbackValue(LocalAlbum(id: '', name: '', updatedAt: DateTime.now()));
- mocktail.registerFallbackValue(
- LocalAsset(
- id: '',
- name: '',
- type: AssetType.image,
- createdAt: DateTime.now(),
- updatedAt: DateTime.now(),
- playbackStyle: AssetPlaybackStyle.image,
- isEdited: false,
- ),
- );
-}
+import 'factories/local_album_factory.dart';
+import 'factories/local_asset_factory.dart';
+import 'factories/user_factory.dart';
class RepositoryMocks {
final localAlbum = MockLocalAlbumRepository();
@@ -28,25 +19,103 @@ class RepositoryMocks {
final nativeApi = MockNativeSyncApi();
RepositoryMocks() {
- _registerFallbacks();
+ resetAll();
}
- void reset() {
- mocktail.reset(localAlbum);
- mocktail.reset(localAsset);
- mocktail.reset(trashedAsset);
- mocktail.reset(nativeApi);
+ void resetAll() {
+ _registerFallbacks();
+ reset(localAlbum);
+ reset(localAsset);
+ reset(trashedAsset);
+ reset(nativeApi);
}
}
class ServiceMocks {
- final partner = MockPartnerService();
+ final PartnerStub partner = PartnerStub(MockPartnerService());
+ final UserStub user = UserStub(MockUserService());
ServiceMocks() {
- _registerFallbacks();
+ resetAll();
}
- void reset() {
- mocktail.reset(partner);
+ void resetAll() {
+ _registerFallbacks();
+ partner.reset();
+ user.reset();
+ _stubUserService();
+ _stubPartnerService();
+ }
+
+ void _stubUserService() {
+ when(user.getMyUser).thenReturn(UserFactory.createDto());
+ when(user.tryGetMyUser).thenReturn(null);
+ when(user.watchMyUser).thenAnswer((_) => const Stream.empty());
+ when(user.refreshMyUser).thenAnswer((_) async => null);
+ when(user.createProfileImage).thenAnswer((_) async => null);
+ }
+
+ void _stubPartnerService() {
+ registerFallbackValue(PartnerDirection.sharedBy);
+ when(partner.getCandidates).thenAnswer((_) => const Stream.empty());
+ when(partner.search).thenAnswer((_) => const Stream.empty());
+ when(partner.update).thenAnswer((_) async {});
+ when(partner.create).thenAnswer((_) async {});
+ when(partner.delete).thenAnswer((_) async {});
}
}
+
+void _registerFallbacks() {
+ registerFallbackValue(LocalAlbumFactory.create());
+ registerFallbackValue(LocalAssetFactory.create());
+ registerFallbackValue(Uint8List(0));
+}
+
+extension type const Stub(T mockedService) {
+ void reset() => mock.reset(mockedService);
+}
+
+extension type const PartnerStub(MockPartnerService service) implements Stub {
+ Stream> Function() get getCandidates =>
+ () => service.getCandidates(any());
+
+ Stream> Function() get search =>
+ () => service.search(any(), any());
+
+ Future Function() get create =>
+ () => service.create(
+ sharedById: any(named: 'sharedById'),
+ sharedWithId: any(named: 'sharedWithId'),
+ inTimeline: any(named: 'inTimeline'),
+ );
+
+ Future Function() get update =>
+ () => service.update(
+ sharedById: any(named: 'sharedById'),
+ sharedWithId: any(named: 'sharedWithId'),
+ inTimeline: any(named: 'inTimeline'),
+ );
+
+ Future Function() get delete =>
+ () => service.delete(
+ sharedById: any(named: 'sharedById'),
+ sharedWithId: any(named: 'sharedWithId'),
+ );
+}
+
+extension type const UserStub(MockUserService service) implements Stub {
+ UserDto Function() get getMyUser =>
+ () => service.getMyUser();
+
+ UserDto? Function() get tryGetMyUser =>
+ () => service.tryGetMyUser();
+
+ Stream Function() get watchMyUser =>
+ () => service.watchMyUser();
+
+ Future Function() get refreshMyUser =>
+ () => service.refreshMyUser();
+
+ Future Function() get createProfileImage =>
+ () => service.createProfileImage(any(), any());
+}
diff --git a/mobile/test/unit/presentation/actions/partner_action_test.dart b/mobile/test/unit/presentation/actions/partner_action_test.dart
new file mode 100644
index 0000000000..1eb89fe4cc
--- /dev/null
+++ b/mobile/test/unit/presentation/actions/partner_action_test.dart
@@ -0,0 +1,83 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/user.model.dart';
+import 'package:immich_mobile/presentation/actions/partner.action.dart';
+import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
+import 'package:immich_mobile/providers/user.provider.dart';
+import 'package:mocktail/mocktail.dart';
+
+import '../../factories/user_factory.dart';
+import '../../mocks.dart';
+import '../../presentation_context.dart';
+
+void main() {
+ late PresentationContext context;
+ late UserDto currentUser;
+ final mocks = ServiceMocks();
+
+ setUp(() async {
+ currentUser = UserFactory.createDto();
+ context = await PresentationContext.create();
+ when(mocks.user.tryGetMyUser).thenReturn(currentUser);
+ });
+
+ tearDown(() async {
+ mocks.resetAll();
+ await context.dispose();
+ });
+
+ List overrides({List candidates = const []}) => [
+ currentUserProvider.overrideWith((ref) => CurrentUserProvider(mocks.user.service)),
+ partnerServiceProvider.overrideWithValue(mocks.partner.service),
+ candidatesStateProvider.overrideWith((ref) => Stream>.value(candidates)),
+ ];
+
+ group('PartnerAddAction', () {
+ testWidgets('creates a partner for the selected candidate', (tester) async {
+ final candidate = UserFactory.create();
+
+ await tester.pumpTestAction(const PartnerAddAction(), overrides: overrides(candidates: [candidate]));
+ await tester.pumpUntilFound(find.text(candidate.name));
+ await tester.tap(find.text(candidate.name));
+ await tester.pumpAndSettle();
+
+ verify(() => mocks.partner.service.create(sharedById: currentUser.id, sharedWithId: candidate.id)).called(1);
+ });
+
+ testWidgets('creates nothing when the selection dialog is dismissed', (tester) async {
+ await tester.pumpTestAction(const PartnerAddAction(), overrides: overrides(candidates: [UserFactory.create()]));
+ await tester.sendKeyEvent(LogicalKeyboardKey.escape); // dismiss without selecting
+ await tester.pumpAndSettle();
+
+ verifyNever(mocks.partner.create);
+ });
+ });
+
+ group('PartnerRemoveAction', () {
+ testWidgets('deletes the partner after confirmation', (tester) async {
+ final partner = UserFactory.create();
+ await tester.pumpTestAction(
+ PartnerRemoveAction(sharedWithId: partner.id, partnerName: partner.name),
+ overrides: overrides(),
+ );
+ await tester.tap(find.byType(TextButton).last); // confirm
+ await tester.pumpAndSettle();
+
+ verify(() => mocks.partner.service.delete(sharedById: currentUser.id, sharedWithId: partner.id)).called(1);
+ });
+
+ testWidgets('deletes nothing when the confirmation is cancelled', (tester) async {
+ final partner = UserFactory.create();
+ await tester.pumpTestAction(
+ PartnerRemoveAction(sharedWithId: partner.id, partnerName: partner.name),
+ overrides: overrides(),
+ );
+ await tester.tap(find.byType(TextButton).first); // cancel
+ await tester.pumpAndSettle();
+
+ verifyNever(mocks.partner.delete);
+ });
+ });
+}
diff --git a/mobile/test/unit/presentation/partner_page_test.dart b/mobile/test/unit/presentation/partner_page_test.dart
index 957a915ad3..4557388dc0 100644
--- a/mobile/test/unit/presentation/partner_page_test.dart
+++ b/mobile/test/unit/presentation/partner_page_test.dart
@@ -3,6 +3,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/pages/library/partner/partner.page.dart';
+import 'package:immich_mobile/presentation/actions/partner.action.dart';
import '../factories/partner_user_factory.dart';
import '../factories/user_factory.dart';
@@ -16,16 +17,18 @@ void main() {
group('PartnerSharedByList', () {
testWidgets('shows the empty-state add button when there are no partners', (tester) async {
- await tester.pumpTestWidget(PartnerSharedByList(partners: const [], onAdd: () {}, onRemove: (_) {}));
+ final action = const PartnerAddAction();
+
+ await tester.pumpTestWidget(const PartnerSharedByList(partners: []), overrides: context.overrides);
expect(find.byType(ListView), findsNothing);
- expect(find.widgetWithIcon(ElevatedButton, Icons.person_add), findsOneWidget);
+ expect(find.widgetWithIcon(TextButton, action.icon), findsOneWidget);
});
testWidgets('renders a tile per partner with name and email', (tester) async {
final partner1 = PartnerFactory.create();
final partner2 = PartnerFactory.create();
- await tester.pumpTestWidget(PartnerSharedByList(partners: [partner1, partner2], onAdd: () {}, onRemove: (_) {}));
+ await tester.pumpTestWidget(PartnerSharedByList(partners: [partner1, partner2]), overrides: context.overrides);
expect(find.byType(ListTile), findsNWidgets(2));
expect(find.text(partner1.name), findsOneWidget);
@@ -34,18 +37,12 @@ void main() {
expect(find.text(partner2.email), findsOneWidget);
});
- testWidgets('invokes onRemovePartner with the tapped partner', (tester) async {
+ testWidgets('renders a remove action for each partner', (tester) async {
final partner1 = PartnerFactory.create(inTimeline: true);
final partner2 = PartnerFactory.create();
- Partner? removed;
- await tester.pumpTestWidget(
- PartnerSharedByList(partners: [partner1, partner2], onAdd: () {}, onRemove: (p) => removed = p),
- );
-
- await tester.tap(find.byIcon(Icons.person_remove).first);
- await tester.pump();
-
- expect(removed, partner1);
+ final action = const PartnerRemoveAction(sharedWithId: '', partnerName: '');
+ await tester.pumpTestWidget(PartnerSharedByList(partners: [partner1, partner2]), overrides: context.overrides);
+ expect(find.byIcon(action.icon), findsNWidgets(2));
});
});
@@ -65,6 +62,7 @@ void main() {
}
List withCandidates(List candidates) => [
+ ...context.overrides,
candidatesStateProvider.overrideWith((ref) => Stream>.value(candidates)),
];
diff --git a/mobile/test/unit/presentation_context.dart b/mobile/test/unit/presentation_context.dart
index 97b09ba85e..e411b21802 100644
--- a/mobile/test/unit/presentation_context.dart
+++ b/mobile/test/unit/presentation_context.dart
@@ -6,20 +6,35 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/locales.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/generated/codegen_loader.g.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/providers/user.provider.dart';
+import 'package:immich_ui/immich_ui.dart';
+import 'package:mocktail/mocktail.dart';
import '../test_utils.dart';
+import 'factories/user_factory.dart';
+import 'mocks.dart';
class PresentationContext {
- const PresentationContext._();
+ PresentationContext._({required UserDto user}) : currentUser = user, mocks = ServiceMocks() {
+ when(mocks.user.tryGetMyUser).thenReturn(currentUser);
+ }
static const String serverEndpoint = 'http://localhost:3000';
static Drift? _db;
+ final UserDto currentUser;
+ final ServiceMocks mocks;
+
+ List get overrides => [currentUserProvider.overrideWith((ref) => CurrentUserProvider(mocks.user.service))];
+
static Future create() async {
TestUtils.init();
if (_db == null) {
@@ -28,7 +43,7 @@ class PresentationContext {
await StoreService.I.put(StoreKey.serverEndpoint, serverEndpoint);
_db = db;
}
- return const PresentationContext._();
+ return PresentationContext._(user: UserFactory.createDto());
}
Future dispose() async {
@@ -54,6 +69,7 @@ extension PumpPresentationWidget on WidgetTester {
child: Builder(
builder: (context) => MaterialApp(
debugShowCheckedModeBanner: false,
+ scaffoldMessengerKey: scaffoldMessengerKey,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
@@ -65,4 +81,23 @@ extension PumpPresentationWidget on WidgetTester {
);
await pumpAndSettle();
}
+
+ Future pumpTestAction(BaseAction action, {List overrides = const []}) async {
+ await pumpTestWidget(
+ Scaffold(body: ActionIconButtonWidget(action: action)),
+ overrides: overrides,
+ );
+ await tap(find.byType(ImmichIconButton));
+ await pump();
+ }
+
+ Future pumpUntilFound(Finder finder, {int maxFrames = 10}) async {
+ for (var i = 0; i < maxFrames; i++) {
+ await pump();
+ if (finder.evaluate().isNotEmpty) {
+ return;
+ }
+ }
+ throw StateError('pumpUntilFound: $finder not found within $maxFrames frames');
+ }
}
diff --git a/mobile/test/unit/services/hash_service_test.dart b/mobile/test/unit/services/hash_service_test.dart
index 223aaf49af..07cf2badf9 100644
--- a/mobile/test/unit/services/hash_service_test.dart
+++ b/mobile/test/unit/services/hash_service_test.dart
@@ -25,7 +25,7 @@ void main() {
});
tearDown(() {
- mocks.reset();
+ mocks.resetAll();
});
group('HashService', () {
From 9d6c21927643c9478806c4bb5b0c58a02e58630d Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Wed, 24 Jun 2026 00:10:24 +0530
Subject: [PATCH 030/435] fix: current viewer asset reactivity (#29282)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
.../asset_viewer/asset_viewer.provider.dart | 32 ++---
mobile/test/domain/service.mock.dart | 3 +
.../asset_viewer_provider_test.dart | 111 ++++++++++++++++++
.../view_intent_handler_android_test.dart | 20 +++-
.../unit/factories/remote_asset_factory.dart | 23 ++++
5 files changed, 168 insertions(+), 21 deletions(-)
create mode 100644 mobile/test/providers/asset_viewer/asset_viewer_provider_test.dart
create mode 100644 mobile/test/unit/factories/remote_asset_factory.dart
diff --git a/mobile/lib/providers/asset_viewer/asset_viewer.provider.dart b/mobile/lib/providers/asset_viewer/asset_viewer.provider.dart
index 5c9f3c92a3..6808860ffc 100644
--- a/mobile/lib/providers/asset_viewer/asset_viewer.provider.dart
+++ b/mobile/lib/providers/asset_viewer/asset_viewer.provider.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_provider.dart';
@@ -77,18 +79,17 @@ class AssetViewerState {
}
class AssetViewerStateNotifier extends Notifier {
+ StreamSubscription? _assetSubscription;
+
@override
AssetViewerState build() {
- ref.listen(_watchedCurrentAssetProvider, (_, next) {
- final updated = next.valueOrNull;
- if (updated != null) {
- state = state.copyWith(currentAsset: updated);
- }
- });
+ ref.onDispose(() => _assetSubscription?.cancel());
return const AssetViewerState();
}
void reset() {
+ _assetSubscription?.cancel();
+ _assetSubscription = null;
state = const AssetViewerState();
}
@@ -97,6 +98,16 @@ class AssetViewerStateNotifier extends Notifier {
return;
}
state = state.copyWith(currentAsset: asset, stackIndex: 0, showingOcr: false);
+ _watchCurrentAsset(asset);
+ }
+
+ void _watchCurrentAsset(BaseAsset asset) {
+ _assetSubscription?.cancel();
+ _assetSubscription = ref.read(assetServiceProvider).watchAsset(asset).listen((updated) {
+ if (updated != null) {
+ state = state.copyWith(currentAsset: updated);
+ }
+ });
}
void setOpacity(double opacity) {
@@ -150,12 +161,3 @@ class AssetViewerStateNotifier extends Notifier {
}
final assetViewerProvider = NotifierProvider(AssetViewerStateNotifier.new);
-
-final _watchedCurrentAssetProvider = StreamProvider((ref) {
- ref.watch(assetViewerProvider.select((s) => s.currentAsset?.heroTag));
- final asset = ref.read(assetViewerProvider).currentAsset;
- if (asset == null) {
- return const Stream.empty();
- }
- return ref.read(assetServiceProvider).watchAsset(asset);
-});
diff --git a/mobile/test/domain/service.mock.dart b/mobile/test/domain/service.mock.dart
index d5feb56563..70f706f7fe 100644
--- a/mobile/test/domain/service.mock.dart
+++ b/mobile/test/domain/service.mock.dart
@@ -1,3 +1,4 @@
+import 'package:immich_mobile/domain/services/asset.service.dart';
import 'package:immich_mobile/domain/services/partner.service.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
@@ -16,4 +17,6 @@ class MockAppSettingsService extends Mock implements AppSettingsService {}
class MockPartnerService extends Mock implements PartnerService {}
+class MockAssetService extends Mock implements AssetService {}
+
class MockUserService extends Mock implements UserService {}
diff --git a/mobile/test/providers/asset_viewer/asset_viewer_provider_test.dart b/mobile/test/providers/asset_viewer/asset_viewer_provider_test.dart
new file mode 100644
index 0000000000..67eb1dd9d1
--- /dev/null
+++ b/mobile/test/providers/asset_viewer/asset_viewer_provider_test.dart
@@ -0,0 +1,111 @@
+import 'dart:async';
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
+import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
+import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
+import 'package:mocktail/mocktail.dart';
+
+import '../../domain/service.mock.dart';
+import '../../unit/factories/remote_asset_factory.dart';
+
+void main() {
+ late ProviderContainer container;
+ late MockAssetService assetService;
+
+ setUpAll(() => registerFallbackValue(RemoteAssetFactory.create()));
+
+ setUp(() {
+ assetService = MockAssetService();
+ when(() => assetService.watchAsset(any())).thenAnswer((_) => const Stream.empty());
+
+ container = ProviderContainer(overrides: [assetServiceProvider.overrideWithValue(assetService)]);
+ addTearDown(container.dispose);
+ });
+
+ group('AssetViewerStateNotifier asset watching', () {
+ test('propagates stream updates for the current asset into state', () async {
+ final controller = StreamController();
+ addTearDown(controller.close);
+ final asset = RemoteAssetFactory.create();
+ when(() => assetService.watchAsset(asset)).thenAnswer((_) => controller.stream);
+
+ final notifier = container.read(assetViewerProvider.notifier);
+ notifier.setAsset(asset);
+
+ final updated = asset.copyWith(isFavorite: true);
+ controller.add(updated);
+ await pumpEventQueue();
+
+ expect(container.read(assetViewerProvider).currentAsset, updated);
+ });
+
+ test('ignores null stream emissions', () async {
+ final controller = StreamController();
+ addTearDown(controller.close);
+ final asset = RemoteAssetFactory.create();
+ when(() => assetService.watchAsset(asset)).thenAnswer((_) => controller.stream);
+
+ container.read(assetViewerProvider.notifier).setAsset(asset);
+
+ controller.add(null);
+ await pumpEventQueue();
+
+ expect(container.read(assetViewerProvider).currentAsset, asset);
+ });
+
+ test('reset cancels the subscription so later emissions are dropped', () async {
+ final controller = StreamController();
+ addTearDown(controller.close);
+ final asset = RemoteAssetFactory.create();
+ when(() => assetService.watchAsset(asset)).thenAnswer((_) => controller.stream);
+
+ final notifier = container.read(assetViewerProvider.notifier);
+ notifier.setAsset(asset);
+ notifier.reset();
+
+ controller.add(RemoteAssetFactory.create(isFavorite: true));
+ await pumpEventQueue();
+
+ expect(container.read(assetViewerProvider).currentAsset, isNull);
+ });
+
+ test('setAsset switches the current asset, cancels the previous watch and listens to the new one', () async {
+ final first = StreamController();
+ final second = StreamController();
+ addTearDown(first.close);
+ addTearDown(second.close);
+
+ final assetOne = RemoteAssetFactory.create();
+ final assetTwo = RemoteAssetFactory.create();
+ when(() => assetService.watchAsset(assetOne)).thenAnswer((_) => first.stream);
+ when(() => assetService.watchAsset(assetTwo)).thenAnswer((_) => second.stream);
+
+ final notifier = container.read(assetViewerProvider.notifier);
+ notifier.setAsset(assetOne);
+ expect(container.read(assetViewerProvider).currentAsset, assetOne);
+
+ // Updates to the first asset propagate into state.
+ final updatedOne = assetOne.copyWith(visibility: .archive);
+ first.add(updatedOne);
+ await pumpEventQueue();
+ expect(container.read(assetViewerProvider).currentAsset, updatedOne);
+
+ // Switch to new asset
+ notifier.setAsset(assetTwo);
+ expect(container.read(assetViewerProvider).currentAsset, assetTwo);
+
+ // The previous watch is cancelled: stale emissions from the first stream are dropped.
+ first.add(assetOne.copyWith(isFavorite: true));
+ await pumpEventQueue();
+ expect(container.read(assetViewerProvider).currentAsset, assetTwo);
+
+ // The new asset is watched instead: its emissions propagate into state.
+ final updatedTwo = assetTwo.copyWith(isFavorite: true);
+ second.add(updatedTwo);
+ await pumpEventQueue();
+ expect(container.read(assetViewerProvider).currentAsset, updatedTwo);
+ });
+ });
+}
diff --git a/mobile/test/providers/view_intent/view_intent_handler_android_test.dart b/mobile/test/providers/view_intent/view_intent_handler_android_test.dart
index f9c2c9d323..be7549e202 100644
--- a/mobile/test/providers/view_intent/view_intent_handler_android_test.dart
+++ b/mobile/test/providers/view_intent/view_intent_handler_android_test.dart
@@ -5,19 +5,21 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/timeline.model.dart';
+import 'package:immich_mobile/domain/services/asset.service.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/models/auth/auth_state.model.dart';
import 'package:immich_mobile/platform/view_intent_api.g.dart';
import 'package:immich_mobile/providers/auth.provider.dart';
+import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
import 'package:immich_mobile/providers/view_intent/view_intent_handler_android.dart';
import 'package:immich_mobile/providers/view_intent/view_intent_pending.provider.dart';
import 'package:immich_mobile/routing/router.dart';
+import 'package:immich_mobile/services/api.service.dart';
+import 'package:immich_mobile/services/auth.service.dart';
+import 'package:immich_mobile/services/secure_storage.service.dart';
import 'package:immich_mobile/services/view_intent.service.dart';
import 'package:immich_mobile/services/view_intent_asset_resolver.service.dart';
-import 'package:immich_mobile/services/auth.service.dart';
-import 'package:immich_mobile/services/api.service.dart';
-import 'package:immich_mobile/services/secure_storage.service.dart';
import 'package:immich_mobile/services/widget.service.dart';
import 'package:mocktail/mocktail.dart';
@@ -41,6 +43,11 @@ class FakePageRouteInfo extends Fake implements PageRouteInfo {}
class FakeTimelineService extends Fake implements TimelineService {}
+class FakeAssetService extends Fake implements AssetService {
+ @override
+ Stream watchAsset(BaseAsset asset) => const Stream.empty();
+}
+
class TestViewIntentService extends ViewIntentService {
ViewIntentPayload? consumedAttachment;
int cleanupStaleTempFilesCalls = 0;
@@ -129,6 +136,7 @@ void main() {
authNotifier = TestAuthNotifier(ref, _authState(isAuthenticated: true));
return authNotifier;
}),
+ assetServiceProvider.overrideWithValue(FakeAssetService()),
],
);
@@ -195,9 +203,9 @@ void main() {
testWidgets('onAppResumed handles attachment immediately when authenticated', (tester) async {
viewIntentService.consumedAttachment = payload;
- when(() => resolver.resolve(payload)).thenAnswer(
- (_) async => ViewIntentResolvedAsset(asset: deepLinkAsset, timelineService: deepLinkTimelineService),
- );
+ when(
+ () => resolver.resolve(payload),
+ ).thenAnswer((_) async => ViewIntentResolvedAsset(asset: deepLinkAsset, timelineService: deepLinkTimelineService));
unawaited(handler.onAppResumed());
await tester.pump();
diff --git a/mobile/test/unit/factories/remote_asset_factory.dart b/mobile/test/unit/factories/remote_asset_factory.dart
new file mode 100644
index 0000000000..669eb3998a
--- /dev/null
+++ b/mobile/test/unit/factories/remote_asset_factory.dart
@@ -0,0 +1,23 @@
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
+
+import '../../utils.dart';
+
+class RemoteAssetFactory {
+ const RemoteAssetFactory();
+
+ static RemoteAsset create({String? id, String? name, String? ownerId, bool isFavorite = false}) {
+ id = TestUtils.uuid(id);
+
+ return RemoteAsset(
+ id: id,
+ name: name ?? 'remote_$id.jpg',
+ ownerId: TestUtils.uuid(ownerId),
+ checksum: 'checksum-$id',
+ type: .image,
+ createdAt: TestUtils.yesterday(),
+ updatedAt: TestUtils.now(),
+ isFavorite: isFavorite,
+ isEdited: false,
+ );
+ }
+}
From e5b50a55a47bf435b412676f0ca530d82dd0a3e0 Mon Sep 17 00:00:00 2001
From: Santo Shakil
Date: Wed, 24 Jun 2026 20:15:28 +0600
Subject: [PATCH 031/435] fix(mobile): blank notifications page after enabling
notifications (#29232)
the old notification toggles were removed in a cleanup, so once notifications were enabled the page had nothing left and went blank. show a "notifications enabled" status tile with a shortcut to the system notification settings instead.
---
i18n/en.json | 3 +++
mobile/lib/widgets/settings/notification_setting.dart | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/i18n/en.json b/i18n/en.json
index 830b5f915b..1587fde604 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1507,6 +1507,9 @@
"notes": "Notes",
"nothing_here_yet": "Nothing here yet",
"notification_backup_reliability": "Enable notifications to improve background backup reliability",
+ "notification_enabled_list_tile_content": "Immich uses notifications for background backup. Manage them in your device settings.",
+ "notification_enabled_list_tile_open_button": "Open settings",
+ "notification_enabled_list_tile_title": "Notifications enabled",
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
"notification_permission_list_tile_enable_button": "Enable Notifications",
diff --git a/mobile/lib/widgets/settings/notification_setting.dart b/mobile/lib/widgets/settings/notification_setting.dart
index cbef5ea109..8b7c652925 100644
--- a/mobile/lib/widgets/settings/notification_setting.dart
+++ b/mobile/lib/widgets/settings/notification_setting.dart
@@ -48,6 +48,14 @@ class NotificationSetting extends HookConsumerWidget {
showPermissionsDialog();
}
}),
+ )
+ else
+ SettingsButtonListTile(
+ icon: Icons.notifications_active_outlined,
+ title: 'notification_enabled_list_tile_title'.tr(),
+ subtileText: 'notification_enabled_list_tile_content'.tr(),
+ buttonText: 'notification_enabled_list_tile_open_button'.tr(),
+ onButtonTap: () => openAppSettings(),
),
];
From 08b2e2c0b5f3b29c1db09d8bf1ddca1a62877d09 Mon Sep 17 00:00:00 2001
From: Alex
Date: Wed, 24 Jun 2026 11:18:37 -0500
Subject: [PATCH 032/435] fix(docs): Revert v3 bump (#29310)
Revert "fix(docsc): v3 bump (#29246)"
This reverts commit dc7d57ff9aec6be945697f4374c2b16e8377a9e8.
---
docker/example.env | 2 +-
docs/docs/install/environment-variables.md | 2 +-
docs/docs/install/upgrading.md | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/docker/example.env b/docker/example.env
index 2403d69a85..6641cceaaa 100644
--- a/docker/example.env
+++ b/docker/example.env
@@ -10,7 +10,7 @@ DB_DATA_LOCATION=./postgres
# TZ=Etc/UTC
# The Immich version to use. You can pin this to a specific version like "v2.1.0"
-IMMICH_VERSION=v3
+IMMICH_VERSION=v2
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md
index 5f0c888982..0932fa2855 100644
--- a/docs/docs/install/environment-variables.md
+++ b/docs/docs/install/environment-variables.md
@@ -19,7 +19,7 @@ If this does not work, try running `docker compose up -d --force-recreate`.
| Variable | Description | Default | Containers |
| :----------------- | :------------------------------ | :-----: | :----------------------- |
-| `IMMICH_VERSION` | Image tags | `v3` | server, machine learning |
+| `IMMICH_VERSION` | Image tags | `v2` | server, machine learning |
| `UPLOAD_LOCATION` | Host path for uploads | | server |
| `DB_DATA_LOCATION` | Host path for Postgres database | | database |
diff --git a/docs/docs/install/upgrading.md b/docs/docs/install/upgrading.md
index 8fc9113e6d..38fc056f80 100644
--- a/docs/docs/install/upgrading.md
+++ b/docs/docs/install/upgrading.md
@@ -29,7 +29,7 @@ docker image prune
## Versioning Policy
Immich follows [semantic versioning][semver], which tags releases in the format `..`. We intend for breaking changes to be limited to major version releases.
-You can configure your Docker image to point to the current major version by using a metatag, such as `:v3`.
+You can configure your Docker image to point to the current major version by using a metatag, such as `:v2`.
Currently, we have no plans to backport patches to earlier versions. We encourage all users to run the most recent release of Immich.
Switching back to an earlier version, even within the same minor release tag, is not supported.
From 0931a19c5cc4d77b24ab792ffc965e18d3ae3f66 Mon Sep 17 00:00:00 2001
From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
Date: Wed, 24 Jun 2026 18:29:46 +0200
Subject: [PATCH 033/435] fix: run test suite for plugin changes (#29311)
---
.github/workflows/test.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 68d5c46e50..222ac1d794 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -45,6 +45,8 @@ jobs:
- 'server/**'
- 'pnpm-lock.yaml'
- 'mise.toml'
+ - 'packages/plugin-core/**'
+ - 'packages/plugin-sdk/**'
cli:
- 'packages/cli/**'
- 'packages/sdk/**'
From 9751530af83d1ead5b708442faf4435ac25ca05e Mon Sep 17 00:00:00 2001
From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
Date: Wed, 24 Jun 2026 21:22:35 +0200
Subject: [PATCH 034/435] feat: plugin wrapper type safety (#29300)
---
packages/plugin-core/manifest.json | 11 +-
packages/plugin-core/package.json | 2 +-
packages/plugin-core/src/index.d.ts | 2 +-
packages/plugin-core/src/index.ts | 46 +++---
packages/plugin-sdk/src/sdk.ts | 139 +++++++++++++------
server/src/repositories/plugin.repository.ts | 1 +
6 files changed, 127 insertions(+), 74 deletions(-)
diff --git a/packages/plugin-core/manifest.json b/packages/plugin-core/manifest.json
index 0f1b88827c..15d705b885 100644
--- a/packages/plugin-core/manifest.json
+++ b/packages/plugin-core/manifest.json
@@ -222,7 +222,16 @@
"name": "assetLock",
"title": "Move to locked folder",
"description": "Change visibility to locked",
- "types": ["AssetV1"]
+ "types": ["AssetV1"],
+ "schema": {
+ "properties": {
+ "inverse": {
+ "title": "Inverse",
+ "description": "When true will unarchive any archived assets",
+ "type": "boolean"
+ }
+ }
+ }
},
{
"name": "assetTimeline",
diff --git a/packages/plugin-core/package.json b/packages/plugin-core/package.json
index 26b5124426..baddf4a6eb 100644
--- a/packages/plugin-core/package.json
+++ b/packages/plugin-core/package.json
@@ -5,7 +5,7 @@
"main": "src/index.ts",
"scripts": {
"build": "pnpm build:tsc && pnpm build:wasm",
- "build:tsc": "tsc --noEmit && node esbuild.js",
+ "build:tsc": "mkdir -p dist && echo \"type Manifest = $(cat manifest.json); \nexport default Manifest;\" > dist/manifest.d.ts && tsc --noEmit && node esbuild.js",
"build:wasm": "extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm"
},
"keywords": [],
diff --git a/packages/plugin-core/src/index.d.ts b/packages/plugin-core/src/index.d.ts
index 107bcc7aa0..636cb03047 100644
--- a/packages/plugin-core/src/index.d.ts
+++ b/packages/plugin-core/src/index.d.ts
@@ -22,6 +22,6 @@ declare module 'main' {
export function assetArchive(): I32;
export function assetLock(): I32;
export function assetTimeline(): I32;
- export function assetTrash(): I32;
+ // export function assetTrash(): I32;
export function assetAddToAlbums(): I32;
}
diff --git a/packages/plugin-core/src/index.ts b/packages/plugin-core/src/index.ts
index fa956b8cec..12eaab404b 100644
--- a/packages/plugin-core/src/index.ts
+++ b/packages/plugin-core/src/index.ts
@@ -1,13 +1,11 @@
-import { wrapper } from '@immich/plugin-sdk';
-import { AssetTypeEnum, AssetVisibility, WorkflowType } from '@immich/sdk';
+import { getWrapper } from '@immich/plugin-sdk';
+import { AssetVisibility } from '@immich/sdk';
+import type manifestType from '../dist/manifest';
+
+const wrapper = getWrapper();
-type AssetFileFilterConfig = {
- pattern: string;
- matchType?: 'contains' | 'exact' | 'regex' | 'startsWith';
- caseSensitive?: boolean;
-};
export const assetFileFilter = () => {
- return wrapper(({ data, config }) => {
+ return wrapper<'assetFileFilter'>(({ data, config }) => {
const { pattern, matchType = 'contains', caseSensitive = false } = config;
const { asset } = data;
@@ -43,7 +41,7 @@ export const assetFileFilter = () => {
};
export const assetMissingTimeZoneFilter = () => {
- return wrapper(({ config, data }) => {
+ return wrapper<'assetMissingTimeZoneFilter'>(({ config, data }) => {
const hasTimeZone = !!data.asset?.exifInfo?.timeZone;
const needsTimeZone = config.inverse ? true : false;
return { workflow: { continue: hasTimeZone === needsTimeZone } };
@@ -51,13 +49,7 @@ export const assetMissingTimeZoneFilter = () => {
};
export const assetLocationFilter = () => {
- return wrapper<
- WorkflowType.AssetV1,
- {
- region?: { country?: string; state?: string; city?: string };
- coordinate?: { latitude?: string; longitude?: string; radius?: number };
- }
- >(({ config, data }) => {
+ return wrapper<'assetLocationFilter'>(({ config, data }) => {
if (
(config.region?.country && config.region.country !== data.asset.exifInfo?.country) ||
(config.region?.state && config.region.state !== data.asset.exifInfo?.state) ||
@@ -96,13 +88,13 @@ export const assetLocationFilter = () => {
};
export const assetTypeFilter = () => {
- return wrapper(({ config, data }) => {
+ return wrapper<'assetTypeFilter'>(({ config, data }) => {
return { workflow: { continue: config.allowedTypes.includes(data.asset.type) } };
});
};
export const assetFavorite = () => {
- return wrapper(({ config, data }) => {
+ return wrapper<'assetFavorite'>(({ config, data }) => {
const target = config.inverse ? false : true;
if (target !== data.asset.isFavorite) {
return {
@@ -115,13 +107,13 @@ export const assetFavorite = () => {
};
export const assetVisibility = () => {
- return wrapper(({ config }) => ({
- changes: { asset: { visibility: config.visibility } },
+ return wrapper<'assetVisibility'>(({ config }) => ({
+ changes: { asset: { visibility: config.visibility as AssetVisibility } },
}));
};
export const assetArchive = () => {
- return wrapper(({ config, data }) => {
+ return wrapper<'assetArchive'>(({ config, data }) => {
if (!config.inverse && data.asset.visibility !== AssetVisibility.Archive) {
return { changes: { asset: { visibility: AssetVisibility.Archive } } };
}
@@ -135,7 +127,7 @@ export const assetArchive = () => {
};
export const assetLock = () => {
- return wrapper(({ config, data }) => {
+ return wrapper<'assetLock'>(({ config, data }) => {
if (!config.inverse && data.asset.visibility !== AssetVisibility.Locked) {
return { changes: { asset: { visibility: AssetVisibility.Locked } } };
}
@@ -148,13 +140,13 @@ export const assetLock = () => {
});
};
-export const assetTrash = () => {
- // TODO use trash/untrash host functions
- return wrapper(() => ({}));
-};
+// export const assetTrash = () => {
+// // TODO use trash/untrash host functions
+// return wrapper(() => ({}));
+// };
export const assetAddToAlbums = () => {
- return wrapper(({ config, data, functions }) => {
+ return wrapper<'assetAddToAlbums'>(({ config, data, functions }) => {
const assetId = data.asset.id;
if (config.albumIds.length === 0) {
diff --git a/packages/plugin-sdk/src/sdk.ts b/packages/plugin-sdk/src/sdk.ts
index 5b0443513a..e428eafed5 100644
--- a/packages/plugin-sdk/src/sdk.ts
+++ b/packages/plugin-sdk/src/sdk.ts
@@ -1,53 +1,104 @@
import type { WorkflowType } from '@immich/sdk';
import { hostFunctions } from 'src/host-functions.js';
import type {
- ConfigValue,
WorkflowEventPayload,
WorkflowResponse,
WorkflowStepConfig,
} from 'src/types.js';
-export const wrapper = <
- T extends WorkflowType,
- TConfig extends ConfigValue = ConfigValue,
->(
- fn: (
- payload: WorkflowEventPayload & {
- functions: ReturnType;
- },
- ) => WorkflowResponse | undefined,
-) => {
- const input = Host.inputString();
-
- try {
- const payload = JSON.parse(input) as WorkflowEventPayload;
- const event = {
- ...payload,
- functions: hostFunctions(payload.workflow.authToken),
- };
-
- const eventConfigBefore = JSON.stringify(event.config);
-
- console.debug(
- `Inputs: trigger=${event.trigger}, event=${event.type}, config=${eventConfigBefore}`,
- );
-
- const response = fn(event) ?? {};
-
- // if config changed, notify host
- const eventConfigAfter = JSON.stringify(event.config);
- if (!response.config && eventConfigBefore !== eventConfigAfter) {
- response.config = event.config as WorkflowStepConfig;
- }
-
- console.debug(
- `Outputs: workflow=${JSON.stringify(response.workflow)}, changes=${JSON.stringify(response.changes)}, data=${JSON.stringify(response.data)}, config=${JSON.stringify(response.config)}`,
- );
-
- const output = JSON.stringify(response);
- Host.outputString(output);
- } catch (error: Error | any) {
- console.error(`Unhandled plugin exception: ${error.message || error}`);
- throw error;
- }
+type Property = {
+ type: 'string' | 'boolean' | 'number';
+ array?: boolean;
+ enum?: string[];
+} & {
+ type: 'object';
+ properties: { [K: string]: Property };
+ required?: string[];
};
+
+type RequiredProperties<
+ Properties extends { [K: string]: unknown },
+ Required extends string[] | undefined,
+ RequiredKeys extends string = Required extends undefined
+ ? never
+ : NonNullable[number],
+> = {
+ properties: Pick &
+ Partial>;
+};
+
+type GetConfigType = 'enum' extends keyof T
+ ? NonNullable[number]
+ : T['type'] extends 'boolean'
+ ? boolean
+ : T['type'] extends 'number'
+ ? number
+ : T['type'] extends 'string'
+ ? string
+ : T['type'] extends 'object'
+ ? ConfigValue
+ : never;
+
+type ConfigValue<
+ T extends { properties: { [K: string]: Property }; required?: string[] },
+ Properties extends { [K: string]: Property } = T['properties'],
+> = T extends never
+ ? never
+ : RequiredProperties<
+ {
+ [K in keyof Properties]: Properties[K]['array'] extends true
+ ? Array>
+ : GetConfigType;
+ },
+ 'required' extends keyof T ? T['required'] : undefined
+ >['properties'];
+
+export const getWrapper =
+ >() =>
+ <
+ K extends T['methods'][number]['name'],
+ L extends WorkflowType = (T['methods'][number] & {
+ name: K;
+ })['types'][number],
+ TConfig = ConfigValue<(T['methods'][number] & { name: K })['schema']>,
+ >(
+ fn: (
+ payload: WorkflowEventPayload & {
+ functions: ReturnType;
+ },
+ ) => WorkflowResponse | undefined,
+ ) => {
+ const input = Host.inputString();
+
+ try {
+ const payload = JSON.parse(input) as WorkflowEventPayload;
+ const event = {
+ ...payload,
+ functions: hostFunctions(payload.workflow.authToken),
+ };
+
+ const eventConfigBefore = JSON.stringify(event.config);
+
+ console.debug(
+ `Inputs: trigger=${event.trigger}, event=${event.type}, config=${eventConfigBefore}`,
+ );
+
+ const response = fn(event) ?? {};
+
+ // if config changed, notify host
+ const eventConfigAfter = JSON.stringify(event.config);
+ if (!response.config && eventConfigBefore !== eventConfigAfter) {
+ response.config = event.config as WorkflowStepConfig;
+ }
+
+ console.debug(
+ `Outputs: workflow=${JSON.stringify(response.workflow)}, changes=${JSON.stringify(response.changes)}, data=${JSON.stringify(response.data)}, config=${JSON.stringify(response.config)}`,
+ );
+
+ const output = JSON.stringify(response);
+ Host.outputString(output);
+ } catch (error: Error | any) {
+ console.error(`Unhandled plugin exception: ${error.message || error}`);
+ throw error;
+ }
+ };
diff --git a/server/src/repositories/plugin.repository.ts b/server/src/repositories/plugin.repository.ts
index 43006c6aa6..154266b965 100644
--- a/server/src/repositories/plugin.repository.ts
+++ b/server/src/repositories/plugin.repository.ts
@@ -224,6 +224,7 @@ export class PluginRepository {
error: (message) => logger.error(message),
} as Console,
logLevel: asExtismLogLevel(logger.getLogLevel()),
+ enableWasiOutput: true,
},
),
destroy: (plugin) => plugin.close(),
From 4099fa6b4a3c9a91489cd0d77cbf2a7118477946 Mon Sep 17 00:00:00 2001
From: Yaros
Date: Thu, 25 Jun 2026 03:48:01 +0200
Subject: [PATCH 035/435] fix(mobile): app doesn't exit full-screen mode
(#29301)
* fix(mobile): app doesn't exit full-screen mode
* chore: rename restoreSystemUI to restoreEdgeToEdge
---
.../lib/presentation/pages/drift_memory.page.dart | 5 +++--
.../presentation/pages/drift_slideshow.page.dart | 5 +++--
.../widgets/asset_viewer/asset_viewer.page.dart | 9 ++++-----
mobile/lib/utils/system_ui.utils.dart | 14 ++++++++++++++
4 files changed, 24 insertions(+), 9 deletions(-)
create mode 100644 mobile/lib/utils/system_ui.utils.dart
diff --git a/mobile/lib/presentation/pages/drift_memory.page.dart b/mobile/lib/presentation/pages/drift_memory.page.dart
index 6919925d55..f601bf8419 100644
--- a/mobile/lib/presentation/pages/drift_memory.page.dart
+++ b/mobile/lib/presentation/pages/drift_memory.page.dart
@@ -12,6 +12,7 @@ import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
import 'package:immich_mobile/presentation/widgets/memory/memory_bottom_info.widget.dart';
import 'package:immich_mobile/presentation/widgets/memory/memory_card.widget.dart';
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
+import 'package:immich_mobile/utils/system_ui.utils.dart';
import 'package:immich_mobile/widgets/memories/memory_epilogue.dart';
import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart';
@@ -49,7 +50,7 @@ class DriftMemoryPage extends HookConsumerWidget {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return () {
// Clean up to normal edge to edge when we are done
- SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
+ restoreEdgeToEdge();
};
});
@@ -328,7 +329,7 @@ class DriftMemoryPage extends HookConsumerWidget {
// turn off full screen mode here
// https://github.com/Milad-Akarie/auto_route_library/issues/1799
context.maybePop();
- SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
+ restoreEdgeToEdge();
},
shape: const CircleBorder(),
color: Colors.white.withValues(alpha: 0.2),
diff --git a/mobile/lib/presentation/pages/drift_slideshow.page.dart b/mobile/lib/presentation/pages/drift_slideshow.page.dart
index 4fae0709aa..596b6fdf36 100644
--- a/mobile/lib/presentation/pages/drift_slideshow.page.dart
+++ b/mobile/lib/presentation/pages/drift_slideshow.page.dart
@@ -19,6 +19,7 @@ import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart'
import 'package:immich_mobile/providers/asset_viewer/video_player_provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/routing/router.dart';
+import 'package:immich_mobile/utils/system_ui.utils.dart';
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
import 'package:immich_mobile/widgets/photo_view/photo_view.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
@@ -76,7 +77,7 @@ class _DriftSlideshowPageState extends ConsumerState with Si
_pageController.dispose();
_crossfadeController.dispose();
unawaited(WakelockPlus.disable());
- SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
+ unawaited(restoreEdgeToEdge());
super.dispose();
}
@@ -255,7 +256,7 @@ class _DriftSlideshowPageState extends ConsumerState with Si
}
void _onTapUp() async {
- await SystemChrome.setEnabledSystemUIMode(_showAppBar ? SystemUiMode.immersive : SystemUiMode.edgeToEdge);
+ await (_showAppBar ? SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive) : restoreEdgeToEdge());
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart
index c8d8f63fa9..8b9dc6f887 100644
--- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart
+++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart
@@ -23,6 +23,7 @@ import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart'
import 'package:immich_mobile/providers/cast.provider.dart';
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
+import 'package:immich_mobile/utils/system_ui.utils.dart';
import 'package:immich_mobile/widgets/photo_view/photo_view.dart';
@RoutePage()
@@ -128,7 +129,7 @@ class _AssetViewerState extends ConsumerState {
_reloadSubscription?.cancel();
_stackChildrenKeepAlive?.close();
- SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
+ unawaited(restoreEdgeToEdge());
super.dispose();
}
@@ -251,10 +252,8 @@ class _AssetViewerState extends ConsumerState {
}
void _setSystemUIMode(bool controls, bool details) {
- final mode = !controls || (CurrentPlatform.isIOS && details)
- ? SystemUiMode.immersiveSticky
- : SystemUiMode.edgeToEdge;
- unawaited(SystemChrome.setEnabledSystemUIMode(mode));
+ final immersive = !controls || (CurrentPlatform.isIOS && details);
+ unawaited(immersive ? SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky) : restoreEdgeToEdge());
}
@override
diff --git a/mobile/lib/utils/system_ui.utils.dart b/mobile/lib/utils/system_ui.utils.dart
new file mode 100644
index 0000000000..0d6d65082f
--- /dev/null
+++ b/mobile/lib/utils/system_ui.utils.dart
@@ -0,0 +1,14 @@
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+
+/// Restore the system bars and return to edge-to-edge layout.
+///
+/// On Android 15+/API 36 edge-to-edge is enforced, so calling
+/// setEnabledSystemUIMode(edgeToEdge) does NOT re-show bars that an immersive
+/// mode (immersive / immersiveSticky) previously hid. Explicitly request all
+/// overlays first, then return to edge-to-edge layout.
+Future restoreEdgeToEdge() async {
+ await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
+ await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
+}
From 3a7034d25e178a5fbdc9b4f9d440c65e5e08e223 Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Thu, 25 Jun 2026 20:19:34 +0530
Subject: [PATCH 036/435] chore: cleanup partner action test (#29296)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
.../actions/partner_action_test.dart | 27 +++++++++----------
.../unit/presentation/partner_page_test.dart | 2 +-
mobile/test/unit/presentation_context.dart | 14 ++++++----
3 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/mobile/test/unit/presentation/actions/partner_action_test.dart b/mobile/test/unit/presentation/actions/partner_action_test.dart
index 1eb89fe4cc..0284371c91 100644
--- a/mobile/test/unit/presentation/actions/partner_action_test.dart
+++ b/mobile/test/unit/presentation/actions/partner_action_test.dart
@@ -5,32 +5,25 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/presentation/actions/partner.action.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
-import 'package:immich_mobile/providers/user.provider.dart';
import 'package:mocktail/mocktail.dart';
import '../../factories/user_factory.dart';
-import '../../mocks.dart';
import '../../presentation_context.dart';
void main() {
late PresentationContext context;
- late UserDto currentUser;
- final mocks = ServiceMocks();
setUp(() async {
- currentUser = UserFactory.createDto();
context = await PresentationContext.create();
- when(mocks.user.tryGetMyUser).thenReturn(currentUser);
});
- tearDown(() async {
- mocks.resetAll();
- await context.dispose();
+ tearDown(() {
+ context.dispose();
});
List overrides({List candidates = const []}) => [
- currentUserProvider.overrideWith((ref) => CurrentUserProvider(mocks.user.service)),
- partnerServiceProvider.overrideWithValue(mocks.partner.service),
+ ...context.overrides,
+ partnerServiceProvider.overrideWithValue(context.mocks.partner.service),
candidatesStateProvider.overrideWith((ref) => Stream>.value(candidates)),
];
@@ -43,7 +36,9 @@ void main() {
await tester.tap(find.text(candidate.name));
await tester.pumpAndSettle();
- verify(() => mocks.partner.service.create(sharedById: currentUser.id, sharedWithId: candidate.id)).called(1);
+ verify(
+ () => context.mocks.partner.service.create(sharedById: context.currentUser.id, sharedWithId: candidate.id),
+ ).called(1);
});
testWidgets('creates nothing when the selection dialog is dismissed', (tester) async {
@@ -51,7 +46,7 @@ void main() {
await tester.sendKeyEvent(LogicalKeyboardKey.escape); // dismiss without selecting
await tester.pumpAndSettle();
- verifyNever(mocks.partner.create);
+ verifyNever(context.mocks.partner.create);
});
});
@@ -65,7 +60,9 @@ void main() {
await tester.tap(find.byType(TextButton).last); // confirm
await tester.pumpAndSettle();
- verify(() => mocks.partner.service.delete(sharedById: currentUser.id, sharedWithId: partner.id)).called(1);
+ verify(
+ () => context.mocks.partner.service.delete(sharedById: context.currentUser.id, sharedWithId: partner.id),
+ ).called(1);
});
testWidgets('deletes nothing when the confirmation is cancelled', (tester) async {
@@ -77,7 +74,7 @@ void main() {
await tester.tap(find.byType(TextButton).first); // cancel
await tester.pumpAndSettle();
- verifyNever(mocks.partner.delete);
+ verifyNever(context.mocks.partner.delete);
});
});
}
diff --git a/mobile/test/unit/presentation/partner_page_test.dart b/mobile/test/unit/presentation/partner_page_test.dart
index 4557388dc0..6575b4a15c 100644
--- a/mobile/test/unit/presentation/partner_page_test.dart
+++ b/mobile/test/unit/presentation/partner_page_test.dart
@@ -13,7 +13,7 @@ void main() {
late PresentationContext context;
setUp(() async => context = await PresentationContext.create());
- tearDown(() async => await context.dispose());
+ tearDown(() => context.dispose());
group('PartnerSharedByList', () {
testWidgets('shows the empty-state add button when there are no partners', (tester) async {
diff --git a/mobile/test/unit/presentation_context.dart b/mobile/test/unit/presentation_context.dart
index e411b21802..31b5bc0aff 100644
--- a/mobile/test/unit/presentation_context.dart
+++ b/mobile/test/unit/presentation_context.dart
@@ -23,7 +23,7 @@ import 'mocks.dart';
class PresentationContext {
PresentationContext._({required UserDto user}) : currentUser = user, mocks = ServiceMocks() {
- when(mocks.user.tryGetMyUser).thenReturn(currentUser);
+ setup();
}
static const String serverEndpoint = 'http://localhost:3000';
@@ -46,10 +46,14 @@ class PresentationContext {
return PresentationContext._(user: UserFactory.createDto());
}
- Future dispose() async {
- // TODO: Dispose the store and database after each test.
- // This is currently not possible because the store is a singleton and is used across tests.
- // Refactor the store to be created per test to allow proper disposal.
+ void setup() {
+ when(mocks.user.tryGetMyUser).thenReturn(currentUser);
+ }
+
+ void dispose() {
+ addTearDown(() {
+ mocks.resetAll();
+ });
}
}
From 49a821b0d0007a60cca567a2dd844dad9de87a85 Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Thu, 25 Jun 2026 22:56:59 +0530
Subject: [PATCH 037/435] chore: fix mobile test flakiness (#29325)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
mobile/test/medium/repository_context.dart | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mobile/test/medium/repository_context.dart b/mobile/test/medium/repository_context.dart
index 00390d455f..ed06774e82 100644
--- a/mobile/test/medium/repository_context.dart
+++ b/mobile/test/medium/repository_context.dart
@@ -217,8 +217,8 @@ class MediumRepositoryContext {
}
Future newFace({String? assetId, String? personId, int? imageWidth, int? imageHeight}) {
- imageWidth ??= TestUtils.randInt(999) + 1;
- imageHeight ??= TestUtils.randInt(999) + 1;
+ imageWidth ??= TestUtils.randInt(999) + 2;
+ imageHeight ??= TestUtils.randInt(999) + 2;
final x1 = TestUtils.randInt(imageWidth - 1);
final y1 = TestUtils.randInt(imageHeight - 1);
From cb1af3a8ec00aff06b453bb6ada0adc1e1d82dc4 Mon Sep 17 00:00:00 2001
From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Date: Fri, 26 Jun 2026 02:25:06 +0530
Subject: [PATCH 038/435] feat: favorite bottom sheet action (#29320)
* chore: cleanup partner action test
* feat: favorite bottom sheet action
* review suggestions
* implicit favorite handling
* feat: viewer favorite icon to action (#29321)
* feat: viewer favorite icon to action
* feat: advance info action
* implicit favorite handling
* feat: viewer favorite icon to action
# Conflicts:
# mobile/lib/presentation/widgets/asset_viewer/viewer_top_app_bar.widget.dart
---------
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
* chore: timeline action test (#29324)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
* clear selection only on success
---------
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
---
mobile/lib/domain/services/asset.service.dart | 39 ++++---
mobile/lib/presentation/actions/action.dart | 9 ++
.../actions/asset_debug.action.dart | 27 +++++
.../presentation/actions/favorite.action.dart | 40 +++++++
.../presentation/actions/timeline.action.dart | 24 ++++
.../advanced_info_action_button.widget.dart | 36 ------
.../viewer_kebab_menu.widget.dart | 7 +-
.../viewer_top_app_bar.widget.dart | 23 ++--
.../archive_bottom_sheet.widget.dart | 9 +-
.../favorite_bottom_sheet.widget.dart | 9 +-
.../general_bottom_sheet.widget.dart | 14 +--
.../remote_album_bottom_sheet.widget.dart | 9 +-
.../infrastructure/asset.provider.dart | 6 +-
mobile/lib/utils/action_button.utils.dart | 16 +--
mobile/packages/ui/lib/immich_ui.dart | 1 +
mobile/test/unit/mocks.dart | 12 ++
.../actions/asset_debug_action_test.dart | 54 +++++++++
.../actions/favorite_action_test.dart | 82 +++++++++++++
.../actions/timeline_action_test.dart | 108 ++++++++++++++++++
mobile/test/unit/presentation_context.dart | 7 +-
20 files changed, 438 insertions(+), 94 deletions(-)
create mode 100644 mobile/lib/presentation/actions/asset_debug.action.dart
create mode 100644 mobile/lib/presentation/actions/favorite.action.dart
create mode 100644 mobile/lib/presentation/actions/timeline.action.dart
delete mode 100644 mobile/lib/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart
create mode 100644 mobile/test/unit/presentation/actions/asset_debug_action_test.dart
create mode 100644 mobile/test/unit/presentation/actions/favorite_action_test.dart
create mode 100644 mobile/test/unit/presentation/actions/timeline_action_test.dart
diff --git a/mobile/lib/domain/services/asset.service.dart b/mobile/lib/domain/services/asset.service.dart
index b055ad38b1..ca16d1f980 100644
--- a/mobile/lib/domain/services/asset.service.dart
+++ b/mobile/lib/domain/services/asset.service.dart
@@ -3,33 +3,35 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
+import 'package:immich_mobile/repositories/asset_api.repository.dart';
class AssetService {
- final RemoteAssetRepository _remoteAssetRepository;
- final DriftLocalAssetRepository _localAssetRepository;
+ final RemoteAssetRepository _remoteRepository;
+ final DriftLocalAssetRepository _localRepository;
+ final AssetApiRepository _apiRepository;
- const AssetService({required this._remoteAssetRepository, required this._localAssetRepository});
+ const AssetService({required this._remoteRepository, required this._localRepository, required this._apiRepository});
Future getAsset(BaseAsset asset) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
- return asset is LocalAsset ? _localAssetRepository.get(id) : _remoteAssetRepository.get(id);
+ return asset is LocalAsset ? _localRepository.get(id) : _remoteRepository.get(id);
}
Stream watchAsset(BaseAsset asset) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
- return asset is LocalAsset ? _localAssetRepository.watch(id) : _remoteAssetRepository.watch(id);
+ return asset is LocalAsset ? _localRepository.watch(id) : _remoteRepository.watch(id);
}
Future> getLocalAssetsByChecksum(String checksum) {
- return _localAssetRepository.getByChecksum(checksum);
+ return _localRepository.getByChecksum(checksum);
}
Future getRemoteAssetByChecksum(String checksum) {
- return _remoteAssetRepository.getByChecksum(checksum);
+ return _remoteRepository.getByChecksum(checksum);
}
Future getRemoteAsset(String id) {
- return _remoteAssetRepository.get(id);
+ return _remoteRepository.get(id);
}
Future> getStack(RemoteAsset asset) async {
@@ -37,7 +39,7 @@ class AssetService {
return const [];
}
- final stack = await _remoteAssetRepository.getStackChildren(asset);
+ final stack = await _remoteRepository.getStackChildren(asset);
// Include the primary asset in the stack as the first item
return [asset, ...stack];
}
@@ -48,22 +50,31 @@ class AssetService {
}
final id = asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
- return _remoteAssetRepository.getExif(id);
+ return _remoteRepository.getExif(id);
}
Future> getPlaces(String userId) {
- return _remoteAssetRepository.getPlaces(userId);
+ return _remoteRepository.getPlaces(userId);
}
Future<(int local, int remote)> getAssetCounts() async {
- return (await _localAssetRepository.getCount(), await _remoteAssetRepository.getCount());
+ return (await _localRepository.getCount(), await _remoteRepository.getCount());
}
Future getLocalHashedCount() {
- return _localAssetRepository.getHashedCount();
+ return _localRepository.getHashedCount();
}
Future> getSourceAlbums(String localAssetId, {BackupSelection? backupSelection}) {
- return _localAssetRepository.getSourceAlbums(localAssetId, backupSelection: backupSelection);
+ return _localRepository.getSourceAlbums(localAssetId, backupSelection: backupSelection);
+ }
+
+ Future updateFavorite(List remoteIds, bool isFavorite) async {
+ if (remoteIds.isEmpty) {
+ return;
+ }
+
+ await _apiRepository.updateFavorite(remoteIds, isFavorite);
+ await _remoteRepository.updateFavorite(remoteIds, isFavorite);
}
}
diff --git a/mobile/lib/presentation/actions/action.dart b/mobile/lib/presentation/actions/action.dart
index 5d37706aaa..5ceb2f855d 100644
--- a/mobile/lib/presentation/actions/action.dart
+++ b/mobile/lib/presentation/actions/action.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
class ActionScope {
@@ -21,3 +22,11 @@ abstract class BaseAction {
Future onAction(ActionScope scope);
}
+
+abstract class AssetAction extends BaseAction {
+ final Iterable assets;
+
+ const AssetAction({required this.assets});
+
+ Iterable filter(ActionScope scope) => assets.whereType();
+}
diff --git a/mobile/lib/presentation/actions/asset_debug.action.dart b/mobile/lib/presentation/actions/asset_debug.action.dart
new file mode 100644
index 0000000000..aec99fc90b
--- /dev/null
+++ b/mobile/lib/presentation/actions/asset_debug.action.dart
@@ -0,0 +1,27 @@
+import 'dart:async';
+
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
+import 'package:immich_mobile/generated/translations.g.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
+import 'package:immich_mobile/routing/router.dart';
+
+class AssetDebugAction extends AssetAction {
+ const AssetDebugAction({required super.assets});
+
+ @override
+ IconData get icon => Icons.help_outline_rounded;
+
+ @override
+ String label(ActionScope scope) => scope.context.t.troubleshoot;
+
+ @override
+ bool isVisible(ActionScope scope) =>
+ assets.length == 1 && scope.ref.watch(settingsProvider.notifier).get(.advancedTroubleshooting);
+
+ @override
+ Future onAction(ActionScope scope) async =>
+ unawaited(scope.context.pushRoute(AssetTroubleshootRoute(asset: assets.first)));
+}
diff --git a/mobile/lib/presentation/actions/favorite.action.dart b/mobile/lib/presentation/actions/favorite.action.dart
new file mode 100644
index 0000000000..33d4bb3b6c
--- /dev/null
+++ b/mobile/lib/presentation/actions/favorite.action.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
+import 'package:immich_mobile/generated/translations.g.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
+import 'package:immich_ui/immich_ui.dart';
+
+class FavoriteAction extends AssetAction {
+ final bool shouldFavorite;
+
+ FavoriteAction({required super.assets}) : shouldFavorite = assets.any((asset) => !asset.isFavorite);
+
+ @override
+ IconData get icon => shouldFavorite ? Icons.favorite_border_rounded : Icons.favorite_rounded;
+
+ @override
+ String label(ActionScope scope) => shouldFavorite ? scope.context.t.favorite : scope.context.t.unfavorite;
+
+ @override
+ Iterable filter(ActionScope scope) => assets
+ .where(
+ (asset) => asset is RemoteAsset && asset.ownerId == scope.authUser.id && asset.isFavorite == !shouldFavorite,
+ )
+ .cast();
+
+ @override
+ bool isVisible(ActionScope scope) => filter(scope).isNotEmpty;
+
+ @override
+ Future onAction(ActionScope scope) async {
+ final ActionScope(:ref) = scope;
+ final assets = filter(scope).map((asset) => asset.id).toList(growable: false);
+
+ await ref.read(assetServiceProvider).updateFavorite(assets, shouldFavorite);
+ final message = shouldFavorite
+ ? StaticTranslations.instance.favorite_action_prompt(count: assets.length)
+ : StaticTranslations.instance.unfavorite_action_prompt(count: assets.length);
+ snackbar.success(message);
+ }
+}
diff --git a/mobile/lib/presentation/actions/timeline.action.dart b/mobile/lib/presentation/actions/timeline.action.dart
new file mode 100644
index 0000000000..d8d367f674
--- /dev/null
+++ b/mobile/lib/presentation/actions/timeline.action.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
+
+class TimelineAction extends BaseAction {
+ final BaseAction action;
+
+ const TimelineAction({required this.action});
+
+ @override
+ IconData get icon => action.icon;
+
+ @override
+ String label(ActionScope scope) => action.label(scope);
+
+ @override
+ bool isVisible(ActionScope scope) => action.isVisible(scope);
+
+ @override
+ Future onAction(ActionScope scope) async {
+ await action.onAction(scope);
+ scope.ref.read(multiSelectProvider.notifier).reset();
+ }
+}
diff --git a/mobile/lib/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart
deleted file mode 100644
index b68ab69b26..0000000000
--- a/mobile/lib/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import 'dart:async';
-
-import 'package:flutter/material.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:immich_mobile/constants/enums.dart';
-import 'package:immich_mobile/extensions/translate_extensions.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
-import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
-
-class AdvancedInfoActionButton extends ConsumerWidget {
- final ActionSource source;
- final bool iconOnly;
- final bool menuItem;
-
- const AdvancedInfoActionButton({super.key, required this.source, this.iconOnly = false, this.menuItem = false});
-
- void _onTap(BuildContext context, WidgetRef ref) async {
- if (!context.mounted) {
- return;
- }
-
- unawaited(ref.read(actionProvider.notifier).troubleshoot(source, context));
- }
-
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return BaseActionButton(
- maxWidth: 115.0,
- iconData: Icons.help_outline_rounded,
- label: "troubleshoot".t(context: context),
- iconOnly: iconOnly,
- menuItem: menuItem,
- onPressed: () => _onTap(context, ref),
- );
- }
-}
diff --git a/mobile/lib/presentation/widgets/asset_viewer/viewer_kebab_menu.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/viewer_kebab_menu.widget.dart
index 418d41e1f2..da0abad1dd 100644
--- a/mobile/lib/presentation/widgets/asset_viewer/viewer_kebab_menu.widget.dart
+++ b/mobile/lib/presentation/widgets/asset_viewer/viewer_kebab_menu.widget.dart
@@ -12,6 +12,7 @@ import 'package:immich_mobile/providers/routes.provider.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/utils/action_button.utils.dart';
+import 'package:immich_ui/immich_ui.dart';
class ViewerKebabMenu extends ConsumerWidget {
const ViewerKebabMenu({super.key, this.originalTheme});
@@ -49,9 +50,9 @@ class ViewerKebabMenu extends ConsumerWidget {
timelineOrigin: timelineOrigin,
);
- final menuChildren = ActionButtonBuilder.buildViewerKebabMenu(actionContext, context, ref);
+ final menuChildren = ActionButtonBuilder.buildViewerKebabMenu(actionContext, context);
- return MenuAnchor(
+ return ImmichMenu(
consumeOutsideTap: true,
style: MenuStyle(
backgroundColor: WidgetStatePropertyAll(context.themeData.scaffoldBackgroundColor),
@@ -62,7 +63,7 @@ class ViewerKebabMenu extends ConsumerWidget {
),
padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(vertical: 6)),
),
- menuChildren: [
+ children: [
ConstrainedBox(
constraints: const BoxConstraints(minWidth: 150),
child: Theme(
diff --git a/mobile/lib/presentation/widgets/asset_viewer/viewer_top_app_bar.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/viewer_top_app_bar.widget.dart
index 3b158c63a8..8d51b8cd2e 100644
--- a/mobile/lib/presentation/widgets/asset_viewer/viewer_top_app_bar.widget.dart
+++ b/mobile/lib/presentation/widgets/asset_viewer/viewer_top_app_bar.widget.dart
@@ -2,12 +2,11 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/favorite_action_button.widget.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/favorite.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/motion_photo_action_button.widget.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/viewer_kebab_menu.widget.dart';
import 'package:immich_mobile/providers/activity.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
@@ -15,9 +14,9 @@ import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provid
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
import 'package:immich_mobile/providers/routes.provider.dart';
-import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/timezone.dart';
+import 'package:immich_ui/immich_ui.dart';
class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
const ViewerTopAppBar({super.key});
@@ -31,8 +30,6 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
final album = ref.watch(currentRemoteAlbumProvider);
- final user = ref.watch(currentUserProvider);
- final isOwner = asset is RemoteAsset && asset.ownerId == user?.id;
final isInLockedView = ref.watch(inLockedViewProvider);
final isReadonlyModeEnabled = ref.watch(readonlyModeProvider);
@@ -46,6 +43,7 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
double opacity = ref.watch(assetViewerProvider.select((s) => s.backgroundOpacity)) * (showingControls ? 1 : 0);
final originalTheme = context.themeData;
+ final assetForAction = [asset];
final actions = [
if (asset.isMotionPhoto) const MotionPhotoActionButton(iconOnly: true),
@@ -63,10 +61,7 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
},
),
- if (asset.hasRemote && isOwner && !asset.isFavorite)
- const FavoriteActionButton(source: ActionSource.viewer, iconOnly: true),
- if (asset.hasRemote && isOwner && asset.isFavorite)
- const UnFavoriteActionButton(source: ActionSource.viewer, iconOnly: true),
+ ActionIconButtonWidget(action: FavoriteAction(assets: assetForAction)),
ViewerKebabMenu(originalTheme: originalTheme),
];
@@ -107,7 +102,13 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
leading: const _AppBarBackButton(),
middle: showingDetails ? null : _AssetInfoTitle(asset: asset),
trailing: !showingDetails && !isReadonlyModeEnabled
- ? Row(mainAxisSize: MainAxisSize.min, children: isInLockedView ? lockedViewActions : actions)
+ ? ImmichColorOverride(
+ color: Colors.white,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: isInLockedView ? lockedViewActions : actions,
+ ),
+ )
: null,
),
),
diff --git a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart
index 2e3d2673c7..3c9c0c692e 100644
--- a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart
+++ b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart
@@ -3,12 +3,14 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/favorite.action.dart';
+import 'package:immich_mobile/presentation/actions/timeline.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/favorite_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
@@ -74,6 +76,9 @@ class _ArchiveBottomSheetState extends ConsumerState {
return sheetController.animateTo(0.85, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut);
}
+ final assets = multiselect.selectedAssets.toList(growable: false);
+ final actions = [FavoriteAction(assets: assets)];
+
return BaseBottomSheet(
controller: sheetController,
initialChildSize: 0.25,
@@ -84,7 +89,7 @@ class _ArchiveBottomSheetState extends ConsumerState {
if (multiselect.hasRemote) ...[
const ShareLinkActionButton(source: ActionSource.timeline),
const UnArchiveActionButton(source: ActionSource.timeline),
- const FavoriteActionButton(source: ActionSource.timeline),
+ ...actions.map((action) => ActionColumnButtonWidget(action: TimelineAction(action: action))),
if (multiselect.onlyRemote) const DownloadActionButton(source: ActionSource.timeline),
isTrashEnable
? const TrashActionButton(source: ActionSource.timeline)
diff --git a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart
index 1dee0f6456..8438d5e8ac 100644
--- a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart
+++ b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart
@@ -4,6 +4,9 @@ import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/favorite.action.dart';
+import 'package:immich_mobile/presentation/actions/timeline.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
@@ -15,7 +18,6 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_b
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart';
@@ -65,6 +67,9 @@ class FavoriteBottomSheet extends ConsumerWidget {
ref.read(multiSelectProvider.notifier).reset();
}
+ final assets = multiselect.selectedAssets.toList(growable: false);
+ final actions = [FavoriteAction(assets: assets)];
+
return BaseBottomSheet(
initialChildSize: 0.4,
maxChildSize: 0.7,
@@ -73,7 +78,7 @@ class FavoriteBottomSheet extends ConsumerWidget {
const ShareActionButton(source: ActionSource.timeline),
if (multiselect.hasRemote) ...[
const ShareLinkActionButton(source: ActionSource.timeline),
- const UnFavoriteActionButton(source: ActionSource.timeline),
+ ...actions.map((action) => ActionColumnButtonWidget(action: TimelineAction(action: action))),
const ArchiveActionButton(source: ActionSource.timeline),
if (multiselect.onlyRemote) const DownloadActionButton(source: ActionSource.timeline),
isTrashEnable
diff --git a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart
index c3a569407a..1949a79495 100644
--- a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart
+++ b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart
@@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
-import 'package:immich_mobile/domain/models/setting.model.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
+import 'package:immich_mobile/presentation/actions/timeline.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/bulk_tag_assets_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
@@ -24,7 +25,6 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart';
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
-import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
import 'package:immich_mobile/providers/infrastructure/user_metadata.provider.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
@@ -56,7 +56,6 @@ class _GeneralBottomSheetState extends ConsumerState {
Widget build(BuildContext context) {
final multiselect = ref.watch(multiSelectProvider);
final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash));
- final advancedTroubleshooting = ref.watch(settingsProvider.notifier).get(Setting.advancedTroubleshooting);
final tagsEnabled = ref.watch(
userMetadataPreferencesProvider.select((value) => value.valueOrNull?.tagsEnabled ?? false),
);
@@ -84,6 +83,9 @@ class _GeneralBottomSheetState extends ConsumerState {
return sheetController.animateTo(0.85, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut);
}
+ final assets = multiselect.selectedAssets.toList(growable: false);
+ final actions = [AssetDebugAction(assets: assets)];
+
return BaseBottomSheet(
controller: sheetController,
initialChildSize: widget.minChildSize ?? 0.15,
@@ -91,9 +93,7 @@ class _GeneralBottomSheetState extends ConsumerState {
maxChildSize: 0.85,
shouldCloseOnMinExtent: false,
actions: [
- if (multiselect.selectedAssets.length == 1 && advancedTroubleshooting) ...[
- const AdvancedInfoActionButton(source: ActionSource.timeline),
- ],
+ ...actions.map((action) => ActionColumnButtonWidget(action: TimelineAction(action: action))),
const ShareActionButton(source: ActionSource.timeline),
if (multiselect.hasRemote) ...[
const ShareLinkActionButton(source: ActionSource.timeline),
diff --git a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart
index 6b914ed077..a292c1899c 100644
--- a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart
+++ b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart
@@ -3,13 +3,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/favorite.action.dart';
+import 'package:immich_mobile/presentation/actions/timeline.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/favorite_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/set_album_cover.widget.dart';
@@ -83,6 +85,9 @@ class _RemoteAlbumBottomSheetState extends ConsumerState
return sheetController.animateTo(0.85, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut);
}
+ final assets = multiselect.selectedAssets.toList(growable: false);
+ final actions = [FavoriteAction(assets: assets)];
+
return BaseBottomSheet(
controller: sheetController,
initialChildSize: 0.22,
@@ -96,7 +101,7 @@ class _RemoteAlbumBottomSheetState extends ConsumerState
if (ownsAlbum) ...[
const ArchiveActionButton(source: ActionSource.timeline),
- const FavoriteActionButton(source: ActionSource.timeline),
+ ...actions.map((action) => ActionColumnButtonWidget(action: TimelineAction(action: action))),
],
const DownloadActionButton(source: ActionSource.timeline),
if (ownsAlbum) ...[
diff --git a/mobile/lib/providers/infrastructure/asset.provider.dart b/mobile/lib/providers/infrastructure/asset.provider.dart
index 70cb200bf1..6326d003e5 100644
--- a/mobile/lib/providers/infrastructure/asset.provider.dart
+++ b/mobile/lib/providers/infrastructure/asset.provider.dart
@@ -5,6 +5,7 @@ import 'package:immich_mobile/infrastructure/repositories/remote_asset.repositor
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
+import 'package:immich_mobile/repositories/asset_api.repository.dart';
final localAssetRepository = Provider(
(ref) => DriftLocalAssetRepository(ref.watch(driftProvider)),
@@ -20,8 +21,9 @@ final trashedLocalAssetRepository = Provider(
final assetServiceProvider = Provider(
(ref) => AssetService(
- remoteAssetRepository: ref.watch(remoteAssetRepositoryProvider),
- localAssetRepository: ref.watch(localAssetRepository),
+ remoteRepository: ref.watch(remoteAssetRepositoryProvider),
+ localRepository: ref.watch(localAssetRepository),
+ apiRepository: ref.watch(assetApiRepositoryProvider),
),
);
diff --git a/mobile/lib/utils/action_button.utils.dart b/mobile/lib/utils/action_button.utils.dart
index b9cff613fd..0e5a3123e7 100644
--- a/mobile/lib/utils/action_button.utils.dart
+++ b/mobile/lib/utils/action_button.utils.dart
@@ -1,14 +1,14 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/events.model.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
-import 'package:immich_mobile/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/cast_action_button.widget.dart';
@@ -185,18 +185,14 @@ enum ActionButtonType {
};
}
- ConsumerWidget buildButton(
+ Widget buildButton(
ActionButtonContext context, [
BuildContext? buildContext,
bool iconOnly = false,
bool menuItem = false,
]) {
return switch (this) {
- ActionButtonType.advancedInfo => AdvancedInfoActionButton(
- source: context.source,
- iconOnly: iconOnly,
- menuItem: menuItem,
- ),
+ ActionButtonType.advancedInfo => ActionMenuItemWidget(action: AssetDebugAction(assets: [context.asset])),
ActionButtonType.share => ShareActionButton(source: context.source, iconOnly: iconOnly, menuItem: menuItem),
ActionButtonType.shareLink => ShareLinkActionButton(
source: context.source,
@@ -334,7 +330,7 @@ class ActionButtonBuilder {
return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList();
}
- static List buildViewerKebabMenu(ActionButtonContext context, BuildContext buildContext, WidgetRef ref) {
+ static List buildViewerKebabMenu(ActionButtonContext context, BuildContext buildContext) {
final visibleButtons = defaultViewerKebabMenuOrder
.where((type) => !defaultViewerBottomBarButtons.contains(type) && type.shouldShow(context))
.toList();
@@ -350,7 +346,7 @@ class ActionButtonBuilder {
if (lastGroup != null && type.kebabMenuGroup != lastGroup) {
result.add(const Divider(height: 1));
}
- result.add(type.buildButton(context, buildContext, false, true).build(buildContext, ref));
+ result.add(type.buildButton(context, buildContext, false, true));
lastGroup = type.kebabMenuGroup;
}
diff --git a/mobile/packages/ui/lib/immich_ui.dart b/mobile/packages/ui/lib/immich_ui.dart
index eaf7051637..8ea88135e5 100644
--- a/mobile/packages/ui/lib/immich_ui.dart
+++ b/mobile/packages/ui/lib/immich_ui.dart
@@ -1,3 +1,4 @@
+export 'src/color_override.dart';
export 'src/components/close_button.dart';
export 'src/components/column_button.dart';
export 'src/components/form.dart';
diff --git a/mobile/test/unit/mocks.dart b/mobile/test/unit/mocks.dart
index 69260d343d..49bab00704 100644
--- a/mobile/test/unit/mocks.dart
+++ b/mobile/test/unit/mocks.dart
@@ -34,6 +34,7 @@ class RepositoryMocks {
class ServiceMocks {
final PartnerStub partner = PartnerStub(MockPartnerService());
final UserStub user = UserStub(MockUserService());
+ final asset = AssetStub(MockAssetService());
ServiceMocks() {
resetAll();
@@ -43,8 +44,10 @@ class ServiceMocks {
_registerFallbacks();
partner.reset();
user.reset();
+ asset.reset();
_stubUserService();
_stubPartnerService();
+ _stubAssetService();
}
void _stubUserService() {
@@ -63,6 +66,10 @@ class ServiceMocks {
when(partner.create).thenAnswer((_) async {});
when(partner.delete).thenAnswer((_) async {});
}
+
+ void _stubAssetService() {
+ when(asset.updateFavorite).thenAnswer((_) async {});
+ }
}
void _registerFallbacks() {
@@ -119,3 +126,8 @@ extension type const UserStub(MockUserService service) implements Stub Function() get createProfileImage =>
() => service.createProfileImage(any(), any());
}
+
+extension type const AssetStub(MockAssetService service) implements Stub {
+ Future Function() get updateFavorite =>
+ () => service.updateFavorite(any(), any());
+}
diff --git a/mobile/test/unit/presentation/actions/asset_debug_action_test.dart b/mobile/test/unit/presentation/actions/asset_debug_action_test.dart
new file mode 100644
index 0000000000..b720c8720e
--- /dev/null
+++ b/mobile/test/unit/presentation/actions/asset_debug_action_test.dart
@@ -0,0 +1,54 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/domain/services/store.service.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
+import 'package:immich_ui/immich_ui.dart';
+
+import '../../factories/remote_asset_factory.dart';
+import '../../presentation_context.dart';
+
+void main() {
+ late PresentationContext context;
+
+ setUp(() async {
+ context = await PresentationContext.create();
+ await StoreService.I.put(StoreKey.advancedTroubleshooting, true);
+ });
+
+ tearDown(() {
+ context.dispose();
+ });
+
+ group('AssetDebugAction', () {
+ testWidgets('visible for a single asset when advanced troubleshooting is on', (tester) async {
+ await tester.pumpTestWidget(
+ ActionIconButtonWidget(action: AssetDebugAction(assets: [RemoteAssetFactory.create()])),
+ overrides: context.overrides,
+ );
+
+ expect(find.byType(ImmichIconButton), findsOneWidget);
+ });
+
+ testWidgets('hidden for multiple assets', (tester) async {
+ await tester.pumpTestWidget(
+ ActionIconButtonWidget(
+ action: AssetDebugAction(assets: [RemoteAssetFactory.create(), RemoteAssetFactory.create()]),
+ ),
+ overrides: context.overrides,
+ );
+
+ expect(find.byType(ImmichIconButton), findsNothing);
+ });
+
+ testWidgets('hidden when advanced troubleshooting is off', (tester) async {
+ await StoreService.I.put(StoreKey.advancedTroubleshooting, false);
+ await tester.pumpTestWidget(
+ ActionIconButtonWidget(action: AssetDebugAction(assets: [RemoteAssetFactory.create()])),
+ overrides: context.overrides,
+ );
+
+ expect(find.byType(ImmichIconButton), findsNothing);
+ });
+ });
+}
diff --git a/mobile/test/unit/presentation/actions/favorite_action_test.dart b/mobile/test/unit/presentation/actions/favorite_action_test.dart
new file mode 100644
index 0000000000..cc8a2fc66c
--- /dev/null
+++ b/mobile/test/unit/presentation/actions/favorite_action_test.dart
@@ -0,0 +1,82 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
+import 'package:immich_mobile/presentation/actions/favorite.action.dart';
+import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
+import 'package:mocktail/mocktail.dart';
+
+import '../../factories/remote_asset_factory.dart';
+import '../../presentation_context.dart';
+
+void main() {
+ late PresentationContext context;
+
+ setUp(() async {
+ context = await PresentationContext.create();
+ });
+
+ tearDown(() {
+ context.dispose();
+ });
+
+ List overrides() => [
+ ...context.overrides,
+ assetServiceProvider.overrideWithValue(context.mocks.asset.service),
+ ];
+
+ RemoteAsset owned({bool isFavorite = false}) =>
+ RemoteAssetFactory.create(ownerId: context.currentUser.id, isFavorite: isFavorite);
+
+ group('FavoriteAction', () {
+ testWidgets('favorites the eligible owned assets', (tester) async {
+ final asset = owned();
+
+ await tester.pumpTestAction(FavoriteAction(assets: [asset]), overrides: overrides());
+
+ verify(() => context.mocks.asset.service.updateFavorite([asset.id], true)).called(1);
+ });
+
+ testWidgets('unfavorite the eligible owned assets', (tester) async {
+ final asset = owned(isFavorite: true);
+
+ await tester.pumpTestAction(FavoriteAction(assets: [asset]), overrides: overrides());
+
+ verify(() => context.mocks.asset.service.updateFavorite([asset.id], false)).called(1);
+ });
+
+ testWidgets('ignores assets owned by someone else', (tester) async {
+ final mine = owned();
+ final theirs = RemoteAssetFactory.create();
+
+ await tester.pumpTestAction(FavoriteAction(assets: [mine, theirs]), overrides: overrides());
+
+ verify(() => context.mocks.asset.service.updateFavorite([mine.id], true)).called(1);
+ });
+
+ testWidgets('batches every eligible owned asset into a single call', (tester) async {
+ final first = owned();
+ final second = owned();
+
+ await tester.pumpTestAction(FavoriteAction(assets: [first, second]), overrides: overrides());
+
+ verify(() => context.mocks.asset.service.updateFavorite([first.id, second.id], true)).called(1);
+ });
+
+ testWidgets('skips owned assets already in the target state', (tester) async {
+ final stale = owned();
+ final alreadyFavorite = owned(isFavorite: true);
+
+ await tester.pumpTestAction(FavoriteAction(assets: [stale, alreadyFavorite]), overrides: overrides());
+
+ verify(() => context.mocks.asset.service.updateFavorite([stale.id], true)).called(1);
+ });
+
+ testWidgets('shows a confirmation snackbar on success', (tester) async {
+ await tester.pumpTestAction(FavoriteAction(assets: [owned()]), overrides: overrides());
+ await tester.pumpUntilFound(find.byType(SnackBar));
+
+ expect(find.byType(SnackBar), findsOneWidget);
+ });
+ });
+}
diff --git a/mobile/test/unit/presentation/actions/timeline_action_test.dart b/mobile/test/unit/presentation/actions/timeline_action_test.dart
new file mode 100644
index 0000000000..6c14053317
--- /dev/null
+++ b/mobile/test/unit/presentation/actions/timeline_action_test.dart
@@ -0,0 +1,108 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/presentation/actions/action.dart';
+import 'package:immich_mobile/presentation/actions/action.widget.dart';
+import 'package:immich_mobile/presentation/actions/timeline.action.dart';
+import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
+
+import '../../factories/remote_asset_factory.dart';
+import '../../presentation_context.dart';
+
+class _FakeAction extends BaseAction {
+ _FakeAction({this.visible = true, this.error});
+
+ final bool visible;
+ final Object? error;
+
+ bool ran = false;
+ bool? selectionDuringOnAction;
+
+ @override
+ IconData get icon => Icons.bolt;
+
+ @override
+ String label(ActionScope scope) => 'fake';
+
+ @override
+ bool isVisible(ActionScope scope) => visible;
+
+ @override
+ Future onAction(ActionScope scope) async {
+ ran = true;
+ selectionDuringOnAction = scope.ref.read(multiSelectProvider).isEnabled;
+ if (error != null) {
+ throw error!;
+ }
+ }
+}
+
+void main() {
+ late PresentationContext context;
+
+ setUp(() async {
+ context = await PresentationContext.create();
+ });
+
+ tearDown(() {
+ context.dispose();
+ });
+
+ List seededOverrides() => [
+ ...context.overrides,
+ multiSelectProvider.overrideWith(
+ () => MultiSelectNotifier(
+ MultiSelectState(selectedAssets: {RemoteAssetFactory.create()}, lockedSelectionAssets: const {}),
+ ),
+ ),
+ ];
+
+ Future<(ActionScope, ProviderContainer)> pumpScope(WidgetTester tester) async {
+ late ActionScope scope;
+ late ProviderContainer container;
+ await tester.pumpTestWidget(
+ Consumer(
+ builder: (innerContext, ref, _) {
+ scope = ActionScope(context: innerContext, ref: ref, authUser: context.currentUser);
+ container = ProviderScope.containerOf(innerContext, listen: false);
+ return const SizedBox.shrink();
+ },
+ ),
+ overrides: seededOverrides(),
+ );
+ return (scope, container);
+ }
+
+ group('TimelineAction', () {
+ testWidgets('runs the wrapped action and then clears the selection', (tester) async {
+ final inner = _FakeAction();
+ final (scope, container) = await pumpScope(tester);
+ await TimelineAction(action: inner).onAction(scope);
+
+ expect(inner.ran, isTrue);
+ expect(inner.selectionDuringOnAction, isTrue, reason: 'reset must run after the inner action, not before');
+ expect(container.read(multiSelectProvider).isEnabled, isFalse);
+ });
+
+ testWidgets('rethrows and keeps the selection when the wrapped action throws', (tester) async {
+ final error = Exception('boom');
+ final inner = _FakeAction(error: error);
+ final (scope, container) = await pumpScope(tester);
+
+ await expectLater(TimelineAction(action: inner).onAction(scope), throwsA(same(error)));
+
+ expect(inner.ran, isTrue);
+ expect(container.read(multiSelectProvider).isEnabled, isTrue);
+ });
+
+ testWidgets('delegates visibility to the wrapped action', (tester) async {
+ await tester.pumpTestWidget(
+ ActionIconButtonWidget(action: TimelineAction(action: _FakeAction(visible: false))),
+ overrides: context.overrides,
+ );
+
+ expect(find.byType(ActionIconButtonWidget), findsOneWidget);
+ expect(find.byIcon(Icons.bolt), findsNothing);
+ });
+ });
+}
diff --git a/mobile/test/unit/presentation_context.dart b/mobile/test/unit/presentation_context.dart
index 31b5bc0aff..d3998994c9 100644
--- a/mobile/test/unit/presentation_context.dart
+++ b/mobile/test/unit/presentation_context.dart
@@ -77,7 +77,7 @@ extension PumpPresentationWidget on WidgetTester {
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
- home: Material(child: widget),
+ home: Scaffold(body: widget),
),
),
),
@@ -87,10 +87,7 @@ extension PumpPresentationWidget on WidgetTester {
}
Future pumpTestAction(BaseAction action, {List overrides = const []}) async {
- await pumpTestWidget(
- Scaffold(body: ActionIconButtonWidget(action: action)),
- overrides: overrides,
- );
+ await pumpTestWidget(ActionIconButtonWidget(action: action), overrides: overrides);
await tap(find.byType(ImmichIconButton));
await pump();
}
From 688241a462050884d9e9a2ab6b7e14eb48db5f25 Mon Sep 17 00:00:00 2001
From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
Date: Fri, 26 Jun 2026 00:23:55 +0200
Subject: [PATCH 039/435] feat: plugin-sdk safety all around (#29323)
---
packages/plugin-core/package.json | 4 +-
packages/plugin-core/src/index.d.ts | 27 ---
packages/plugin-core/src/index.ts | 270 ++++++++++------------
packages/plugin-core/tsconfig.json | 2 +-
packages/plugin-sdk/esbuild.js | 3 +-
packages/plugin-sdk/package.json | 6 +
packages/plugin-sdk/plugin-sdk.mjs | 2 +
packages/plugin-sdk/src/cli.ts | 43 ++++
packages/plugin-sdk/src/host-functions.ts | 20 +-
packages/plugin-sdk/src/sdk.ts | 3 +-
pnpm-lock.yaml | 4 +
11 files changed, 200 insertions(+), 184 deletions(-)
delete mode 100644 packages/plugin-core/src/index.d.ts
create mode 100755 packages/plugin-sdk/plugin-sdk.mjs
create mode 100644 packages/plugin-sdk/src/cli.ts
diff --git a/packages/plugin-core/package.json b/packages/plugin-core/package.json
index baddf4a6eb..5e4812bb1c 100644
--- a/packages/plugin-core/package.json
+++ b/packages/plugin-core/package.json
@@ -5,8 +5,8 @@
"main": "src/index.ts",
"scripts": {
"build": "pnpm build:tsc && pnpm build:wasm",
- "build:tsc": "mkdir -p dist && echo \"type Manifest = $(cat manifest.json); \nexport default Manifest;\" > dist/manifest.d.ts && tsc --noEmit && node esbuild.js",
- "build:wasm": "extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm"
+ "build:tsc": "plugin-sdk prepareBuild && tsc --noEmit && node esbuild.js",
+ "build:wasm": "extism-js dist/index.js -i dist/index.d.ts -o dist/plugin.wasm"
},
"keywords": [],
"author": "",
diff --git a/packages/plugin-core/src/index.d.ts b/packages/plugin-core/src/index.d.ts
deleted file mode 100644
index 636cb03047..0000000000
--- a/packages/plugin-core/src/index.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// keep in sync with plugin-sdk/host-functions.ts';
-declare module 'extism:host' {
- interface user {
- searchAlbums(ptr: PTR): I64;
- createAlbum(ptr: PTR): I64;
- addAssetsToAlbum(ptr: PTR): I64;
- addAssetsToAlbums(ptr: PTR): I64;
- }
-}
-
-// keep in sync with manifest.json
-declare module 'main' {
- // filters
- export function assetFileFilter(): I32;
- export function assetMissingTimeZoneFilter(): I32;
- export function assetLocationFilter(): I32;
- export function assetTypeFilter(): I32;
-
- // updates
- export function assetFavorite(): I32;
- export function assetVisibility(): I32;
- export function assetArchive(): I32;
- export function assetLock(): I32;
- export function assetTimeline(): I32;
- // export function assetTrash(): I32;
- export function assetAddToAlbums(): I32;
-}
diff --git a/packages/plugin-core/src/index.ts b/packages/plugin-core/src/index.ts
index 12eaab404b..164f33d72b 100644
--- a/packages/plugin-core/src/index.ts
+++ b/packages/plugin-core/src/index.ts
@@ -1,175 +1,157 @@
import { getWrapper } from '@immich/plugin-sdk';
import { AssetVisibility } from '@immich/sdk';
-import type manifestType from '../dist/manifest';
+import type { Manifest } from '../dist/index.d.ts';
-const wrapper = getWrapper();
+const wrapper = getWrapper