diff --git a/README.md b/README.md index 02e27ca8bd..5fe4e92a86 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ RapidRAW is still in active development and isn't yet as polished as mature tool
Recent Changes +- **2026-06-12:** Added Lightroom XMP sidecar adjustment import for individual images and matching sidecars in folders - **2026-06-07:** Fixed copy-pasting, improved library performance & eight new languages - **2026-06-01:** Improved thumbnail performance, polished metadata panel & non-blocking exif reading - **2026-05-30:** Implemented reliable edited status, sorting & filtering options @@ -285,6 +286,7 @@ RapidRAW is still in active development and isn't yet as polished as mature tool **Table of Contents** - [Key Features](#key-features) +- [Importing Lightroom XMP Sidecars](#importing-lightroom-xmp-sidecars) - [Demo & Screenshots](#demo--screenshots) - [The Idea](#the-idea) - [Current Priorities](#current-priorities) @@ -329,6 +331,7 @@ RapidRAW is still in active development and isn't yet as polished as mature tool
  • Image Library: Effortlessly manage and cull your entire photo collection for a streamlined and efficient workflow.
  • Organization: Recursive folder view, virtual copies, color labels, star ratings, tags and more.
  • File Operations: Import, copy, move, rename, and duplicate images/folders.
  • +
  • Lightroom XMP Import: Import .xmp sidecar adjustments for a single image, or batch import matching sidecars from a folder by filename.
  • Filmstrip View: Quickly navigate between all the images in your current folder while editing.
  • Batch Operations: Save significant time by applying a consistent set of adjustments or exporting entire batches of images simultaneously.
  • EXIF Data Viewer: Gain insights by inspecting the complete metadata from your camera.
  • @@ -346,6 +349,36 @@ RapidRAW is still in active development and isn't yet as polished as mature tool +## Importing Lightroom XMP Sidecars + +RapidRAW can import Adobe Lightroom® / Camera Raw `.xmp` sidecars into its non-destructive `.rrdata` workflow. Imported XMP adjustments replace the current RapidRAW adjustments for the target image while preserving the original image file. + +### Import XMP for a Single Image + +1. Open the image in the editor, or select it in the library. +2. Right-click the image. +3. Choose **Import XMP Adjustments**. +4. Select the `.xmp` sidecar file to import. + +RapidRAW imports supported Lightroom adjustment values, then refreshes the image preview and thumbnail. Rating, color label, and keyword metadata from the XMP are also merged when present. + +### Import Matching XMP Sidecars in a Folder + +Use this when a folder contains images and Lightroom sidecars with the same filename stem: + +```text +IMG_0001.CR3 +IMG_0001.xmp +IMG_0002.NEF +IMG_0002.XMP +``` + +1. Open the folder in RapidRAW's library. +2. Right-click the folder in the folder tree. +3. Choose **Import Matching XMP Sidecars**. + +RapidRAW scans the selected folder, matches supported image files to `.xmp` files by filename without the extension, and imports each matching sidecar. The folder import is non-recursive; subfolders are left untouched. + ## Demo & Screenshots Here's RapidRAW in action. diff --git a/src-tauri/src/file_management.rs b/src-tauri/src/file_management.rs index 8e6d8e65f4..6ccb5c6acf 100644 --- a/src-tauri/src/file_management.rs +++ b/src-tauri/src/file_management.rs @@ -2,6 +2,7 @@ use memmap2::{Mmap, MmapOptions}; use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; +use std::ffi::OsString; use std::fmt; use std::fs; use std::hash::{Hash, Hasher}; @@ -162,6 +163,23 @@ pub struct ImportSettings { pub delete_after_import: bool, } +#[derive(Debug)] +struct ImportedXmpSidecar { + source_path: PathBuf, + sidecar_path: PathBuf, + metadata: ImageMetadata, +} + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct XmpSidecarImportResult { + pub imported: usize, + pub skipped: usize, + pub failed: usize, + pub failures: Vec, + pub imported_paths: Vec, +} + pub fn parse_virtual_path(virtual_path: &str) -> (PathBuf, PathBuf) { let (source_path_str, copy_id) = if let Some((base, id)) = virtual_path.rsplit_once("?vc=") { (base.to_string(), Some(id.to_string())) @@ -2103,6 +2121,201 @@ pub fn save_metadata_and_update_thumbnail( Ok(()) } +fn is_xmp_sidecar_path(path: &Path) -> bool { + path.extension() + .and_then(|ext| ext.to_str()) + .is_some_and(|ext| ext.eq_ignore_ascii_case("xmp")) +} + +fn import_xmp_adjustments_to_sidecar( + path: &str, + xmp_path: &Path, + lens_db: Option<&crate::lens_correction::LensDatabase>, +) -> Result { + if !is_xmp_sidecar_path(xmp_path) { + return Err("Selected file is not an XMP sidecar.".to_string()); + } + + let xmp_content = + fs::read_to_string(xmp_path).map_err(|e| format!("Failed to read XMP file: {}", e))?; + let converted_preset = preset_converter::convert_xmp_to_preset(&xmp_content)?; + + if converted_preset + .adjustments + .as_object() + .is_none_or(|adjustments| adjustments.is_empty()) + { + return Err( + "No supported Lightroom adjustments were found in the selected XMP file.".to_string(), + ); + } + + let (source_path, sidecar_path) = parse_virtual_path(path); + let mut metadata = crate::exif_processing::load_sidecar(&sidecar_path); + metadata.adjustments = converted_preset.adjustments.clone(); + resolve_lens_params_in_adjustments(&mut metadata.adjustments, &metadata.exif, lens_db); + merge_xmp_metadata_fields(&xmp_content, &mut metadata); + + let json_string = serde_json::to_string_pretty(&metadata).map_err(|e| e.to_string())?; + std::fs::write(&sidecar_path, json_string).map_err(|e| e.to_string())?; + + Ok(ImportedXmpSidecar { + source_path, + sidecar_path, + metadata, + }) +} + +#[tauri::command] +pub fn import_xmp_adjustments_for_image( + path: String, + xmp_path: String, + app_handle: AppHandle, + state: tauri::State, +) -> Result { + let lens_db = state.lens_db.lock().unwrap().clone(); + let imported = + import_xmp_adjustments_to_sidecar(&path, Path::new(&xmp_path), lens_db.as_deref())?; + let imported_adjustments = imported.metadata.adjustments.clone(); + let sidecar_path = imported.sidecar_path.clone(); + + save_metadata_and_update_thumbnail(path, imported_adjustments, app_handle, state)?; + + Ok(crate::exif_processing::load_sidecar(&sidecar_path)) +} + +#[tauri::command] +pub async fn import_matching_xmp_sidecars_in_folder( + folder_path: String, + app_handle: AppHandle, +) -> Result { + tauri::async_runtime::spawn_blocking(move || { + let folder = PathBuf::from(&folder_path); + if !folder.is_dir() { + return Err(format!("Folder not found: {}", folder.display())); + } + + let entries: Vec = fs::read_dir(&folder) + .map_err(|e| format!("Failed to read folder: {}", e))? + .filter_map(|entry| entry.ok().map(|entry| entry.path())) + .filter(|path| path.is_file()) + .collect(); + + let mut xmp_by_stem: HashMap = HashMap::new(); + for path in &entries { + if is_xmp_sidecar_path(path) + && let Some(stem) = path.file_stem() + { + xmp_by_stem + .entry(stem.to_os_string()) + .or_insert_with(|| path.clone()); + } + } + + let settings = load_settings(app_handle.clone()).unwrap_or_default(); + let enable_xmp_sync = settings.enable_xmp_sync.unwrap_or(false); + let create_xmp_if_missing = settings.create_xmp_if_missing.unwrap_or(false); + let lens_db = app_handle.state::().lens_db.lock().unwrap().clone(); + + let mut result = XmpSidecarImportResult { + imported: 0, + skipped: 0, + failed: 0, + failures: Vec::new(), + imported_paths: Vec::new(), + }; + + for path in entries.iter().filter(|path| is_supported_image_file(path)) { + let Some(stem) = path.file_stem() else { + result.skipped += 1; + continue; + }; + + let Some(xmp_path) = xmp_by_stem.get(stem) else { + result.skipped += 1; + continue; + }; + + let path_str = path.to_string_lossy().to_string(); + match import_xmp_adjustments_to_sidecar(&path_str, xmp_path, lens_db.as_deref()) { + Ok(imported) => { + if enable_xmp_sync { + sync_metadata_to_xmp( + &imported.source_path, + &imported.metadata, + create_xmp_if_missing, + ); + } + result.imported += 1; + result.imported_paths.push(path_str); + } + Err(err) => { + result.failed += 1; + let file_name = path + .file_name() + .map(|name| name.to_string_lossy()) + .unwrap_or_else(|| path.to_string_lossy()); + result.failures.push(format!("{}: {}", file_name, err)); + } + } + } + + if !result.imported_paths.is_empty() { + let imported_paths = result.imported_paths.clone(); + let app_handle_clone = app_handle.clone(); + let state = app_handle.state::(); + add_to_thumbnail_queue(&state, imported_paths.len(), &app_handle); + + thread::spawn(move || { + let state = app_handle_clone.state::(); + let settings = load_settings(app_handle_clone.clone()).unwrap_or_default(); + + let thumb_cache_dir = match resolve_thumbnail_cache_dir(&app_handle_clone) { + Ok(dir) => dir, + Err(e) => { + log::warn!("Unable to initialize thumbnail cache directory: {}", e); + for path in &imported_paths { + emit_thumbnail_cache_setup_error(&app_handle_clone, path, &e); + } + for _ in 0..imported_paths.len() { + increment_thumbnail_progress(&state, &app_handle_clone); + } + return; + } + }; + + let gpu_context = + gpu_processing::get_or_init_gpu_context(&state, &app_handle_clone).ok(); + + imported_paths.par_iter().for_each(|path_str| { + let result = generate_single_thumbnail_and_cache( + path_str, + &thumb_cache_dir, + gpu_context.as_ref(), + None, + true, + &app_handle_clone, + &settings, + ); + + if let Some((thumbnail_data, rating, is_edited)) = result { + let _ = app_handle_clone.emit( + "thumbnail-generated", + serde_json::json!({ "path": path_str, "data": thumbnail_data, "rating": rating, "is_edited": is_edited }), + ); + } + + increment_thumbnail_progress(&state, &app_handle_clone); + }); + }); + } + + Ok(result) + }) + .await + .unwrap_or_else(|e| Err(format!("Task failed: {}", e))) +} + #[tauri::command] pub async fn apply_adjustments_to_paths( paths: Vec, @@ -3447,6 +3660,44 @@ pub fn extract_xmp_tags(content: &str) -> Vec { tags } +fn merge_xmp_metadata_fields(content: &str, metadata: &mut ImageMetadata) { + if let Some(rating) = extract_xmp_rating(content) { + metadata.rating = rating; + if let Some(obj) = metadata.adjustments.as_object_mut() { + obj.insert("rating".to_string(), serde_json::json!(rating)); + } else { + metadata.adjustments = serde_json::json!({ "rating": rating }); + } + } + + let xmp_label = extract_xmp_label(content); + let xmp_tags = extract_xmp_tags(content); + + if xmp_label.is_none() && xmp_tags.is_empty() { + return; + } + + let mut current_tags = metadata.tags.clone().unwrap_or_default(); + + for tag in xmp_tags { + if !current_tags.contains(&tag) { + current_tags.push(tag); + } + } + + if let Some(label) = xmp_label { + let label_tag = format!("{}{}", COLOR_TAG_PREFIX, label.to_lowercase()); + if !current_tags.contains(&label_tag) { + current_tags.retain(|t| !t.starts_with(COLOR_TAG_PREFIX)); + current_tags.push(label_tag); + } + } + + if !current_tags.is_empty() { + metadata.tags = Some(current_tags); + } +} + pub fn sync_metadata_from_xmp(source_path: &Path, metadata: &mut ImageMetadata) -> bool { let xmp_path = source_path.with_extension("xmp"); let xmp_path_upper = source_path.with_extension("XMP"); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 597d74c1b0..735b60bda0 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2284,6 +2284,8 @@ pub fn run() { file_management::delete_files_from_disk, file_management::delete_files_with_associated, file_management::save_metadata_and_update_thumbnail, + file_management::import_xmp_adjustments_for_image, + file_management::import_matching_xmp_sidecars_in_folder, file_management::apply_adjustments_to_paths, file_management::load_metadata, file_management::load_presets, diff --git a/src-tauri/src/preset_converter.rs b/src-tauri/src/preset_converter.rs index 0a10c4f281..68a11a31c0 100644 --- a/src-tauri/src/preset_converter.rs +++ b/src-tauri/src/preset_converter.rs @@ -101,6 +101,16 @@ pub fn convert_xmp_to_preset(xmp_content: &str) -> Result { attrs.insert(cap[1].to_string(), cap[2].to_string()); } + let elem_re = Regex::new(r#"(?s)\s*([^<]+?)\s*"#) + .map_err(|e| format!("Regex compilation failed: {}", e))?; + for cap in elem_re.captures_iter(xmp_content) { + if cap[1] == cap[3] { + attrs + .entry(cap[1].to_string()) + .or_insert_with(|| cap[2].trim().to_string()); + } + } + let mut adjustments = Map::new(); let mut hsl_map = Map::new(); let mut color_grading_map = Map::new(); @@ -349,3 +359,36 @@ pub fn convert_xmp_to_preset(xmp_content: &str) -> Result { preset_type: Some("style".to_string()), }) } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn converts_attribute_based_xmp_adjustments() { + let preset = convert_xmp_to_preset( + r#""#, + ) + .unwrap(); + + assert_eq!(preset.adjustments["exposure"], json!(0.5)); + assert_eq!(preset.adjustments["contrast"], json!(25)); + } + + #[test] + fn converts_element_based_xmp_adjustments() { + let preset = convert_xmp_to_preset( + r#" + + +0.50 + 25 + + "#, + ) + .unwrap(); + + assert_eq!(preset.adjustments["exposure"], json!(0.5)); + assert_eq!(preset.adjustments["contrast"], json!(25)); + } +} diff --git a/src/components/ui/AppProperties.tsx b/src/components/ui/AppProperties.tsx index 6c2d685355..a08d160af6 100644 --- a/src/components/ui/AppProperties.tsx +++ b/src/components/ui/AppProperties.tsx @@ -69,6 +69,8 @@ export enum Invokes { HandleExportPresetsToFile = 'handle_export_presets_to_file', HandleImportPresetsFromFile = 'handle_import_presets_from_file', HandleImportLegacyPresetsFromFile = 'handle_import_legacy_presets_from_file', + ImportXmpAdjustmentsForImage = 'import_xmp_adjustments_for_image', + ImportMatchingXmpSidecarsInFolder = 'import_matching_xmp_sidecars_in_folder', ImportFiles = 'import_files', InvokeGenerativeReplace = 'invoke_generative_replace', InvokeGenerativeReplaseWithMaskDef = 'invoke_generative_replace_with_mask_def', diff --git a/src/hooks/useAppContextMenus.ts b/src/hooks/useAppContextMenus.ts index 77319b1708..70e0bbcd9e 100644 --- a/src/hooks/useAppContextMenus.ts +++ b/src/hooks/useAppContextMenus.ts @@ -1,5 +1,6 @@ import { useCallback, useMemo } from 'react'; import { invoke } from '@tauri-apps/api/core'; +import { open as openDialog } from '@tauri-apps/plugin-dialog'; import { Aperture, Check, @@ -9,6 +10,7 @@ import { Edit, FileEdit, FileInput, + FileUp, Folder, FolderInput, FolderPlus, @@ -51,12 +53,30 @@ import { useProcessStore } from '../store/useProcessStore'; import { useUIStore } from '../store/useUIStore'; import { useSettingsStore } from '../store/useSettingsStore'; import { Invokes, Option, OPTION_SEPARATOR, Panel, AlbumItem, Album, AlbumGroup } from '../components/ui/AppProperties'; -import { Color, COLOR_LABELS, INITIAL_ADJUSTMENTS, normalizeLoadedAdjustments } from '../utils/adjustments'; +import { + Color, + COLOR_LABELS, + INITIAL_ADJUSTMENTS, + normalizeLoadedAdjustments, + type Adjustments, +} from '../utils/adjustments'; import TaggingSubMenu from '../context/TaggingSubMenu'; import { useEditorActions } from './useEditorActions'; import { useLibraryActions } from './useLibraryActions'; import { globalImageCache } from '../utils/ImageLRUCache'; +interface ImportedXmpMetadata { + adjustments?: (Partial & { is_null?: boolean }) | null; +} + +interface MatchingXmpSidecarImportResult { + imported: number; + skipped: number; + failed: number; + failures: string[]; + importedPaths: string[]; +} + export interface UseAppContextMenusProps { handleImageSelect: (path: string) => void; handleBackToLibrary: () => void; @@ -156,6 +176,107 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { [albumIcons, t], ); + const applyImportedXmpMetadata = useCallback((targetPath: string, metadata: ImportedXmpMetadata) => { + if (!metadata.adjustments || metadata.adjustments.is_null) return; + + const normalized = normalizeLoadedAdjustments(metadata.adjustments as Adjustments); + const editorState = useEditorStore.getState(); + if (editorState.selectedImage?.path === targetPath) { + editorState.setEditor({ adjustments: normalized }); + editorState.resetHistory(normalized); + } + + const libraryState = useLibraryStore.getState(); + if (libraryState.libraryActivePath === targetPath) { + libraryState.setLibrary({ libraryActiveAdjustments: normalized }); + } + }, []); + + const refreshImportedXmpPaths = useCallback( + async (importedPaths: string[]) => { + importedPaths.forEach((path) => globalImageCache.delete(path)); + + const editorState = useEditorStore.getState(); + const libraryState = useLibraryStore.getState(); + const pathsToRefresh = new Set(); + if (editorState.selectedImage?.path && importedPaths.includes(editorState.selectedImage.path)) { + pathsToRefresh.add(editorState.selectedImage.path); + } + if (libraryState.libraryActivePath && importedPaths.includes(libraryState.libraryActivePath)) { + pathsToRefresh.add(libraryState.libraryActivePath); + } + + await Promise.all( + [...pathsToRefresh].map(async (path) => { + const metadata = await invoke(Invokes.LoadMetadata, { path }); + applyImportedXmpMetadata(path, metadata); + }), + ); + }, + [applyImportedXmpMetadata], + ); + + const importXmpAdjustmentsForImage = useCallback( + async (targetPath: string) => { + try { + const selectedPath = await openDialog({ + filters: [{ name: t('contextMenus.dialogs.xmpSidecar'), extensions: ['xmp'] }], + multiple: false, + title: t('contextMenus.dialogs.importXmpAdjustmentsTitle'), + }); + + if (typeof selectedPath !== 'string') return; + + globalImageCache.delete(targetPath); + const metadata = await invoke(Invokes.ImportXmpAdjustmentsForImage, { + path: targetPath, + xmpPath: selectedPath, + }); + + applyImportedXmpMetadata(targetPath, metadata); + + await props.refreshImageList(); + toast.success(t('contextMenus.toasts.importedXmpAdjustments')); + } catch (err) { + console.error('Failed to import XMP adjustments:', err); + toast.error(t('contextMenus.toasts.failedImportXmpAdjustments', { err })); + } + }, + [applyImportedXmpMetadata, props, t], + ); + + const importMatchingXmpSidecarsInFolder = useCallback( + async (targetPath: string) => { + try { + const result = await invoke(Invokes.ImportMatchingXmpSidecarsInFolder, { + folderPath: targetPath, + }); + + await refreshImportedXmpPaths(result.importedPaths); + + const { currentFolderPath } = useLibraryStore.getState(); + if (targetPath === currentFolderPath) { + await props.refreshImageList(); + } + + if (result.imported > 0) { + toast.success(t('contextMenus.toasts.importedMatchingXmpSidecars', { count: result.imported })); + } else if (result.failed === 0) { + toast.info(t('contextMenus.toasts.noMatchingXmpSidecars')); + } + + if (result.failed > 0) { + console.warn('Some matching XMP sidecars failed to import:', result.failures); + toast.error(t('contextMenus.toasts.failedMatchingXmpSidecars', { count: result.failed })); + } + } catch (err) { + console.error('Failed to import matching XMP sidecars:', err); + toast.error(t('contextMenus.toasts.failedImportMatchingXmpSidecars', { err })); + } + }, + [props, refreshImportedXmpPaths, t], + ); + const handleEditorContextMenu = useCallback( (event: any) => { event.preventDefault(); @@ -193,6 +314,11 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { onClick: () => handlePasteAdjustments(), disabled: copiedAdjustments === null, }, + { + label: t('contextMenus.editor.importXmpAdjustments'), + icon: FileUp, + onClick: () => importXmpAdjustmentsForImage(selectedImage.path), + }, { label: t('contextMenus.editor.productivity'), icon: Gauge, @@ -310,6 +436,7 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { getCommonTags, handleCopyAdjustments, handlePasteAdjustments, + importXmpAdjustmentsForImage, handleAutoAdjustments, handleRate, handleSetColorLabel, @@ -539,6 +666,12 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { label: pasteLabel, onClick: () => handlePasteAdjustments(finalSelection), }, + { + disabled: !isSingleSelection, + icon: FileUp, + label: t('contextMenus.thumbnail.importXmpAdjustments'), + onClick: () => importXmpAdjustmentsForImage(finalSelection[0]), + }, { label: t('contextMenus.editor.productivity'), icon: Gauge, @@ -767,6 +900,7 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { buildAddToAlbumMenu, handleCopyAdjustments, handlePasteAdjustments, + importXmpAdjustmentsForImage, handleRate, handleSetColorLabel, handleTagsChanged, @@ -941,6 +1075,11 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { label: t('contextMenus.folders.importImages'), onClick: () => props.handleImportClick(targetPath), }, + { + icon: FileUp, + label: t('contextMenus.folders.importMatchingXmpSidecars'), + onClick: () => importMatchingXmpSidecarsInFolder(targetPath), + }, { type: OPTION_SEPARATOR }, { icon: Folder, @@ -1002,7 +1141,7 @@ export function useAppContextMenus(props: UseAppContextMenusProps) { ]; showContextMenu(event.clientX, event.clientY, options); }, - [props, showContextMenu, albumIcons, t], + [props, showContextMenu, albumIcons, importMatchingXmpSidecarsInFolder, t], ); const handleAlbumTreeContextMenu = useCallback( diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 7cb769a477..432358de46 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -168,6 +168,10 @@ "red": "Rot", "yellow": "Gelb" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Bild autom. anpassen", "cancel": "Abbrechen", @@ -180,6 +184,7 @@ "editImage": "Bild bearbeiten", "exportImage": "Bild exportieren", "frameImage": "Bild rahmen", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Zu HDR zusammenfügen", "noLabel": "Keine Markierung", "noRating": "Keine Bewertung", @@ -201,6 +206,7 @@ "copyHere_other": "{{count}} Bilder hierher kopieren", "deleteFolder": "Ordner löschen", "importImages": "Bilder importieren", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Bild hierher verschieben", "moveHere_other": "{{count}} Bilder hierher verschieben", "newFolder": "Neuer Ordner", @@ -247,6 +253,7 @@ "duplicateImage": "Bild duplizieren", "exportImage_one": "Bild exportieren", "exportImage_other": "{{count}} Bilder exportieren", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Keine Alben verfügbar", "pasteAdjustments_one": "Einstellungen einfügen", "pasteAdjustments_other": "Einstellungen in {{count}} Bilder einfügen", @@ -271,10 +278,22 @@ "failedDelete": "Löschen fehlgeschlagen: {{err}}", "failedDeleteFolder": "Ordner löschen fehlgeschlagen: {{err}}", "failedDuplicate": "Datei duplizieren fehlgeschlagen: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Dateien verschieben fehlgeschlagen: {{err}}", "failedMoveError": "Verschieben fehlgeschlagen: {{err}}", "failedMoveInvalid": "Verschieben fehlgeschlagen: Zielgruppe nicht gefunden oder ungültig.", - "failedRemoveImages": "Bilder entfernen fehlgeschlagen: {{err}}" + "failedRemoveImages": "Bilder entfernen fehlgeschlagen: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 638f74bd0a..af767c4614 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -168,6 +168,10 @@ "red": "Red", "yellow": "Yellow" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Auto Adjust Image", "cancel": "Cancel", @@ -180,6 +184,7 @@ "editImage": "Edit Image", "exportImage": "Export Image", "frameImage": "Frame Image", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Merge to HDR", "noLabel": "No Label", "noRating": "No Rating", @@ -201,6 +206,7 @@ "copyHere_other": "Copy {{count}} images here", "deleteFolder": "Delete Folder", "importImages": "Import Images", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Move image here", "moveHere_other": "Move {{count}} images here", "newFolder": "New Folder", @@ -247,6 +253,7 @@ "duplicateImage": "Duplicate Image", "exportImage_one": "Export Image", "exportImage_other": "Export {{count}} Images", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "No Albums Available", "pasteAdjustments_one": "Paste Adjustments", "pasteAdjustments_other": "Paste Adjustments to {{count}} Images", @@ -271,10 +278,22 @@ "failedDelete": "Failed to delete: {{err}}", "failedDeleteFolder": "Failed to delete folder: {{err}}", "failedDuplicate": "Failed to duplicate file: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Failed to move files: {{err}}", "failedMoveError": "Failed to move: {{err}}", "failedMoveInvalid": "Failed to move: Target group not found or invalid.", - "failedRemoveImages": "Failed to remove images: {{err}}" + "failedRemoveImages": "Failed to remove images: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 0e9f17d66f..aabb8d6065 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -168,6 +168,10 @@ "red": "Rojo", "yellow": "Amarillo" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Ajuste automático de imagen", "cancel": "Cancelar", @@ -180,6 +184,7 @@ "editImage": "Editar imagen", "exportImage": "Exportar imagen", "frameImage": "Enmarcar imagen", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Combinar en HDR", "noLabel": "Sin etiqueta", "noRating": "Sin puntuación", @@ -201,6 +206,7 @@ "copyHere_other": "Copiar {{count}} imágenes aquí", "deleteFolder": "Eliminar carpeta", "importImages": "Importar imágenes", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Mover imagen aquí", "moveHere_other": "Mover {{count}} imágenes aquí", "newFolder": "Nueva carpeta", @@ -247,6 +253,7 @@ "duplicateImage": "Duplicar imagen", "exportImage_one": "Exportar imagen", "exportImage_other": "Exportar {{count}} imágenes", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Sin álbumes disponibles", "pasteAdjustments_one": "Pegar ajustes", "pasteAdjustments_other": "Pegar ajustes a {{count}} imágenes", @@ -271,10 +278,22 @@ "failedDelete": "Error al eliminar: {{err}}", "failedDeleteFolder": "Error al eliminar la carpeta: {{err}}", "failedDuplicate": "Error al duplicar el archivo: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Error al mover los archivos: {{err}}", "failedMoveError": "Error al mover: {{err}}", "failedMoveInvalid": "Error al mover: Grupo de destino no encontrado o inválido.", - "failedRemoveImages": "Error al quitar las imágenes: {{err}}" + "failedRemoveImages": "Error al quitar las imágenes: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 57c45f2eea..e5fb3ca45f 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -168,6 +168,10 @@ "red": "Rouge", "yellow": "Jaune" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Ajustement auto de l'image", "cancel": "Annuler", @@ -180,6 +184,7 @@ "editImage": "Modifier l'image", "exportImage": "Exporter l'image", "frameImage": "Encadrer l'image", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Fusionner en HDR", "noLabel": "Aucune étiquette", "noRating": "Aucune note", @@ -201,6 +206,7 @@ "copyHere_other": "Copier {{count}} images ici", "deleteFolder": "Supprimer le dossier", "importImages": "Importer des images", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Déplacer l'image ici", "moveHere_other": "Déplacer {{count}} images ici", "newFolder": "Nouveau dossier", @@ -247,6 +253,7 @@ "duplicateImage": "Dupliquer l'image", "exportImage_one": "Exporter l'image", "exportImage_other": "Exporter {{count}} images", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Aucun album disponible", "pasteAdjustments_one": "Coller les ajustements", "pasteAdjustments_other": "Coller les ajustements sur {{count}} images", @@ -271,10 +278,22 @@ "failedDelete": "Échec de la suppression : {{err}}", "failedDeleteFolder": "Échec de la suppression du dossier : {{err}}", "failedDuplicate": "Échec de la duplication du fichier : {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Échec du déplacement des fichiers : {{err}}", "failedMoveError": "Échec du déplacement : {{err}}", "failedMoveInvalid": "Échec du déplacement : Groupe cible introuvable ou invalide.", - "failedRemoveImages": "Échec de la suppression des images : {{err}}" + "failedRemoveImages": "Échec de la suppression des images : {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 12723921df..59081b68e1 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -168,6 +168,10 @@ "red": "Rosso", "yellow": "Giallo" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Regolazione Automatica Immagine", "cancel": "Annulla", @@ -180,6 +184,7 @@ "editImage": "Modifica Immagine", "exportImage": "Esporta Immagine", "frameImage": "Incornicia Immagine", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Unisci in HDR", "noLabel": "Nessuna Etichetta", "noRating": "Nessuna Valutazione", @@ -201,6 +206,7 @@ "copyHere_other": "Copia {{count}} immagini qui", "deleteFolder": "Elimina Cartella", "importImages": "Importa Immagini", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Sposta immagine qui", "moveHere_other": "Sposta {{count}} immagini qui", "newFolder": "Nuova Cartella", @@ -247,6 +253,7 @@ "duplicateImage": "Duplica Immagine", "exportImage_one": "Esporta Immagine", "exportImage_other": "Esporta {{count}} Immagini", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Nessun Album Disponibile", "pasteAdjustments_one": "Incolla Regolazioni", "pasteAdjustments_other": "Incolla Regolazioni su {{count}} Immagini", @@ -271,10 +278,22 @@ "failedDelete": "Impossibile eliminare: {{err}}", "failedDeleteFolder": "Impossibile eliminare la cartella: {{err}}", "failedDuplicate": "Impossibile duplicare il file: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Impossibile spostare i file: {{err}}", "failedMoveError": "Impossibile spostare: {{err}}", "failedMoveInvalid": "Impossibile spostare: Gruppo di destinazione non trovato o non valido.", - "failedRemoveImages": "Impossibile rimuovere le immagini: {{err}}" + "failedRemoveImages": "Impossibile rimuovere le immagini: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index e9326b9779..404ba435e7 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -168,6 +168,10 @@ "red": "レッド", "yellow": "イエロー" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "画像を自動補正", "cancel": "キャンセル", @@ -180,6 +184,7 @@ "editImage": "画像を編集", "exportImage": "画像を書き出し", "frameImage": "画像にフレームを追加", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "HDRに統合", "noLabel": "ラベルなし", "noRating": "評価なし", @@ -201,6 +206,7 @@ "copyHere_other": "{{count}} 枚の画像をここにコピー", "deleteFolder": "フォルダを削除", "importImages": "画像をインポート", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "画像をここに移動", "moveHere_other": "{{count}} 枚の画像をここに移動", "newFolder": "新規フォルダ", @@ -247,6 +253,7 @@ "duplicateImage": "画像を複製", "exportImage_one": "画像を書き出し", "exportImage_other": "{{count}} 枚の画像を書き出し", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "利用可能なアルバムがありません", "pasteAdjustments_one": "補正設定を貼り付け", "pasteAdjustments_other": "{{count}} 枚の画像に補正設定を貼り付け", @@ -271,10 +278,22 @@ "failedDelete": "削除に失敗しました: {{err}}", "failedDeleteFolder": "フォルダの削除に失敗しました: {{err}}", "failedDuplicate": "ファイルの複製に失敗しました: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "ファイルの移動に失敗しました: {{err}}", "failedMoveError": "移動に失敗しました: {{err}}", "failedMoveInvalid": "移動に失敗しました: 対象グループが見つからないか無効です。", - "failedRemoveImages": "画像の削除に失敗しました: {{err}}" + "failedRemoveImages": "画像の削除に失敗しました: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index 600da629e7..8901af57cb 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -168,6 +168,10 @@ "red": "Czerwony", "yellow": "Żółty" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Auto-korekta obrazu", "cancel": "Anuluj", @@ -180,6 +184,7 @@ "editImage": "Edytuj obraz", "exportImage": "Eksportuj obraz", "frameImage": "Dodaj ramkę do obrazu", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Scal do HDR", "noLabel": "Brak etykiety", "noRating": "Brak oceny", @@ -205,6 +210,7 @@ "copyHere_other": "Skopiuj {{count}} obrazów tutaj", "deleteFolder": "Usuń folder", "importImages": "Importuj obrazy", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Przenieś obraz tutaj", "moveHere_few": "Przenieś {{count}} obrazy tutaj", "moveHere_many": "Przenieś {{count}} obrazów tutaj", @@ -271,6 +277,7 @@ "exportImage_few": "Eksportuj {{count}} obrazy", "exportImage_many": "Eksportuj {{count}} obrazów", "exportImage_other": "Eksportuj {{count}} obrazów", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Brak dostępnych albumów", "pasteAdjustments_one": "Wklej ustawienia", "pasteAdjustments_few": "Wklej ustawienia do {{count}} obrazów", @@ -303,10 +310,22 @@ "failedDelete": "Nie udało się usunąć: {{err}}", "failedDeleteFolder": "Nie udało się usunąć folderu: {{err}}", "failedDuplicate": "Nie udało się zduplikować pliku: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Nie udało się przenieść plików: {{err}}", "failedMoveError": "Nie udało się przenieść: {{err}}", "failedMoveInvalid": "Nie udało się przenieść: Grupa docelowa nie znaleziona lub nieprawidłowa.", - "failedRemoveImages": "Nie udało się usunąć obrazów: {{err}}" + "failedRemoveImages": "Nie udało się usunąć obrazów: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 05d7f40295..374a9eadc9 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -168,6 +168,10 @@ "red": "Vermelho", "yellow": "Amarelo" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Ajuste Automático", "cancel": "Cancelar", @@ -180,6 +184,7 @@ "editImage": "Editar Imagem", "exportImage": "Exportar Imagem", "frameImage": "Emoldurar Imagem", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Mesclar para HDR", "noLabel": "Sem Rótulo", "noRating": "Sem Avaliação", @@ -201,6 +206,7 @@ "copyHere_other": "Copiar {{count}} imagens para cá", "deleteFolder": "Excluir Pasta", "importImages": "Importar Imagens", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Mover imagem para cá", "moveHere_other": "Mover {{count}} imagens para cá", "newFolder": "Nova Pasta", @@ -247,6 +253,7 @@ "duplicateImage": "Duplicar Imagem", "exportImage_one": "Exportar Imagem", "exportImage_other": "Exportar {{count}} Imagens", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Nenhum Álbum Disponível", "pasteAdjustments_one": "Colar Ajustes", "pasteAdjustments_other": "Colar Ajustes em {{count}} Imagens", @@ -271,10 +278,22 @@ "failedDelete": "Falha ao excluir: {{err}}", "failedDeleteFolder": "Falha ao excluir pasta: {{err}}", "failedDuplicate": "Falha ao duplicar arquivo: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Falha ao mover arquivos: {{err}}", "failedMoveError": "Falha ao mover: {{err}}", "failedMoveInvalid": "Falha ao mover: Grupo de destino não encontrado ou inválido.", - "failedRemoveImages": "Falha ao remover imagens: {{err}}" + "failedRemoveImages": "Falha ao remover imagens: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 505056109a..663f53189c 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -168,6 +168,10 @@ "red": "Красный", "yellow": "Желтый" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "Автонастройка изображения", "cancel": "Отмена", @@ -180,6 +184,7 @@ "editImage": "Редактировать изображение", "exportImage": "Экспортировать изображение", "frameImage": "Добавить рамку", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "Объединить в HDR", "noLabel": "Без метки", "noRating": "Без рейтинга", @@ -201,6 +206,7 @@ "copyHere_other": "Копировать {{count}} изображений сюда", "deleteFolder": "Удалить папку", "importImages": "Импортировать изображения", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "Переместить изображение сюда", "moveHere_other": "Переместить {{count}} изображений сюда", "newFolder": "Новая папка", @@ -247,6 +253,7 @@ "duplicateImage": "Дублировать изображение", "exportImage_one": "Экспортировать изображение", "exportImage_other": "Экспортировать {{count}} изображений", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "Нет доступных альбомов", "pasteAdjustments_one": "Вставить настройки", "pasteAdjustments_other": "Вставить настройки для {{count}} изображений", @@ -271,10 +278,22 @@ "failedDelete": "Не удалось удалить: {{err}}", "failedDeleteFolder": "Не удалось удалить папку: {{err}}", "failedDuplicate": "Не удалось дублировать файл: {{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "Не удалось переместить файлы: {{err}}", "failedMoveError": "Не удалось переместить: {{err}}", "failedMoveInvalid": "Не удалось переместить: целевая группа не найдена или недействительна.", - "failedRemoveImages": "Не удалось удалить изображения: {{err}}" + "failedRemoveImages": "Не удалось удалить изображения: {{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index c97f28ecbd..391b837a82 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -168,6 +168,10 @@ "red": "红色", "yellow": "黄色" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "自动调整图像", "cancel": "取消", @@ -180,6 +184,7 @@ "editImage": "编辑图像", "exportImage": "导出图像", "frameImage": "装裱图像", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "合并为 HDR", "noLabel": "无标签", "noRating": "无评分", @@ -201,6 +206,7 @@ "copyHere_other": "复制 {{count}} 张图像至此", "deleteFolder": "删除文件夹", "importImages": "导入图像", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "移动图像至此", "moveHere_other": "移动 {{count}} 张图像至此", "newFolder": "新建文件夹", @@ -247,6 +253,7 @@ "duplicateImage": "复制图像", "exportImage_one": "导出图像", "exportImage_other": "导出 {{count}} 张图像", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "无可用相册", "pasteAdjustments_one": "粘贴调整", "pasteAdjustments_other": "粘贴调整到 {{count}} 张图像", @@ -271,10 +278,22 @@ "failedDelete": "删除失败:{{err}}", "failedDeleteFolder": "删除文件夹失败:{{err}}", "failedDuplicate": "复制文件失败:{{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "移动文件失败:{{err}}", "failedMoveError": "移动失败:{{err}}", "failedMoveInvalid": "移动失败:未找到目标组或目标组无效。", - "failedRemoveImages": "移除图像失败:{{err}}" + "failedRemoveImages": "移除图像失败:{{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": { diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index c88f40dd33..ea91808672 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -168,6 +168,10 @@ "red": "紅色", "yellow": "黃色" }, + "dialogs": { + "importXmpAdjustmentsTitle": "Import XMP Adjustments", + "xmpSidecar": "XMP Sidecar" + }, "editor": { "autoAdjust": "自動調整影像", "cancel": "取消", @@ -180,6 +184,7 @@ "editImage": "編輯影像", "exportImage": "匯出影像", "frameImage": "裝裱影像", + "importXmpAdjustments": "Import XMP Adjustments", "mergeHdr": "合併為 HDR", "noLabel": "無標籤", "noRating": "無評分", @@ -201,6 +206,7 @@ "copyHere_other": "複製 {{count}} 張影像至此", "deleteFolder": "刪除資料夾", "importImages": "匯入影像", + "importMatchingXmpSidecars": "Import Matching XMP Sidecars", "moveHere_one": "移動影像至此", "moveHere_other": "移動 {{count}} 張影像至此", "newFolder": "新建資料夾", @@ -247,6 +253,7 @@ "duplicateImage": "複製影像", "exportImage_one": "匯出影像", "exportImage_other": "匯出 {{count}} 張影像", + "importXmpAdjustments": "Import XMP Adjustments", "noAlbums": "無可用相簿", "pasteAdjustments_one": "貼上調整", "pasteAdjustments_other": "貼上調整到 {{count}} 張影像", @@ -271,10 +278,22 @@ "failedDelete": "刪除失敗:{{err}}", "failedDeleteFolder": "刪除資料夾失敗:{{err}}", "failedDuplicate": "複製檔案失敗:{{err}}", + "failedImportXmpAdjustments": "Failed to import XMP adjustments: {{err}}", + "failedImportMatchingXmpSidecars": "Failed to import matching XMP sidecars: {{err}}", + "failedMatchingXmpSidecars_one": "Failed to import {{count}} matching XMP sidecar.", + "failedMatchingXmpSidecars_few": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_many": "Failed to import {{count}} matching XMP sidecars.", + "failedMatchingXmpSidecars_other": "Failed to import {{count}} matching XMP sidecars.", "failedMove": "移動檔案失敗:{{err}}", "failedMoveError": "移動失敗:{{err}}", "failedMoveInvalid": "移動失敗:未找到目標組或目標組無效。", - "failedRemoveImages": "移除影像失敗:{{err}}" + "failedRemoveImages": "移除影像失敗:{{err}}", + "importedXmpAdjustments": "Imported XMP adjustments.", + "importedMatchingXmpSidecars_one": "Imported {{count}} matching XMP sidecar.", + "importedMatchingXmpSidecars_few": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_many": "Imported {{count}} matching XMP sidecars.", + "importedMatchingXmpSidecars_other": "Imported {{count}} matching XMP sidecars.", + "noMatchingXmpSidecars": "No matching XMP sidecars found." } }, "editor": {