chore: lots of i18n
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useAppStore, MediaData } from '../../store';
|
||||
import { showToast } from '../Toast';
|
||||
import { useI18n } from '../../i18n';
|
||||
import './LinkedMediaPanel.css';
|
||||
|
||||
/** Get display name for media: title (truncated to 60 chars) or fallback to filename */
|
||||
@@ -35,6 +36,7 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
collapsed = false,
|
||||
onToggleCollapse,
|
||||
}) => {
|
||||
const { t } = useI18n();
|
||||
const [linkedMedia, setLinkedMedia] = useState<MediaData[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
|
||||
@@ -118,13 +120,13 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
await window.electronAPI?.postMedia.link(postId, media.id);
|
||||
}
|
||||
|
||||
showToast.success(`Imported and linked ${imported.length} file(s)`);
|
||||
showToast.success(t('linkedMediaPanel.toast.importedLinked', { count: imported.length }));
|
||||
|
||||
// Refresh the linked media list
|
||||
loadLinkedMedia();
|
||||
} catch (error) {
|
||||
console.error('Failed to import media:', error);
|
||||
showToast.error('Failed to import media');
|
||||
showToast.error(t('linkedMediaPanel.toast.importFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,11 +134,11 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
const handleUnlink = async (mediaId: string) => {
|
||||
try {
|
||||
await window.electronAPI?.postMedia.unlink(postId, mediaId);
|
||||
showToast.success('Media unlinked from post');
|
||||
showToast.success(t('linkedMediaPanel.toast.unlinked'));
|
||||
loadLinkedMedia();
|
||||
} catch (error) {
|
||||
console.error('Failed to unlink media:', error);
|
||||
showToast.error('Failed to unlink media');
|
||||
showToast.error(t('linkedMediaPanel.toast.unlinkFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,13 +146,13 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
const handleLinkExisting = async (mediaId: string) => {
|
||||
try {
|
||||
await window.electronAPI?.postMedia.link(postId, mediaId);
|
||||
showToast.success('Media linked to post');
|
||||
showToast.success(t('linkedMediaPanel.toast.linked'));
|
||||
setShowMediaPicker(false);
|
||||
setMediaSearchQuery('');
|
||||
loadLinkedMedia();
|
||||
} catch (error) {
|
||||
console.error('Failed to link media:', error);
|
||||
showToast.error('Failed to link media');
|
||||
showToast.error(t('linkedMediaPanel.toast.linkFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -223,7 +225,7 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
<div className="linked-media-panel collapsed" onClick={onToggleCollapse}>
|
||||
<div className="panel-header">
|
||||
<span className="panel-title">
|
||||
📷 Media ({linkedMedia.length})
|
||||
{t('linkedMediaPanel.collapsedTitle', { count: linkedMedia.length })}
|
||||
</span>
|
||||
<span className="expand-icon">▶</span>
|
||||
</div>
|
||||
@@ -234,19 +236,19 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
return (
|
||||
<div className="linked-media-panel">
|
||||
<div className="panel-header" onClick={onToggleCollapse}>
|
||||
<span className="panel-title">📷 Linked Media</span>
|
||||
<span className="panel-title">{t('linkedMediaPanel.title')}</span>
|
||||
<div className="panel-actions">
|
||||
<button
|
||||
className="panel-action"
|
||||
onClick={(e) => { e.stopPropagation(); handleImportMedia(); }}
|
||||
title="Import and link media"
|
||||
title={t('linkedMediaPanel.importAndLink')}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<button
|
||||
className="panel-action"
|
||||
onClick={(e) => { e.stopPropagation(); setShowMediaPicker(!showMediaPicker); }}
|
||||
title="Link existing media"
|
||||
title={t('linkedMediaPanel.linkExisting')}
|
||||
>
|
||||
🔗
|
||||
</button>
|
||||
@@ -257,13 +259,13 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
{showMediaPicker && (
|
||||
<div className="media-picker">
|
||||
<div className="media-picker-header">
|
||||
<span>Select media to link</span>
|
||||
<span>{t('linkedMediaPanel.selectMediaToLink')}</span>
|
||||
<button onClick={() => { setShowMediaPicker(false); setMediaSearchQuery(''); }}>×</button>
|
||||
</div>
|
||||
<div className="media-picker-search">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search media..."
|
||||
placeholder={t('linkedMediaPanel.searchPlaceholder')}
|
||||
value={mediaSearchQuery}
|
||||
onChange={(e) => setMediaSearchQuery(e.target.value)}
|
||||
autoFocus
|
||||
@@ -271,7 +273,7 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
</div>
|
||||
<div className="media-picker-grid">
|
||||
{unlinkedMedia.length === 0 ? (
|
||||
<div className="no-media">No unlinked media available</div>
|
||||
<div className="no-media">{t('linkedMediaPanel.noUnlinkedMedia')}</div>
|
||||
) : (
|
||||
unlinkedMedia.map(media => (
|
||||
<div
|
||||
@@ -295,11 +297,11 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
|
||||
<div className="panel-content">
|
||||
{isLoading ? (
|
||||
<div className="loading">Loading...</div>
|
||||
<div className="loading">{t('gitSidebar.loading')}</div>
|
||||
) : linkedMedia.length === 0 ? (
|
||||
<div className="empty-state">
|
||||
<p>No media linked to this post</p>
|
||||
<button onClick={handleImportMedia}>Import Media</button>
|
||||
<p>{t('linkedMediaPanel.noMediaLinked')}</p>
|
||||
<button onClick={handleImportMedia}>{t('linkedMediaPanel.importMedia')}</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="media-list">
|
||||
@@ -330,7 +332,7 @@ export const LinkedMediaPanel: React.FC<LinkedMediaPanelProps> = ({
|
||||
<button
|
||||
className="unlink-btn"
|
||||
onClick={(e) => { e.stopPropagation(); handleUnlink(media.id); }}
|
||||
title="Unlink from post"
|
||||
title={t('linkedMediaPanel.unlinkFromPost')}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useAppStore } from '../../store';
|
||||
import type { TaskProgress } from '../../../main/shared/electronApi';
|
||||
import { useI18n } from '../../i18n';
|
||||
import './Panel.css';
|
||||
|
||||
function getPostRelativePath(createdAt: string, slug: string): string | null {
|
||||
@@ -101,6 +102,7 @@ function buildTaskEntries(tasks: TaskProgress[]): TaskEntry[] {
|
||||
}
|
||||
|
||||
export const Panel: React.FC = () => {
|
||||
const { t, language } = useI18n();
|
||||
const {
|
||||
panelVisible,
|
||||
panelActiveTab,
|
||||
@@ -191,7 +193,7 @@ export const Panel: React.FC = () => {
|
||||
|
||||
setPostLinksEntries([...fromEntries, ...toEntries]);
|
||||
} catch (error) {
|
||||
setPostLinksError(error instanceof Error ? error.message : 'Failed to load post links.');
|
||||
setPostLinksError(error instanceof Error ? error.message : t('panel.error.loadPostLinks'));
|
||||
setPostLinksEntries([]);
|
||||
} finally {
|
||||
setPostLinksLoading(false);
|
||||
@@ -277,7 +279,7 @@ export const Panel: React.FC = () => {
|
||||
if (requestIdRef.current !== currentRequestId) {
|
||||
return;
|
||||
}
|
||||
setGitLogError(error instanceof Error ? error.message : 'Failed to load git log.');
|
||||
setGitLogError(error instanceof Error ? error.message : t('panel.error.loadGitLog'));
|
||||
setGitLogEntries([]);
|
||||
} finally {
|
||||
if (requestIdRef.current === currentRequestId) {
|
||||
@@ -339,7 +341,7 @@ export const Panel: React.FC = () => {
|
||||
className="task-cancel"
|
||||
onClick={() => window.electronAPI?.tasks.cancel(task.taskId)}
|
||||
>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -348,7 +350,7 @@ export const Panel: React.FC = () => {
|
||||
return (
|
||||
<div className="panel">
|
||||
<div className="panel-header">
|
||||
<div className="panel-tabs" role="tablist" aria-label="Panel tabs">
|
||||
<div className="panel-tabs" role="tablist" aria-label={t('panel.tabsAria')}>
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
@@ -356,7 +358,7 @@ export const Panel: React.FC = () => {
|
||||
aria-selected={effectiveActivePanelTab === 'tasks'}
|
||||
onClick={() => setPanelActiveTab('tasks')}
|
||||
>
|
||||
Tasks
|
||||
{t('common.tasks')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -365,7 +367,7 @@ export const Panel: React.FC = () => {
|
||||
aria-selected={effectiveActivePanelTab === 'output'}
|
||||
onClick={() => setPanelActiveTab('output')}
|
||||
>
|
||||
Output
|
||||
{t('panel.output')}
|
||||
</button>
|
||||
{canActivatePostLinks && (
|
||||
<button
|
||||
@@ -375,7 +377,7 @@ export const Panel: React.FC = () => {
|
||||
aria-selected={effectiveActivePanelTab === 'post-links'}
|
||||
onClick={() => setPanelActiveTab('post-links')}
|
||||
>
|
||||
Post Links
|
||||
{t('panel.postLinks')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
@@ -390,13 +392,13 @@ export const Panel: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
Git Log
|
||||
{t('panel.gitLog')}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
className="panel-close"
|
||||
onClick={() => useAppStore.getState().togglePanel()}
|
||||
title="Close Panel"
|
||||
title={t('panel.closeTitle')}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
@@ -404,7 +406,7 @@ export const Panel: React.FC = () => {
|
||||
<div className="panel-content">
|
||||
{effectiveActivePanelTab === 'tasks' && (
|
||||
recentTasks.length === 0 ? (
|
||||
<div className="panel-empty">No recent tasks</div>
|
||||
<div className="panel-empty">{t('panel.noRecentTasks')}</div>
|
||||
) : (
|
||||
<div className="task-list">
|
||||
{recentTaskEntries.map((entry) => {
|
||||
@@ -434,18 +436,18 @@ export const Panel: React.FC = () => {
|
||||
)}
|
||||
|
||||
{effectiveActivePanelTab === 'output' && (
|
||||
<div className="panel-empty">No output</div>
|
||||
<div className="panel-empty">{t('panel.noOutput')}</div>
|
||||
)}
|
||||
|
||||
{effectiveActivePanelTab === 'post-links' && (
|
||||
!canActivatePostLinks ? (
|
||||
<div className="panel-empty">Open a post editor to view post links</div>
|
||||
<div className="panel-empty">{t('panel.openPostEditor')}</div>
|
||||
) : postLinksLoading ? (
|
||||
<div className="panel-empty">Loading post links...</div>
|
||||
<div className="panel-empty">{t('panel.loadingPostLinks')}</div>
|
||||
) : postLinksError ? (
|
||||
<div className="panel-empty">{postLinksError}</div>
|
||||
) : postLinksEntries.length === 0 ? (
|
||||
<div className="panel-empty">No post links for this post</div>
|
||||
<div className="panel-empty">{t('panel.noPostLinks')}</div>
|
||||
) : (
|
||||
<div className="post-links-list">
|
||||
{postLinksEntries.map((entry) => (
|
||||
@@ -454,9 +456,9 @@ export const Panel: React.FC = () => {
|
||||
type="button"
|
||||
className="post-links-item"
|
||||
onClick={() => handlePostLinkClick(entry.id)}
|
||||
title={`Open ${entry.title || entry.slug}`}
|
||||
title={t('postLinks.openTitle', { title: entry.title || entry.slug })}
|
||||
>
|
||||
<span className="post-links-direction">{entry.direction} {entry.slug}</span>
|
||||
<span className="post-links-direction">{t(`panel.direction.${entry.direction}`)} {entry.slug}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -465,13 +467,13 @@ export const Panel: React.FC = () => {
|
||||
|
||||
{effectiveActivePanelTab === 'git-log' && (
|
||||
!canActivateGitLog ? (
|
||||
<div className="panel-empty">Open a post or media editor to view git log</div>
|
||||
<div className="panel-empty">{t('panel.openPostOrMediaEditor')}</div>
|
||||
) : gitLogLoading ? (
|
||||
<div className="panel-empty">Loading git log...</div>
|
||||
<div className="panel-empty">{t('panel.loadingGitLog')}</div>
|
||||
) : gitLogError ? (
|
||||
<div className="panel-empty">{gitLogError}</div>
|
||||
) : gitLogEntries.length === 0 ? (
|
||||
<div className="panel-empty">No commits found for this item</div>
|
||||
<div className="panel-empty">{t('panel.noCommits')}</div>
|
||||
) : (
|
||||
<div className="git-log-list">
|
||||
<div className="git-log-target">{gitLogTargetLabel}</div>
|
||||
@@ -481,7 +483,7 @@ export const Panel: React.FC = () => {
|
||||
<div className="git-log-meta">
|
||||
<span className="git-log-hash">{entry.shortHash}</span>
|
||||
<span>{entry.author}</span>
|
||||
<span>{new Date(entry.date).toLocaleString()}</span>
|
||||
<span>{new Date(entry.date).toLocaleString(language)}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -2,9 +2,11 @@ import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useAppStore, ProjectData, PostData, MediaData } from '../../store';
|
||||
import { loadTabsForProject, saveTabsForProject } from '../../utils';
|
||||
import { showToast } from '../Toast';
|
||||
import { useI18n } from '../../i18n';
|
||||
import './ProjectSelector.css';
|
||||
|
||||
export const ProjectSelector: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const { projects, activeProject, setProjects, setActiveProject, setPosts, setMedia, setSelectedPost, setSelectedMedia, removeProject, getTabState, restoreTabState, clearTabs } = useAppStore();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
@@ -83,11 +85,11 @@ export const ProjectSelector: React.FC = () => {
|
||||
restoreTabState(savedTabState);
|
||||
}
|
||||
|
||||
showToast.success(`Switched to ${project.name}`);
|
||||
showToast.success(t('projectSelector.toast.switched', { name: project.name }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to switch project:', error);
|
||||
showToast.error('Failed to switch project');
|
||||
showToast.error(t('projectSelector.toast.switchFailed'));
|
||||
}
|
||||
setIsOpen(false);
|
||||
};
|
||||
@@ -104,7 +106,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
});
|
||||
if (newProject) {
|
||||
setProjects([...projects, newProject as ProjectData]);
|
||||
showToast.success(`Created project "${newProjectName}"`);
|
||||
showToast.success(t('projectSelector.toast.created', { name: newProjectName }));
|
||||
setNewProjectName('');
|
||||
setNewProjectDescription('');
|
||||
setNewProjectDataPath(null);
|
||||
@@ -115,13 +117,13 @@ export const ProjectSelector: React.FC = () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create project:', error);
|
||||
showToast.error('Failed to create project');
|
||||
showToast.error(t('projectSelector.toast.createFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectFolder = async () => {
|
||||
try {
|
||||
const selectedPath = await window.electronAPI?.app.selectFolder('Select Project Location');
|
||||
const selectedPath = await window.electronAPI?.app.selectFolder(t('projectSelector.selectProjectLocation'));
|
||||
if (selectedPath) {
|
||||
setNewProjectDataPath(selectedPath);
|
||||
|
||||
@@ -135,12 +137,12 @@ export const ProjectSelector: React.FC = () => {
|
||||
if (existingMetadata.description) {
|
||||
setNewProjectDescription(existingMetadata.description);
|
||||
}
|
||||
showToast.info('Found existing project settings');
|
||||
showToast.info(t('projectSelector.toast.existingSettingsFound'));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to select folder:', error);
|
||||
showToast.error('Failed to select folder');
|
||||
showToast.error(t('projectSelector.toast.selectFolderFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -171,16 +173,16 @@ export const ProjectSelector: React.FC = () => {
|
||||
const success = await window.electronAPI?.projects.deleteWithData(projectToDelete.id);
|
||||
if (success) {
|
||||
removeProject(projectToDelete.id);
|
||||
showToast.success(`Deleted project "${projectToDelete.name}" and all its data`);
|
||||
showToast.success(t('projectSelector.toast.deletedWithData', { name: projectToDelete.name }));
|
||||
setShowDeleteModal(false);
|
||||
setProjectToDelete(null);
|
||||
setDeleteConfirmText('');
|
||||
} else {
|
||||
showToast.error('Failed to delete project');
|
||||
showToast.error(t('projectSelector.toast.deleteFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to delete project:', error);
|
||||
showToast.error('Failed to delete project');
|
||||
showToast.error(t('projectSelector.toast.deleteFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -194,12 +196,12 @@ export const ProjectSelector: React.FC = () => {
|
||||
<button
|
||||
className="project-selector-trigger"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
title="Switch project"
|
||||
title={t('projectSelector.switchProject')}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" className="project-icon">
|
||||
<path d="M14.5 3H7.71l-.85-.85A.5.5 0 0 0 6.5 2h-5a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-10a.5.5 0 0 0-.5-.5zm-13 1h5.29l.85.85c.1.1.23.15.36.15h6.5v9h-13V4z"/>
|
||||
</svg>
|
||||
<span className="project-name">{activeProject?.name || 'Select Project'}</span>
|
||||
<span className="project-name">{activeProject?.name || t('projectSelector.selectProject')}</span>
|
||||
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" className="dropdown-arrow">
|
||||
<path d="M4.5 5.5L8 9l3.5-3.5h-7z"/>
|
||||
</svg>
|
||||
@@ -208,7 +210,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
{isOpen && (
|
||||
<div className="project-dropdown">
|
||||
<div className="project-dropdown-header">
|
||||
<span>PROJECTS</span>
|
||||
<span>{t('projectSelector.projectsHeader')}</span>
|
||||
</div>
|
||||
<div className="project-list">
|
||||
{projects.map(project => (
|
||||
@@ -231,7 +233,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
<button
|
||||
className="project-item-delete"
|
||||
onClick={(e) => openDeleteModal(e, project)}
|
||||
title={`Delete ${project.name}`}
|
||||
title={t('projectSelector.deleteProjectTitle', { name: project.name })}
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M5.5 5.5A.5.5 0 016 6v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm2.5 0a.5.5 0 01.5.5v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm3 .5a.5.5 0 00-1 0v6a.5.5 0 001 0V6z"/>
|
||||
@@ -242,7 +244,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
</div>
|
||||
))}
|
||||
{projects.length === 0 && (
|
||||
<div className="project-empty">No projects yet</div>
|
||||
<div className="project-empty">{t('projectSelector.noProjectsYet')}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="project-dropdown-footer">
|
||||
@@ -250,7 +252,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M14 7v1H8v6H7V8H1V7h6V1h1v6h6z"/>
|
||||
</svg>
|
||||
New Project
|
||||
{t('projectSelector.newProject')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -260,7 +262,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
<div className="modal-overlay" onClick={handleCloseCreateModal}>
|
||||
<div className="modal-content" onClick={e => e.stopPropagation()}>
|
||||
<div className="modal-header">
|
||||
<h3>Create New Project</h3>
|
||||
<h3>{t('projectSelector.createNewProject')}</h3>
|
||||
<button className="modal-close" onClick={handleCloseCreateModal}>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 8.707l3.646 3.647.708-.707L8.707 8l3.647-3.646-.707-.708L8 7.293 4.354 3.646l-.707.708L7.293 8l-3.646 3.646.707.708L8 8.707z"/>
|
||||
@@ -270,33 +272,33 @@ export const ProjectSelector: React.FC = () => {
|
||||
<form onSubmit={handleCreateProject}>
|
||||
<div className="modal-body">
|
||||
<div className="form-field">
|
||||
<label htmlFor="project-name">Project Name</label>
|
||||
<label htmlFor="project-name">{t('projectSelector.projectName')}</label>
|
||||
<input
|
||||
id="project-name"
|
||||
type="text"
|
||||
value={newProjectName}
|
||||
onChange={e => setNewProjectName(e.target.value)}
|
||||
placeholder="My Blog"
|
||||
placeholder={t('projectSelector.projectNamePlaceholder')}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="form-field">
|
||||
<label htmlFor="project-description">Description (optional)</label>
|
||||
<label htmlFor="project-description">{t('projectSelector.descriptionOptional')}</label>
|
||||
<textarea
|
||||
id="project-description"
|
||||
value={newProjectDescription}
|
||||
onChange={e => setNewProjectDescription(e.target.value)}
|
||||
placeholder="A brief description of this project..."
|
||||
placeholder={t('projectSelector.descriptionPlaceholder')}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-field">
|
||||
<label>Project Location</label>
|
||||
<label>{t('projectSelector.projectLocation')}</label>
|
||||
<div className="folder-picker">
|
||||
{newProjectDataPath ? (
|
||||
<div className="folder-path-display">
|
||||
<span className="folder-path" title={newProjectDataPath}>{newProjectDataPath}</span>
|
||||
<button type="button" className="btn-icon" onClick={handleClearFolder} title="Use default location">
|
||||
<button type="button" className="btn-icon" onClick={handleClearFolder} title={t('projectSelector.useDefaultLocation')}>
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 8.707l3.646 3.647.708-.707L8.707 8l3.647-3.646-.707-.708L8 7.293 4.354 3.646l-.707.708L7.293 8l-3.646 3.646.707.708L8 8.707z"/>
|
||||
</svg>
|
||||
@@ -304,27 +306,27 @@ export const ProjectSelector: React.FC = () => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="folder-default-info">
|
||||
<span className="default-label">Default (internal storage)</span>
|
||||
<span className="default-label">{t('projectSelector.defaultInternalStorage')}</span>
|
||||
</div>
|
||||
)}
|
||||
<button type="button" className="btn-secondary btn-small" onClick={handleSelectFolder}>
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M14.5 3H7.71l-.85-.85A.5.5 0 0 0 6.5 2h-5a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-10a.5.5 0 0 0-.5-.5zm-13 1h5.29l.85.85c.1.1.23.15.36.15h6.5v9h-13V4z"/>
|
||||
</svg>
|
||||
Choose Folder...
|
||||
{t('projectSelector.chooseFolder')}
|
||||
</button>
|
||||
</div>
|
||||
<p className="form-hint">
|
||||
Choose a custom folder for cloud storage backup, or use the default internal storage.
|
||||
{t('projectSelector.projectLocationHint')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn-secondary" onClick={handleCloseCreateModal}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</button>
|
||||
<button type="submit" className="btn-primary" disabled={!newProjectName.trim()}>
|
||||
Create Project
|
||||
{t('projectSelector.createProject')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -336,7 +338,7 @@ export const ProjectSelector: React.FC = () => {
|
||||
<div className="modal-overlay" onClick={() => setShowDeleteModal(false)}>
|
||||
<div className="modal-content modal-danger" onClick={e => e.stopPropagation()}>
|
||||
<div className="modal-header">
|
||||
<h3>Delete Project</h3>
|
||||
<h3>{t('projectSelector.deleteProject')}</h3>
|
||||
<button className="modal-close" onClick={() => setShowDeleteModal(false)}>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 8.707l3.646 3.647.708-.707L8.707 8l3.647-3.646-.707-.708L8 7.293 4.354 3.646l-.707.708L7.293 8l-3.646 3.646.707.708L8 8.707z"/>
|
||||
@@ -346,15 +348,15 @@ export const ProjectSelector: React.FC = () => {
|
||||
<form onSubmit={handleDeleteProject}>
|
||||
<div className="modal-body">
|
||||
<p className="delete-warning">
|
||||
This will permanently delete the project <strong>"{projectToDelete.name}"</strong> and all its data including:
|
||||
{t('projectSelector.deleteWarning', { name: projectToDelete.name })}
|
||||
</p>
|
||||
<ul className="delete-list">
|
||||
<li>All blog posts</li>
|
||||
<li>All media files</li>
|
||||
<li>All project settings</li>
|
||||
<li>{t('projectSelector.deleteItemPosts')}</li>
|
||||
<li>{t('projectSelector.deleteItemMedia')}</li>
|
||||
<li>{t('projectSelector.deleteItemSettings')}</li>
|
||||
</ul>
|
||||
<p className="delete-confirm-text">
|
||||
Type <strong>{projectToDelete.name}</strong> to confirm deletion:
|
||||
{t('projectSelector.typeToConfirm', { name: projectToDelete.name })}
|
||||
</p>
|
||||
<div className="form-field">
|
||||
<input
|
||||
@@ -368,14 +370,14 @@ export const ProjectSelector: React.FC = () => {
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn-secondary" onClick={() => setShowDeleteModal(false)}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="btn-danger"
|
||||
disabled={deleteConfirmText !== projectToDelete.name}
|
||||
>
|
||||
Delete Project
|
||||
{t('projectSelector.deleteProject')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -2,6 +2,11 @@ import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useAppStore } from '../../store';
|
||||
import { showToast } from '../Toast';
|
||||
import { useI18n } from '../../i18n';
|
||||
import {
|
||||
resolveSupportedRenderLanguage,
|
||||
SUPPORTED_RENDER_LANGUAGES,
|
||||
type SupportedLanguage,
|
||||
} from '../../../main/shared/i18n';
|
||||
import './SettingsView.css';
|
||||
|
||||
// Export category IDs for sidebar navigation
|
||||
@@ -33,6 +38,14 @@ interface CategoryRenderSettings {
|
||||
showTitle: boolean;
|
||||
}
|
||||
|
||||
const RENDER_LANGUAGE_LABEL_KEY: Record<SupportedLanguage, string> = {
|
||||
en: 'settings.language.english',
|
||||
de: 'settings.language.german',
|
||||
fr: 'settings.language.french',
|
||||
it: 'settings.language.italian',
|
||||
es: 'settings.language.spanish',
|
||||
};
|
||||
|
||||
const defaultCredentials: Credentials = {
|
||||
ftpHost: '',
|
||||
ftpUser: '',
|
||||
@@ -123,7 +136,7 @@ export const SettingsView: React.FC = () => {
|
||||
const [projectDataPath, setProjectDataPath] = useState('');
|
||||
const [projectPublicUrl, setProjectPublicUrl] = useState('');
|
||||
const [defaultProjectPath, setDefaultProjectPath] = useState('');
|
||||
const [projectMainLanguage, setProjectMainLanguage] = useState('en');
|
||||
const [projectMainLanguage, setProjectMainLanguage] = useState<SupportedLanguage>('en');
|
||||
const [projectDefaultAuthor, setProjectDefaultAuthor] = useState('');
|
||||
const [projectMaxPostsPerPage, setProjectMaxPostsPerPage] = useState(50);
|
||||
|
||||
@@ -169,7 +182,7 @@ export const SettingsView: React.FC = () => {
|
||||
setProjectPublicUrl('');
|
||||
}
|
||||
if (metadata?.mainLanguage) {
|
||||
setProjectMainLanguage(metadata.mainLanguage);
|
||||
setProjectMainLanguage(resolveSupportedRenderLanguage(metadata.mainLanguage));
|
||||
}
|
||||
if (metadata?.defaultAuthor) {
|
||||
setProjectDefaultAuthor(metadata.defaultAuthor);
|
||||
@@ -302,7 +315,7 @@ export const SettingsView: React.FC = () => {
|
||||
description: projectDescription.trim(),
|
||||
dataPath: projectDataPath.trim() || undefined,
|
||||
publicUrl: projectPublicUrl.trim() || undefined,
|
||||
mainLanguage: projectMainLanguage,
|
||||
mainLanguage: resolveSupportedRenderLanguage(projectMainLanguage),
|
||||
defaultAuthor: projectDefaultAuthor.trim() || undefined,
|
||||
maxPostsPerPage: Math.min(500, Math.max(1, Math.floor(projectMaxPostsPerPage || 50))),
|
||||
categorySettings,
|
||||
@@ -415,28 +428,11 @@ export const SettingsView: React.FC = () => {
|
||||
<select
|
||||
id="project-language"
|
||||
value={projectMainLanguage}
|
||||
onChange={(e) => setProjectMainLanguage(e.target.value)}
|
||||
onChange={(e) => setProjectMainLanguage(resolveSupportedRenderLanguage(e.target.value))}
|
||||
>
|
||||
<option value="en">{t('settings.language.english')}</option>
|
||||
<option value="de">{t('settings.language.german')}</option>
|
||||
<option value="es">{t('settings.language.spanish')}</option>
|
||||
<option value="fr">{t('settings.language.french')}</option>
|
||||
<option value="it">{t('settings.language.italian')}</option>
|
||||
<option value="pt">{t('settings.language.portuguese')}</option>
|
||||
<option value="nl">{t('settings.language.dutch')}</option>
|
||||
<option value="pl">{t('settings.language.polish')}</option>
|
||||
<option value="ru">{t('settings.language.russian')}</option>
|
||||
<option value="ja">{t('settings.language.japanese')}</option>
|
||||
<option value="zh">{t('settings.language.chinese')}</option>
|
||||
<option value="ko">{t('settings.language.korean')}</option>
|
||||
<option value="ar">{t('settings.language.arabic')}</option>
|
||||
<option value="hi">{t('settings.language.hindi')}</option>
|
||||
<option value="tr">{t('settings.language.turkish')}</option>
|
||||
<option value="sv">{t('settings.language.swedish')}</option>
|
||||
<option value="da">{t('settings.language.danish')}</option>
|
||||
<option value="no">{t('settings.language.norwegian')}</option>
|
||||
<option value="fi">{t('settings.language.finnish')}</option>
|
||||
<option value="cs">{t('settings.language.czech')}</option>
|
||||
{SUPPORTED_RENDER_LANGUAGES.map((language) => (
|
||||
<option key={language} value={language}>{t(RENDER_LANGUAGE_LABEL_KEY[language])}</option>
|
||||
))}
|
||||
</select>
|
||||
</SettingRow>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useAppStore } from '../../store';
|
||||
import { showToast } from '../Toast';
|
||||
import { useI18n } from '../../i18n';
|
||||
import { PICO_THEME_NAMES, PICO_THEME_PREVIEW_TOKENS, getRendererPicoTheme, ensureRendererPicoThemeStylesheet, type PicoThemeName } from '../../utils/picoTheme';
|
||||
import './StyleView.css';
|
||||
|
||||
@@ -12,6 +13,7 @@ function toDisplayName(theme: PicoThemeName): string {
|
||||
}
|
||||
|
||||
export const StyleView: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const { activeProject, picoTheme, setPicoTheme } = useAppStore();
|
||||
const [selectedTheme, setSelectedTheme] = useState<PicoThemeName>(getRendererPicoTheme(picoTheme));
|
||||
const [previewMode, setPreviewMode] = useState<PreviewMode>('auto');
|
||||
@@ -51,10 +53,10 @@ export const StyleView: React.FC = () => {
|
||||
setIsApplying(true);
|
||||
await window.electronAPI?.meta.updateProjectMetadata({ picoTheme: selectedTheme });
|
||||
setPicoTheme(selectedTheme);
|
||||
showToast.success(`Applied theme: ${toDisplayName(selectedTheme)}`);
|
||||
showToast.success(t('styleView.toast.appliedTheme', { theme: toDisplayName(selectedTheme) }));
|
||||
} catch (error) {
|
||||
console.error('Failed to apply style theme:', error);
|
||||
showToast.error('Failed to apply theme');
|
||||
showToast.error(t('styleView.toast.applyThemeFailed'));
|
||||
} finally {
|
||||
setIsApplying(false);
|
||||
}
|
||||
@@ -63,11 +65,11 @@ export const StyleView: React.FC = () => {
|
||||
return (
|
||||
<div className="style-view">
|
||||
<div className="style-view-header">
|
||||
<h2>Style</h2>
|
||||
<p>Select a Pico CSS theme and preview the top posts before applying.</p>
|
||||
<h2>{t('styleView.title')}</h2>
|
||||
<p>{t('styleView.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="style-theme-picker" role="group" aria-label="Pico Theme Picker">
|
||||
<div className="style-theme-picker" role="group" aria-label={t('styleView.themePickerAria')}>
|
||||
{PICO_THEME_NAMES.map((theme) => {
|
||||
const isSelected = selectedTheme === theme;
|
||||
const preview = PICO_THEME_PREVIEW_TOKENS[theme];
|
||||
@@ -104,15 +106,15 @@ export const StyleView: React.FC = () => {
|
||||
|
||||
<div className="style-apply-row">
|
||||
<label className="style-preview-mode-control">
|
||||
<span>Preview mode</span>
|
||||
<span>{t('styleView.previewMode')}</span>
|
||||
<select
|
||||
aria-label="Preview mode"
|
||||
aria-label={t('styleView.previewMode')}
|
||||
value={previewMode}
|
||||
onChange={(event) => setPreviewMode(event.target.value as PreviewMode)}
|
||||
>
|
||||
<option value="auto">Auto</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="auto">{t('styleView.mode.auto')}</option>
|
||||
<option value="light">{t('styleView.mode.light')}</option>
|
||||
<option value="dark">{t('styleView.mode.dark')}</option>
|
||||
</select>
|
||||
</label>
|
||||
<button
|
||||
@@ -120,13 +122,13 @@ export const StyleView: React.FC = () => {
|
||||
onClick={handleApplyTheme}
|
||||
disabled={isApplying || picoTheme === selectedTheme}
|
||||
>
|
||||
Apply Theme
|
||||
{t('styleView.applyTheme')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="style-preview-container">
|
||||
<iframe
|
||||
title="Theme preview"
|
||||
title={t('styleView.themePreviewTitle')}
|
||||
className="style-preview-frame"
|
||||
src={previewUrl}
|
||||
/>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useAppStore } from '../../store';
|
||||
import { showToast } from '../Toast';
|
||||
import { getContrastColor } from '../../utils/color';
|
||||
import { subscribeToTagEvents } from '../../utils/tagEventSubscriptions';
|
||||
import { useI18n } from '../../i18n';
|
||||
import './TagsView.css';
|
||||
|
||||
// Types
|
||||
@@ -46,7 +47,8 @@ const TagCloudItem: React.FC<{
|
||||
isSelected: boolean;
|
||||
onSelect: (name: string) => void;
|
||||
maxCount: number;
|
||||
}> = ({ tag, isSelected, onSelect, maxCount }) => {
|
||||
title: string;
|
||||
}> = ({ tag, isSelected, onSelect, maxCount, title }) => {
|
||||
// Calculate font size based on count (range: 0.8rem to 2rem)
|
||||
const minSize = 0.85;
|
||||
const maxSize = 1.8;
|
||||
@@ -69,7 +71,7 @@ const TagCloudItem: React.FC<{
|
||||
className={`tag-cloud-item ${isSelected ? 'selected' : ''} ${hasColor ? 'has-color' : ''}`}
|
||||
style={style}
|
||||
onClick={() => onSelect(tag.name)}
|
||||
title={`${tag.count} post${tag.count !== 1 ? 's' : ''}`}
|
||||
title={title}
|
||||
>
|
||||
{tag.name}
|
||||
<span className="tag-count">{tag.count}</span>
|
||||
@@ -128,6 +130,7 @@ const SectionHeader: React.FC<{
|
||||
);
|
||||
|
||||
export const TagsView: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const { showErrorModal } = useAppStore();
|
||||
|
||||
// State
|
||||
@@ -198,7 +201,7 @@ export const TagsView: React.FC = () => {
|
||||
// Create tag
|
||||
const handleCreateTag = async () => {
|
||||
if (!newTagName.trim()) {
|
||||
showToast.error('Tag name is required');
|
||||
showToast.error(t('tagsView.toast.tagNameRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,7 +212,7 @@ export const TagsView: React.FC = () => {
|
||||
});
|
||||
setNewTagName('');
|
||||
setNewTagColor('');
|
||||
showToast.success('Tag created');
|
||||
showToast.success(t('tagsView.toast.tagCreated'));
|
||||
loadTags();
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
@@ -224,14 +227,14 @@ export const TagsView: React.FC = () => {
|
||||
try {
|
||||
const result = await window.electronAPI?.tags.delete(deleteConfirm.tagId);
|
||||
if (result?.success) {
|
||||
showToast.success(`Tag deleted. ${result.postsUpdated} post(s) updated.`);
|
||||
showToast.success(t('tagsView.toast.tagDeleted', { postsUpdated: result.postsUpdated }));
|
||||
setSelectedTags(prev => prev.filter(n => n !== deleteConfirm.tagName));
|
||||
loadTags();
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
showErrorModal({
|
||||
title: 'Delete Failed',
|
||||
title: t('tagsView.error.deleteFailedTitle'),
|
||||
message: err.message,
|
||||
});
|
||||
} finally {
|
||||
@@ -262,7 +265,7 @@ export const TagsView: React.FC = () => {
|
||||
await window.electronAPI?.tags.rename(editingTagId, editTagName.trim());
|
||||
}
|
||||
|
||||
showToast.success('Tag updated');
|
||||
showToast.success(t('tagsView.toast.tagUpdated'));
|
||||
setEditingTagId(null);
|
||||
loadTags();
|
||||
} catch (error) {
|
||||
@@ -279,7 +282,7 @@ export const TagsView: React.FC = () => {
|
||||
// Find target tag
|
||||
const targetTag = allTags.find(t => t.name === mergeConfirm.targetName);
|
||||
if (!targetTag) {
|
||||
showToast.error('Target tag not found');
|
||||
showToast.error(t('tagsView.toast.targetTagNotFound'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -289,7 +292,7 @@ export const TagsView: React.FC = () => {
|
||||
);
|
||||
|
||||
if (sourceTags.length === 0) {
|
||||
showToast.error('No source tags to merge');
|
||||
showToast.error(t('tagsView.toast.noSourceTagsToMerge'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -300,7 +303,11 @@ export const TagsView: React.FC = () => {
|
||||
|
||||
if (result?.success) {
|
||||
showToast.success(
|
||||
`Merged ${result.tagsDeleted} tag(s) into "${result.targetTag}". ${result.postsUpdated} post(s) updated.`
|
||||
t('tagsView.toast.tagsMerged', {
|
||||
tagsDeleted: result.tagsDeleted,
|
||||
targetTag: result.targetTag,
|
||||
postsUpdated: result.postsUpdated,
|
||||
})
|
||||
);
|
||||
setSelectedTags([]);
|
||||
setMergeTargetName('');
|
||||
@@ -309,7 +316,7 @@ export const TagsView: React.FC = () => {
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
showErrorModal({
|
||||
title: 'Merge Failed',
|
||||
title: t('tagsView.error.mergeFailedTitle'),
|
||||
message: err.message,
|
||||
});
|
||||
} finally {
|
||||
@@ -323,9 +330,9 @@ export const TagsView: React.FC = () => {
|
||||
const result = await window.electronAPI?.tags.syncFromPosts();
|
||||
if (result) {
|
||||
if (result.added.length > 0) {
|
||||
showToast.success(`Discovered ${result.added.length} new tag(s)`);
|
||||
showToast.success(t('tagsView.toast.discoveredTags', { count: result.added.length }));
|
||||
} else {
|
||||
showToast.info('All tags are already synced');
|
||||
showToast.info(t('tagsView.toast.alreadySynced'));
|
||||
}
|
||||
loadTags();
|
||||
}
|
||||
@@ -349,23 +356,23 @@ export const TagsView: React.FC = () => {
|
||||
return (
|
||||
<div className="tags-view">
|
||||
<div className="tags-view-header">
|
||||
<h2>Tag Management</h2>
|
||||
<p className="text-muted">Manage your blog's tags, assign colors, and perform bulk operations.</p>
|
||||
<h2>{t('tagsView.title')}</h2>
|
||||
<p className="text-muted">{t('tagsView.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="tags-view-content">
|
||||
{/* Tag Cloud Section */}
|
||||
<SectionHeader
|
||||
id="tags-section-cloud"
|
||||
title="Tag Cloud"
|
||||
description="Click tags to select them for bulk operations. Hover to see post counts."
|
||||
title={t('tagsView.cloud.title')}
|
||||
description={t('tagsView.cloud.description')}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="tags-loading">Loading tags...</div>
|
||||
<div className="tags-loading">{t('tagsView.loadingTags')}</div>
|
||||
) : tagsWithCounts.length === 0 ? (
|
||||
<div className="tags-empty">
|
||||
<p>No tags found</p>
|
||||
<button onClick={handleSyncFromPosts}>Discover tags from posts</button>
|
||||
<p>{t('tagsView.noTagsFound')}</p>
|
||||
<button onClick={handleSyncFromPosts}>{t('tagsView.discoverFromPosts')}</button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@@ -377,13 +384,17 @@ export const TagsView: React.FC = () => {
|
||||
isSelected={selectedTags.includes(tag.name)}
|
||||
onSelect={handleTagSelect}
|
||||
maxCount={maxCount}
|
||||
title={t('tagsView.tagCountTitle', {
|
||||
count: tag.count,
|
||||
item: tag.count === 1 ? t('tagsView.postsSingular') : t('tagsView.postsPlural'),
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{selectedTags.length > 0 && (
|
||||
<div className="tag-selection-info">
|
||||
<span>{selectedTags.length} tag(s) selected</span>
|
||||
<button onClick={handleClearSelection}>Clear selection</button>
|
||||
<span>{t('tagsView.selectedCount', { count: selectedTags.length })}</span>
|
||||
<button onClick={handleClearSelection}>{t('tagsView.clearSelection')}</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@@ -393,16 +404,16 @@ export const TagsView: React.FC = () => {
|
||||
{/* Tag Management Section */}
|
||||
<SectionHeader
|
||||
id="tags-section-manage"
|
||||
title="Create & Edit Tags"
|
||||
description="Create new tags or edit existing ones. Assign colors to make tags visually distinct."
|
||||
title={t('tagsView.manage.title')}
|
||||
description={t('tagsView.manage.description')}
|
||||
>
|
||||
{/* Create new tag */}
|
||||
<div className="tag-create-form">
|
||||
<h4>Create New Tag</h4>
|
||||
<h4>{t('tagsView.create.title')}</h4>
|
||||
<div className="tag-form-row">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Tag name"
|
||||
placeholder={t('tagsView.tagNamePlaceholder')}
|
||||
value={newTagName}
|
||||
onChange={(e) => setNewTagName(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleCreateTag()}
|
||||
@@ -412,19 +423,19 @@ export const TagsView: React.FC = () => {
|
||||
type="color"
|
||||
value={newTagColor || '#808080'}
|
||||
onChange={(e) => setNewTagColor(e.target.value)}
|
||||
title="Choose color"
|
||||
title={t('tagsView.chooseColor')}
|
||||
/>
|
||||
{newTagColor && (
|
||||
<button
|
||||
className="clear-color"
|
||||
onClick={() => setNewTagColor('')}
|
||||
title="Remove color"
|
||||
title={t('tagsView.removeColor')}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<button onClick={handleCreateTag} className="primary">Create</button>
|
||||
<button onClick={handleCreateTag} className="primary">{t('tagsView.create.action')}</button>
|
||||
</div>
|
||||
<div className="color-presets">
|
||||
{COLOR_PRESETS.map(color => (
|
||||
@@ -442,14 +453,14 @@ export const TagsView: React.FC = () => {
|
||||
{/* Selected tag editor */}
|
||||
{selectedTagObjects.length === 1 && (
|
||||
<div className="tag-edit-form">
|
||||
<h4>Edit Tag: {selectedTagObjects[0].name}</h4>
|
||||
<h4>{t('tagsView.edit.title', { name: selectedTagObjects[0].name })}</h4>
|
||||
{editingTagId === selectedTagObjects[0].id ? (
|
||||
<div className="tag-form-row">
|
||||
<input
|
||||
type="text"
|
||||
value={editTagName}
|
||||
onChange={(e) => setEditTagName(e.target.value)}
|
||||
placeholder="Tag name"
|
||||
placeholder={t('tagsView.tagNamePlaceholder')}
|
||||
/>
|
||||
<div className="color-picker-group">
|
||||
<input
|
||||
@@ -461,14 +472,14 @@ export const TagsView: React.FC = () => {
|
||||
<button
|
||||
className="clear-color"
|
||||
onClick={() => setEditTagColor('')}
|
||||
title="Remove color"
|
||||
title={t('tagsView.removeColor')}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<button onClick={handleSaveEdit} className="primary">Save</button>
|
||||
<button onClick={() => setEditingTagId(null)}>Cancel</button>
|
||||
<button onClick={handleSaveEdit} className="primary">{t('common.save')}</button>
|
||||
<button onClick={() => setEditingTagId(null)}>{t('common.cancel')}</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="tag-form-row">
|
||||
@@ -480,7 +491,7 @@ export const TagsView: React.FC = () => {
|
||||
{selectedTagObjects[0].name}
|
||||
</span>
|
||||
<button onClick={() => handleStartEdit(selectedTagObjects[0])}>
|
||||
Edit
|
||||
{t('tagsView.edit.action')}
|
||||
</button>
|
||||
<button
|
||||
className="danger"
|
||||
@@ -489,7 +500,7 @@ export const TagsView: React.FC = () => {
|
||||
tagName: selectedTagObjects[0].name
|
||||
})}
|
||||
>
|
||||
Delete
|
||||
{t('tagsView.deleteAction')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -500,20 +511,20 @@ export const TagsView: React.FC = () => {
|
||||
{/* Merge Tags Section */}
|
||||
<SectionHeader
|
||||
id="tags-section-merge"
|
||||
title="Merge Tags"
|
||||
description="Select multiple tags above, then merge them into a single tag. All posts will be updated."
|
||||
title={t('tagsView.merge.title')}
|
||||
description={t('tagsView.merge.description')}
|
||||
>
|
||||
{selectedTags.length < 2 ? (
|
||||
<p className="text-muted">Select 2 or more tags from the cloud above to merge them.</p>
|
||||
<p className="text-muted">{t('tagsView.merge.selectAtLeastTwo')}</p>
|
||||
) : (
|
||||
<div className="merge-form">
|
||||
<p>Merge <strong>{selectedTags.length}</strong> tags into:</p>
|
||||
<p>{t('tagsView.merge.countInto', { count: selectedTags.length })}</p>
|
||||
<div className="tag-form-row">
|
||||
<select
|
||||
value={mergeTargetName}
|
||||
onChange={(e) => setMergeTargetName(e.target.value)}
|
||||
>
|
||||
<option value="">Select target tag...</option>
|
||||
<option value="">{t('tagsView.merge.selectTarget')}</option>
|
||||
{selectedTags.map(name => (
|
||||
<option key={name} value={name}>{name}</option>
|
||||
))}
|
||||
@@ -530,11 +541,13 @@ export const TagsView: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
Merge Tags
|
||||
{t('tagsView.merge.action')}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-muted text-small">
|
||||
Tags to be deleted: {selectedTags.filter(n => n !== mergeTargetName).join(', ') || '(none)'}
|
||||
{t('tagsView.merge.tagsToDelete', {
|
||||
tags: selectedTags.filter(n => n !== mergeTargetName).join(', ') || t('tagsView.none'),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -543,11 +556,11 @@ export const TagsView: React.FC = () => {
|
||||
{/* Sync Section */}
|
||||
<SectionHeader
|
||||
id="tags-section-sync"
|
||||
title="Sync Tags"
|
||||
description="Discover tags that exist in posts but not in the tag database."
|
||||
title={t('tagsView.sync.title')}
|
||||
description={t('tagsView.sync.description')}
|
||||
>
|
||||
<button onClick={handleSyncFromPosts}>
|
||||
Sync Tags from Posts
|
||||
{t('tagsView.sync.action')}
|
||||
</button>
|
||||
</SectionHeader>
|
||||
</div>
|
||||
@@ -555,9 +568,10 @@ export const TagsView: React.FC = () => {
|
||||
{/* Confirm Dialogs */}
|
||||
<ConfirmDialog
|
||||
isOpen={!!deleteConfirm}
|
||||
title="Delete Tag"
|
||||
message={`Are you sure you want to delete the tag "${deleteConfirm?.tagName}"? This will remove it from all posts. This action runs as a background task.`}
|
||||
confirmText="Delete Tag"
|
||||
title={t('tagsView.confirmDelete.title')}
|
||||
message={t('tagsView.confirmDelete.message', { tagName: deleteConfirm?.tagName || '' })}
|
||||
confirmText={t('tagsView.confirmDelete.action')}
|
||||
cancelText={t('common.cancel')}
|
||||
isDestructive
|
||||
onConfirm={handleDeleteTag}
|
||||
onCancel={() => setDeleteConfirm(null)}
|
||||
@@ -565,9 +579,13 @@ export const TagsView: React.FC = () => {
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={!!mergeConfirm}
|
||||
title="Merge Tags"
|
||||
message={`Are you sure you want to merge ${mergeConfirm?.sourceNames.length} tag(s) into "${mergeConfirm?.targetName}"? The source tags will be deleted and all posts will be updated. This runs as a background task.`}
|
||||
confirmText="Merge Tags"
|
||||
title={t('tagsView.confirmMerge.title')}
|
||||
message={t('tagsView.confirmMerge.message', {
|
||||
count: mergeConfirm?.sourceNames.length || 0,
|
||||
target: mergeConfirm?.targetName || '',
|
||||
})}
|
||||
confirmText={t('tagsView.confirmMerge.action')}
|
||||
cancelText={t('common.cancel')}
|
||||
onConfirm={handleMergeTags}
|
||||
onCancel={() => setMergeConfirm(null)}
|
||||
/>
|
||||
|
||||
@@ -14,10 +14,10 @@ export const SUPPORTED_UI_LANGUAGES: UiLanguage[] = ['en', 'de', 'fr', 'it', 'es
|
||||
type TranslationTable = Record<string, string>;
|
||||
|
||||
const en = enJson as TranslationTable;
|
||||
const de = { ...en, ...(deJson as TranslationTable) };
|
||||
const fr = { ...en, ...(frJson as TranslationTable) };
|
||||
const it = { ...en, ...(itJson as TranslationTable) };
|
||||
const es = { ...en, ...(esJson as TranslationTable) };
|
||||
const de = deJson as TranslationTable;
|
||||
const fr = frJson as TranslationTable;
|
||||
const it = itJson as TranslationTable;
|
||||
const es = esJson as TranslationTable;
|
||||
|
||||
const uiCatalog: Record<UiLanguage, TranslationTable> = { en, de, fr, it, es };
|
||||
|
||||
@@ -55,7 +55,7 @@ export function translateUi(
|
||||
key: string,
|
||||
params?: Record<string, string | number>
|
||||
): string {
|
||||
const localized = uiCatalog[language]?.[key] ?? uiCatalog.en[key] ?? key;
|
||||
const localized = uiCatalog[language]?.[key] ?? key;
|
||||
return interpolate(localized, params);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,46 +69,46 @@
|
||||
"settings.data.title": "Datenbankwartung",
|
||||
"settings.data.fileSystemTitle": "Dateisystem",
|
||||
"settings.search.placeholder": "Einstellungen durchsuchen...",
|
||||
"settings.search.noResults": "No Einstellungen found matching \"{query}\"",
|
||||
"settings.search.noResults": "Keine passenden Einstellungen für \"{query}\" gefunden",
|
||||
"settings.search.clear": "Suche löschen",
|
||||
"settings.toast.publishingSaved": "Veröffentlichungs-Anmeldedaten gespeichert",
|
||||
"settings.toast.saveCredentialsFailed": "Fehler beim save credentials",
|
||||
"settings.toast.saveCredentialsFailed": "Anmeldedaten konnten nicht gespeichert werden",
|
||||
"settings.toast.credentialsCleared": "{type}-Anmeldedaten gelöscht",
|
||||
"settings.toast.projectSaved": "Project Einstellungen saved",
|
||||
"settings.toast.projectSaveFailed": "Fehler beim save project Einstellungen",
|
||||
"settings.toast.projectSaved": "Projekteinstellungen gespeichert",
|
||||
"settings.toast.projectSaveFailed": "Projekteinstellungen konnten nicht gespeichert werden",
|
||||
"settings.toast.categoryAdded": "Kategorie \"{category}\" hinzugefügt",
|
||||
"settings.toast.categoryAddFailed": "Fehler beim add category",
|
||||
"settings.toast.categoryAddFailed": "Kategorie konnte nicht hinzugefügt werden",
|
||||
"settings.toast.categoryExists": "Kategorie existiert bereits",
|
||||
"settings.toast.categoryProtected": "Standardkategorie \"{category}\" kann nicht gelöscht werden",
|
||||
"settings.toast.categoryAtLeastOne": "Mindestens eine Kategorie ist erforderlich",
|
||||
"settings.toast.categoryRemoved": "Kategorie \"{category}\" entfernt",
|
||||
"settings.toast.categoryRemoveFailed": "Fehler beim remove category",
|
||||
"settings.toast.categoryRemoveFailed": "Kategorie konnte nicht entfernt werden",
|
||||
"settings.toast.categoriesReset": "Kategorien auf Standard zurückgesetzt",
|
||||
"settings.toast.categoriesResetFailed": "Fehler beim reset categories",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Fehler beim update category Einstellungen",
|
||||
"settings.toast.categoriesResetFailed": "Kategorien konnten nicht zurückgesetzt werden",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Kategorieeinstellungen konnten nicht aktualisiert werden",
|
||||
"settings.toast.systemPromptSaved": "System-Prompt gespeichert",
|
||||
"settings.toast.systemPromptSaveFailed": "Fehler beim save system prompt",
|
||||
"settings.toast.systemPromptSaveFailed": "System-Prompt konnte nicht gespeichert werden",
|
||||
"settings.toast.systemPromptReset": "System-Prompt auf Standard zurückgesetzt",
|
||||
"settings.toast.systemPromptResetFailed": "Fehler beim reset system prompt",
|
||||
"settings.toast.systemPromptResetFailed": "System-Prompt konnte nicht zurückgesetzt werden",
|
||||
"settings.toast.apiKeySaved": "API-Schlüssel gespeichert und validiert",
|
||||
"settings.toast.apiKeyInvalid": "Ungültiger API-Schlüssel",
|
||||
"settings.toast.apiKeySaveFailed": "Fehler beim save API key",
|
||||
"settings.toast.apiKeySaveFailed": "API-Schlüssel konnte nicht gespeichert werden",
|
||||
"settings.toast.defaultModelUpdated": "Standardmodell aktualisiert",
|
||||
"settings.toast.defaultModelUpdateFailed": "Fehler beim set default model",
|
||||
"settings.toast.rebuildPostsLoading": "Rebuilding Beiträge database...",
|
||||
"settings.toast.defaultModelUpdateFailed": "Standardmodell konnte nicht gesetzt werden",
|
||||
"settings.toast.rebuildPostsLoading": "Beitragsdatenbank wird neu aufgebaut...",
|
||||
"settings.toast.rebuildPostsSuccess": "Beitragsdatenbank neu aufgebaut",
|
||||
"settings.toast.rebuildPostsFailed": "Fehler beim rebuild Beiträge database",
|
||||
"settings.toast.rebuildMediaLoading": "Rebuilding Medien database...",
|
||||
"settings.toast.rebuildPostsFailed": "Beitragsdatenbank konnte nicht neu aufgebaut werden",
|
||||
"settings.toast.rebuildMediaLoading": "Mediendatenbank wird neu aufgebaut...",
|
||||
"settings.toast.rebuildMediaSuccess": "Mediendatenbank neu aufgebaut",
|
||||
"settings.toast.rebuildMediaFailed": "Fehler beim rebuild Medien database",
|
||||
"settings.toast.rebuildLinksLoading": "Rebuilding Beitrag links...",
|
||||
"settings.toast.rebuildMediaFailed": "Mediendatenbank konnte nicht neu aufgebaut werden",
|
||||
"settings.toast.rebuildLinksLoading": "Beitragslinks werden neu aufgebaut...",
|
||||
"settings.toast.rebuildLinksSuccess": "Beitragslinks neu aufgebaut",
|
||||
"settings.toast.rebuildLinksFailed": "Fehler beim rebuild Beitrag links",
|
||||
"settings.toast.rebuildLinksFailed": "Beitragslinks konnten nicht neu aufgebaut werden",
|
||||
"settings.toast.thumbnailsLoading": "Vorschaubilder werden erzeugt...",
|
||||
"settings.toast.thumbnailsGenerated": "{count} Vorschaubilder erzeugt",
|
||||
"settings.toast.thumbnailsAlreadyExist": "Alle Vorschaubilder existieren bereits",
|
||||
"settings.toast.thumbnailsComplete": "Generierung der Vorschaubilder abgeschlossen",
|
||||
"settings.toast.thumbnailsFailed": "Fehler beim generate thumbnails",
|
||||
"settings.toast.thumbnailsFailed": "Vorschaubilder konnten nicht erzeugt werden",
|
||||
"chat.setupTitle": "KI-Chat-Einrichtung",
|
||||
"chat.apiKeyRequiredTitle": "OpenCode Zen API-Schlüssel erforderlich",
|
||||
"chat.apiKeyRequiredDescription": "Gib deinen OpenCode API-Schlüssel ein, um den KI-Chat zu aktivieren.",
|
||||
@@ -116,23 +116,23 @@
|
||||
"chat.apiKeySave": "Schlüssel speichern",
|
||||
"chat.apiKeyValidating": "Wird validiert...",
|
||||
"chat.apiKeyInvalid": "Ungültiger API-Schlüssel. Bitte prüfen und erneut versuchen.",
|
||||
"chat.apiKeyValidationFailed": "Fehler beim validate API key.",
|
||||
"chat.apiKeyValidationFailed": "API-Schlüssel konnte nicht validiert werden.",
|
||||
"chat.newChat": "Neuer Chat",
|
||||
"chat.welcomeTitle": "Willkommen beim KI-Assistenten",
|
||||
"chat.welcomeDescription": "I can help you manage your Beiträge and Medien. Try asking me to:",
|
||||
"chat.welcomeTipSearch": "Suche for Beiträge about a specific topic",
|
||||
"chat.welcomeTipDetails": "Get details about a specific Beitrag",
|
||||
"chat.welcomeDescription": "Ich kann dir helfen, deine Beiträge und Medien zu verwalten. Frag mich zum Beispiel:",
|
||||
"chat.welcomeTipSearch": "Nach Beiträgen zu einem bestimmten Thema suchen",
|
||||
"chat.welcomeTipDetails": "Details zu einem bestimmten Beitrag anzeigen",
|
||||
"chat.welcomeTipTags": "Alle Tags oder Kategorien in deinem Blog auflisten",
|
||||
"chat.welcomeTipMetadata": "Update metadata for Beiträge or Medien",
|
||||
"chat.welcomeTipImages": "List all images in your Medien library",
|
||||
"chat.welcomeTipMetadata": "Metadaten für Beiträge oder Medien aktualisieren",
|
||||
"chat.welcomeTipImages": "Alle Bilder in deiner Mediathek auflisten",
|
||||
"chat.role.you": "Du",
|
||||
"chat.role.assistant": "Assistent",
|
||||
"chat.stop": "Stopp",
|
||||
"chat.inputPlaceholder": "Nachricht eingeben...",
|
||||
"chat.errorPrefix": "Fehler: {error}",
|
||||
"chat.errorNoResponse": "Fehler beim get a response. Please try again.",
|
||||
"chat.errorNoResponse": "Es konnte keine Antwort abgerufen werden. Bitte versuche es erneut.",
|
||||
"chat.errorEmptyResponse": "Das Modell hat eine leere Antwort zurückgegeben. Versuche ein anderes Modell oder formuliere deine Frage neu.",
|
||||
"chat.errorGeneric": "Sorry, an error occurred while processing your Nachricht.",
|
||||
"chat.errorGeneric": "Beim Verarbeiten deiner Nachricht ist ein Fehler aufgetreten.",
|
||||
"chat.cancelledSuffix": "(abgebrochen)",
|
||||
"aiSuggestions.title": "KI-Bildanalyse",
|
||||
"aiSuggestions.close": "Schließen",
|
||||
@@ -152,8 +152,8 @@
|
||||
"insert.tab.imageInternal": "Mediathek",
|
||||
"insert.tab.linkExternal": "Externe URL",
|
||||
"insert.tab.imageExternal": "Externes Bild",
|
||||
"insert.searchPlaceholder.link": "Suche Beiträge by title or content...",
|
||||
"insert.searchPlaceholder.image": "Suche Medien by name, title, or alt text...",
|
||||
"insert.searchPlaceholder.link": "Beiträge nach Titel oder Inhalt durchsuchen...",
|
||||
"insert.searchPlaceholder.image": "Medien nach Name, Titel oder Alt-Text durchsuchen...",
|
||||
"insert.status.searching": "Suche...",
|
||||
"insert.status.typeMore": "Zum Suchen mindestens 2 Zeichen eingeben",
|
||||
"insert.status.noResults": "Keine {kind} für \"{query}\" gefunden",
|
||||
@@ -169,7 +169,7 @@
|
||||
"insert.hint.internal": "Mit ↑↓ navigieren, Enter zum Auswählen, Esc zum Schließen",
|
||||
"insert.hint.external": "URL eingeben und Enter drücken oder auf die Schaltfläche klicken, Esc zum Schließen",
|
||||
"insert.hint.canonicalPost": "Kanonisch: /YYYY/MM/DD/slug",
|
||||
"insert.hint.canonicalMedia": "Canonical: /Medien/YYYY/MM/file.ext",
|
||||
"insert.hint.canonicalMedia": "Kanonisch: /media/YYYY/MM/datei.ext",
|
||||
"postLinks.loading": "Links werden geladen...",
|
||||
"postLinks.link": "Link",
|
||||
"postLinks.links": "Links",
|
||||
@@ -181,7 +181,7 @@
|
||||
"gitDiff.header": "Unterschied: {target}",
|
||||
"gitDiff.noProject": "Kein aktives Projekt ausgewählt.",
|
||||
"gitDiff.noProjectPath": "Projektpfad konnte nicht ermittelt werden.",
|
||||
"gitDiff.loadFailed": "Fehler beim load diff.",
|
||||
"gitDiff.loadFailed": "Diff konnte nicht geladen werden.",
|
||||
"gitDiff.loading": "Diff wird geladen...",
|
||||
"gitDiff.changedFiles": "Geänderte Dateien",
|
||||
"gitDiff.previousFile": "Vorherige Datei",
|
||||
@@ -192,8 +192,8 @@
|
||||
"errorModal.copy": "Kopieren",
|
||||
"errorModal.noStack": "Kein Stack-Trace verfügbar",
|
||||
"confirmDelete.title": "Löschen bestätigen",
|
||||
"confirmDelete.promptPost": "Are you sure you want to delete the Beitrag",
|
||||
"confirmDelete.promptMedia": "Are you sure you want to delete the Medien file",
|
||||
"confirmDelete.promptPost": "Möchtest du den Beitrag wirklich löschen",
|
||||
"confirmDelete.promptMedia": "Möchtest du die Mediendatei wirklich löschen",
|
||||
"confirmDelete.warning": "Warnung:",
|
||||
"confirmDelete.referencedBy": "Diese(r) {itemType} wird von folgenden Elementen referenziert:",
|
||||
"confirmDelete.note": "Beim Löschen dieses/dieser {itemType} werden alle diese Verweise entfernt.",
|
||||
@@ -205,12 +205,12 @@
|
||||
"lightbox.close": "Schließen (Esc)",
|
||||
"lightbox.previous": "Vorheriges (←)",
|
||||
"lightbox.next": "Nächstes (→)",
|
||||
"credentials.error.load": "Fehler beim load credentials:",
|
||||
"credentials.error.save": "Fehler beim save credentials:",
|
||||
"credentials.error.load": "Anmeldedaten konnten nicht geladen werden:",
|
||||
"credentials.error.save": "Anmeldedaten konnten nicht gespeichert werden:",
|
||||
"credentials.toast.saved": "Anmeldedaten gespeichert",
|
||||
"credentials.toast.saveFailed": "Fehler beim save credentials",
|
||||
"credentials.toast.saveFailed": "Anmeldedaten konnten nicht gespeichert werden",
|
||||
"credentials.toast.testing": "{type}-Verbindung wird getestet...",
|
||||
"credentials.toast.connectionFailed": "Connection fehlgeschlagen - check credentials",
|
||||
"credentials.toast.connectionFailed": "Verbindung fehlgeschlagen – Anmeldedaten prüfen",
|
||||
"credentials.tab.ftp": "FTP-Zugang",
|
||||
"credentials.tab.ssh": "SSH-Zugang",
|
||||
"credentials.ftp.title": "FTP-Veröffentlichung",
|
||||
@@ -230,14 +230,14 @@
|
||||
"credentials.ssh.placeholder.keyPath": "~/.ssh/mein_schluessel",
|
||||
"gitSidebar.header": "QUELLSTEUERUNG",
|
||||
"gitSidebar.loading": "Laden...",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Fehler beim fetch remote updates.",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Remote-Aktualisierungen konnten nicht abgerufen werden.",
|
||||
"gitSidebar.error.refreshRemoteState": "Remote-Tracking-Status konnte nicht aktualisiert werden.",
|
||||
"gitSidebar.error.gitMissing": "Git-Programm nicht gefunden. Bitte installiere Git und starte die App neu.",
|
||||
"gitSidebar.error.noActiveProject": "Kein aktives Projekt ausgewählt.",
|
||||
"gitSidebar.error.loadRepoStatus": "Repository-Status konnte nicht geladen werden.",
|
||||
"gitSidebar.error.initFailed": "Fehler beim initialize git repository.",
|
||||
"gitSidebar.error.initFailed": "Git-Repository konnte nicht initialisiert werden.",
|
||||
"gitSidebar.error.actionFailed": "Fehler beim {action}.",
|
||||
"gitSidebar.error.commitFailed": "Fehler beim commit changes.",
|
||||
"gitSidebar.error.commitFailed": "Änderungen konnten nicht committet werden.",
|
||||
"gitSidebar.progress.preparingInit": "Repository-Initialisierung wird vorbereitet...",
|
||||
"gitSidebar.progress.pushingRemote": "Commits werden zum Remote übertragen... das kann bei großen Uploads eine Weile dauern.",
|
||||
"gitSidebar.progress.fetching": "Remote-Aktualisierungen werden abgerufen...",
|
||||
@@ -265,7 +265,7 @@
|
||||
"gitSidebar.action.committing": "Commit wird erstellt...",
|
||||
"gitSidebar.action.initializeGit": "Git initialisieren",
|
||||
"gitSidebar.action.initializing": "Initialisieren...",
|
||||
"gitSidebar.openChanges": "Öffnen Changes ({count})",
|
||||
"gitSidebar.openChanges": "Offene Änderungen ({count})",
|
||||
"gitSidebar.versionHistory": "Versionsverlauf ({count})",
|
||||
"gitSidebar.loadingChanges": "Änderungen werden geladen...",
|
||||
"gitSidebar.noChanges": "Keine Änderungen",
|
||||
@@ -286,16 +286,16 @@
|
||||
"tabBar.scrollLeft": "Tabs nach links scrollen",
|
||||
"tabBar.scrollRight": "Tabs nach rechts scrollen",
|
||||
"tabBar.commitTitle": "Änderung {hash}",
|
||||
"tabBar.error.fetchPostTitle": "Fehler beim fetch Beitrag title:",
|
||||
"tabBar.error.fetchChatTitle": "Fehler beim fetch chat title:",
|
||||
"tabBar.error.fetchImportTitle": "Fehler beim fetch import definition title:",
|
||||
"tabBar.error.fetchCommitTitle": "Fehler beim fetch commit titles:",
|
||||
"tabBar.error.fetchPostTitle": "Beitragstitel konnte nicht geladen werden:",
|
||||
"tabBar.error.fetchChatTitle": "Chat-Titel konnte nicht geladen werden:",
|
||||
"tabBar.error.fetchImportTitle": "Titel der Importdefinition konnte nicht geladen werden:",
|
||||
"tabBar.error.fetchCommitTitle": "Commit-Titel konnten nicht geladen werden:",
|
||||
"metadataDiff.title": "Metadaten-Diff-Werkzeug",
|
||||
"metadataDiff.description": "Compare Beitrag metadata between database and markdown files. Fix inconsistencies caused by bugs or manual edits.",
|
||||
"metadataDiff.error.loadStats": "Fehler beim load database statistics",
|
||||
"metadataDiff.error.scan": "Fehler beim scan for differences",
|
||||
"metadataDiff.description": "Vergleicht Beitragsmetadaten zwischen Datenbank und Markdown-Dateien. Behebt Abweichungen durch Bugs oder manuelle Änderungen.",
|
||||
"metadataDiff.error.loadStats": "Datenbankstatistiken konnten nicht geladen werden",
|
||||
"metadataDiff.error.scan": "Unterschiede konnten nicht gescannt werden",
|
||||
"metadataDiff.progress.starting": "Scan wird gestartet...",
|
||||
"metadataDiff.progress.scanningPublished": "Scanning published Beiträge...",
|
||||
"metadataDiff.progress.scanningPublished": "Veröffentlichte Beiträge werden gescannt...",
|
||||
"metadataDiff.progress.scanning": "Scanne...",
|
||||
"metadataDiff.action.scan": "Nach Unterschieden suchen",
|
||||
"metadataDiff.action.rescan": "Erneut scannen",
|
||||
@@ -303,23 +303,23 @@
|
||||
"metadataDiff.stats.published": "Veröffentlicht",
|
||||
"metadataDiff.stats.drafts": "Entwürfe",
|
||||
"metadataDiff.stats.mediaFiles": "Mediendateien",
|
||||
"metadataDiff.summary.noDiffs": "✅ No differences found! All {total} published Beiträge are in sync.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Found {count} Beiträge with differences out of {total} published Beiträge.",
|
||||
"metadataDiff.summary.noDiffs": "✅ Keine Unterschiede gefunden! Alle {total} veröffentlichten Beiträge sind synchron.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ {count} Beiträge mit Unterschieden gefunden, von insgesamt {total} veröffentlichten Beiträgen.",
|
||||
"metadataDiff.group.differences": "{label}-Unterschiede",
|
||||
"metadataDiff.group.postsCount": "{count} Beiträge",
|
||||
"metadataDiff.sync.failed": "fehlgeschlagen",
|
||||
"metadataDiff.sync.dbToFile.title": "Dateien mit Datenbankwerten aktualisieren",
|
||||
"metadataDiff.sync.dbToFile.success": "Synced {success} Beiträge to files{fehlgeschlagen}",
|
||||
"metadataDiff.sync.dbToFile.error": "Fehler beim sync to files",
|
||||
"metadataDiff.sync.dbToFile.success": "{success} Beiträge in Dateien synchronisiert{fehlgeschlagen}",
|
||||
"metadataDiff.sync.dbToFile.error": "Synchronisierung in Dateien fehlgeschlagen",
|
||||
"metadataDiff.sync.fileToDb.title": "Datenbank mit Dateiwerten aktualisieren",
|
||||
"metadataDiff.sync.fileToDb.success": "Synced {success} files to database{fehlgeschlagen}",
|
||||
"metadataDiff.sync.fileToDb.error": "Fehler beim sync to database",
|
||||
"metadataDiff.sync.fileToDb.success": "{success} Dateien in die Datenbank synchronisiert{fehlgeschlagen}",
|
||||
"metadataDiff.sync.fileToDb.error": "Synchronisierung in die Datenbank fehlgeschlagen",
|
||||
"metadataDiff.value.database": "Datenbank",
|
||||
"metadataDiff.value.file": "Datei",
|
||||
"metadataDiff.empty": "Klicke auf „Nach Unterschieden suchen“, um Datenbank-Metadaten mit Datei-Metadaten zu vergleichen.",
|
||||
"sidebar.archive": "Archiv",
|
||||
"sidebar.clearFilter": "Filter löschen",
|
||||
"sidebar.tags": "Tags",
|
||||
"sidebar.tags": "Schlagwörter",
|
||||
"sidebar.categories": "Kategorien",
|
||||
"sidebar.clearTags": "Tags löschen",
|
||||
"sidebar.clearCategories": "Kategorien löschen",
|
||||
@@ -346,7 +346,7 @@
|
||||
"sidebar.loading": "Lädt...",
|
||||
"sidebar.noMediaFiles": "Keine Mediendateien",
|
||||
"sidebar.settingsHeader": "Einstellungen",
|
||||
"sidebar.tagsHeader": "Tags",
|
||||
"sidebar.tagsHeader": "Schlagwörter",
|
||||
"sidebar.nav.project": "Projekt",
|
||||
"sidebar.nav.editor": "Texteditor",
|
||||
"sidebar.nav.content": "Inhalt",
|
||||
@@ -390,7 +390,7 @@
|
||||
"editor.delete": "Löschen",
|
||||
"editor.deleteTitle": "Diesen Beitrag dauerhaft löschen",
|
||||
"editor.field.title": "Titel",
|
||||
"editor.field.tags": "Tags",
|
||||
"editor.field.tags": "Schlagwörter",
|
||||
"editor.field.author": "Autor",
|
||||
"editor.field.slug": "Slug",
|
||||
"editor.field.categories": "Kategorien",
|
||||
@@ -410,5 +410,131 @@
|
||||
"editor.previewLoading": "Vorschau wird geladen...",
|
||||
"editor.footer.created": "Erstellt",
|
||||
"editor.footer.updated": "Aktualisiert",
|
||||
"editor.footer.published": "Veröffentlicht"
|
||||
"editor.footer.published": "Veröffentlicht",
|
||||
"projectSelector.switchProject": "Projekt wechseln",
|
||||
"projectSelector.selectProject": "Projekt auswählen",
|
||||
"projectSelector.projectsHeader": "Projekte",
|
||||
"projectSelector.noProjectsYet": "Noch keine Projekte",
|
||||
"projectSelector.newProject": "Neues Projekt",
|
||||
"projectSelector.createNewProject": "Neues Projekt erstellen",
|
||||
"projectSelector.projectName": "Projektname",
|
||||
"projectSelector.projectNamePlaceholder": "Mein Blog",
|
||||
"projectSelector.descriptionOptional": "Beschreibung (optional)",
|
||||
"projectSelector.descriptionPlaceholder": "Eine kurze Beschreibung dieses Projekts...",
|
||||
"projectSelector.projectLocation": "Projektort",
|
||||
"projectSelector.useDefaultLocation": "Standardort verwenden",
|
||||
"projectSelector.defaultInternalStorage": "Standard (interner Speicher)",
|
||||
"projectSelector.chooseFolder": "Ordner wählen...",
|
||||
"projectSelector.projectLocationHint": "Wähle einen benutzerdefinierten Ordner für Cloud-Backups oder nutze den internen Standardordner.",
|
||||
"projectSelector.createProject": "Projekt erstellen",
|
||||
"projectSelector.deleteProject": "Projekt löschen",
|
||||
"projectSelector.deleteWarning": "Dadurch wird das Projekt \"{name}\" und alle zugehörigen Daten dauerhaft gelöscht, einschließlich:",
|
||||
"projectSelector.deleteItemPosts": "Aller Blogbeiträge",
|
||||
"projectSelector.deleteItemMedia": "Aller Mediendateien",
|
||||
"projectSelector.deleteItemSettings": "Aller Projekteinstellungen",
|
||||
"projectSelector.typeToConfirm": "Tippe {name}, um das Löschen zu bestätigen:",
|
||||
"projectSelector.selectProjectLocation": "Projektordner auswählen",
|
||||
"projectSelector.deleteProjectTitle": "{name} löschen",
|
||||
"projectSelector.toast.switched": "Zu {name} gewechselt",
|
||||
"projectSelector.toast.switchFailed": "Projektwechsel fehlgeschlagen",
|
||||
"projectSelector.toast.created": "Projekt \"{name}\" erstellt",
|
||||
"projectSelector.toast.createFailed": "Projekt konnte nicht erstellt werden",
|
||||
"projectSelector.toast.existingSettingsFound": "Vorhandene Projekteinstellungen gefunden",
|
||||
"projectSelector.toast.selectFolderFailed": "Ordnerauswahl fehlgeschlagen",
|
||||
"projectSelector.toast.deletedWithData": "Projekt \"{name}\" und alle Daten gelöscht",
|
||||
"projectSelector.toast.deleteFailed": "Projekt konnte nicht gelöscht werden",
|
||||
"tagsView.title": "Tag-Verwaltung",
|
||||
"tagsView.subtitle": "Verwalte die Tags deines Blogs, weise Farben zu und führe Sammelaktionen aus.",
|
||||
"tagsView.loadingTags": "Tags werden geladen...",
|
||||
"tagsView.noTagsFound": "Keine Tags gefunden",
|
||||
"tagsView.discoverFromPosts": "Tags aus Beiträgen erkennen",
|
||||
"tagsView.selectedCount": "{count} Tag(s) ausgewählt",
|
||||
"tagsView.clearSelection": "Auswahl aufheben",
|
||||
"tagsView.cloud.title": "Tag-Cloud",
|
||||
"tagsView.cloud.description": "Klicke auf Tags, um sie für Sammelaktionen auszuwählen. Fahre mit der Maus darüber, um Beitragszahlen zu sehen.",
|
||||
"tagsView.manage.title": "Tags erstellen & bearbeiten",
|
||||
"tagsView.manage.description": "Erstelle neue Tags oder bearbeite bestehende. Weise Farben zu, um Tags besser zu unterscheiden.",
|
||||
"tagsView.create.title": "Neuen Tag erstellen",
|
||||
"tagsView.create.action": "Erstellen",
|
||||
"tagsView.tagNamePlaceholder": "Tag-Name",
|
||||
"tagsView.chooseColor": "Farbe wählen",
|
||||
"tagsView.removeColor": "Farbe entfernen",
|
||||
"tagsView.edit.title": "Tag bearbeiten: {name}",
|
||||
"tagsView.edit.action": "Bearbeiten",
|
||||
"tagsView.deleteAction": "Löschen",
|
||||
"tagsView.merge.title": "Tags zusammenführen",
|
||||
"tagsView.merge.description": "Wähle oben mehrere Tags aus und führe sie zu einem einzigen zusammen. Alle Beiträge werden aktualisiert.",
|
||||
"tagsView.merge.selectAtLeastTwo": "Wähle mindestens 2 Tags aus der Cloud oben aus, um sie zusammenzuführen.",
|
||||
"tagsView.merge.countInto": "{count} Tags zusammenführen in:",
|
||||
"tagsView.merge.selectTarget": "Ziel-Tag auswählen...",
|
||||
"tagsView.merge.action": "Tags zusammenführen",
|
||||
"tagsView.merge.tagsToDelete": "Zu löschende Tags: {tags}",
|
||||
"tagsView.sync.title": "Tags synchronisieren",
|
||||
"tagsView.sync.description": "Erkenne Tags, die in Beiträgen vorkommen, aber nicht in der Tag-Datenbank vorhanden sind.",
|
||||
"tagsView.sync.action": "Tags aus Beiträgen synchronisieren",
|
||||
"tagsView.confirmDelete.title": "Tag löschen",
|
||||
"tagsView.confirmDelete.message": "Möchtest du den Tag \"{tagName}\" wirklich löschen? Er wird aus allen Beiträgen entfernt. Diese Aktion läuft als Hintergrundaufgabe.",
|
||||
"tagsView.confirmDelete.action": "Tag löschen",
|
||||
"tagsView.confirmMerge.title": "Tags zusammenführen",
|
||||
"tagsView.confirmMerge.message": "Möchtest du wirklich {count} Tag(s) in \"{target}\" zusammenführen? Die Quell-Tags werden gelöscht und alle Beiträge werden aktualisiert. Dies läuft als Hintergrundaufgabe.",
|
||||
"tagsView.confirmMerge.action": "Tags zusammenführen",
|
||||
"tagsView.none": "(keine)",
|
||||
"tagsView.tagCountTitle": "{count} {item}",
|
||||
"tagsView.postsSingular": "Beitrag",
|
||||
"tagsView.postsPlural": "Beiträge",
|
||||
"tagsView.toast.tagNameRequired": "Tag-Name ist erforderlich",
|
||||
"tagsView.toast.tagCreated": "Tag erstellt",
|
||||
"tagsView.toast.tagDeleted": "Tag gelöscht. {postsUpdated} Beitrag/Beiträge aktualisiert.",
|
||||
"tagsView.toast.tagUpdated": "Tag aktualisiert",
|
||||
"tagsView.toast.targetTagNotFound": "Ziel-Tag nicht gefunden",
|
||||
"tagsView.toast.noSourceTagsToMerge": "Keine Quell-Tags zum Zusammenführen",
|
||||
"tagsView.toast.tagsMerged": "{tagsDeleted} Tag(s) in \"{targetTag}\" zusammengeführt. {postsUpdated} Beitrag/Beiträge aktualisiert.",
|
||||
"tagsView.toast.discoveredTags": "{count} neue Tag(s) gefunden",
|
||||
"tagsView.toast.alreadySynced": "Alle Tags sind bereits synchronisiert",
|
||||
"tagsView.error.deleteFailedTitle": "Löschen fehlgeschlagen",
|
||||
"tagsView.error.mergeFailedTitle": "Zusammenführen fehlgeschlagen",
|
||||
"linkedMediaPanel.title": "📷 Verknüpfte Medien",
|
||||
"linkedMediaPanel.collapsedTitle": "📷 Medien ({count})",
|
||||
"linkedMediaPanel.importAndLink": "Medien importieren und verknüpfen",
|
||||
"linkedMediaPanel.linkExisting": "Vorhandene Medien verknüpfen",
|
||||
"linkedMediaPanel.selectMediaToLink": "Zu verknüpfende Medien auswählen",
|
||||
"linkedMediaPanel.searchPlaceholder": "Medien suchen...",
|
||||
"linkedMediaPanel.noUnlinkedMedia": "Keine unverknüpften Medien verfügbar",
|
||||
"linkedMediaPanel.noMediaLinked": "Keine Medien mit diesem Beitrag verknüpft",
|
||||
"linkedMediaPanel.importMedia": "Medien importieren",
|
||||
"linkedMediaPanel.unlinkFromPost": "Vom Beitrag lösen",
|
||||
"linkedMediaPanel.toast.importedLinked": "{count} Datei(en) importiert und verknüpft",
|
||||
"linkedMediaPanel.toast.importFailed": "Medienimport fehlgeschlagen",
|
||||
"linkedMediaPanel.toast.unlinked": "Medium vom Beitrag gelöst",
|
||||
"linkedMediaPanel.toast.unlinkFailed": "Lösen des Mediums fehlgeschlagen",
|
||||
"linkedMediaPanel.toast.linked": "Medium mit Beitrag verknüpft",
|
||||
"linkedMediaPanel.toast.linkFailed": "Verknüpfen des Mediums fehlgeschlagen",
|
||||
"styleView.title": "Stil",
|
||||
"styleView.subtitle": "Wähle ein Pico-CSS-Theme und sieh dir vor dem Anwenden eine Vorschau der Top-Beiträge an.",
|
||||
"styleView.themePickerAria": "Pico-Theme-Auswahl",
|
||||
"styleView.previewMode": "Vorschaumodus",
|
||||
"styleView.mode.auto": "Automatisch",
|
||||
"styleView.mode.light": "Hell",
|
||||
"styleView.mode.dark": "Dunkel",
|
||||
"styleView.applyTheme": "Theme anwenden",
|
||||
"styleView.themePreviewTitle": "Theme-Vorschau",
|
||||
"styleView.toast.appliedTheme": "Theme angewendet: {theme}",
|
||||
"styleView.toast.applyThemeFailed": "Theme konnte nicht angewendet werden",
|
||||
"panel.tabsAria": "Panel-Tabs",
|
||||
"panel.output": "Ausgabe",
|
||||
"panel.postLinks": "Beitragslinks",
|
||||
"panel.gitLog": "Git-Log",
|
||||
"panel.closeTitle": "Panel schließen",
|
||||
"panel.noRecentTasks": "Keine aktuellen Aufgaben",
|
||||
"panel.noOutput": "Keine Ausgabe",
|
||||
"panel.openPostEditor": "Öffne einen Beitragseditor, um Beitragslinks zu sehen",
|
||||
"panel.loadingPostLinks": "Beitragslinks werden geladen...",
|
||||
"panel.noPostLinks": "Keine Beitragslinks für diesen Beitrag",
|
||||
"panel.openPostOrMediaEditor": "Öffne einen Beitrags- oder Medieneditor, um das Git-Log zu sehen",
|
||||
"panel.loadingGitLog": "Git-Log wird geladen...",
|
||||
"panel.noCommits": "Keine Commits für dieses Element gefunden",
|
||||
"panel.error.loadPostLinks": "Beitragslinks konnten nicht geladen werden.",
|
||||
"panel.error.loadGitLog": "Git-Log konnte nicht geladen werden.",
|
||||
"panel.direction.from": "von",
|
||||
"panel.direction.to": "zu"
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
"gitSidebar.action.committing": "Committing...",
|
||||
"gitSidebar.action.initializeGit": "Initialize Git",
|
||||
"gitSidebar.action.initializing": "Initializing...",
|
||||
"gitSidebar.openChanges": "Open Changes ({count})",
|
||||
"gitSidebar.openChanges": "Open changes ({count})",
|
||||
"gitSidebar.versionHistory": "Version History ({count})",
|
||||
"gitSidebar.loadingChanges": "Loading changes...",
|
||||
"gitSidebar.noChanges": "No changes",
|
||||
@@ -410,5 +410,131 @@
|
||||
"editor.previewLoading": "Loading preview...",
|
||||
"editor.footer.created": "Created",
|
||||
"editor.footer.updated": "Updated",
|
||||
"editor.footer.published": "Published"
|
||||
"editor.footer.published": "Published",
|
||||
"projectSelector.switchProject": "Switch project",
|
||||
"projectSelector.selectProject": "Select project",
|
||||
"projectSelector.projectsHeader": "Projects",
|
||||
"projectSelector.noProjectsYet": "No projects yet",
|
||||
"projectSelector.newProject": "New project",
|
||||
"projectSelector.createNewProject": "Create new project",
|
||||
"projectSelector.projectName": "Project name",
|
||||
"projectSelector.projectNamePlaceholder": "My Blog",
|
||||
"projectSelector.descriptionOptional": "Description (optional)",
|
||||
"projectSelector.descriptionPlaceholder": "A brief description of this project...",
|
||||
"projectSelector.projectLocation": "Project location",
|
||||
"projectSelector.useDefaultLocation": "Use default location",
|
||||
"projectSelector.defaultInternalStorage": "Default (internal storage)",
|
||||
"projectSelector.chooseFolder": "Choose folder...",
|
||||
"projectSelector.projectLocationHint": "Choose a custom folder for cloud storage backup, or use the default internal storage.",
|
||||
"projectSelector.createProject": "Create project",
|
||||
"projectSelector.deleteProject": "Delete project",
|
||||
"projectSelector.deleteWarning": "This will permanently delete the project \"{name}\" and all its data including:",
|
||||
"projectSelector.deleteItemPosts": "All blog posts",
|
||||
"projectSelector.deleteItemMedia": "All media files",
|
||||
"projectSelector.deleteItemSettings": "All project settings",
|
||||
"projectSelector.typeToConfirm": "Type {name} to confirm deletion:",
|
||||
"projectSelector.selectProjectLocation": "Select project location",
|
||||
"projectSelector.deleteProjectTitle": "Delete {name}",
|
||||
"projectSelector.toast.switched": "Switched to {name}",
|
||||
"projectSelector.toast.switchFailed": "Failed to switch project",
|
||||
"projectSelector.toast.created": "Created project \"{name}\"",
|
||||
"projectSelector.toast.createFailed": "Failed to create project",
|
||||
"projectSelector.toast.existingSettingsFound": "Found existing project settings",
|
||||
"projectSelector.toast.selectFolderFailed": "Failed to select folder",
|
||||
"projectSelector.toast.deletedWithData": "Deleted project \"{name}\" and all its data",
|
||||
"projectSelector.toast.deleteFailed": "Failed to delete project",
|
||||
"tagsView.title": "Tag Management",
|
||||
"tagsView.subtitle": "Manage your blog's tags, assign colors, and perform bulk operations.",
|
||||
"tagsView.loadingTags": "Loading tags...",
|
||||
"tagsView.noTagsFound": "No tags found",
|
||||
"tagsView.discoverFromPosts": "Discover tags from posts",
|
||||
"tagsView.selectedCount": "{count} tag(s) selected",
|
||||
"tagsView.clearSelection": "Clear selection",
|
||||
"tagsView.cloud.title": "Tag Cloud",
|
||||
"tagsView.cloud.description": "Click tags to select them for bulk operations. Hover to see post counts.",
|
||||
"tagsView.manage.title": "Create & Edit Tags",
|
||||
"tagsView.manage.description": "Create new tags or edit existing ones. Assign colors to make tags visually distinct.",
|
||||
"tagsView.create.title": "Create New Tag",
|
||||
"tagsView.create.action": "Create",
|
||||
"tagsView.tagNamePlaceholder": "Tag name",
|
||||
"tagsView.chooseColor": "Choose color",
|
||||
"tagsView.removeColor": "Remove color",
|
||||
"tagsView.edit.title": "Edit Tag: {name}",
|
||||
"tagsView.edit.action": "Edit",
|
||||
"tagsView.deleteAction": "Delete",
|
||||
"tagsView.merge.title": "Merge Tags",
|
||||
"tagsView.merge.description": "Select multiple tags above, then merge them into a single tag. All posts will be updated.",
|
||||
"tagsView.merge.selectAtLeastTwo": "Select 2 or more tags from the cloud above to merge them.",
|
||||
"tagsView.merge.countInto": "Merge {count} tags into:",
|
||||
"tagsView.merge.selectTarget": "Select target tag...",
|
||||
"tagsView.merge.action": "Merge Tags",
|
||||
"tagsView.merge.tagsToDelete": "Tags to be deleted: {tags}",
|
||||
"tagsView.sync.title": "Sync Tags",
|
||||
"tagsView.sync.description": "Discover tags that exist in posts but not in the tag database.",
|
||||
"tagsView.sync.action": "Sync Tags from Posts",
|
||||
"tagsView.confirmDelete.title": "Delete Tag",
|
||||
"tagsView.confirmDelete.message": "Are you sure you want to delete the tag \"{tagName}\"? This will remove it from all posts. This action runs as a background task.",
|
||||
"tagsView.confirmDelete.action": "Delete Tag",
|
||||
"tagsView.confirmMerge.title": "Merge Tags",
|
||||
"tagsView.confirmMerge.message": "Are you sure you want to merge {count} tag(s) into \"{target}\"? The source tags will be deleted and all posts will be updated. This runs as a background task.",
|
||||
"tagsView.confirmMerge.action": "Merge Tags",
|
||||
"tagsView.none": "(none)",
|
||||
"tagsView.tagCountTitle": "{count} {item}",
|
||||
"tagsView.postsSingular": "post",
|
||||
"tagsView.postsPlural": "posts",
|
||||
"tagsView.toast.tagNameRequired": "Tag name is required",
|
||||
"tagsView.toast.tagCreated": "Tag created",
|
||||
"tagsView.toast.tagDeleted": "Tag deleted. {postsUpdated} post(s) updated.",
|
||||
"tagsView.toast.tagUpdated": "Tag updated",
|
||||
"tagsView.toast.targetTagNotFound": "Target tag not found",
|
||||
"tagsView.toast.noSourceTagsToMerge": "No source tags to merge",
|
||||
"tagsView.toast.tagsMerged": "Merged {tagsDeleted} tag(s) into \"{targetTag}\". {postsUpdated} post(s) updated.",
|
||||
"tagsView.toast.discoveredTags": "Discovered {count} new tag(s)",
|
||||
"tagsView.toast.alreadySynced": "All tags are already synced",
|
||||
"tagsView.error.deleteFailedTitle": "Delete Failed",
|
||||
"tagsView.error.mergeFailedTitle": "Merge Failed",
|
||||
"linkedMediaPanel.title": "📷 Linked Media",
|
||||
"linkedMediaPanel.collapsedTitle": "📷 Media ({count})",
|
||||
"linkedMediaPanel.importAndLink": "Import and link media",
|
||||
"linkedMediaPanel.linkExisting": "Link existing media",
|
||||
"linkedMediaPanel.selectMediaToLink": "Select media to link",
|
||||
"linkedMediaPanel.searchPlaceholder": "Search media...",
|
||||
"linkedMediaPanel.noUnlinkedMedia": "No unlinked media available",
|
||||
"linkedMediaPanel.noMediaLinked": "No media linked to this post",
|
||||
"linkedMediaPanel.importMedia": "Import Media",
|
||||
"linkedMediaPanel.unlinkFromPost": "Unlink from post",
|
||||
"linkedMediaPanel.toast.importedLinked": "Imported and linked {count} file(s)",
|
||||
"linkedMediaPanel.toast.importFailed": "Failed to import media",
|
||||
"linkedMediaPanel.toast.unlinked": "Media unlinked from post",
|
||||
"linkedMediaPanel.toast.unlinkFailed": "Failed to unlink media",
|
||||
"linkedMediaPanel.toast.linked": "Media linked to post",
|
||||
"linkedMediaPanel.toast.linkFailed": "Failed to link media",
|
||||
"styleView.title": "Style",
|
||||
"styleView.subtitle": "Select a Pico CSS theme and preview the top posts before applying.",
|
||||
"styleView.themePickerAria": "Pico theme picker",
|
||||
"styleView.previewMode": "Preview mode",
|
||||
"styleView.mode.auto": "Auto",
|
||||
"styleView.mode.light": "Light",
|
||||
"styleView.mode.dark": "Dark",
|
||||
"styleView.applyTheme": "Apply Theme",
|
||||
"styleView.themePreviewTitle": "Theme preview",
|
||||
"styleView.toast.appliedTheme": "Applied theme: {theme}",
|
||||
"styleView.toast.applyThemeFailed": "Failed to apply theme",
|
||||
"panel.tabsAria": "Panel tabs",
|
||||
"panel.output": "Output",
|
||||
"panel.postLinks": "Post Links",
|
||||
"panel.gitLog": "Git Log",
|
||||
"panel.closeTitle": "Close panel",
|
||||
"panel.noRecentTasks": "No recent tasks",
|
||||
"panel.noOutput": "No output",
|
||||
"panel.openPostEditor": "Open a post editor to view post links",
|
||||
"panel.loadingPostLinks": "Loading post links...",
|
||||
"panel.noPostLinks": "No post links for this post",
|
||||
"panel.openPostOrMediaEditor": "Open a post or media editor to view git log",
|
||||
"panel.loadingGitLog": "Loading git log...",
|
||||
"panel.noCommits": "No commits found for this item",
|
||||
"panel.error.loadPostLinks": "Failed to load post links.",
|
||||
"panel.error.loadGitLog": "Failed to load git log.",
|
||||
"panel.direction.from": "from",
|
||||
"panel.direction.to": "to"
|
||||
}
|
||||
|
||||
@@ -69,46 +69,46 @@
|
||||
"settings.data.title": "Mantenimiento de base de datos",
|
||||
"settings.data.fileSystemTitle": "Sistema de archivos",
|
||||
"settings.search.placeholder": "Buscar configuración...",
|
||||
"settings.search.noResults": "No configuración found matching \"{query}\"",
|
||||
"settings.search.noResults": "No se encontró configuración que coincida con \"{query}\"",
|
||||
"settings.search.clear": "Limpiar búsqueda",
|
||||
"settings.toast.publishingSaved": "Credenciales de publicación guardadas",
|
||||
"settings.toast.saveCredentialsFailed": "No se pudo save credentials",
|
||||
"settings.toast.saveCredentialsFailed": "No se pudieron guardar las credenciales",
|
||||
"settings.toast.credentialsCleared": "Credenciales de {type} borradas",
|
||||
"settings.toast.projectSaved": "Project configuración saved",
|
||||
"settings.toast.projectSaveFailed": "No se pudo save project configuración",
|
||||
"settings.toast.projectSaved": "Configuración del proyecto guardada",
|
||||
"settings.toast.projectSaveFailed": "No se pudo guardar la configuración del proyecto",
|
||||
"settings.toast.categoryAdded": "Categoría \"{category}\" agregada",
|
||||
"settings.toast.categoryAddFailed": "No se pudo add category",
|
||||
"settings.toast.categoryAddFailed": "No se pudo agregar la categoría",
|
||||
"settings.toast.categoryExists": "La categoría ya existe",
|
||||
"settings.toast.categoryProtected": "No se puede eliminar la categoría estándar \"{category}\"",
|
||||
"settings.toast.categoryAtLeastOne": "Debe haber al menos una categoría",
|
||||
"settings.toast.categoryRemoved": "Categoría \"{category}\" eliminada",
|
||||
"settings.toast.categoryRemoveFailed": "No se pudo remove category",
|
||||
"settings.toast.categoryRemoveFailed": "No se pudo eliminar la categoría",
|
||||
"settings.toast.categoriesReset": "Categorías restablecidas a los valores predeterminados",
|
||||
"settings.toast.categoriesResetFailed": "No se pudo reset categories",
|
||||
"settings.toast.categorySettingsUpdateFailed": "No se pudo update category configuración",
|
||||
"settings.toast.categoriesResetFailed": "No se pudieron restablecer las categorías",
|
||||
"settings.toast.categorySettingsUpdateFailed": "No se pudo actualizar la configuración de categorías",
|
||||
"settings.toast.systemPromptSaved": "Prompt del sistema guardado",
|
||||
"settings.toast.systemPromptSaveFailed": "No se pudo save system prompt",
|
||||
"settings.toast.systemPromptSaveFailed": "No se pudo guardar el prompt del sistema",
|
||||
"settings.toast.systemPromptReset": "Prompt del sistema restablecido al predeterminado",
|
||||
"settings.toast.systemPromptResetFailed": "No se pudo reset system prompt",
|
||||
"settings.toast.systemPromptResetFailed": "No se pudo restablecer el prompt del sistema",
|
||||
"settings.toast.apiKeySaved": "Clave API guardada y validada",
|
||||
"settings.toast.apiKeyInvalid": "Clave API no válida",
|
||||
"settings.toast.apiKeySaveFailed": "No se pudo save API key",
|
||||
"settings.toast.apiKeySaveFailed": "No se pudo guardar la clave API",
|
||||
"settings.toast.defaultModelUpdated": "Modelo predeterminado actualizado",
|
||||
"settings.toast.defaultModelUpdateFailed": "No se pudo set default model",
|
||||
"settings.toast.rebuildPostsLoading": "Rebuilding entradas database...",
|
||||
"settings.toast.defaultModelUpdateFailed": "No se pudo establecer el modelo predeterminado",
|
||||
"settings.toast.rebuildPostsLoading": "Reconstruyendo base de datos de entradas...",
|
||||
"settings.toast.rebuildPostsSuccess": "Base de datos de publicaciones reconstruida",
|
||||
"settings.toast.rebuildPostsFailed": "No se pudo rebuild entradas database",
|
||||
"settings.toast.rebuildMediaLoading": "Rebuilding medios database...",
|
||||
"settings.toast.rebuildPostsFailed": "No se pudo reconstruir la base de datos de entradas",
|
||||
"settings.toast.rebuildMediaLoading": "Reconstruyendo base de datos de medios...",
|
||||
"settings.toast.rebuildMediaSuccess": "Base de datos de medios reconstruida",
|
||||
"settings.toast.rebuildMediaFailed": "No se pudo rebuild medios database",
|
||||
"settings.toast.rebuildLinksLoading": "Rebuilding entrada links...",
|
||||
"settings.toast.rebuildMediaFailed": "No se pudo reconstruir la base de datos de medios",
|
||||
"settings.toast.rebuildLinksLoading": "Reconstruyendo enlaces de entradas...",
|
||||
"settings.toast.rebuildLinksSuccess": "Enlaces de publicaciones reconstruidos",
|
||||
"settings.toast.rebuildLinksFailed": "No se pudo rebuild entrada links",
|
||||
"settings.toast.rebuildLinksFailed": "No se pudieron reconstruir los enlaces de entradas",
|
||||
"settings.toast.thumbnailsLoading": "Generando miniaturas...",
|
||||
"settings.toast.thumbnailsGenerated": "Se generaron {count} miniaturas",
|
||||
"settings.toast.thumbnailsAlreadyExist": "Todas las miniaturas ya existen",
|
||||
"settings.toast.thumbnailsComplete": "Generación de miniaturas completa",
|
||||
"settings.toast.thumbnailsFailed": "No se pudo generate thumbnails",
|
||||
"settings.toast.thumbnailsFailed": "No se pudieron generar miniaturas",
|
||||
"chat.setupTitle": "Configuración de chat IA",
|
||||
"chat.apiKeyRequiredTitle": "Se requiere clave API de OpenCode Zen",
|
||||
"chat.apiKeyRequiredDescription": "Introduce tu clave API de OpenCode para habilitar el chat de IA.",
|
||||
@@ -116,23 +116,23 @@
|
||||
"chat.apiKeySave": "Guardar clave",
|
||||
"chat.apiKeyValidating": "Validando...",
|
||||
"chat.apiKeyInvalid": "Clave API no válida. Compruébala e inténtalo de nuevo.",
|
||||
"chat.apiKeyValidationFailed": "No se pudo validate API key.",
|
||||
"chat.apiKeyValidationFailed": "No se pudo validar la clave API.",
|
||||
"chat.newChat": "Nuevo chat",
|
||||
"chat.welcomeTitle": "Bienvenido al asistente de IA",
|
||||
"chat.welcomeDescription": "I can help you manage your entradas and medios. Try asking me to:",
|
||||
"chat.welcomeTipSearch": "Buscar for entradas about a specific topic",
|
||||
"chat.welcomeTipDetails": "Get details about a specific entrada",
|
||||
"chat.welcomeDescription": "Puedo ayudarte a gestionar tus entradas y medios. Prueba a pedirme que:",
|
||||
"chat.welcomeTipSearch": "Busque entradas sobre un tema específico",
|
||||
"chat.welcomeTipDetails": "Muestre detalles de una entrada específica",
|
||||
"chat.welcomeTipTags": "Lista todas las etiquetas o categorías de tu blog",
|
||||
"chat.welcomeTipMetadata": "Update metadata for entradas or medios",
|
||||
"chat.welcomeTipImages": "List all images in your medios library",
|
||||
"chat.welcomeTipMetadata": "Actualice metadatos de entradas o medios",
|
||||
"chat.welcomeTipImages": "Liste todas las imágenes de tu biblioteca de medios",
|
||||
"chat.role.you": "Tú",
|
||||
"chat.role.assistant": "Asistente",
|
||||
"chat.stop": "Detener",
|
||||
"chat.inputPlaceholder": "Escribe un mensaje...",
|
||||
"chat.errorPrefix": "Error del sistema: {error}",
|
||||
"chat.errorNoResponse": "No se pudo get a response. Please try again.",
|
||||
"chat.errorNoResponse": "No se pudo obtener una respuesta. Inténtalo de nuevo.",
|
||||
"chat.errorEmptyResponse": "El modelo devolvió una respuesta vacía. Prueba otro modelo o reformula tu pregunta.",
|
||||
"chat.errorGeneric": "Sorry, an error occurred while processing your mensaje.",
|
||||
"chat.errorGeneric": "Lo siento, ocurrió un error al procesar tu mensaje.",
|
||||
"chat.cancelledSuffix": "(cancelado)",
|
||||
"aiSuggestions.title": "Análisis de imagen IA",
|
||||
"aiSuggestions.close": "Cerrar",
|
||||
@@ -152,8 +152,8 @@
|
||||
"insert.tab.imageInternal": "Biblioteca multimedia",
|
||||
"insert.tab.linkExternal": "URL externa",
|
||||
"insert.tab.imageExternal": "Imagen externa",
|
||||
"insert.searchPlaceholder.link": "Buscar entradas by title or content...",
|
||||
"insert.searchPlaceholder.image": "Buscar medios by name, title, or alt text...",
|
||||
"insert.searchPlaceholder.link": "Buscar entradas por título o contenido...",
|
||||
"insert.searchPlaceholder.image": "Buscar medios por nombre, título o texto alternativo...",
|
||||
"insert.status.searching": "Buscando...",
|
||||
"insert.status.typeMore": "Escribe al menos 2 caracteres para buscar",
|
||||
"insert.status.noResults": "No se encontró {kind} para \"{query}\"",
|
||||
@@ -169,7 +169,7 @@
|
||||
"insert.hint.internal": "Usa ↑↓ para navegar, Enter para seleccionar, Esc para cerrar",
|
||||
"insert.hint.external": "Introduce la URL y pulsa Enter o haz clic en el botón, Esc para cerrar",
|
||||
"insert.hint.canonicalPost": "Canónico: /YYYY/MM/DD/slug",
|
||||
"insert.hint.canonicalMedia": "Canonical: /medios/YYYY/MM/file.ext",
|
||||
"insert.hint.canonicalMedia": "Canónico: /media/YYYY/MM/archivo.ext",
|
||||
"postLinks.loading": "Cargando enlaces...",
|
||||
"postLinks.link": "enlace",
|
||||
"postLinks.links": "enlaces",
|
||||
@@ -181,7 +181,7 @@
|
||||
"gitDiff.header": "Diferencia: {target}",
|
||||
"gitDiff.noProject": "No hay un proyecto activo seleccionado.",
|
||||
"gitDiff.noProjectPath": "No se pudo resolver la ruta del proyecto.",
|
||||
"gitDiff.loadFailed": "No se pudo load diff.",
|
||||
"gitDiff.loadFailed": "No se pudo cargar el diff.",
|
||||
"gitDiff.loading": "Cargando diff...",
|
||||
"gitDiff.changedFiles": "Archivos modificados",
|
||||
"gitDiff.previousFile": "Archivo anterior",
|
||||
@@ -192,8 +192,8 @@
|
||||
"errorModal.copy": "Copiar",
|
||||
"errorModal.noStack": "No hay traza de pila disponible",
|
||||
"confirmDelete.title": "Confirmar eliminación",
|
||||
"confirmDelete.promptPost": "Are you sure you want to delete the entrada",
|
||||
"confirmDelete.promptMedia": "Are you sure you want to delete the medios file",
|
||||
"confirmDelete.promptPost": "¿Seguro que quieres eliminar la entrada",
|
||||
"confirmDelete.promptMedia": "¿Seguro que quieres eliminar el archivo multimedia",
|
||||
"confirmDelete.warning": "Advertencia:",
|
||||
"confirmDelete.referencedBy": "Este {itemType} está referenciado por los siguientes elementos:",
|
||||
"confirmDelete.note": "Eliminar este {itemType} quitará todas estas referencias.",
|
||||
@@ -205,12 +205,12 @@
|
||||
"lightbox.close": "Cerrar (Esc)",
|
||||
"lightbox.previous": "Anterior (←)",
|
||||
"lightbox.next": "Siguiente (→)",
|
||||
"credentials.error.load": "No se pudo load credentials:",
|
||||
"credentials.error.save": "No se pudo save credentials:",
|
||||
"credentials.error.load": "No se pudieron cargar las credenciales:",
|
||||
"credentials.error.save": "No se pudieron guardar las credenciales:",
|
||||
"credentials.toast.saved": "Credenciales guardadas",
|
||||
"credentials.toast.saveFailed": "No se pudo save credentials",
|
||||
"credentials.toast.saveFailed": "No se pudieron guardar las credenciales",
|
||||
"credentials.toast.testing": "Probando conexión {type}...",
|
||||
"credentials.toast.connectionFailed": "Connection falló - check credentials",
|
||||
"credentials.toast.connectionFailed": "La conexión falló - revisa las credenciales",
|
||||
"credentials.tab.ftp": "Acceso FTP",
|
||||
"credentials.tab.ssh": "Acceso SSH",
|
||||
"credentials.ftp.title": "Publicación FTP",
|
||||
@@ -230,14 +230,14 @@
|
||||
"credentials.ssh.placeholder.keyPath": "~/.ssh/clave_id_rsa",
|
||||
"gitSidebar.header": "CONTROL DE CÓDIGO FUENTE",
|
||||
"gitSidebar.loading": "Cargando...",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "No se pudo fetch remote updates.",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "No se pudieron obtener las actualizaciones remotas.",
|
||||
"gitSidebar.error.refreshRemoteState": "No se pudo actualizar el estado de seguimiento remoto.",
|
||||
"gitSidebar.error.gitMissing": "No se encontró el ejecutable de Git. Instala Git y reinicia la aplicación.",
|
||||
"gitSidebar.error.noActiveProject": "No hay un proyecto activo seleccionado.",
|
||||
"gitSidebar.error.loadRepoStatus": "No se pudo cargar el estado del repositorio.",
|
||||
"gitSidebar.error.initFailed": "No se pudo initialize git repository.",
|
||||
"gitSidebar.error.initFailed": "No se pudo inicializar el repositorio Git.",
|
||||
"gitSidebar.error.actionFailed": "No se pudo {action}.",
|
||||
"gitSidebar.error.commitFailed": "No se pudo commit changes.",
|
||||
"gitSidebar.error.commitFailed": "No se pudieron confirmar los cambios.",
|
||||
"gitSidebar.progress.preparingInit": "Preparando inicialización del repositorio...",
|
||||
"gitSidebar.progress.pushingRemote": "Enviando commits al remoto... esto puede tardar con cargas grandes.",
|
||||
"gitSidebar.progress.fetching": "Obteniendo actualizaciones remotas...",
|
||||
@@ -265,7 +265,7 @@
|
||||
"gitSidebar.action.committing": "Haciendo commit...",
|
||||
"gitSidebar.action.initializeGit": "Inicializar Git",
|
||||
"gitSidebar.action.initializing": "Inicializando...",
|
||||
"gitSidebar.openChanges": "Abrir Changes ({count})",
|
||||
"gitSidebar.openChanges": "Cambios abiertos ({count})",
|
||||
"gitSidebar.versionHistory": "Historial de versiones ({count})",
|
||||
"gitSidebar.loadingChanges": "Cargando cambios...",
|
||||
"gitSidebar.noChanges": "Sin cambios",
|
||||
@@ -286,16 +286,16 @@
|
||||
"tabBar.scrollLeft": "Desplazar pestañas a la izquierda",
|
||||
"tabBar.scrollRight": "Desplazar pestañas a la derecha",
|
||||
"tabBar.commitTitle": "Confirmación {hash}",
|
||||
"tabBar.error.fetchPostTitle": "No se pudo fetch entrada title:",
|
||||
"tabBar.error.fetchChatTitle": "No se pudo fetch chat title:",
|
||||
"tabBar.error.fetchImportTitle": "No se pudo fetch import definition title:",
|
||||
"tabBar.error.fetchCommitTitle": "No se pudo fetch commit titles:",
|
||||
"tabBar.error.fetchPostTitle": "No se pudo cargar el título de la entrada:",
|
||||
"tabBar.error.fetchChatTitle": "No se pudo cargar el título del chat:",
|
||||
"tabBar.error.fetchImportTitle": "No se pudo cargar el título de la definición de importación:",
|
||||
"tabBar.error.fetchCommitTitle": "No se pudieron cargar los títulos de los commits:",
|
||||
"metadataDiff.title": "Herramienta diff de metadatos",
|
||||
"metadataDiff.description": "Compare entrada metadata between database and markdown files. Fix inconsistencies caused by bugs or manual edits.",
|
||||
"metadataDiff.error.loadStats": "No se pudo load database statistics",
|
||||
"metadataDiff.error.scan": "No se pudo scan for differences",
|
||||
"metadataDiff.description": "Compara los metadatos de las entradas entre la base de datos y los archivos Markdown. Corrige inconsistencias causadas por errores o ediciones manuales.",
|
||||
"metadataDiff.error.loadStats": "No se pudieron cargar las estadísticas de la base de datos",
|
||||
"metadataDiff.error.scan": "No se pudieron analizar las diferencias",
|
||||
"metadataDiff.progress.starting": "Iniciando escaneo...",
|
||||
"metadataDiff.progress.scanningPublished": "Scanning published entradas...",
|
||||
"metadataDiff.progress.scanningPublished": "Escaneando entradas publicadas...",
|
||||
"metadataDiff.progress.scanning": "Escaneando...",
|
||||
"metadataDiff.action.scan": "Buscar diferencias",
|
||||
"metadataDiff.action.rescan": "Volver a escanear",
|
||||
@@ -303,112 +303,238 @@
|
||||
"metadataDiff.stats.published": "Publicadas",
|
||||
"metadataDiff.stats.drafts": "Borradores",
|
||||
"metadataDiff.stats.mediaFiles": "Archivos multimedia",
|
||||
"metadataDiff.summary.noDiffs": "✅ No differences found! All {total} published entradas are in sync.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Found {count} entradas with differences out of {total} published entradas.",
|
||||
"metadataDiff.summary.noDiffs": "✅ ¡No se encontraron diferencias! Todas las {total} entradas publicadas están sincronizadas.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Se encontraron {count} entradas con diferencias de un total de {total} entradas publicadas.",
|
||||
"metadataDiff.group.differences": "Diferencias de {label}",
|
||||
"metadataDiff.group.postsCount": "{count} entradas",
|
||||
"metadataDiff.sync.failed": "falló",
|
||||
"metadataDiff.sync.dbToFile.title": "Actualizar archivos con valores de la base de datos",
|
||||
"metadataDiff.sync.dbToFile.success": "Synced {success} entradas to files{falló}",
|
||||
"metadataDiff.sync.dbToFile.error": "No se pudo sync to files",
|
||||
"metadataDiff.sync.dbToFile.success": "Se sincronizaron {success} entradas a archivos{falló}",
|
||||
"metadataDiff.sync.dbToFile.error": "No se pudo sincronizar a archivos",
|
||||
"metadataDiff.sync.fileToDb.title": "Actualizar base de datos con valores de archivos",
|
||||
"metadataDiff.sync.fileToDb.success": "Synced {success} files to database{falló}",
|
||||
"metadataDiff.sync.fileToDb.error": "No se pudo sync to database",
|
||||
"metadataDiff.sync.fileToDb.success": "Se sincronizaron {success} archivos a la base de datos{falló}",
|
||||
"metadataDiff.sync.fileToDb.error": "No se pudo sincronizar a la base de datos",
|
||||
"metadataDiff.value.database": "Base de datos",
|
||||
"metadataDiff.value.file": "Archivo",
|
||||
"metadataDiff.empty": "Haz clic en \"Buscar diferencias\" para comparar metadatos de base de datos con metadatos de archivos.",
|
||||
"sidebar.archive": "Archive",
|
||||
"sidebar.clearFilter": "Clear filter",
|
||||
"sidebar.tags": "Tags",
|
||||
"sidebar.categories": "Categories",
|
||||
"sidebar.clearTags": "Clear tags",
|
||||
"sidebar.clearCategories": "Clear categories",
|
||||
"sidebar.noPostsYet": "No posts yet",
|
||||
"sidebar.noPagesYet": "No pages yet",
|
||||
"sidebar.noMediaYet": "No media yet",
|
||||
"sidebar.search": "Search",
|
||||
"sidebar.searchPostsPlaceholder": "Search posts...",
|
||||
"sidebar.searchPagesPlaceholder": "Search pages...",
|
||||
"sidebar.searchMediaPlaceholder": "Search media...",
|
||||
"sidebar.toggleFilters": "Toggle Filters",
|
||||
"sidebar.newPost": "New Post",
|
||||
"sidebar.importMedia": "Import media",
|
||||
"sidebar.results": "{count} results",
|
||||
"sidebar.resultsFor": "{count} results for \"{query}\"",
|
||||
"sidebar.clearFilters": "Clear filters",
|
||||
"sidebar.drafts": "Drafts",
|
||||
"sidebar.published": "Published",
|
||||
"sidebar.archived": "Archived",
|
||||
"sidebar.untitled": "Untitled",
|
||||
"sidebar.noMatchingPosts": "No matching posts",
|
||||
"sidebar.createFirstPost": "Create your first post",
|
||||
"sidebar.loadMore": "Load more ({loaded} of {total})",
|
||||
"sidebar.loading": "Loading...",
|
||||
"sidebar.noMediaFiles": "No media files",
|
||||
"sidebar.settingsHeader": "Settings",
|
||||
"sidebar.tagsHeader": "Tags",
|
||||
"sidebar.nav.project": "Project",
|
||||
"sidebar.archive": "Archivo",
|
||||
"sidebar.clearFilter": "Limpiar filtro",
|
||||
"sidebar.tags": "Etiquetas",
|
||||
"sidebar.categories": "Categorías",
|
||||
"sidebar.clearTags": "Limpiar etiquetas",
|
||||
"sidebar.clearCategories": "Limpiar categorías",
|
||||
"sidebar.noPostsYet": "Aún no hay entradas",
|
||||
"sidebar.noPagesYet": "Aún no hay páginas",
|
||||
"sidebar.noMediaYet": "Aún no hay medios",
|
||||
"sidebar.search": "Buscar",
|
||||
"sidebar.searchPostsPlaceholder": "Buscar entradas...",
|
||||
"sidebar.searchPagesPlaceholder": "Buscar páginas...",
|
||||
"sidebar.searchMediaPlaceholder": "Buscar medios...",
|
||||
"sidebar.toggleFilters": "Alternar filtros",
|
||||
"sidebar.newPost": "Nueva entrada",
|
||||
"sidebar.importMedia": "Importar medios",
|
||||
"sidebar.results": "{count} resultados",
|
||||
"sidebar.resultsFor": "{count} resultados para \"{query}\"",
|
||||
"sidebar.clearFilters": "Limpiar filtros",
|
||||
"sidebar.drafts": "Borradores",
|
||||
"sidebar.published": "Publicadas",
|
||||
"sidebar.archived": "Archivadas",
|
||||
"sidebar.untitled": "Sin título",
|
||||
"sidebar.noMatchingPosts": "No hay entradas coincidentes",
|
||||
"sidebar.createFirstPost": "Crea tu primera entrada",
|
||||
"sidebar.loadMore": "Cargar más ({loaded} de {total})",
|
||||
"sidebar.loading": "Cargando...",
|
||||
"sidebar.noMediaFiles": "No hay archivos multimedia",
|
||||
"sidebar.settingsHeader": "Configuración",
|
||||
"sidebar.tagsHeader": "Etiquetas",
|
||||
"sidebar.nav.project": "Proyecto",
|
||||
"sidebar.nav.editor": "Editor",
|
||||
"sidebar.nav.content": "Content",
|
||||
"sidebar.nav.ai": "AI Assistant",
|
||||
"sidebar.nav.publishing": "Publishing",
|
||||
"sidebar.nav.data": "Data",
|
||||
"sidebar.nav.style": "Style",
|
||||
"sidebar.tagCloud": "Tag Cloud",
|
||||
"sidebar.createEdit": "Create & Edit",
|
||||
"sidebar.mergeTags": "Merge Tags",
|
||||
"settings.project.descriptionGeneral": "General settings for the active blog project.",
|
||||
"settings.project.nameLabel": "Project Name",
|
||||
"settings.project.nameDescription": "The display name of your blog project.",
|
||||
"settings.project.namePlaceholder": "My Blog",
|
||||
"settings.project.descriptionLabel": "Description",
|
||||
"settings.project.descriptionDescription": "A short description of your blog. This can be used in templates and metadata.",
|
||||
"settings.project.descriptionPlaceholder": "A blog about...",
|
||||
"settings.project.dataPathLabel": "Project Data Path",
|
||||
"settings.project.dataPathDescription": "Custom folder for storing posts, media, and metadata. Leave empty to use the default location: {path}",
|
||||
"settings.project.defaultLocation": "Default location",
|
||||
"settings.project.publicUrlLabel": "Public URL",
|
||||
"settings.project.publicUrlDescription": "The public base URL of your published blog (used for sitemap generation).",
|
||||
"sidebar.nav.content": "Contenido",
|
||||
"sidebar.nav.ai": "Asistente IA",
|
||||
"sidebar.nav.publishing": "Publicación",
|
||||
"sidebar.nav.data": "Datos",
|
||||
"sidebar.nav.style": "Estilo",
|
||||
"sidebar.tagCloud": "Nube de etiquetas",
|
||||
"sidebar.createEdit": "Crear y editar",
|
||||
"sidebar.mergeTags": "Combinar etiquetas",
|
||||
"settings.project.descriptionGeneral": "Configuración general del proyecto de blog activo.",
|
||||
"settings.project.nameLabel": "Nombre del proyecto",
|
||||
"settings.project.nameDescription": "Nombre visible de tu proyecto de blog.",
|
||||
"settings.project.namePlaceholder": "Mi blog",
|
||||
"settings.project.descriptionLabel": "Descripción",
|
||||
"settings.project.descriptionDescription": "Descripción breve de tu blog. Puede usarse en plantillas y metadatos.",
|
||||
"settings.project.descriptionPlaceholder": "Un blog sobre...",
|
||||
"settings.project.dataPathLabel": "Ruta de datos del proyecto",
|
||||
"settings.project.dataPathDescription": "Carpeta personalizada para guardar entradas, medios y metadatos. Déjala vacía para usar la ubicación predeterminada: {path}",
|
||||
"settings.project.defaultLocation": "Ubicación predeterminada",
|
||||
"settings.project.publicUrlLabel": "URL pública",
|
||||
"settings.project.publicUrlDescription": "URL base pública de tu blog publicado (se usa para generar el sitemap).",
|
||||
"settings.project.publicUrlPlaceholder": "https://example.com",
|
||||
"settings.project.mainLanguageLabel": "Main Language",
|
||||
"settings.project.mainLanguageDescription": "The primary language for your blog content. AI-generated titles, alt text, and captions will use this language.",
|
||||
"settings.project.defaultAuthorLabel": "Default Author",
|
||||
"settings.project.defaultAuthorDescription": "The default author name for new posts and media. Can be overridden per item.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Author Name",
|
||||
"settings.project.maxPostsPerPageLabel": "Max Posts Per Page",
|
||||
"settings.project.maxPostsPerPageDescription": "Maximum number of posts shown per preview route page.",
|
||||
"settings.project.saveButton": "Save Project Settings",
|
||||
"editor.loadingPost": "Loading post...",
|
||||
"editor.unsavedChanges": "Unsaved changes (auto-saves on switch)",
|
||||
"editor.saving": "Saving...",
|
||||
"editor.publish": "Publish",
|
||||
"editor.publishTitle": "Save and make this post public",
|
||||
"editor.discardChanges": "Discard Changes",
|
||||
"editor.discardDraft": "Discard Draft",
|
||||
"editor.discardChangesTitle": "Revert to last published version",
|
||||
"editor.discardDraftTitle": "Delete this draft permanently",
|
||||
"editor.delete": "Delete",
|
||||
"editor.deleteTitle": "Delete this post permanently",
|
||||
"editor.field.title": "Title",
|
||||
"editor.field.tags": "Tags",
|
||||
"editor.field.author": "Author",
|
||||
"settings.project.mainLanguageLabel": "Idioma principal",
|
||||
"settings.project.mainLanguageDescription": "Idioma principal del contenido del blog. Los títulos, textos alternativos y pies generados por IA usarán este idioma.",
|
||||
"settings.project.defaultAuthorLabel": "Autor predeterminado",
|
||||
"settings.project.defaultAuthorDescription": "Nombre de autor predeterminado para nuevas entradas y medios. Se puede reemplazar por elemento.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Nombre del autor",
|
||||
"settings.project.maxPostsPerPageLabel": "Máx. entradas por página",
|
||||
"settings.project.maxPostsPerPageDescription": "Número máximo de entradas mostradas por página de ruta de vista previa.",
|
||||
"settings.project.saveButton": "Guardar configuración del proyecto",
|
||||
"editor.loadingPost": "Cargando entrada...",
|
||||
"editor.unsavedChanges": "Cambios sin guardar (se guarda automáticamente al cambiar)",
|
||||
"editor.saving": "Guardando...",
|
||||
"editor.publish": "Publicar",
|
||||
"editor.publishTitle": "Guardar y hacer pública esta entrada",
|
||||
"editor.discardChanges": "Descartar cambios",
|
||||
"editor.discardDraft": "Descartar borrador",
|
||||
"editor.discardChangesTitle": "Volver a la última versión publicada",
|
||||
"editor.discardDraftTitle": "Eliminar este borrador de forma permanente",
|
||||
"editor.delete": "Eliminar",
|
||||
"editor.deleteTitle": "Eliminar esta entrada de forma permanente",
|
||||
"editor.field.title": "Título",
|
||||
"editor.field.tags": "Etiquetas",
|
||||
"editor.field.author": "Autor",
|
||||
"editor.field.slug": "Slug",
|
||||
"editor.field.categories": "Categories",
|
||||
"editor.field.content": "Content",
|
||||
"editor.placeholder.tags": "Add tags...",
|
||||
"editor.placeholder.author": "Author name",
|
||||
"editor.placeholder.categories": "Add categories...",
|
||||
"editor.placeholder.startWriting": "Start writing...",
|
||||
"editor.field.categories": "Categorías",
|
||||
"editor.field.content": "Contenido",
|
||||
"editor.placeholder.tags": "Agregar etiquetas...",
|
||||
"editor.placeholder.author": "Nombre del autor",
|
||||
"editor.placeholder.categories": "Agregar categorías...",
|
||||
"editor.placeholder.startWriting": "Empieza a escribir...",
|
||||
"editor.mode.visual": "Visual",
|
||||
"editor.mode.visualTitle": "Visual editor",
|
||||
"editor.mode.markdownTitle": "Markdown source",
|
||||
"editor.mode.previewTitle": "Read-only preview",
|
||||
"editor.galleryTitle": "View {count} image(s)",
|
||||
"editor.insertPostLinkTitle": "Link to post (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Insert image from media library",
|
||||
"editor.previewFrameTitle": "Post preview",
|
||||
"editor.previewLoading": "Loading preview...",
|
||||
"editor.footer.created": "Created",
|
||||
"editor.footer.updated": "Updated",
|
||||
"editor.footer.published": "Published"
|
||||
"editor.mode.visualTitle": "Editor visual",
|
||||
"editor.mode.markdownTitle": "Código Markdown",
|
||||
"editor.mode.previewTitle": "Vista previa de solo lectura",
|
||||
"editor.galleryTitle": "Ver {count} imagen(es)",
|
||||
"editor.insertPostLinkTitle": "Enlazar entrada (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Insertar imagen desde la biblioteca multimedia",
|
||||
"editor.previewFrameTitle": "Vista previa de la entrada",
|
||||
"editor.previewLoading": "Cargando vista previa...",
|
||||
"editor.footer.created": "Creado",
|
||||
"editor.footer.updated": "Actualizado",
|
||||
"editor.footer.published": "Publicado",
|
||||
"projectSelector.switchProject": "Cambiar proyecto",
|
||||
"projectSelector.selectProject": "Seleccionar proyecto",
|
||||
"projectSelector.projectsHeader": "Proyectos",
|
||||
"projectSelector.noProjectsYet": "Aún no hay proyectos",
|
||||
"projectSelector.newProject": "Nuevo proyecto",
|
||||
"projectSelector.createNewProject": "Crear nuevo proyecto",
|
||||
"projectSelector.projectName": "Nombre del proyecto",
|
||||
"projectSelector.projectNamePlaceholder": "Mi blog",
|
||||
"projectSelector.descriptionOptional": "Descripción (opcional)",
|
||||
"projectSelector.descriptionPlaceholder": "Breve descripción de este proyecto...",
|
||||
"projectSelector.projectLocation": "Ubicación del proyecto",
|
||||
"projectSelector.useDefaultLocation": "Usar ubicación predeterminada",
|
||||
"projectSelector.defaultInternalStorage": "Predeterminado (almacenamiento interno)",
|
||||
"projectSelector.chooseFolder": "Elegir carpeta...",
|
||||
"projectSelector.projectLocationHint": "Elige una carpeta personalizada para copia de seguridad en la nube o usa el almacenamiento interno predeterminado.",
|
||||
"projectSelector.createProject": "Crear proyecto",
|
||||
"projectSelector.deleteProject": "Eliminar proyecto",
|
||||
"projectSelector.deleteWarning": "Esto eliminará permanentemente el proyecto \"{name}\" y todos sus datos, incluyendo:",
|
||||
"projectSelector.deleteItemPosts": "Todas las entradas del blog",
|
||||
"projectSelector.deleteItemMedia": "Todos los archivos multimedia",
|
||||
"projectSelector.deleteItemSettings": "Toda la configuración del proyecto",
|
||||
"projectSelector.typeToConfirm": "Escribe {name} para confirmar la eliminación:",
|
||||
"projectSelector.selectProjectLocation": "Seleccionar ubicación del proyecto",
|
||||
"projectSelector.deleteProjectTitle": "Eliminar {name}",
|
||||
"projectSelector.toast.switched": "Cambiado a {name}",
|
||||
"projectSelector.toast.switchFailed": "No se pudo cambiar de proyecto",
|
||||
"projectSelector.toast.created": "Proyecto \"{name}\" creado",
|
||||
"projectSelector.toast.createFailed": "No se pudo crear el proyecto",
|
||||
"projectSelector.toast.existingSettingsFound": "Se encontró configuración de proyecto existente",
|
||||
"projectSelector.toast.selectFolderFailed": "No se pudo seleccionar la carpeta",
|
||||
"projectSelector.toast.deletedWithData": "Proyecto \"{name}\" y todos sus datos eliminados",
|
||||
"projectSelector.toast.deleteFailed": "No se pudo eliminar el proyecto",
|
||||
"tagsView.title": "Gestión de etiquetas",
|
||||
"tagsView.subtitle": "Administra las etiquetas del blog, asigna colores y realiza operaciones masivas.",
|
||||
"tagsView.loadingTags": "Cargando etiquetas...",
|
||||
"tagsView.noTagsFound": "No se encontraron etiquetas",
|
||||
"tagsView.discoverFromPosts": "Descubrir etiquetas desde entradas",
|
||||
"tagsView.selectedCount": "{count} etiqueta(s) seleccionada(s)",
|
||||
"tagsView.clearSelection": "Limpiar selección",
|
||||
"tagsView.cloud.title": "Nube de etiquetas",
|
||||
"tagsView.cloud.description": "Haz clic en las etiquetas para seleccionarlas para operaciones masivas. Pasa el cursor para ver el número de entradas.",
|
||||
"tagsView.manage.title": "Crear y editar etiquetas",
|
||||
"tagsView.manage.description": "Crea etiquetas nuevas o edita las existentes. Asigna colores para distinguirlas visualmente.",
|
||||
"tagsView.create.title": "Crear nueva etiqueta",
|
||||
"tagsView.create.action": "Crear",
|
||||
"tagsView.tagNamePlaceholder": "Nombre de etiqueta",
|
||||
"tagsView.chooseColor": "Elegir color",
|
||||
"tagsView.removeColor": "Quitar color",
|
||||
"tagsView.edit.title": "Editar etiqueta: {name}",
|
||||
"tagsView.edit.action": "Editar",
|
||||
"tagsView.deleteAction": "Eliminar",
|
||||
"tagsView.merge.title": "Combinar etiquetas",
|
||||
"tagsView.merge.description": "Selecciona varias etiquetas arriba y combínalas en una sola. Se actualizarán todas las entradas.",
|
||||
"tagsView.merge.selectAtLeastTwo": "Selecciona 2 o más etiquetas de la nube para combinarlas.",
|
||||
"tagsView.merge.countInto": "Combinar {count} etiquetas en:",
|
||||
"tagsView.merge.selectTarget": "Seleccionar etiqueta de destino...",
|
||||
"tagsView.merge.action": "Combinar etiquetas",
|
||||
"tagsView.merge.tagsToDelete": "Etiquetas que se eliminarán: {tags}",
|
||||
"tagsView.sync.title": "Sincronizar etiquetas",
|
||||
"tagsView.sync.description": "Descubre etiquetas que existen en entradas pero no en la base de datos de etiquetas.",
|
||||
"tagsView.sync.action": "Sincronizar etiquetas desde entradas",
|
||||
"tagsView.confirmDelete.title": "Eliminar etiqueta",
|
||||
"tagsView.confirmDelete.message": "¿Seguro que quieres eliminar la etiqueta \"{tagName}\"? Se quitará de todas las entradas. Esta acción se ejecuta en segundo plano.",
|
||||
"tagsView.confirmDelete.action": "Eliminar etiqueta",
|
||||
"tagsView.confirmMerge.title": "Combinar etiquetas",
|
||||
"tagsView.confirmMerge.message": "¿Seguro que quieres combinar {count} etiqueta(s) en \"{target}\"? Las etiquetas de origen se eliminarán y se actualizarán todas las entradas. Esta acción se ejecuta en segundo plano.",
|
||||
"tagsView.confirmMerge.action": "Combinar etiquetas",
|
||||
"tagsView.none": "(ninguna)",
|
||||
"tagsView.tagCountTitle": "{count} {item}",
|
||||
"tagsView.postsSingular": "entrada",
|
||||
"tagsView.postsPlural": "entradas",
|
||||
"tagsView.toast.tagNameRequired": "El nombre de la etiqueta es obligatorio",
|
||||
"tagsView.toast.tagCreated": "Etiqueta creada",
|
||||
"tagsView.toast.tagDeleted": "Etiqueta eliminada. {postsUpdated} entrada(s) actualizada(s).",
|
||||
"tagsView.toast.tagUpdated": "Etiqueta actualizada",
|
||||
"tagsView.toast.targetTagNotFound": "No se encontró la etiqueta de destino",
|
||||
"tagsView.toast.noSourceTagsToMerge": "No hay etiquetas de origen para combinar",
|
||||
"tagsView.toast.tagsMerged": "Se combinaron {tagsDeleted} etiqueta(s) en \"{targetTag}\". {postsUpdated} entrada(s) actualizada(s).",
|
||||
"tagsView.toast.discoveredTags": "Se descubrieron {count} etiqueta(s) nueva(s)",
|
||||
"tagsView.toast.alreadySynced": "Todas las etiquetas ya están sincronizadas",
|
||||
"tagsView.error.deleteFailedTitle": "Error al eliminar",
|
||||
"tagsView.error.mergeFailedTitle": "Error al combinar",
|
||||
"linkedMediaPanel.title": "📷 Medios vinculados",
|
||||
"linkedMediaPanel.collapsedTitle": "📷 Medios ({count})",
|
||||
"linkedMediaPanel.importAndLink": "Importar y vincular medios",
|
||||
"linkedMediaPanel.linkExisting": "Vincular medio existente",
|
||||
"linkedMediaPanel.selectMediaToLink": "Seleccionar medios para vincular",
|
||||
"linkedMediaPanel.searchPlaceholder": "Buscar medios...",
|
||||
"linkedMediaPanel.noUnlinkedMedia": "No hay medios sin vincular disponibles",
|
||||
"linkedMediaPanel.noMediaLinked": "No hay medios vinculados a esta entrada",
|
||||
"linkedMediaPanel.importMedia": "Importar medios",
|
||||
"linkedMediaPanel.unlinkFromPost": "Desvincular de la entrada",
|
||||
"linkedMediaPanel.toast.importedLinked": "Se importaron y vincularon {count} archivo(s)",
|
||||
"linkedMediaPanel.toast.importFailed": "Error al importar medios",
|
||||
"linkedMediaPanel.toast.unlinked": "Medio desvinculado de la entrada",
|
||||
"linkedMediaPanel.toast.unlinkFailed": "Error al desvincular medio",
|
||||
"linkedMediaPanel.toast.linked": "Medio vinculado a la entrada",
|
||||
"linkedMediaPanel.toast.linkFailed": "Error al vincular medio",
|
||||
"styleView.title": "Estilo",
|
||||
"styleView.subtitle": "Selecciona un tema de Pico CSS y previsualiza las entradas principales antes de aplicarlo.",
|
||||
"styleView.themePickerAria": "Selector de tema Pico",
|
||||
"styleView.previewMode": "Modo de vista previa",
|
||||
"styleView.mode.auto": "Auto",
|
||||
"styleView.mode.light": "Claro",
|
||||
"styleView.mode.dark": "Oscuro",
|
||||
"styleView.applyTheme": "Aplicar tema",
|
||||
"styleView.themePreviewTitle": "Vista previa del tema",
|
||||
"styleView.toast.appliedTheme": "Tema aplicado: {theme}",
|
||||
"styleView.toast.applyThemeFailed": "No se pudo aplicar el tema",
|
||||
"panel.tabsAria": "Pestañas del panel",
|
||||
"panel.output": "Salida",
|
||||
"panel.postLinks": "Enlaces de entrada",
|
||||
"panel.gitLog": "Registro Git",
|
||||
"panel.closeTitle": "Cerrar panel",
|
||||
"panel.noRecentTasks": "No hay tareas recientes",
|
||||
"panel.noOutput": "Sin salida",
|
||||
"panel.openPostEditor": "Abre un editor de entradas para ver los enlaces",
|
||||
"panel.loadingPostLinks": "Cargando enlaces de entradas...",
|
||||
"panel.noPostLinks": "No hay enlaces para esta entrada",
|
||||
"panel.openPostOrMediaEditor": "Abre un editor de entradas o medios para ver el registro Git",
|
||||
"panel.loadingGitLog": "Cargando registro Git...",
|
||||
"panel.noCommits": "No se encontraron commits para este elemento",
|
||||
"panel.error.loadPostLinks": "No se pudieron cargar los enlaces de la entrada.",
|
||||
"panel.error.loadGitLog": "No se pudo cargar el registro Git.",
|
||||
"panel.direction.from": "desde",
|
||||
"panel.direction.to": "hacia"
|
||||
}
|
||||
|
||||
@@ -69,46 +69,46 @@
|
||||
"settings.data.title": "Maintenance de la base de données",
|
||||
"settings.data.fileSystemTitle": "Système de fichiers",
|
||||
"settings.search.placeholder": "Rechercher des paramètres...",
|
||||
"settings.search.noResults": "No paramètres found matching \"{query}\"",
|
||||
"settings.search.noResults": "Aucun paramètre correspondant à \"{query}\"",
|
||||
"settings.search.clear": "Effacer la recherche",
|
||||
"settings.toast.publishingSaved": "Identifiants de publication enregistrés",
|
||||
"settings.toast.saveCredentialsFailed": "Échec de save credentials",
|
||||
"settings.toast.saveCredentialsFailed": "Impossible d’enregistrer les identifiants",
|
||||
"settings.toast.credentialsCleared": "Identifiants {type} effacés",
|
||||
"settings.toast.projectSaved": "Project paramètres saved",
|
||||
"settings.toast.projectSaveFailed": "Échec de save project paramètres",
|
||||
"settings.toast.projectSaved": "Paramètres du projet enregistrés",
|
||||
"settings.toast.projectSaveFailed": "Impossible d’enregistrer les paramètres du projet",
|
||||
"settings.toast.categoryAdded": "Catégorie \"{category}\" ajoutée",
|
||||
"settings.toast.categoryAddFailed": "Échec de add category",
|
||||
"settings.toast.categoryAddFailed": "Impossible d’ajouter la catégorie",
|
||||
"settings.toast.categoryExists": "La catégorie existe déjà",
|
||||
"settings.toast.categoryProtected": "Impossible de supprimer la catégorie standard \"{category}\"",
|
||||
"settings.toast.categoryAtLeastOne": "Au moins une catégorie est requise",
|
||||
"settings.toast.categoryRemoved": "Catégorie \"{category}\" supprimée",
|
||||
"settings.toast.categoryRemoveFailed": "Échec de remove category",
|
||||
"settings.toast.categoryRemoveFailed": "Impossible de supprimer la catégorie",
|
||||
"settings.toast.categoriesReset": "Catégories réinitialisées aux valeurs par défaut",
|
||||
"settings.toast.categoriesResetFailed": "Échec de reset categories",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Échec de update category paramètres",
|
||||
"settings.toast.categoriesResetFailed": "Impossible de réinitialiser les catégories",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Impossible de mettre à jour les paramètres de catégorie",
|
||||
"settings.toast.systemPromptSaved": "Prompt système enregistré",
|
||||
"settings.toast.systemPromptSaveFailed": "Échec de save system prompt",
|
||||
"settings.toast.systemPromptSaveFailed": "Impossible d’enregistrer le prompt système",
|
||||
"settings.toast.systemPromptReset": "Prompt système réinitialisé par défaut",
|
||||
"settings.toast.systemPromptResetFailed": "Échec de reset system prompt",
|
||||
"settings.toast.systemPromptResetFailed": "Impossible de réinitialiser le prompt système",
|
||||
"settings.toast.apiKeySaved": "Clé API enregistrée et validée",
|
||||
"settings.toast.apiKeyInvalid": "Clé API invalide",
|
||||
"settings.toast.apiKeySaveFailed": "Échec de save API key",
|
||||
"settings.toast.apiKeySaveFailed": "Impossible d’enregistrer la clé API",
|
||||
"settings.toast.defaultModelUpdated": "Modèle par défaut mis à jour",
|
||||
"settings.toast.defaultModelUpdateFailed": "Échec de set default model",
|
||||
"settings.toast.rebuildPostsLoading": "Rebuilding articles database...",
|
||||
"settings.toast.defaultModelUpdateFailed": "Impossible de définir le modèle par défaut",
|
||||
"settings.toast.rebuildPostsLoading": "Reconstruction de la base des articles...",
|
||||
"settings.toast.rebuildPostsSuccess": "Base des articles reconstruite",
|
||||
"settings.toast.rebuildPostsFailed": "Échec de rebuild articles database",
|
||||
"settings.toast.rebuildMediaLoading": "Rebuilding médias database...",
|
||||
"settings.toast.rebuildPostsFailed": "Impossible de reconstruire la base des articles",
|
||||
"settings.toast.rebuildMediaLoading": "Reconstruction de la base des médias...",
|
||||
"settings.toast.rebuildMediaSuccess": "Base médias reconstruite",
|
||||
"settings.toast.rebuildMediaFailed": "Échec de rebuild médias database",
|
||||
"settings.toast.rebuildLinksLoading": "Rebuilding article links...",
|
||||
"settings.toast.rebuildMediaFailed": "Impossible de reconstruire la base des médias",
|
||||
"settings.toast.rebuildLinksLoading": "Reconstruction des liens d’articles...",
|
||||
"settings.toast.rebuildLinksSuccess": "Liens d’articles reconstruits",
|
||||
"settings.toast.rebuildLinksFailed": "Échec de rebuild article links",
|
||||
"settings.toast.rebuildLinksFailed": "Impossible de reconstruire les liens d’articles",
|
||||
"settings.toast.thumbnailsLoading": "Génération des miniatures...",
|
||||
"settings.toast.thumbnailsGenerated": "{count} miniatures générées",
|
||||
"settings.toast.thumbnailsAlreadyExist": "Toutes les miniatures existent déjà",
|
||||
"settings.toast.thumbnailsComplete": "Génération des miniatures terminée",
|
||||
"settings.toast.thumbnailsFailed": "Échec de generate thumbnails",
|
||||
"settings.toast.thumbnailsFailed": "Impossible de générer les miniatures",
|
||||
"chat.setupTitle": "Configuration du chat IA",
|
||||
"chat.apiKeyRequiredTitle": "Clé API OpenCode Zen requise",
|
||||
"chat.apiKeyRequiredDescription": "Saisissez votre clé API OpenCode pour activer le chat IA.",
|
||||
@@ -116,21 +116,21 @@
|
||||
"chat.apiKeySave": "Enregistrer la clé",
|
||||
"chat.apiKeyValidating": "Validation...",
|
||||
"chat.apiKeyInvalid": "Clé API invalide. Veuillez vérifier et réessayer.",
|
||||
"chat.apiKeyValidationFailed": "Échec de validate API key.",
|
||||
"chat.apiKeyValidationFailed": "Impossible de valider la clé API.",
|
||||
"chat.newChat": "Nouveau chat",
|
||||
"chat.welcomeTitle": "Bienvenue dans l’assistant IA",
|
||||
"chat.welcomeDescription": "I can help you manage your articles and médias. Try asking me to:",
|
||||
"chat.welcomeTipSearch": "Recherche for articles about a specific topic",
|
||||
"chat.welcomeTipDetails": "Get details about a specific article",
|
||||
"chat.welcomeDescription": "Je peux vous aider à gérer vos articles et médias. Essayez par exemple :",
|
||||
"chat.welcomeTipSearch": "Rechercher des articles sur un sujet précis",
|
||||
"chat.welcomeTipDetails": "Afficher les détails d’un article précis",
|
||||
"chat.welcomeTipTags": "Lister toutes les étiquettes ou catégories de votre blog",
|
||||
"chat.welcomeTipMetadata": "Update metadata for articles or médias",
|
||||
"chat.welcomeTipImages": "List all images in your médias library",
|
||||
"chat.welcomeTipMetadata": "Mettre à jour les métadonnées des articles ou médias",
|
||||
"chat.welcomeTipImages": "Lister toutes les images de votre bibliothèque média",
|
||||
"chat.role.you": "Vous",
|
||||
"chat.role.assistant": "Assistant IA",
|
||||
"chat.stop": "Arrêter",
|
||||
"chat.inputPlaceholder": "Saisissez un message...",
|
||||
"chat.errorPrefix": "Erreur : {error}",
|
||||
"chat.errorNoResponse": "Échec de get a response. Please try again.",
|
||||
"chat.errorNoResponse": "Impossible d’obtenir une réponse. Veuillez réessayer.",
|
||||
"chat.errorEmptyResponse": "Le modèle a renvoyé une réponse vide. Essayez un autre modèle ou reformulez votre question.",
|
||||
"chat.errorGeneric": "Désolé, une erreur est survenue lors du traitement de votre message.",
|
||||
"chat.cancelledSuffix": "(annulé)",
|
||||
@@ -152,8 +152,8 @@
|
||||
"insert.tab.imageInternal": "Bibliothèque média",
|
||||
"insert.tab.linkExternal": "URL externe",
|
||||
"insert.tab.imageExternal": "Image externe",
|
||||
"insert.searchPlaceholder.link": "Recherche articles by title or content...",
|
||||
"insert.searchPlaceholder.image": "Recherche médias by name, title, or alt text...",
|
||||
"insert.searchPlaceholder.link": "Rechercher des articles par titre ou contenu...",
|
||||
"insert.searchPlaceholder.image": "Rechercher des médias par nom, titre ou texte alternatif...",
|
||||
"insert.status.searching": "Recherche...",
|
||||
"insert.status.typeMore": "Saisissez au moins 2 caractères pour rechercher",
|
||||
"insert.status.noResults": "Aucun(e) {kind} trouvé(e) pour \"{query}\"",
|
||||
@@ -169,7 +169,7 @@
|
||||
"insert.hint.internal": "Utilisez ↑↓ pour naviguer, Entrée pour sélectionner, Esc pour fermer",
|
||||
"insert.hint.external": "Entrez l’URL et appuyez sur Entrée ou cliquez sur le bouton, Esc pour fermer",
|
||||
"insert.hint.canonicalPost": "Canonique : /YYYY/MM/DD/slug",
|
||||
"insert.hint.canonicalMedia": "Canonical: /médias/YYYY/MM/file.ext",
|
||||
"insert.hint.canonicalMedia": "Canonique : /media/YYYY/MM/fichier.ext",
|
||||
"postLinks.loading": "Chargement des liens...",
|
||||
"postLinks.link": "lien",
|
||||
"postLinks.links": "liens",
|
||||
@@ -181,7 +181,7 @@
|
||||
"gitDiff.header": "Diff : {target}",
|
||||
"gitDiff.noProject": "Aucun projet actif sélectionné.",
|
||||
"gitDiff.noProjectPath": "Impossible de résoudre le chemin du projet.",
|
||||
"gitDiff.loadFailed": "Échec de load diff.",
|
||||
"gitDiff.loadFailed": "Impossible de charger le diff.",
|
||||
"gitDiff.loading": "Chargement du diff...",
|
||||
"gitDiff.changedFiles": "Fichiers modifiés",
|
||||
"gitDiff.previousFile": "Fichier précédent",
|
||||
@@ -192,8 +192,8 @@
|
||||
"errorModal.copy": "Copier",
|
||||
"errorModal.noStack": "Aucune trace de pile disponible",
|
||||
"confirmDelete.title": "Confirmer la suppression",
|
||||
"confirmDelete.promptPost": "Are you sure you want to delete the article",
|
||||
"confirmDelete.promptMedia": "Are you sure you want to delete the médias file",
|
||||
"confirmDelete.promptPost": "Voulez-vous vraiment supprimer l’article",
|
||||
"confirmDelete.promptMedia": "Voulez-vous vraiment supprimer le fichier média",
|
||||
"confirmDelete.warning": "Avertissement :",
|
||||
"confirmDelete.referencedBy": "Ce/cette {itemType} est référencé(e) par les éléments suivants :",
|
||||
"confirmDelete.note": "La suppression de ce/cette {itemType} supprimera toutes ces références.",
|
||||
@@ -205,12 +205,12 @@
|
||||
"lightbox.close": "Fermer (Esc)",
|
||||
"lightbox.previous": "Précédent (←)",
|
||||
"lightbox.next": "Suivant (→)",
|
||||
"credentials.error.load": "Échec de load credentials:",
|
||||
"credentials.error.save": "Échec de save credentials:",
|
||||
"credentials.error.load": "Impossible de charger les identifiants :",
|
||||
"credentials.error.save": "Impossible d’enregistrer les identifiants :",
|
||||
"credentials.toast.saved": "Identifiants enregistrés",
|
||||
"credentials.toast.saveFailed": "Échec de save credentials",
|
||||
"credentials.toast.saveFailed": "Impossible d’enregistrer les identifiants",
|
||||
"credentials.toast.testing": "Test de la connexion {type}...",
|
||||
"credentials.toast.connectionFailed": "Connection échoué - check credentials",
|
||||
"credentials.toast.connectionFailed": "Échec de la connexion - vérifiez les identifiants",
|
||||
"credentials.tab.ftp": "Accès FTP",
|
||||
"credentials.tab.ssh": "Accès SSH",
|
||||
"credentials.ftp.title": "Publication FTP",
|
||||
@@ -230,14 +230,14 @@
|
||||
"credentials.ssh.placeholder.keyPath": "~/.ssh/ma_cle",
|
||||
"gitSidebar.header": "CONTRÔLE DE SOURCE",
|
||||
"gitSidebar.loading": "Chargement...",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Échec de fetch remote updates.",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Impossible de récupérer les mises à jour distantes.",
|
||||
"gitSidebar.error.refreshRemoteState": "Impossible d’actualiser l’état de suivi distant.",
|
||||
"gitSidebar.error.gitMissing": "Exécutable Git introuvable. Veuillez installer Git et redémarrer l’application.",
|
||||
"gitSidebar.error.noActiveProject": "Aucun projet actif sélectionné.",
|
||||
"gitSidebar.error.loadRepoStatus": "Impossible de charger l’état du dépôt.",
|
||||
"gitSidebar.error.initFailed": "Échec de initialize git repository.",
|
||||
"gitSidebar.error.initFailed": "Impossible d’initialiser le dépôt Git.",
|
||||
"gitSidebar.error.actionFailed": "Échec de {action}.",
|
||||
"gitSidebar.error.commitFailed": "Échec de commit changes.",
|
||||
"gitSidebar.error.commitFailed": "Impossible de valider les modifications.",
|
||||
"gitSidebar.progress.preparingInit": "Préparation de l’initialisation du dépôt...",
|
||||
"gitSidebar.progress.pushingRemote": "Envoi des commits vers le distant... cela peut prendre un moment pour les gros envois.",
|
||||
"gitSidebar.progress.fetching": "Récupération des mises à jour distantes...",
|
||||
@@ -265,7 +265,7 @@
|
||||
"gitSidebar.action.committing": "Commit en cours...",
|
||||
"gitSidebar.action.initializeGit": "Initialiser Git",
|
||||
"gitSidebar.action.initializing": "Initialisation...",
|
||||
"gitSidebar.openChanges": "Ouvrir Changes ({count})",
|
||||
"gitSidebar.openChanges": "Modifications ouvertes ({count})",
|
||||
"gitSidebar.versionHistory": "Historique des versions ({count})",
|
||||
"gitSidebar.loadingChanges": "Chargement des modifications...",
|
||||
"gitSidebar.noChanges": "Aucune modification",
|
||||
@@ -286,16 +286,16 @@
|
||||
"tabBar.scrollLeft": "Faire défiler les onglets vers la gauche",
|
||||
"tabBar.scrollRight": "Faire défiler les onglets vers la droite",
|
||||
"tabBar.commitTitle": "Validation {hash}",
|
||||
"tabBar.error.fetchPostTitle": "Échec de fetch article title:",
|
||||
"tabBar.error.fetchChatTitle": "Échec de fetch chat title:",
|
||||
"tabBar.error.fetchImportTitle": "Échec de fetch import definition title:",
|
||||
"tabBar.error.fetchCommitTitle": "Échec de fetch commit titles:",
|
||||
"tabBar.error.fetchPostTitle": "Impossible de charger le titre de l’article :",
|
||||
"tabBar.error.fetchChatTitle": "Impossible de charger le titre du chat :",
|
||||
"tabBar.error.fetchImportTitle": "Impossible de charger le titre de la définition d’import :",
|
||||
"tabBar.error.fetchCommitTitle": "Impossible de charger les titres des commits :",
|
||||
"metadataDiff.title": "Outil de diff des métadonnées",
|
||||
"metadataDiff.description": "Compare article metadata between database and markdown files. Fix inconsistencies caused by bugs or manual edits.",
|
||||
"metadataDiff.error.loadStats": "Échec de load database statistics",
|
||||
"metadataDiff.error.scan": "Échec de scan for differences",
|
||||
"metadataDiff.description": "Compare les métadonnées des articles entre la base de données et les fichiers Markdown. Corrige les incohérences causées par des bugs ou des modifications manuelles.",
|
||||
"metadataDiff.error.loadStats": "Impossible de charger les statistiques de la base de données",
|
||||
"metadataDiff.error.scan": "Impossible d’analyser les différences",
|
||||
"metadataDiff.progress.starting": "Démarrage de l’analyse...",
|
||||
"metadataDiff.progress.scanningPublished": "Scanning published articles...",
|
||||
"metadataDiff.progress.scanningPublished": "Analyse des articles publiés...",
|
||||
"metadataDiff.progress.scanning": "Analyse en cours...",
|
||||
"metadataDiff.action.scan": "Analyser les différences",
|
||||
"metadataDiff.action.rescan": "Relancer l’analyse",
|
||||
@@ -303,112 +303,238 @@
|
||||
"metadataDiff.stats.published": "Publiés",
|
||||
"metadataDiff.stats.drafts": "Brouillons",
|
||||
"metadataDiff.stats.mediaFiles": "Fichiers média",
|
||||
"metadataDiff.summary.noDiffs": "✅ No differences found! All {total} published articles are in sync.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Found {count} articles with differences out of {total} published articles.",
|
||||
"metadataDiff.summary.noDiffs": "✅ Aucune différence trouvée ! Les {total} articles publiés sont synchronisés.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ {count} articles présentent des différences sur {total} articles publiés.",
|
||||
"metadataDiff.group.differences": "Différences de {label}",
|
||||
"metadataDiff.group.postsCount": "{count} articles",
|
||||
"metadataDiff.sync.failed": "échoué",
|
||||
"metadataDiff.sync.dbToFile.title": "Mettre à jour les fichiers avec les valeurs de la base",
|
||||
"metadataDiff.sync.dbToFile.success": "Synced {success} articles to files{échoué}",
|
||||
"metadataDiff.sync.dbToFile.error": "Échec de sync to files",
|
||||
"metadataDiff.sync.dbToFile.success": "{success} articles synchronisés vers les fichiers{échoué}",
|
||||
"metadataDiff.sync.dbToFile.error": "Échec de la synchronisation vers les fichiers",
|
||||
"metadataDiff.sync.fileToDb.title": "Mettre à jour la base avec les valeurs des fichiers",
|
||||
"metadataDiff.sync.fileToDb.success": "Synced {success} files to database{échoué}",
|
||||
"metadataDiff.sync.fileToDb.error": "Échec de sync to database",
|
||||
"metadataDiff.sync.fileToDb.success": "{success} fichiers synchronisés vers la base de données{échoué}",
|
||||
"metadataDiff.sync.fileToDb.error": "Échec de la synchronisation vers la base de données",
|
||||
"metadataDiff.value.database": "Base de données",
|
||||
"metadataDiff.value.file": "Fichier",
|
||||
"metadataDiff.empty": "Cliquez sur « Rechercher les différences » pour comparer les métadonnées de la base et celles des fichiers.",
|
||||
"sidebar.archive": "Archive",
|
||||
"sidebar.clearFilter": "Clear filter",
|
||||
"sidebar.tags": "Tags",
|
||||
"sidebar.categories": "Categories",
|
||||
"sidebar.clearTags": "Clear tags",
|
||||
"sidebar.clearCategories": "Clear categories",
|
||||
"sidebar.noPostsYet": "No posts yet",
|
||||
"sidebar.noPagesYet": "No pages yet",
|
||||
"sidebar.noMediaYet": "No media yet",
|
||||
"sidebar.search": "Search",
|
||||
"sidebar.searchPostsPlaceholder": "Search posts...",
|
||||
"sidebar.searchPagesPlaceholder": "Search pages...",
|
||||
"sidebar.searchMediaPlaceholder": "Search media...",
|
||||
"sidebar.toggleFilters": "Toggle Filters",
|
||||
"sidebar.newPost": "New Post",
|
||||
"sidebar.importMedia": "Import media",
|
||||
"sidebar.results": "{count} results",
|
||||
"sidebar.resultsFor": "{count} results for \"{query}\"",
|
||||
"sidebar.clearFilters": "Clear filters",
|
||||
"sidebar.drafts": "Drafts",
|
||||
"sidebar.published": "Published",
|
||||
"sidebar.archived": "Archived",
|
||||
"sidebar.untitled": "Untitled",
|
||||
"sidebar.noMatchingPosts": "No matching posts",
|
||||
"sidebar.createFirstPost": "Create your first post",
|
||||
"sidebar.loadMore": "Load more ({loaded} of {total})",
|
||||
"sidebar.loading": "Loading...",
|
||||
"sidebar.noMediaFiles": "No media files",
|
||||
"sidebar.settingsHeader": "Settings",
|
||||
"sidebar.tagsHeader": "Tags",
|
||||
"sidebar.nav.project": "Project",
|
||||
"sidebar.nav.editor": "Editor",
|
||||
"sidebar.nav.content": "Content",
|
||||
"sidebar.nav.ai": "AI Assistant",
|
||||
"sidebar.nav.publishing": "Publishing",
|
||||
"sidebar.nav.data": "Data",
|
||||
"sidebar.clearFilter": "Effacer le filtre",
|
||||
"sidebar.tags": "Étiquettes",
|
||||
"sidebar.categories": "Catégories",
|
||||
"sidebar.clearTags": "Effacer les étiquettes",
|
||||
"sidebar.clearCategories": "Effacer les catégories",
|
||||
"sidebar.noPostsYet": "Aucun article pour le moment",
|
||||
"sidebar.noPagesYet": "Aucune page pour le moment",
|
||||
"sidebar.noMediaYet": "Aucun média pour le moment",
|
||||
"sidebar.search": "Rechercher",
|
||||
"sidebar.searchPostsPlaceholder": "Rechercher des articles...",
|
||||
"sidebar.searchPagesPlaceholder": "Rechercher des pages...",
|
||||
"sidebar.searchMediaPlaceholder": "Rechercher des médias...",
|
||||
"sidebar.toggleFilters": "Afficher/masquer les filtres",
|
||||
"sidebar.newPost": "Nouvel article",
|
||||
"sidebar.importMedia": "Importer des médias",
|
||||
"sidebar.results": "{count} résultats",
|
||||
"sidebar.resultsFor": "{count} résultats pour \"{query}\"",
|
||||
"sidebar.clearFilters": "Effacer les filtres",
|
||||
"sidebar.drafts": "Brouillons",
|
||||
"sidebar.published": "Publiés",
|
||||
"sidebar.archived": "Archivés",
|
||||
"sidebar.untitled": "Sans titre",
|
||||
"sidebar.noMatchingPosts": "Aucun article correspondant",
|
||||
"sidebar.createFirstPost": "Créer votre premier article",
|
||||
"sidebar.loadMore": "Charger plus ({loaded} sur {total})",
|
||||
"sidebar.loading": "Chargement...",
|
||||
"sidebar.noMediaFiles": "Aucun fichier média",
|
||||
"sidebar.settingsHeader": "Paramètres",
|
||||
"sidebar.tagsHeader": "Étiquettes",
|
||||
"sidebar.nav.project": "Projet",
|
||||
"sidebar.nav.editor": "Éditeur",
|
||||
"sidebar.nav.content": "Contenu",
|
||||
"sidebar.nav.ai": "Assistant IA",
|
||||
"sidebar.nav.publishing": "Publication",
|
||||
"sidebar.nav.data": "Données",
|
||||
"sidebar.nav.style": "Style",
|
||||
"sidebar.tagCloud": "Tag Cloud",
|
||||
"sidebar.createEdit": "Create & Edit",
|
||||
"sidebar.mergeTags": "Merge Tags",
|
||||
"settings.project.descriptionGeneral": "General settings for the active blog project.",
|
||||
"settings.project.nameLabel": "Project Name",
|
||||
"settings.project.nameDescription": "The display name of your blog project.",
|
||||
"settings.project.namePlaceholder": "My Blog",
|
||||
"sidebar.tagCloud": "Nuage d’étiquettes",
|
||||
"sidebar.createEdit": "Créer & modifier",
|
||||
"sidebar.mergeTags": "Fusionner les étiquettes",
|
||||
"settings.project.descriptionGeneral": "Paramètres généraux du projet de blog actif.",
|
||||
"settings.project.nameLabel": "Nom du projet",
|
||||
"settings.project.nameDescription": "Nom d’affichage de votre projet de blog.",
|
||||
"settings.project.namePlaceholder": "Mon blog",
|
||||
"settings.project.descriptionLabel": "Description",
|
||||
"settings.project.descriptionDescription": "A short description of your blog. This can be used in templates and metadata.",
|
||||
"settings.project.descriptionPlaceholder": "A blog about...",
|
||||
"settings.project.dataPathLabel": "Project Data Path",
|
||||
"settings.project.dataPathDescription": "Custom folder for storing posts, media, and metadata. Leave empty to use the default location: {path}",
|
||||
"settings.project.defaultLocation": "Default location",
|
||||
"settings.project.publicUrlLabel": "Public URL",
|
||||
"settings.project.publicUrlDescription": "The public base URL of your published blog (used for sitemap generation).",
|
||||
"settings.project.descriptionDescription": "Courte description de votre blog. Elle peut être utilisée dans les modèles et métadonnées.",
|
||||
"settings.project.descriptionPlaceholder": "Un blog sur...",
|
||||
"settings.project.dataPathLabel": "Chemin des données du projet",
|
||||
"settings.project.dataPathDescription": "Dossier personnalisé pour stocker les articles, médias et métadonnées. Laissez vide pour utiliser l’emplacement par défaut : {path}",
|
||||
"settings.project.defaultLocation": "Emplacement par défaut",
|
||||
"settings.project.publicUrlLabel": "URL publique",
|
||||
"settings.project.publicUrlDescription": "URL de base publique de votre blog publié (utilisée pour générer le sitemap).",
|
||||
"settings.project.publicUrlPlaceholder": "https://example.com",
|
||||
"settings.project.mainLanguageLabel": "Main Language",
|
||||
"settings.project.mainLanguageDescription": "The primary language for your blog content. AI-generated titles, alt text, and captions will use this language.",
|
||||
"settings.project.defaultAuthorLabel": "Default Author",
|
||||
"settings.project.defaultAuthorDescription": "The default author name for new posts and media. Can be overridden per item.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Author Name",
|
||||
"settings.project.maxPostsPerPageLabel": "Max Posts Per Page",
|
||||
"settings.project.maxPostsPerPageDescription": "Maximum number of posts shown per preview route page.",
|
||||
"settings.project.saveButton": "Save Project Settings",
|
||||
"editor.loadingPost": "Loading post...",
|
||||
"editor.unsavedChanges": "Unsaved changes (auto-saves on switch)",
|
||||
"editor.saving": "Saving...",
|
||||
"editor.publish": "Publish",
|
||||
"editor.publishTitle": "Save and make this post public",
|
||||
"editor.discardChanges": "Discard Changes",
|
||||
"editor.discardDraft": "Discard Draft",
|
||||
"editor.discardChangesTitle": "Revert to last published version",
|
||||
"editor.discardDraftTitle": "Delete this draft permanently",
|
||||
"editor.delete": "Delete",
|
||||
"editor.deleteTitle": "Delete this post permanently",
|
||||
"editor.field.title": "Title",
|
||||
"editor.field.tags": "Tags",
|
||||
"editor.field.author": "Author",
|
||||
"settings.project.mainLanguageLabel": "Langue principale",
|
||||
"settings.project.mainLanguageDescription": "Langue principale de votre contenu. Les titres, textes alternatifs et légendes générés par l’IA utiliseront cette langue.",
|
||||
"settings.project.defaultAuthorLabel": "Auteur par défaut",
|
||||
"settings.project.defaultAuthorDescription": "Nom d’auteur par défaut pour les nouveaux articles et médias. Peut être remplacé par élément.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Nom de l’auteur",
|
||||
"settings.project.maxPostsPerPageLabel": "Nombre max d’articles par page",
|
||||
"settings.project.maxPostsPerPageDescription": "Nombre maximum d’articles affichés par page de route d’aperçu.",
|
||||
"settings.project.saveButton": "Enregistrer les paramètres du projet",
|
||||
"editor.loadingPost": "Chargement de l’article...",
|
||||
"editor.unsavedChanges": "Modifications non enregistrées (enregistrement auto au changement)",
|
||||
"editor.saving": "Enregistrement...",
|
||||
"editor.publish": "Publier",
|
||||
"editor.publishTitle": "Enregistrer et publier cet article",
|
||||
"editor.discardChanges": "Annuler les modifications",
|
||||
"editor.discardDraft": "Supprimer le brouillon",
|
||||
"editor.discardChangesTitle": "Revenir à la dernière version publiée",
|
||||
"editor.discardDraftTitle": "Supprimer définitivement ce brouillon",
|
||||
"editor.delete": "Supprimer",
|
||||
"editor.deleteTitle": "Supprimer définitivement cet article",
|
||||
"editor.field.title": "Titre",
|
||||
"editor.field.tags": "Étiquettes",
|
||||
"editor.field.author": "Auteur",
|
||||
"editor.field.slug": "Slug",
|
||||
"editor.field.categories": "Categories",
|
||||
"editor.field.content": "Content",
|
||||
"editor.placeholder.tags": "Add tags...",
|
||||
"editor.placeholder.author": "Author name",
|
||||
"editor.placeholder.categories": "Add categories...",
|
||||
"editor.placeholder.startWriting": "Start writing...",
|
||||
"editor.mode.visual": "Visual",
|
||||
"editor.mode.visualTitle": "Visual editor",
|
||||
"editor.mode.markdownTitle": "Markdown source",
|
||||
"editor.mode.previewTitle": "Read-only preview",
|
||||
"editor.galleryTitle": "View {count} image(s)",
|
||||
"editor.insertPostLinkTitle": "Link to post (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Insert image from media library",
|
||||
"editor.previewFrameTitle": "Post preview",
|
||||
"editor.previewLoading": "Loading preview...",
|
||||
"editor.footer.created": "Created",
|
||||
"editor.footer.updated": "Updated",
|
||||
"editor.footer.published": "Published"
|
||||
"editor.field.categories": "Catégories",
|
||||
"editor.field.content": "Contenu",
|
||||
"editor.placeholder.tags": "Ajouter des étiquettes...",
|
||||
"editor.placeholder.author": "Nom de l’auteur",
|
||||
"editor.placeholder.categories": "Ajouter des catégories...",
|
||||
"editor.placeholder.startWriting": "Commencez à écrire...",
|
||||
"editor.mode.visual": "Visuel",
|
||||
"editor.mode.visualTitle": "Éditeur visuel",
|
||||
"editor.mode.markdownTitle": "Source Markdown",
|
||||
"editor.mode.previewTitle": "Aperçu en lecture seule",
|
||||
"editor.galleryTitle": "Voir {count} image(s)",
|
||||
"editor.insertPostLinkTitle": "Lier à un article (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Insérer une image depuis la bibliothèque média",
|
||||
"editor.previewFrameTitle": "Aperçu de l’article",
|
||||
"editor.previewLoading": "Chargement de l’aperçu...",
|
||||
"editor.footer.created": "Créé",
|
||||
"editor.footer.updated": "Mis à jour",
|
||||
"editor.footer.published": "Publié",
|
||||
"projectSelector.switchProject": "Changer de projet",
|
||||
"projectSelector.selectProject": "Sélectionner un projet",
|
||||
"projectSelector.projectsHeader": "Projets",
|
||||
"projectSelector.noProjectsYet": "Aucun projet pour le moment",
|
||||
"projectSelector.newProject": "Nouveau projet",
|
||||
"projectSelector.createNewProject": "Créer un nouveau projet",
|
||||
"projectSelector.projectName": "Nom du projet",
|
||||
"projectSelector.projectNamePlaceholder": "Mon blog",
|
||||
"projectSelector.descriptionOptional": "Description (facultative)",
|
||||
"projectSelector.descriptionPlaceholder": "Brève description du projet...",
|
||||
"projectSelector.projectLocation": "Emplacement du projet",
|
||||
"projectSelector.useDefaultLocation": "Utiliser l'emplacement par défaut",
|
||||
"projectSelector.defaultInternalStorage": "Par défaut (stockage interne)",
|
||||
"projectSelector.chooseFolder": "Choisir un dossier...",
|
||||
"projectSelector.projectLocationHint": "Choisissez un dossier personnalisé pour la sauvegarde cloud, ou utilisez l'emplacement interne par défaut.",
|
||||
"projectSelector.createProject": "Créer le projet",
|
||||
"projectSelector.deleteProject": "Supprimer le projet",
|
||||
"projectSelector.deleteWarning": "Cela supprimera définitivement le projet \"{name}\" et toutes ses données, y compris :",
|
||||
"projectSelector.deleteItemPosts": "Tous les articles",
|
||||
"projectSelector.deleteItemMedia": "Tous les médias",
|
||||
"projectSelector.deleteItemSettings": "Tous les paramètres du projet",
|
||||
"projectSelector.typeToConfirm": "Saisissez {name} pour confirmer la suppression :",
|
||||
"projectSelector.selectProjectLocation": "Sélectionner l'emplacement du projet",
|
||||
"projectSelector.deleteProjectTitle": "Supprimer {name}",
|
||||
"projectSelector.toast.switched": "Projet actif : {name}",
|
||||
"projectSelector.toast.switchFailed": "Échec du changement de projet",
|
||||
"projectSelector.toast.created": "Projet \"{name}\" créé",
|
||||
"projectSelector.toast.createFailed": "Impossible de créer le projet",
|
||||
"projectSelector.toast.existingSettingsFound": "Paramètres de projet existants détectés",
|
||||
"projectSelector.toast.selectFolderFailed": "Échec de la sélection du dossier",
|
||||
"projectSelector.toast.deletedWithData": "Projet \"{name}\" et toutes ses données supprimés",
|
||||
"projectSelector.toast.deleteFailed": "Impossible de supprimer le projet",
|
||||
"tagsView.title": "Gestion des tags",
|
||||
"tagsView.subtitle": "Gérez les tags du blog, attribuez des couleurs et lancez des actions groupées.",
|
||||
"tagsView.loadingTags": "Chargement des tags...",
|
||||
"tagsView.noTagsFound": "Aucun tag trouvé",
|
||||
"tagsView.discoverFromPosts": "Découvrir les tags à partir des articles",
|
||||
"tagsView.selectedCount": "{count} tag(s) sélectionné(s)",
|
||||
"tagsView.clearSelection": "Effacer la sélection",
|
||||
"tagsView.cloud.title": "Nuage de tags",
|
||||
"tagsView.cloud.description": "Cliquez sur les tags pour les sélectionner. Survolez-les pour voir le nombre d'articles.",
|
||||
"tagsView.manage.title": "Créer et modifier des tags",
|
||||
"tagsView.manage.description": "Créez de nouveaux tags ou modifiez les existants. Attribuez des couleurs pour mieux les distinguer.",
|
||||
"tagsView.create.title": "Créer un tag",
|
||||
"tagsView.create.action": "Créer",
|
||||
"tagsView.tagNamePlaceholder": "Nom du tag",
|
||||
"tagsView.chooseColor": "Choisir une couleur",
|
||||
"tagsView.removeColor": "Supprimer la couleur",
|
||||
"tagsView.edit.title": "Modifier le tag : {name}",
|
||||
"tagsView.edit.action": "Modifier",
|
||||
"tagsView.deleteAction": "Supprimer",
|
||||
"tagsView.merge.title": "Fusionner des tags",
|
||||
"tagsView.merge.description": "Sélectionnez plusieurs tags ci-dessus puis fusionnez-les en un seul. Tous les articles seront mis à jour.",
|
||||
"tagsView.merge.selectAtLeastTwo": "Sélectionnez au moins 2 tags dans le nuage pour les fusionner.",
|
||||
"tagsView.merge.countInto": "Fusionner {count} tags vers :",
|
||||
"tagsView.merge.selectTarget": "Sélectionner le tag cible...",
|
||||
"tagsView.merge.action": "Fusionner les tags",
|
||||
"tagsView.merge.tagsToDelete": "Tags à supprimer : {tags}",
|
||||
"tagsView.sync.title": "Synchroniser les tags",
|
||||
"tagsView.sync.description": "Découvrir les tags présents dans les articles mais absents de la base de tags.",
|
||||
"tagsView.sync.action": "Synchroniser les tags depuis les articles",
|
||||
"tagsView.confirmDelete.title": "Supprimer le tag",
|
||||
"tagsView.confirmDelete.message": "Voulez-vous vraiment supprimer le tag \"{tagName}\" ? Il sera retiré de tous les articles. Cette action s'exécute en tâche de fond.",
|
||||
"tagsView.confirmDelete.action": "Supprimer le tag",
|
||||
"tagsView.confirmMerge.title": "Fusionner des tags",
|
||||
"tagsView.confirmMerge.message": "Voulez-vous vraiment fusionner {count} tag(s) vers \"{target}\" ? Les tags source seront supprimés et tous les articles seront mis à jour. Cette action s'exécute en tâche de fond.",
|
||||
"tagsView.confirmMerge.action": "Fusionner les tags",
|
||||
"tagsView.none": "(aucun)",
|
||||
"tagsView.tagCountTitle": "{count} {item}",
|
||||
"tagsView.postsSingular": "article",
|
||||
"tagsView.postsPlural": "articles",
|
||||
"tagsView.toast.tagNameRequired": "Le nom du tag est requis",
|
||||
"tagsView.toast.tagCreated": "Tag créé",
|
||||
"tagsView.toast.tagDeleted": "Tag supprimé. {postsUpdated} article(s) mis à jour.",
|
||||
"tagsView.toast.tagUpdated": "Tag mis à jour",
|
||||
"tagsView.toast.targetTagNotFound": "Tag cible introuvable",
|
||||
"tagsView.toast.noSourceTagsToMerge": "Aucun tag source à fusionner",
|
||||
"tagsView.toast.tagsMerged": "{tagsDeleted} tag(s) fusionné(s) vers \"{targetTag}\". {postsUpdated} article(s) mis à jour.",
|
||||
"tagsView.toast.discoveredTags": "{count} nouveau(x) tag(s) découvert(s)",
|
||||
"tagsView.toast.alreadySynced": "Tous les tags sont déjà synchronisés",
|
||||
"tagsView.error.deleteFailedTitle": "Échec de la suppression",
|
||||
"tagsView.error.mergeFailedTitle": "Échec de la fusion",
|
||||
"linkedMediaPanel.title": "📷 Médias liés",
|
||||
"linkedMediaPanel.collapsedTitle": "📷 Médias ({count})",
|
||||
"linkedMediaPanel.importAndLink": "Importer et lier des médias",
|
||||
"linkedMediaPanel.linkExisting": "Lier un média existant",
|
||||
"linkedMediaPanel.selectMediaToLink": "Sélectionner les médias à lier",
|
||||
"linkedMediaPanel.searchPlaceholder": "Rechercher des médias...",
|
||||
"linkedMediaPanel.noUnlinkedMedia": "Aucun média non lié disponible",
|
||||
"linkedMediaPanel.noMediaLinked": "Aucun média lié à cet article",
|
||||
"linkedMediaPanel.importMedia": "Importer des médias",
|
||||
"linkedMediaPanel.unlinkFromPost": "Délier de l'article",
|
||||
"linkedMediaPanel.toast.importedLinked": "{count} fichier(s) importé(s) et lié(s)",
|
||||
"linkedMediaPanel.toast.importFailed": "Échec de l'import des médias",
|
||||
"linkedMediaPanel.toast.unlinked": "Média délié de l'article",
|
||||
"linkedMediaPanel.toast.unlinkFailed": "Échec du déliage du média",
|
||||
"linkedMediaPanel.toast.linked": "Média lié à l'article",
|
||||
"linkedMediaPanel.toast.linkFailed": "Échec de la liaison du média",
|
||||
"styleView.title": "Style",
|
||||
"styleView.subtitle": "Sélectionnez un thème Pico CSS et prévisualisez les principaux articles avant application.",
|
||||
"styleView.themePickerAria": "Sélecteur de thème Pico",
|
||||
"styleView.previewMode": "Mode d'aperçu",
|
||||
"styleView.mode.auto": "Auto",
|
||||
"styleView.mode.light": "Clair",
|
||||
"styleView.mode.dark": "Sombre",
|
||||
"styleView.applyTheme": "Appliquer le thème",
|
||||
"styleView.themePreviewTitle": "Aperçu du thème",
|
||||
"styleView.toast.appliedTheme": "Thème appliqué : {theme}",
|
||||
"styleView.toast.applyThemeFailed": "Échec de l'application du thème",
|
||||
"panel.tabsAria": "Onglets du panneau",
|
||||
"panel.output": "Sortie",
|
||||
"panel.postLinks": "Liens d'articles",
|
||||
"panel.gitLog": "Journal Git",
|
||||
"panel.closeTitle": "Fermer le panneau",
|
||||
"panel.noRecentTasks": "Aucune tâche récente",
|
||||
"panel.noOutput": "Aucune sortie",
|
||||
"panel.openPostEditor": "Ouvrez un éditeur d'article pour voir les liens",
|
||||
"panel.loadingPostLinks": "Chargement des liens d'articles...",
|
||||
"panel.noPostLinks": "Aucun lien pour cet article",
|
||||
"panel.openPostOrMediaEditor": "Ouvrez un éditeur d'article ou de média pour voir le journal Git",
|
||||
"panel.loadingGitLog": "Chargement du journal Git...",
|
||||
"panel.noCommits": "Aucun commit trouvé pour cet élément",
|
||||
"panel.error.loadPostLinks": "Impossible de charger les liens d'articles.",
|
||||
"panel.error.loadGitLog": "Impossible de charger le journal Git.",
|
||||
"panel.direction.from": "depuis",
|
||||
"panel.direction.to": "vers"
|
||||
}
|
||||
|
||||
@@ -67,48 +67,48 @@
|
||||
"settings.publishing.ftpTitle": "Pubblicazione FTP",
|
||||
"settings.publishing.sshTitle": "Pubblicazione SSH",
|
||||
"settings.data.title": "Manutenzione database",
|
||||
"settings.data.fileSystemTitle": "File system",
|
||||
"settings.data.fileSystemTitle": "Sistema file",
|
||||
"settings.search.placeholder": "Cerca impostazioni...",
|
||||
"settings.search.noResults": "No impostazioni found matching \"{query}\"",
|
||||
"settings.search.noResults": "Nessuna impostazione trovata per \"{query}\"",
|
||||
"settings.search.clear": "Cancella ricerca",
|
||||
"settings.toast.publishingSaved": "Credenziali di pubblicazione salvate",
|
||||
"settings.toast.saveCredentialsFailed": "Impossibile save credentials",
|
||||
"settings.toast.saveCredentialsFailed": "Impossibile salvare le credenziali",
|
||||
"settings.toast.credentialsCleared": "Credenziali {type} cancellate",
|
||||
"settings.toast.projectSaved": "Project impostazioni saved",
|
||||
"settings.toast.projectSaveFailed": "Impossibile save project impostazioni",
|
||||
"settings.toast.projectSaved": "Impostazioni progetto salvate",
|
||||
"settings.toast.projectSaveFailed": "Impossibile salvare le impostazioni del progetto",
|
||||
"settings.toast.categoryAdded": "Categoria \"{category}\" aggiunta",
|
||||
"settings.toast.categoryAddFailed": "Impossibile add category",
|
||||
"settings.toast.categoryAddFailed": "Impossibile aggiungere la categoria",
|
||||
"settings.toast.categoryExists": "La categoria esiste già",
|
||||
"settings.toast.categoryProtected": "Impossibile eliminare la categoria standard \"{category}\"",
|
||||
"settings.toast.categoryAtLeastOne": "Deve esserci almeno una categoria",
|
||||
"settings.toast.categoryRemoved": "Categoria \"{category}\" rimossa",
|
||||
"settings.toast.categoryRemoveFailed": "Impossibile remove category",
|
||||
"settings.toast.categoryRemoveFailed": "Impossibile rimuovere la categoria",
|
||||
"settings.toast.categoriesReset": "Categorie ripristinate ai predefiniti",
|
||||
"settings.toast.categoriesResetFailed": "Impossibile reset categories",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Impossibile update category impostazioni",
|
||||
"settings.toast.categoriesResetFailed": "Impossibile ripristinare le categorie",
|
||||
"settings.toast.categorySettingsUpdateFailed": "Impossibile aggiornare le impostazioni delle categorie",
|
||||
"settings.toast.systemPromptSaved": "Prompt di sistema salvato",
|
||||
"settings.toast.systemPromptSaveFailed": "Impossibile save system prompt",
|
||||
"settings.toast.systemPromptSaveFailed": "Impossibile salvare il prompt di sistema",
|
||||
"settings.toast.systemPromptReset": "Prompt di sistema ripristinato al predefinito",
|
||||
"settings.toast.systemPromptResetFailed": "Impossibile reset system prompt",
|
||||
"settings.toast.systemPromptResetFailed": "Impossibile ripristinare il prompt di sistema",
|
||||
"settings.toast.apiKeySaved": "Chiave API salvata e convalidata",
|
||||
"settings.toast.apiKeyInvalid": "Chiave API non valida",
|
||||
"settings.toast.apiKeySaveFailed": "Impossibile save API key",
|
||||
"settings.toast.apiKeySaveFailed": "Impossibile salvare la chiave API",
|
||||
"settings.toast.defaultModelUpdated": "Modello predefinito aggiornato",
|
||||
"settings.toast.defaultModelUpdateFailed": "Impossibile set default model",
|
||||
"settings.toast.rebuildPostsLoading": "Rebuilding post database...",
|
||||
"settings.toast.defaultModelUpdateFailed": "Impossibile impostare il modello predefinito",
|
||||
"settings.toast.rebuildPostsLoading": "Ricostruzione database post...",
|
||||
"settings.toast.rebuildPostsSuccess": "Database post ricostruito",
|
||||
"settings.toast.rebuildPostsFailed": "Impossibile rebuild post database",
|
||||
"settings.toast.rebuildPostsFailed": "Impossibile ricostruire il database dei post",
|
||||
"settings.toast.rebuildMediaLoading": "Ricostruzione database media...",
|
||||
"settings.toast.rebuildMediaSuccess": "Database media ricostruito",
|
||||
"settings.toast.rebuildMediaFailed": "Impossibile rebuild media database",
|
||||
"settings.toast.rebuildMediaFailed": "Impossibile ricostruire il database dei media",
|
||||
"settings.toast.rebuildLinksLoading": "Ricostruzione dei link dei post...",
|
||||
"settings.toast.rebuildLinksSuccess": "Link dei post ricostruiti",
|
||||
"settings.toast.rebuildLinksFailed": "Impossibile rebuild post links",
|
||||
"settings.toast.rebuildLinksFailed": "Impossibile ricostruire i link dei post",
|
||||
"settings.toast.thumbnailsLoading": "Generazione miniature in corso...",
|
||||
"settings.toast.thumbnailsGenerated": "Generate {count} miniature",
|
||||
"settings.toast.thumbnailsAlreadyExist": "Tutte le miniature esistono già",
|
||||
"settings.toast.thumbnailsComplete": "Generazione miniature completata",
|
||||
"settings.toast.thumbnailsFailed": "Impossibile generate thumbnails",
|
||||
"settings.toast.thumbnailsFailed": "Impossibile generare le miniature",
|
||||
"chat.setupTitle": "Configurazione chat IA",
|
||||
"chat.apiKeyRequiredTitle": "Chiave API OpenCode Zen richiesta",
|
||||
"chat.apiKeyRequiredDescription": "Inserisci la tua chiave API OpenCode per abilitare la chat IA.",
|
||||
@@ -116,23 +116,23 @@
|
||||
"chat.apiKeySave": "Salva chiave",
|
||||
"chat.apiKeyValidating": "Convalida in corso...",
|
||||
"chat.apiKeyInvalid": "Chiave API non valida. Controlla e riprova.",
|
||||
"chat.apiKeyValidationFailed": "Impossibile validate API key.",
|
||||
"chat.apiKeyValidationFailed": "Impossibile convalidare la chiave API.",
|
||||
"chat.newChat": "Nuova chat",
|
||||
"chat.welcomeTitle": "Benvenuto nell’assistente IA",
|
||||
"chat.welcomeDescription": "I can help you manage your post and media. Try asking me to:",
|
||||
"chat.welcomeTipSearch": "Ricerca for post about a specific topic",
|
||||
"chat.welcomeDescription": "Posso aiutarti a gestire post e media. Prova a chiedermi di:",
|
||||
"chat.welcomeTipSearch": "Cercare post su un argomento specifico",
|
||||
"chat.welcomeTipDetails": "Ottieni dettagli su un post specifico",
|
||||
"chat.welcomeTipTags": "Elenca tutti i tag o le categorie del tuo blog",
|
||||
"chat.welcomeTipMetadata": "Update metadata for post or media",
|
||||
"chat.welcomeTipMetadata": "Aggiornare i metadati di post o media",
|
||||
"chat.welcomeTipImages": "Elenca tutte le immagini nella tua libreria media",
|
||||
"chat.role.you": "Tu",
|
||||
"chat.role.assistant": "Assistente",
|
||||
"chat.stop": "Ferma",
|
||||
"chat.inputPlaceholder": "Scrivi un messaggio...",
|
||||
"chat.errorPrefix": "Errore: {error}",
|
||||
"chat.errorNoResponse": "Impossibile get a response. Please try again.",
|
||||
"chat.errorNoResponse": "Impossibile ottenere una risposta. Riprova.",
|
||||
"chat.errorEmptyResponse": "Il modello ha restituito una risposta vuota. Prova un modello diverso o riformula la domanda.",
|
||||
"chat.errorGeneric": "Sorry, an error occurred while processing your messaggio.",
|
||||
"chat.errorGeneric": "Si è verificato un errore durante l’elaborazione del messaggio.",
|
||||
"chat.cancelledSuffix": "(annullato)",
|
||||
"aiSuggestions.title": "Analisi immagine IA",
|
||||
"aiSuggestions.close": "Chiudi",
|
||||
@@ -152,8 +152,8 @@
|
||||
"insert.tab.imageInternal": "Libreria media",
|
||||
"insert.tab.linkExternal": "URL esterno",
|
||||
"insert.tab.imageExternal": "Immagine esterna",
|
||||
"insert.searchPlaceholder.link": "Ricerca post by title or content...",
|
||||
"insert.searchPlaceholder.image": "Ricerca media by name, title, or alt text...",
|
||||
"insert.searchPlaceholder.link": "Cerca post per titolo o contenuto...",
|
||||
"insert.searchPlaceholder.image": "Cerca media per nome, titolo o testo alternativo...",
|
||||
"insert.status.searching": "Ricerca...",
|
||||
"insert.status.typeMore": "Digita almeno 2 caratteri per cercare",
|
||||
"insert.status.noResults": "Nessun {kind} trovato per \"{query}\"",
|
||||
@@ -181,7 +181,7 @@
|
||||
"gitDiff.header": "Differenza: {target}",
|
||||
"gitDiff.noProject": "Nessun progetto attivo selezionato.",
|
||||
"gitDiff.noProjectPath": "Impossibile risolvere il percorso del progetto.",
|
||||
"gitDiff.loadFailed": "Impossibile load diff.",
|
||||
"gitDiff.loadFailed": "Impossibile caricare il diff.",
|
||||
"gitDiff.loading": "Caricamento diff...",
|
||||
"gitDiff.changedFiles": "File modificati",
|
||||
"gitDiff.previousFile": "File precedente",
|
||||
@@ -205,12 +205,12 @@
|
||||
"lightbox.close": "Chiudi (Esc)",
|
||||
"lightbox.previous": "Precedente (←)",
|
||||
"lightbox.next": "Successivo (→)",
|
||||
"credentials.error.load": "Impossibile load credentials:",
|
||||
"credentials.error.save": "Impossibile save credentials:",
|
||||
"credentials.error.load": "Impossibile caricare le credenziali:",
|
||||
"credentials.error.save": "Impossibile salvare le credenziali:",
|
||||
"credentials.toast.saved": "Credenziali salvate",
|
||||
"credentials.toast.saveFailed": "Impossibile save credentials",
|
||||
"credentials.toast.saveFailed": "Impossibile salvare le credenziali",
|
||||
"credentials.toast.testing": "Test della connessione {type} in corso...",
|
||||
"credentials.toast.connectionFailed": "Connection fallito - check credentials",
|
||||
"credentials.toast.connectionFailed": "Connessione non riuscita - controlla le credenziali",
|
||||
"credentials.tab.ftp": "Accesso FTP",
|
||||
"credentials.tab.ssh": "Accesso SSH",
|
||||
"credentials.ftp.title": "Pubblicazione FTP",
|
||||
@@ -230,14 +230,14 @@
|
||||
"credentials.ssh.placeholder.keyPath": "~/.ssh/chiave_id_rsa",
|
||||
"gitSidebar.header": "CONTROLLO SORGENTE",
|
||||
"gitSidebar.loading": "Caricamento...",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Impossibile fetch remote updates.",
|
||||
"gitSidebar.error.fetchRemoteUpdates": "Impossibile recuperare gli aggiornamenti remoti.",
|
||||
"gitSidebar.error.refreshRemoteState": "Impossibile aggiornare lo stato di tracciamento remoto.",
|
||||
"gitSidebar.error.gitMissing": "Eseguibile Git non trovato. Installa Git e riavvia l’app.",
|
||||
"gitSidebar.error.noActiveProject": "Nessun progetto attivo selezionato.",
|
||||
"gitSidebar.error.loadRepoStatus": "Impossibile caricare lo stato del repository.",
|
||||
"gitSidebar.error.initFailed": "Impossibile initialize git repository.",
|
||||
"gitSidebar.error.initFailed": "Impossibile inizializzare il repository Git.",
|
||||
"gitSidebar.error.actionFailed": "Impossibile {action}.",
|
||||
"gitSidebar.error.commitFailed": "Impossibile commit changes.",
|
||||
"gitSidebar.error.commitFailed": "Impossibile eseguire il commit delle modifiche.",
|
||||
"gitSidebar.progress.preparingInit": "Preparazione inizializzazione repository...",
|
||||
"gitSidebar.progress.pushingRemote": "Invio dei commit al remoto... può richiedere tempo per upload grandi.",
|
||||
"gitSidebar.progress.fetching": "Recupero aggiornamenti remoti...",
|
||||
@@ -265,7 +265,7 @@
|
||||
"gitSidebar.action.committing": "Commit in corso...",
|
||||
"gitSidebar.action.initializeGit": "Inizializza Git",
|
||||
"gitSidebar.action.initializing": "Inizializzazione...",
|
||||
"gitSidebar.openChanges": "Apri Changes ({count})",
|
||||
"gitSidebar.openChanges": "Modifiche aperte ({count})",
|
||||
"gitSidebar.versionHistory": "Cronologia versioni ({count})",
|
||||
"gitSidebar.loadingChanges": "Caricamento modifiche...",
|
||||
"gitSidebar.noChanges": "Nessuna modifica",
|
||||
@@ -286,16 +286,16 @@
|
||||
"tabBar.scrollLeft": "Scorri le schede a sinistra",
|
||||
"tabBar.scrollRight": "Scorri le schede a destra",
|
||||
"tabBar.commitTitle": "Revisione {hash}",
|
||||
"tabBar.error.fetchPostTitle": "Impossibile fetch post title:",
|
||||
"tabBar.error.fetchChatTitle": "Impossibile fetch chat title:",
|
||||
"tabBar.error.fetchImportTitle": "Impossibile fetch import definition title:",
|
||||
"tabBar.error.fetchCommitTitle": "Impossibile fetch commit titles:",
|
||||
"tabBar.error.fetchPostTitle": "Impossibile caricare il titolo del post:",
|
||||
"tabBar.error.fetchChatTitle": "Impossibile caricare il titolo della chat:",
|
||||
"tabBar.error.fetchImportTitle": "Impossibile caricare il titolo della definizione di importazione:",
|
||||
"tabBar.error.fetchCommitTitle": "Impossibile caricare i titoli dei commit:",
|
||||
"metadataDiff.title": "Strumento diff metadati",
|
||||
"metadataDiff.description": "Confronta i metadati dei post tra database e file markdown. Correggi incongruenze causate da bug o modifiche manuali.",
|
||||
"metadataDiff.error.loadStats": "Impossibile load database statistics",
|
||||
"metadataDiff.error.scan": "Impossibile scan for differences",
|
||||
"metadataDiff.error.loadStats": "Impossibile caricare le statistiche del database",
|
||||
"metadataDiff.error.scan": "Impossibile analizzare le differenze",
|
||||
"metadataDiff.progress.starting": "Avvio scansione...",
|
||||
"metadataDiff.progress.scanningPublished": "Scanning published post...",
|
||||
"metadataDiff.progress.scanningPublished": "Scansione dei post pubblicati...",
|
||||
"metadataDiff.progress.scanning": "Scansione in corso...",
|
||||
"metadataDiff.action.scan": "Cerca differenze",
|
||||
"metadataDiff.action.rescan": "Riesegui scansione",
|
||||
@@ -303,112 +303,238 @@
|
||||
"metadataDiff.stats.published": "Pubblicati",
|
||||
"metadataDiff.stats.drafts": "Bozze",
|
||||
"metadataDiff.stats.mediaFiles": "File multimediali",
|
||||
"metadataDiff.summary.noDiffs": "✅ No differences found! All {total} published post are in sync.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Found {count} post with differences out of {total} published post.",
|
||||
"metadataDiff.summary.noDiffs": "✅ Nessuna differenza trovata! Tutti i {total} post pubblicati sono sincronizzati.",
|
||||
"metadataDiff.summary.withDiffs": "⚠️ Trovati {count} post con differenze su {total} post pubblicati.",
|
||||
"metadataDiff.group.differences": "Differenze {label}",
|
||||
"metadataDiff.group.postsCount": "{count} post",
|
||||
"metadataDiff.sync.failed": "fallito",
|
||||
"metadataDiff.sync.dbToFile.title": "Aggiorna i file con i valori del database",
|
||||
"metadataDiff.sync.dbToFile.success": "Synced {success} post to files{fallito}",
|
||||
"metadataDiff.sync.dbToFile.error": "Impossibile sync to files",
|
||||
"metadataDiff.sync.dbToFile.success": "Sincronizzati {success} post nei file{fallito}",
|
||||
"metadataDiff.sync.dbToFile.error": "Impossibile sincronizzare nei file",
|
||||
"metadataDiff.sync.fileToDb.title": "Aggiorna il database con i valori dei file",
|
||||
"metadataDiff.sync.fileToDb.success": "Synced {success} files to database{fallito}",
|
||||
"metadataDiff.sync.fileToDb.error": "Impossibile sync to database",
|
||||
"metadataDiff.sync.fileToDb.success": "Sincronizzati {success} file nel database{fallito}",
|
||||
"metadataDiff.sync.fileToDb.error": "Impossibile sincronizzare nel database",
|
||||
"metadataDiff.value.database": "Database locale",
|
||||
"metadataDiff.value.file": "File sorgente",
|
||||
"metadataDiff.empty": "Fai clic su \"Scansiona differenze\" per confrontare i metadati del database con quelli dei file.",
|
||||
"sidebar.archive": "Archive",
|
||||
"sidebar.clearFilter": "Clear filter",
|
||||
"sidebar.tags": "Tags",
|
||||
"sidebar.categories": "Categories",
|
||||
"sidebar.clearTags": "Clear tags",
|
||||
"sidebar.clearCategories": "Clear categories",
|
||||
"sidebar.noPostsYet": "No posts yet",
|
||||
"sidebar.noPagesYet": "No pages yet",
|
||||
"sidebar.noMediaYet": "No media yet",
|
||||
"sidebar.search": "Search",
|
||||
"sidebar.searchPostsPlaceholder": "Search posts...",
|
||||
"sidebar.searchPagesPlaceholder": "Search pages...",
|
||||
"sidebar.searchMediaPlaceholder": "Search media...",
|
||||
"sidebar.toggleFilters": "Toggle Filters",
|
||||
"sidebar.newPost": "New Post",
|
||||
"sidebar.importMedia": "Import media",
|
||||
"sidebar.results": "{count} results",
|
||||
"sidebar.resultsFor": "{count} results for \"{query}\"",
|
||||
"sidebar.clearFilters": "Clear filters",
|
||||
"sidebar.drafts": "Drafts",
|
||||
"sidebar.published": "Published",
|
||||
"sidebar.archived": "Archived",
|
||||
"sidebar.untitled": "Untitled",
|
||||
"sidebar.noMatchingPosts": "No matching posts",
|
||||
"sidebar.createFirstPost": "Create your first post",
|
||||
"sidebar.loadMore": "Load more ({loaded} of {total})",
|
||||
"sidebar.loading": "Loading...",
|
||||
"sidebar.noMediaFiles": "No media files",
|
||||
"sidebar.settingsHeader": "Settings",
|
||||
"sidebar.tagsHeader": "Tags",
|
||||
"sidebar.nav.project": "Project",
|
||||
"sidebar.archive": "Archivio",
|
||||
"sidebar.clearFilter": "Cancella filtro",
|
||||
"sidebar.tags": "Tag",
|
||||
"sidebar.categories": "Categorie",
|
||||
"sidebar.clearTags": "Cancella tag",
|
||||
"sidebar.clearCategories": "Cancella categorie",
|
||||
"sidebar.noPostsYet": "Nessun post",
|
||||
"sidebar.noPagesYet": "Nessuna pagina",
|
||||
"sidebar.noMediaYet": "Nessun media",
|
||||
"sidebar.search": "Cerca",
|
||||
"sidebar.searchPostsPlaceholder": "Cerca post...",
|
||||
"sidebar.searchPagesPlaceholder": "Cerca pagine...",
|
||||
"sidebar.searchMediaPlaceholder": "Cerca media...",
|
||||
"sidebar.toggleFilters": "Mostra/nascondi filtri",
|
||||
"sidebar.newPost": "Nuovo post",
|
||||
"sidebar.importMedia": "Importa media",
|
||||
"sidebar.results": "{count} risultati",
|
||||
"sidebar.resultsFor": "{count} risultati per \"{query}\"",
|
||||
"sidebar.clearFilters": "Cancella filtri",
|
||||
"sidebar.drafts": "Bozze",
|
||||
"sidebar.published": "Pubblicati",
|
||||
"sidebar.archived": "Archiviati",
|
||||
"sidebar.untitled": "Senza titolo",
|
||||
"sidebar.noMatchingPosts": "Nessun post corrispondente",
|
||||
"sidebar.createFirstPost": "Crea il tuo primo post",
|
||||
"sidebar.loadMore": "Carica altro ({loaded} di {total})",
|
||||
"sidebar.loading": "Caricamento...",
|
||||
"sidebar.noMediaFiles": "Nessun file multimediale",
|
||||
"sidebar.settingsHeader": "Impostazioni",
|
||||
"sidebar.tagsHeader": "Tag",
|
||||
"sidebar.nav.project": "Progetto",
|
||||
"sidebar.nav.editor": "Editor",
|
||||
"sidebar.nav.content": "Content",
|
||||
"sidebar.nav.ai": "AI Assistant",
|
||||
"sidebar.nav.publishing": "Publishing",
|
||||
"sidebar.nav.data": "Data",
|
||||
"sidebar.nav.style": "Style",
|
||||
"sidebar.tagCloud": "Tag Cloud",
|
||||
"sidebar.createEdit": "Create & Edit",
|
||||
"sidebar.mergeTags": "Merge Tags",
|
||||
"settings.project.descriptionGeneral": "General settings for the active blog project.",
|
||||
"settings.project.nameLabel": "Project Name",
|
||||
"settings.project.nameDescription": "The display name of your blog project.",
|
||||
"settings.project.namePlaceholder": "My Blog",
|
||||
"settings.project.descriptionLabel": "Description",
|
||||
"settings.project.descriptionDescription": "A short description of your blog. This can be used in templates and metadata.",
|
||||
"settings.project.descriptionPlaceholder": "A blog about...",
|
||||
"settings.project.dataPathLabel": "Project Data Path",
|
||||
"settings.project.dataPathDescription": "Custom folder for storing posts, media, and metadata. Leave empty to use the default location: {path}",
|
||||
"settings.project.defaultLocation": "Default location",
|
||||
"settings.project.publicUrlLabel": "Public URL",
|
||||
"settings.project.publicUrlDescription": "The public base URL of your published blog (used for sitemap generation).",
|
||||
"sidebar.nav.content": "Contenuto",
|
||||
"sidebar.nav.ai": "Assistente IA",
|
||||
"sidebar.nav.publishing": "Pubblicazione",
|
||||
"sidebar.nav.data": "Dati",
|
||||
"sidebar.nav.style": "Stile",
|
||||
"sidebar.tagCloud": "Nuvola tag",
|
||||
"sidebar.createEdit": "Crea e modifica",
|
||||
"sidebar.mergeTags": "Unisci tag",
|
||||
"settings.project.descriptionGeneral": "Impostazioni generali per il progetto blog attivo.",
|
||||
"settings.project.nameLabel": "Nome progetto",
|
||||
"settings.project.nameDescription": "Nome visualizzato del tuo progetto blog.",
|
||||
"settings.project.namePlaceholder": "Il mio blog",
|
||||
"settings.project.descriptionLabel": "Descrizione",
|
||||
"settings.project.descriptionDescription": "Breve descrizione del blog. Può essere usata in template e metadati.",
|
||||
"settings.project.descriptionPlaceholder": "Un blog su...",
|
||||
"settings.project.dataPathLabel": "Percorso dati progetto",
|
||||
"settings.project.dataPathDescription": "Cartella personalizzata per salvare post, media e metadati. Lascia vuoto per usare il percorso predefinito: {path}",
|
||||
"settings.project.defaultLocation": "Percorso predefinito",
|
||||
"settings.project.publicUrlLabel": "URL pubblica",
|
||||
"settings.project.publicUrlDescription": "URL base pubblica del blog pubblicato (usata per la generazione della sitemap).",
|
||||
"settings.project.publicUrlPlaceholder": "https://example.com",
|
||||
"settings.project.mainLanguageLabel": "Main Language",
|
||||
"settings.project.mainLanguageDescription": "The primary language for your blog content. AI-generated titles, alt text, and captions will use this language.",
|
||||
"settings.project.defaultAuthorLabel": "Default Author",
|
||||
"settings.project.defaultAuthorDescription": "The default author name for new posts and media. Can be overridden per item.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Author Name",
|
||||
"settings.project.maxPostsPerPageLabel": "Max Posts Per Page",
|
||||
"settings.project.maxPostsPerPageDescription": "Maximum number of posts shown per preview route page.",
|
||||
"settings.project.saveButton": "Save Project Settings",
|
||||
"editor.loadingPost": "Loading post...",
|
||||
"editor.unsavedChanges": "Unsaved changes (auto-saves on switch)",
|
||||
"editor.saving": "Saving...",
|
||||
"editor.publish": "Publish",
|
||||
"editor.publishTitle": "Save and make this post public",
|
||||
"editor.discardChanges": "Discard Changes",
|
||||
"editor.discardDraft": "Discard Draft",
|
||||
"editor.discardChangesTitle": "Revert to last published version",
|
||||
"editor.discardDraftTitle": "Delete this draft permanently",
|
||||
"editor.delete": "Delete",
|
||||
"editor.deleteTitle": "Delete this post permanently",
|
||||
"editor.field.title": "Title",
|
||||
"editor.field.tags": "Tags",
|
||||
"editor.field.author": "Author",
|
||||
"settings.project.mainLanguageLabel": "Lingua principale",
|
||||
"settings.project.mainLanguageDescription": "Lingua principale dei contenuti del blog. Titoli, alt text e didascalie generate dall’IA useranno questa lingua.",
|
||||
"settings.project.defaultAuthorLabel": "Autore predefinito",
|
||||
"settings.project.defaultAuthorDescription": "Nome autore predefinito per nuovi post e media. Può essere modificato per singolo elemento.",
|
||||
"settings.project.defaultAuthorPlaceholder": "Nome autore",
|
||||
"settings.project.maxPostsPerPageLabel": "Max post per pagina",
|
||||
"settings.project.maxPostsPerPageDescription": "Numero massimo di post mostrati per pagina di anteprima.",
|
||||
"settings.project.saveButton": "Salva impostazioni progetto",
|
||||
"editor.loadingPost": "Caricamento post...",
|
||||
"editor.unsavedChanges": "Modifiche non salvate (salvataggio automatico al cambio)",
|
||||
"editor.saving": "Salvataggio...",
|
||||
"editor.publish": "Pubblica",
|
||||
"editor.publishTitle": "Salva e rendi pubblico questo post",
|
||||
"editor.discardChanges": "Scarta modifiche",
|
||||
"editor.discardDraft": "Scarta bozza",
|
||||
"editor.discardChangesTitle": "Ripristina l’ultima versione pubblicata",
|
||||
"editor.discardDraftTitle": "Elimina definitivamente questa bozza",
|
||||
"editor.delete": "Elimina",
|
||||
"editor.deleteTitle": "Elimina definitivamente questo post",
|
||||
"editor.field.title": "Titolo",
|
||||
"editor.field.tags": "Tag",
|
||||
"editor.field.author": "Autore",
|
||||
"editor.field.slug": "Slug",
|
||||
"editor.field.categories": "Categories",
|
||||
"editor.field.content": "Content",
|
||||
"editor.placeholder.tags": "Add tags...",
|
||||
"editor.placeholder.author": "Author name",
|
||||
"editor.placeholder.categories": "Add categories...",
|
||||
"editor.placeholder.startWriting": "Start writing...",
|
||||
"editor.mode.visual": "Visual",
|
||||
"editor.mode.visualTitle": "Visual editor",
|
||||
"editor.mode.markdownTitle": "Markdown source",
|
||||
"editor.mode.previewTitle": "Read-only preview",
|
||||
"editor.galleryTitle": "View {count} image(s)",
|
||||
"editor.insertPostLinkTitle": "Link to post (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Insert image from media library",
|
||||
"editor.previewFrameTitle": "Post preview",
|
||||
"editor.previewLoading": "Loading preview...",
|
||||
"editor.footer.created": "Created",
|
||||
"editor.footer.updated": "Updated",
|
||||
"editor.footer.published": "Published"
|
||||
"editor.field.categories": "Categorie",
|
||||
"editor.field.content": "Contenuto",
|
||||
"editor.placeholder.tags": "Aggiungi tag...",
|
||||
"editor.placeholder.author": "Nome autore",
|
||||
"editor.placeholder.categories": "Aggiungi categorie...",
|
||||
"editor.placeholder.startWriting": "Inizia a scrivere...",
|
||||
"editor.mode.visual": "Visuale",
|
||||
"editor.mode.visualTitle": "Editor visuale",
|
||||
"editor.mode.markdownTitle": "Sorgente Markdown",
|
||||
"editor.mode.previewTitle": "Anteprima in sola lettura",
|
||||
"editor.galleryTitle": "Visualizza {count} immagine/i",
|
||||
"editor.insertPostLinkTitle": "Collega a post (Ctrl+K)",
|
||||
"editor.insertMediaTitle": "Inserisci immagine dalla libreria media",
|
||||
"editor.previewFrameTitle": "Anteprima post",
|
||||
"editor.previewLoading": "Caricamento anteprima...",
|
||||
"editor.footer.created": "Creato",
|
||||
"editor.footer.updated": "Aggiornato",
|
||||
"editor.footer.published": "Pubblicato",
|
||||
"projectSelector.switchProject": "Cambia progetto",
|
||||
"projectSelector.selectProject": "Seleziona progetto",
|
||||
"projectSelector.projectsHeader": "Progetti",
|
||||
"projectSelector.noProjectsYet": "Nessun progetto",
|
||||
"projectSelector.newProject": "Nuovo progetto",
|
||||
"projectSelector.createNewProject": "Crea nuovo progetto",
|
||||
"projectSelector.projectName": "Nome progetto",
|
||||
"projectSelector.projectNamePlaceholder": "Il mio blog",
|
||||
"projectSelector.descriptionOptional": "Descrizione (facoltativa)",
|
||||
"projectSelector.descriptionPlaceholder": "Breve descrizione del progetto...",
|
||||
"projectSelector.projectLocation": "Percorso progetto",
|
||||
"projectSelector.useDefaultLocation": "Usa percorso predefinito",
|
||||
"projectSelector.defaultInternalStorage": "Predefinito (archiviazione interna)",
|
||||
"projectSelector.chooseFolder": "Scegli cartella...",
|
||||
"projectSelector.projectLocationHint": "Scegli una cartella personalizzata per il backup cloud oppure usa l'archiviazione interna predefinita.",
|
||||
"projectSelector.createProject": "Crea progetto",
|
||||
"projectSelector.deleteProject": "Elimina progetto",
|
||||
"projectSelector.deleteWarning": "Questo eliminerà definitivamente il progetto \"{name}\" e tutti i suoi dati, inclusi:",
|
||||
"projectSelector.deleteItemPosts": "Tutti i post del blog",
|
||||
"projectSelector.deleteItemMedia": "Tutti i file multimediali",
|
||||
"projectSelector.deleteItemSettings": "Tutte le impostazioni del progetto",
|
||||
"projectSelector.typeToConfirm": "Digita {name} per confermare l'eliminazione:",
|
||||
"projectSelector.selectProjectLocation": "Seleziona percorso del progetto",
|
||||
"projectSelector.deleteProjectTitle": "Elimina {name}",
|
||||
"projectSelector.toast.switched": "Passato a {name}",
|
||||
"projectSelector.toast.switchFailed": "Cambio progetto non riuscito",
|
||||
"projectSelector.toast.created": "Progetto \"{name}\" creato",
|
||||
"projectSelector.toast.createFailed": "Creazione progetto non riuscita",
|
||||
"projectSelector.toast.existingSettingsFound": "Trovate impostazioni di progetto esistenti",
|
||||
"projectSelector.toast.selectFolderFailed": "Selezione cartella non riuscita",
|
||||
"projectSelector.toast.deletedWithData": "Progetto \"{name}\" e tutti i dati eliminati",
|
||||
"projectSelector.toast.deleteFailed": "Eliminazione progetto non riuscita",
|
||||
"tagsView.title": "Gestione tag",
|
||||
"tagsView.subtitle": "Gestisci i tag del blog, assegna colori ed esegui operazioni in blocco.",
|
||||
"tagsView.loadingTags": "Caricamento tag...",
|
||||
"tagsView.noTagsFound": "Nessun tag trovato",
|
||||
"tagsView.discoverFromPosts": "Scopri tag dai post",
|
||||
"tagsView.selectedCount": "{count} tag selezionati",
|
||||
"tagsView.clearSelection": "Cancella selezione",
|
||||
"tagsView.cloud.title": "Nuvola tag",
|
||||
"tagsView.cloud.description": "Fai clic sui tag per selezionarli per operazioni in blocco. Passa il mouse per vedere il numero di post.",
|
||||
"tagsView.manage.title": "Crea e modifica tag",
|
||||
"tagsView.manage.description": "Crea nuovi tag o modifica quelli esistenti. Assegna colori per distinguerli visivamente.",
|
||||
"tagsView.create.title": "Crea nuovo tag",
|
||||
"tagsView.create.action": "Crea",
|
||||
"tagsView.tagNamePlaceholder": "Nome tag",
|
||||
"tagsView.chooseColor": "Scegli colore",
|
||||
"tagsView.removeColor": "Rimuovi colore",
|
||||
"tagsView.edit.title": "Modifica tag: {name}",
|
||||
"tagsView.edit.action": "Modifica",
|
||||
"tagsView.deleteAction": "Elimina",
|
||||
"tagsView.merge.title": "Unisci tag",
|
||||
"tagsView.merge.description": "Seleziona più tag sopra, quindi uniscili in un unico tag. Tutti i post verranno aggiornati.",
|
||||
"tagsView.merge.selectAtLeastTwo": "Seleziona 2 o più tag dalla nuvola sopra per unirli.",
|
||||
"tagsView.merge.countInto": "Unisci {count} tag in:",
|
||||
"tagsView.merge.selectTarget": "Seleziona tag di destinazione...",
|
||||
"tagsView.merge.action": "Unisci tag",
|
||||
"tagsView.merge.tagsToDelete": "Tag da eliminare: {tags}",
|
||||
"tagsView.sync.title": "Sincronizza tag",
|
||||
"tagsView.sync.description": "Scopri i tag presenti nei post ma non nel database dei tag.",
|
||||
"tagsView.sync.action": "Sincronizza tag dai post",
|
||||
"tagsView.confirmDelete.title": "Elimina tag",
|
||||
"tagsView.confirmDelete.message": "Vuoi davvero eliminare il tag \"{tagName}\"? Verrà rimosso da tutti i post. Questa azione viene eseguita in background.",
|
||||
"tagsView.confirmDelete.action": "Elimina tag",
|
||||
"tagsView.confirmMerge.title": "Unisci tag",
|
||||
"tagsView.confirmMerge.message": "Vuoi davvero unire {count} tag in \"{target}\"? I tag di origine verranno eliminati e tutti i post saranno aggiornati. Questa azione viene eseguita in background.",
|
||||
"tagsView.confirmMerge.action": "Unisci tag",
|
||||
"tagsView.none": "(nessuno)",
|
||||
"tagsView.tagCountTitle": "{count} {item}",
|
||||
"tagsView.postsSingular": "post",
|
||||
"tagsView.postsPlural": "post",
|
||||
"tagsView.toast.tagNameRequired": "Il nome del tag è obbligatorio",
|
||||
"tagsView.toast.tagCreated": "Tag creato",
|
||||
"tagsView.toast.tagDeleted": "Tag eliminato. {postsUpdated} post aggiornati.",
|
||||
"tagsView.toast.tagUpdated": "Tag aggiornato",
|
||||
"tagsView.toast.targetTagNotFound": "Tag di destinazione non trovato",
|
||||
"tagsView.toast.noSourceTagsToMerge": "Nessun tag di origine da unire",
|
||||
"tagsView.toast.tagsMerged": "Uniti {tagsDeleted} tag in \"{targetTag}\". {postsUpdated} post aggiornati.",
|
||||
"tagsView.toast.discoveredTags": "Rilevati {count} nuovi tag",
|
||||
"tagsView.toast.alreadySynced": "Tutti i tag sono già sincronizzati",
|
||||
"tagsView.error.deleteFailedTitle": "Eliminazione non riuscita",
|
||||
"tagsView.error.mergeFailedTitle": "Unione non riuscita",
|
||||
"linkedMediaPanel.title": "📷 Media collegati",
|
||||
"linkedMediaPanel.collapsedTitle": "📷 Media ({count})",
|
||||
"linkedMediaPanel.importAndLink": "Importa e collega media",
|
||||
"linkedMediaPanel.linkExisting": "Collega media esistente",
|
||||
"linkedMediaPanel.selectMediaToLink": "Seleziona media da collegare",
|
||||
"linkedMediaPanel.searchPlaceholder": "Cerca media...",
|
||||
"linkedMediaPanel.noUnlinkedMedia": "Nessun media scollegato disponibile",
|
||||
"linkedMediaPanel.noMediaLinked": "Nessun media collegato a questo post",
|
||||
"linkedMediaPanel.importMedia": "Importa media",
|
||||
"linkedMediaPanel.unlinkFromPost": "Scollega dal post",
|
||||
"linkedMediaPanel.toast.importedLinked": "Importati e collegati {count} file",
|
||||
"linkedMediaPanel.toast.importFailed": "Importazione media non riuscita",
|
||||
"linkedMediaPanel.toast.unlinked": "Media scollegato dal post",
|
||||
"linkedMediaPanel.toast.unlinkFailed": "Scollegamento media non riuscito",
|
||||
"linkedMediaPanel.toast.linked": "Media collegato al post",
|
||||
"linkedMediaPanel.toast.linkFailed": "Collegamento media non riuscito",
|
||||
"styleView.title": "Stile",
|
||||
"styleView.subtitle": "Seleziona un tema Pico CSS e visualizza l'anteprima dei post principali prima di applicarlo.",
|
||||
"styleView.themePickerAria": "Selettore tema Pico",
|
||||
"styleView.previewMode": "Modalità anteprima",
|
||||
"styleView.mode.auto": "Auto",
|
||||
"styleView.mode.light": "Chiaro",
|
||||
"styleView.mode.dark": "Scuro",
|
||||
"styleView.applyTheme": "Applica tema",
|
||||
"styleView.themePreviewTitle": "Anteprima tema",
|
||||
"styleView.toast.appliedTheme": "Tema applicato: {theme}",
|
||||
"styleView.toast.applyThemeFailed": "Applicazione tema non riuscita",
|
||||
"panel.tabsAria": "Schede pannello",
|
||||
"panel.output": "Uscita",
|
||||
"panel.postLinks": "Link post",
|
||||
"panel.gitLog": "Registro Git",
|
||||
"panel.closeTitle": "Chiudi pannello",
|
||||
"panel.noRecentTasks": "Nessuna attività recente",
|
||||
"panel.noOutput": "Nessun output",
|
||||
"panel.openPostEditor": "Apri un editor post per visualizzare i collegamenti",
|
||||
"panel.loadingPostLinks": "Caricamento collegamenti post...",
|
||||
"panel.noPostLinks": "Nessun collegamento per questo post",
|
||||
"panel.openPostOrMediaEditor": "Apri un editor post o media per vedere il registro Git",
|
||||
"panel.loadingGitLog": "Caricamento registro Git...",
|
||||
"panel.noCommits": "Nessun commit trovato per questo elemento",
|
||||
"panel.error.loadPostLinks": "Impossibile caricare i collegamenti del post.",
|
||||
"panel.error.loadGitLog": "Impossibile caricare il registro Git.",
|
||||
"panel.direction.from": "da",
|
||||
"panel.direction.to": "a"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user