Merge pull request #31 from cadtoolbox/copilot/update-static-text-for-i18n

Internationalize Advanced Authentication strings
This commit is contained in:
Thomas Rambach
2026-02-10 10:00:34 -05:00
committed by GitHub
11 changed files with 1270 additions and 179 deletions
+11 -9
View File
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query';
import { X, Save, Loader2, Wifi, WifiOff, CheckCircle, Bell, Clock, LayoutGrid, Search, Plug, Power, Home, Radio, Eye } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { api } from '../api/client';
import type { SmartPlug, SmartPlugCreate, SmartPlugUpdate, DiscoveredTasmotaDevice } from '../api/client';
import { Button } from './Button';
@@ -11,6 +12,7 @@ interface AddSmartPlugModalProps {
}
export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
const { t } = useTranslation();
const queryClient = useQueryClient();
const isEditing = !!plug;
@@ -469,7 +471,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
{isScanning && scanProgress.total > 0 && (
<div className="space-y-1">
<div className="flex justify-between text-xs text-bambu-gray">
<span>Scanning network...</span>
<span>{t('smartPlugs.addSmartPlug.scanningNetwork')}</span>
<span>{scanProgress.scanned} / {scanProgress.total}</span>
</div>
<div className="w-full bg-bambu-dark-tertiary rounded-full h-2">
@@ -538,7 +540,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
disabled
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-bambu-gray cursor-not-allowed opacity-50"
>
<option>Choose an entity...</option>
<option>{t('smartPlugs.addSmartPlug.chooseEntity')}</option>
</select>
</div>
</div>
@@ -585,7 +587,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
setIsEntityDropdownOpen(true);
setHaEntitySearch('');
}}
placeholder="Search entities..."
placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEntities')}
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
/>
{haEntityId && !isEntityDropdownOpen && (
@@ -697,7 +699,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
setIsPowerDropdownOpen(true);
setPowerSensorSearch('');
}}
placeholder="Search power sensors..."
placeholder={t('smartPlugs.addSmartPlug.placeholders.searchPowerSensors')}
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
/>
{haPowerEntity && !isPowerDropdownOpen && (
@@ -781,7 +783,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
setIsEnergyTodayDropdownOpen(true);
setEnergyTodaySearch('');
}}
placeholder="Search energy sensors..."
placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEnergySensors')}
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
/>
{haEnergyTodayEntity && !isEnergyTodayDropdownOpen && (
@@ -865,7 +867,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
setIsEnergyTotalDropdownOpen(true);
setEnergyTotalSearch('');
}}
placeholder="Search energy sensors..."
placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEnergySensors')}
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
/>
{haEnergyTotalEntity && !isEnergyTotalDropdownOpen && (
@@ -1060,7 +1062,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
type="text"
value={mqttStateOnValue}
onChange={(e) => setMqttStateOnValue(e.target.value)}
placeholder="ON, true, 1"
placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttStateOnValue')}
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
/>
</div>
@@ -1128,7 +1130,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
) : (
<>
<WifiOff className="w-5 h-5" />
<span>Connection failed</span>
<span>{t('smartPlugs.addSmartPlug.connectionFailed')}</span>
</>
)}
</div>
@@ -1141,7 +1143,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Living Room Plug"
placeholder={t('smartPlugs.addSmartPlug.placeholders.plugName')}
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
/>
</div>
@@ -1,6 +1,7 @@
import { useState, useMemo, useEffect, useCallback } from 'react';
import { useQuery, useMutation } from '@tanstack/react-query';
import { X, Loader2, Settings2, ChevronDown, CheckCircle2, RotateCcw } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { api } from '../api/client';
import type { KProfile } from '../api/client';
import { Button } from './Button';
@@ -216,6 +217,7 @@ export function ConfigureAmsSlotModal({
nozzleDiameter = '0.4',
onSuccess,
}: ConfigureAmsSlotModalProps) {
const { t } = useTranslation();
const [selectedPresetId, setSelectedPresetId] = useState<string>('');
const [selectedKProfile, setSelectedKProfile] = useState<KProfile | null>(null);
const [colorHex, setColorHex] = useState<string>(''); // Just the 6-char hex, no alpha
@@ -569,7 +571,7 @@ export function ConfigureAmsSlotModal({
<div className="text-center space-y-3">
<CheckCircle2 className="w-16 h-16 text-bambu-green mx-auto" />
<p className="text-lg font-semibold text-white">Slot Configured!</p>
<p className="text-sm text-bambu-gray">Settings sent to printer</p>
<p className="text-sm text-bambu-gray">{t('configureAmsSlot.settingsSentToPrinter')}</p>
</div>
</div>
)}
@@ -607,7 +609,7 @@ export function ConfigureAmsSlotModal({
<div className="relative">
<input
type="text"
placeholder="Search presets..."
placeholder={t('configureAmsSlot.searchPresets')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder:text-bambu-gray focus:border-bambu-green focus:outline-none mb-2"
@@ -634,7 +636,7 @@ export function ConfigureAmsSlotModal({
<span className="text-white text-sm truncate">{preset.name}</span>
{isUserPreset(preset.setting_id) && (
<span className="text-xs px-1.5 py-0.5 rounded bg-bambu-blue/20 text-bambu-blue">
Custom
{t('configureAmsSlot.custom')}
</span>
)}
</div>
@@ -750,7 +752,7 @@ export function ConfigureAmsSlotModal({
/>
<input
type="text"
placeholder="Color name or hex (e.g., brown, FF8800)"
placeholder={t('configureAmsSlot.colorPlaceholder')}
value={colorInput}
onChange={(e) => {
const input = e.target.value;
@@ -780,7 +782,7 @@ export function ConfigureAmsSlotModal({
setColorInput('');
}}
className="px-2 py-1 text-xs text-bambu-gray hover:text-white bg-bambu-dark-tertiary rounded"
title="Clear custom color"
title={t('configureAmsSlot.clearCustomColor')}
>
Clear
</button>
+12 -12
View File
@@ -54,7 +54,7 @@ export function EmailSettings() {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['smtpSettings'] });
queryClient.invalidateQueries({ queryKey: ['advancedAuthStatus'] });
showToast('SMTP settings saved successfully', 'success');
showToast(t('settings.email.success.settingsSaved'), 'success');
},
onError: (error: Error) => {
showToast(error.message, 'error');
@@ -88,12 +88,12 @@ export function EmailSettings() {
const handleSave = () => {
// Validate required fields
if (!smtpSettings.smtp_host || !smtpSettings.smtp_from_email) {
showToast('Please fill in all required fields', 'error');
showToast(t('settings.email.errors.requiredFields'), 'error');
return;
}
// Validate auth fields when authentication is enabled
if (smtpSettings.smtp_auth_enabled && (!smtpSettings.smtp_username)) {
showToast('Username is required when authentication is enabled', 'error');
showToast(t('settings.email.errors.usernameRequired'), 'error');
return;
}
saveMutation.mutate(smtpSettings);
@@ -101,16 +101,16 @@ export function EmailSettings() {
const handleTest = () => {
if (!testEmail) {
showToast('Please enter a test email address', 'error');
showToast(t('settings.email.errors.enterTestEmail'), 'error');
return;
}
if (!smtpSettings.smtp_host || !smtpSettings.smtp_from_email) {
showToast('Please fill in SMTP Server and From Email before testing', 'error');
showToast(t('settings.email.errors.smtpServerAndEmail'), 'error');
return;
}
// Validate auth fields when authentication is enabled
if (smtpSettings.smtp_auth_enabled && (!smtpSettings.smtp_username || !smtpSettings.smtp_password)) {
showToast('Username and Password are required when authentication is enabled', 'error');
showToast(t('settings.email.errors.usernamePasswordRequired'), 'error');
return;
}
testMutation.mutate({
@@ -127,7 +127,7 @@ export function EmailSettings() {
const handleToggleAdvancedAuth = () => {
if (!advancedAuthStatus?.advanced_auth_enabled && !advancedAuthStatus?.smtp_configured) {
showToast('Please configure and test SMTP settings first', 'error');
showToast(t('settings.email.errors.configureSmtpFirst'), 'error');
return;
}
toggleAdvancedAuthMutation.mutate(!advancedAuthStatus?.advanced_auth_enabled);
@@ -189,9 +189,9 @@ export function EmailSettings() {
onChange={(e) => setSMTPSettings({ ...smtpSettings, smtp_security: e.target.value as 'starttls' | 'ssl' | 'none' })}
className="w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors"
>
<option value="starttls">STARTTLS (Port 587)</option>
<option value="ssl">SSL/TLS (Port 465)</option>
<option value="none">None (Port 25)</option>
<option value="starttls">{t('settings.email.securityOptions.starttls')}</option>
<option value="ssl">{t('settings.email.securityOptions.ssl')}</option>
<option value="none">{t('settings.email.securityOptions.none')}</option>
</select>
</div>
<div>
@@ -203,8 +203,8 @@ export function EmailSettings() {
onChange={(e) => setSMTPSettings({ ...smtpSettings, smtp_auth_enabled: e.target.value === 'true' })}
className="w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors"
>
<option value="true">Enabled</option>
<option value="false">Disabled</option>
<option value="true">{t('settings.email.authOptions.enabled')}</option>
<option value="false">{t('settings.email.authOptions.disabled')}</option>
</select>
</div>
</div>
@@ -1,6 +1,7 @@
import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Link2, Plus, Pencil, Trash2, GripVertical, Loader2, ExternalLink as ExternalLinkIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { api } from '../api/client';
import type { ExternalLink } from '../api/client';
import { Card, CardContent, CardHeader } from './Card';
@@ -10,6 +11,7 @@ import { ConfirmModal } from './ConfirmModal';
import { getIconByName } from './IconPicker';
export function ExternalLinksSettings() {
const { t } = useTranslation();
const queryClient = useQueryClient();
const [showAddModal, setShowAddModal] = useState(false);
const [editingLink, setEditingLink] = useState<ExternalLink | null>(null);
@@ -132,7 +134,7 @@ export function ExternalLinksSettings() {
<button
onClick={() => setEditingLink(link)}
className="p-2 rounded-lg hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors"
title="Edit"
title={t('common.edit')}
>
<Pencil className="w-4 h-4" />
</button>
@@ -140,7 +142,7 @@ export function ExternalLinksSettings() {
onClick={() => handleDelete(link)}
disabled={deleteMutation.isPending}
className="p-2 rounded-lg hover:bg-red-500/20 text-bambu-gray hover:text-red-400 transition-colors disabled:opacity-50"
title="Delete"
title={t('externalLinks.deleteLink')}
>
<Trash2 className="w-4 h-4" />
</button>
@@ -152,7 +154,7 @@ export function ExternalLinksSettings() {
) : (
<div className="text-center py-8 text-bambu-gray">
<Link2 className="w-8 h-8 mx-auto mb-2 opacity-50" />
<p>No external links configured</p>
<p>{t('externalLinks.noLinksConfigured')}</p>
<p className="text-sm">Click "Add Link" to add one</p>
</div>
)}
+12 -10
View File
@@ -18,6 +18,7 @@ import {
Link as LinkIcon,
Unlink,
} from 'lucide-react';
import { useTranslation } from 'react-i18next';
interface RichTextEditorProps {
content: string;
@@ -26,6 +27,7 @@ interface RichTextEditorProps {
}
export function RichTextEditor({ content, onChange, placeholder }: RichTextEditorProps) {
const { t } = useTranslation();
const editor = useEditor({
extensions: [
StarterKit.configure({
@@ -105,21 +107,21 @@ export function RichTextEditor({ content, onChange, placeholder }: RichTextEdito
<ToolbarButton
onClick={() => editor.chain().focus().toggleBold().run()}
isActive={editor.isActive('bold')}
title="Bold"
title={t('richTextEditor.bold')}
>
<Bold className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton
onClick={() => editor.chain().focus().toggleItalic().run()}
isActive={editor.isActive('italic')}
title="Italic"
title={t('richTextEditor.italic')}
>
<Italic className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton
onClick={() => editor.chain().focus().toggleUnderline().run()}
isActive={editor.isActive('underline')}
title="Underline"
title={t('richTextEditor.underline')}
>
<UnderlineIcon className="w-4 h-4" />
</ToolbarButton>
@@ -129,14 +131,14 @@ export function RichTextEditor({ content, onChange, placeholder }: RichTextEdito
<ToolbarButton
onClick={() => editor.chain().focus().toggleBulletList().run()}
isActive={editor.isActive('bulletList')}
title="Bullet List"
title={t('richTextEditor.bulletList')}
>
<List className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton
onClick={() => editor.chain().focus().toggleOrderedList().run()}
isActive={editor.isActive('orderedList')}
title="Numbered List"
title={t('richTextEditor.numberedList')}
>
<ListOrdered className="w-4 h-4" />
</ToolbarButton>
@@ -146,21 +148,21 @@ export function RichTextEditor({ content, onChange, placeholder }: RichTextEdito
<ToolbarButton
onClick={() => editor.chain().focus().setTextAlign('left').run()}
isActive={editor.isActive({ textAlign: 'left' })}
title="Align Left"
title={t('richTextEditor.alignLeft')}
>
<AlignLeft className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton
onClick={() => editor.chain().focus().setTextAlign('center').run()}
isActive={editor.isActive({ textAlign: 'center' })}
title="Align Center"
title={t('richTextEditor.alignCenter')}
>
<AlignCenter className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton
onClick={() => editor.chain().focus().setTextAlign('right').run()}
isActive={editor.isActive({ textAlign: 'right' })}
title="Align Right"
title={t('richTextEditor.alignRight')}
>
<AlignRight className="w-4 h-4" />
</ToolbarButton>
@@ -170,14 +172,14 @@ export function RichTextEditor({ content, onChange, placeholder }: RichTextEdito
<ToolbarButton
onClick={setLink}
isActive={editor.isActive('link')}
title="Add Link"
title={t('richTextEditor.addLink')}
>
<LinkIcon className="w-4 h-4" />
</ToolbarButton>
{editor.isActive('link') && (
<ToolbarButton
onClick={() => editor.chain().focus().unsetLink().run()}
title="Remove Link"
title={t('richTextEditor.removeLink')}
>
<Unlink className="w-4 h-4" />
</ToolbarButton>
+10 -8
View File
@@ -1,6 +1,7 @@
import { useState } from 'react';
import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query';
import { Plug, Power, PowerOff, Loader2, Trash2, Settings2, Thermometer, Clock, Wifi, WifiOff, Edit2, Bell, Calendar, LayoutGrid, ExternalLink, Home, Radio, Eye } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { api } from '../api/client';
import type { SmartPlug, SmartPlugUpdate } from '../api/client';
import { Card, CardContent } from './Card';
@@ -14,6 +15,7 @@ interface SmartPlugCardProps {
}
export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
const { t } = useTranslation();
const queryClient = useQueryClient();
const { showToast } = useToast();
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
@@ -171,7 +173,7 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
) : (
<div className="flex items-center gap-1 text-sm text-status-error">
<WifiOff className="w-4 h-4" />
<span>Offline</span>
<span>{t('smartPlugs.offline')}</span>
</div>
)}
{/* Admin page link - only for Tasmota */}
@@ -181,10 +183,10 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 px-2 py-0.5 bg-bambu-dark hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white text-xs rounded-full transition-colors"
title="Open plug admin page"
title={t('smartPlugs.openPlugAdminPage')}
>
<ExternalLink className="w-3 h-3" />
Admin
{t('smartPlugs.admin')}
</a>
)}
</div>
@@ -449,7 +451,7 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
{/* Delete Confirmation */}
{showDeleteConfirm && (
<ConfirmModal
title="Delete Smart Plug"
title={t('smartPlugs.deleteSmartPlug')}
message={`Are you sure you want to delete "${plug.name}"? This cannot be undone.`}
confirmText="Delete"
variant="danger"
@@ -464,9 +466,9 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
{/* Power On Confirmation */}
{showPowerOnConfirm && (
<ConfirmModal
title="Turn On Smart Plug"
title={t('smartPlugs.turnOnSmartPlug')}
message={`Are you sure you want to turn on "${plug.name}"?`}
confirmText="Turn On"
confirmText={t('smartPlugs.turnOn')}
variant="default"
onConfirm={() => {
controlMutation.mutate('on');
@@ -479,9 +481,9 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
{/* Power Off Confirmation */}
{showPowerOffConfirm && (
<ConfirmModal
title="Turn Off Smart Plug"
title={t('smartPlugs.turnOffSmartPlug')}
message={`Are you sure you want to turn off "${plug.name}"? This will cut power to the connected device.`}
confirmText="Turn Off"
confirmText={t('smartPlugs.turnOff')}
variant="danger"
onConfirm={() => {
controlMutation.mutate('off');
+371
View File
@@ -1030,6 +1030,30 @@ export default {
feature2: 'Benutzer können sich mit Benutzername oder E-Mail anmelden',
feature3: 'Passwort vergessen Funktion ist verfügbar',
feature4: 'Administratoren können Benutzerpasswörter per E-Mail zurücksetzen',
// Error messages
errors: {
requiredFields: 'Bitte füllen Sie alle Pflichtfelder aus',
usernameRequired: 'Benutzername ist erforderlich, wenn Authentifizierung aktiviert ist',
enterTestEmail: 'Bitte geben Sie eine Test-E-Mail-Adresse ein',
smtpServerAndEmail: 'Bitte füllen Sie SMTP-Server und Absender-E-Mail aus, bevor Sie testen',
usernamePasswordRequired: 'Benutzername und Passwort sind erforderlich, wenn Authentifizierung aktiviert ist',
configureSmtpFirst: 'Bitte konfigurieren und testen Sie zuerst die SMTP-Einstellungen',
},
// Success messages
success: {
settingsSaved: 'SMTP-Einstellungen erfolgreich gespeichert',
},
// Security options
securityOptions: {
starttls: 'STARTTLS (Port 587)',
ssl: 'SSL/TLS (Port 465)',
none: 'Keine (Port 25)',
},
// Authentication options
authOptions: {
enabled: 'Aktiviert',
disabled: 'Deaktiviert',
},
},
appearance: 'Erscheinungsbild',
notifications: 'Benachrichtigungen',
@@ -2286,6 +2310,9 @@ export default {
noPrintersAvailable: 'Keine Drucker verfügbar',
printerBusy: 'Drucker ist beschäftigt',
printerOffline: 'Drucker ist offline',
sameTypeDifferentColor: 'Gleicher Typ, andere Farbe',
filamentTypeNotLoaded: 'Filamenttyp nicht geladen',
openCalendar: 'Kalender öffnen',
},
// Backup
@@ -2640,4 +2667,348 @@ export default {
replaceCarbonFilter: 'Aktivkohlefilter ersetzen',
lubricateLeftNozzleRail: 'Linke Düsenschiene schmieren (H2-Serie)',
},
// Smart Plugs
smartPlugs: {
offline: 'Offline',
admin: 'Admin',
openPlugAdminPage: 'Plug-Admin-Seite öffnen',
deleteSmartPlug: 'Smart Plug löschen',
turnOnSmartPlug: 'Smart Plug einschalten',
turnOffSmartPlug: 'Smart Plug ausschalten',
turnOn: 'Einschalten',
turnOff: 'Ausschalten',
addSmartPlug: {
scanningNetwork: 'Netzwerk wird durchsucht...',
chooseEntity: 'Entität auswählen...',
connectionFailed: 'Verbindung fehlgeschlagen',
searchEntities: 'Entitäten suchen...',
searchPowerSensors: 'Leistungssensoren suchen...',
searchEnergySensors: 'Energiesensoren suchen...',
placeholders: {
plugName: 'Wohnzimmer Steckdose',
mqttStateOnValue: 'ON, true, 1',
mqttSameAsPower: 'Gleich wie Leistungs-Topic oder anders',
},
},
},
// Rich Text Editor
richTextEditor: {
bold: 'Fett',
italic: 'Kursiv',
underline: 'Unterstrichen',
bulletList: 'Aufzählungsliste',
numberedList: 'Nummerierte Liste',
alignLeft: 'Linksbündig',
alignCenter: 'Zentriert',
alignRight: 'Rechtsbündig',
addLink: 'Link hinzufügen',
removeLink: 'Link entfernen',
},
// External Links
externalLinks: {
noLinksConfigured: 'Keine externen Links konfiguriert',
deleteLink: 'Link löschen',
removeCustomIcon: 'Benutzerdefiniertes Symbol entfernen',
placeholders: {
linkName: 'Mein Link',
},
},
// Keyboard Shortcuts Modal
keyboardShortcuts: {
title: 'Tastaturkürzel',
navigation: 'Navigation',
archivesSection: 'Archive',
kProfilesSection: 'K-Profile',
generalSection: 'Allgemein',
shortcuts: {
goToPrinters: 'Zu Drucker gehen',
goToArchives: 'Zu Archiv gehen',
goToQueue: 'Zur Warteschlange gehen',
goToStats: 'Zu Statistiken gehen',
goToProfiles: 'Zu Cloud-Profilen gehen',
goToSettings: 'Zu Einstellungen gehen',
focusSearch: 'Suche fokussieren',
openUploadModal: 'Upload-Modal öffnen',
clearSelection: 'Auswahl löschen / Eingabe aufheben',
contextMenu: 'Kontextmenü auf Karten',
refreshProfiles: 'Profile aktualisieren',
newProfile: 'Neues Profil',
exitSelectionMode: 'Auswahlmodus beenden',
showHelp: 'Diese Hilfe anzeigen',
},
footer: 'Drücken Sie Esc oder klicken Sie außerhalb, um zu schließen',
},
// Notification Log
notificationLog: {
title: 'Benachrichtigungsprotokoll',
events: {
printStarted: 'Druck gestartet',
printComplete: 'Druck abgeschlossen',
printFailed: 'Druck fehlgeschlagen',
printStopped: 'Druck gestoppt',
progress: 'Fortschritt',
printerOffline: 'Drucker offline',
printerError: 'Druckerfehler',
lowFilament: 'Wenig Filament',
maintenanceDue: 'Wartung fällig',
test: 'Test',
},
timeAgo: {
justNow: 'Gerade eben',
minutesAgo: 'vor {{minutes}}m',
hoursAgo: 'vor {{hours}}h',
},
},
// Restore/Backup Modal
restoreBackup: {
title: 'Backup wiederherstellen',
restoring: 'Wird wiederhergestellt...',
restoreComplete: 'Wiederherstellung abgeschlossen',
restoreFailed: 'Wiederherstellung fehlgeschlagen',
importSettings: 'Einstellungen aus Backup-Datei importieren',
pleaseWait: 'Bitte warten Sie, während Ihre Daten wiederhergestellt werden',
clickToSelect: 'Klicken Sie, um Backup-Datei auszuwählen (.json oder .zip)',
howDuplicateHandling: 'So funktioniert die Duplikatbehandlung:',
categories: {
printers: 'Drucker',
smartPlugs: 'Smart Plugs',
notificationProviders: 'Benachrichtigungsanbieter',
filaments: 'Filamente',
archives: 'Archive',
pendingUploads: 'Ausstehende Uploads',
settingsTemplates: 'Einstellungen & Vorlagen',
},
matchingInfo: {
printers: 'abgeglichen nach Seriennummer',
smartPlugs: 'abgeglichen nach IP-Adresse',
notificationProviders: 'abgeglichen nach Name',
filaments: 'abgeglichen nach Name + Typ + Marke',
archives: 'abgeglichen nach Inhalts-Hash',
pendingUploads: 'abgeglichen nach Dateiname',
settingsTemplates: 'immer überschrieben',
},
replaceExisting: 'Vorhandene Daten ersetzen',
keepExisting: 'Vorhandene Daten behalten',
replaceDescription: 'Bereits vorhandene Elemente mit Backup-Daten überschreiben',
keepDescription: 'Nur Elemente wiederherstellen, die noch nicht existieren',
caution: 'Vorsicht:',
cautionText: 'Das Überschreiben ersetzt Ihre aktuellen Konfigurationen durch Backup-Daten. Drucker-Zugangscodes werden aus Sicherheitsgründen niemals überschrieben.',
itemsRestored: 'Wiederhergestellte Elemente',
itemsSkipped: 'Übersprungene Elemente',
restored: 'Wiederhergestellt',
skipped: 'Übersprungen (existieren bereits)',
filesLabel: 'Dateien (3MF, Thumbnails, etc.)',
newApiKeysGenerated: 'Neue API-Schlüssel generiert',
newApiKeysWarning: 'Diese Schlüssel werden nur einmal angezeigt. Kopieren Sie sie jetzt!',
processingBackup: 'Backup-Datei wird verarbeitet...',
noDataFound: 'In der Backup-Datei wurden keine wiederherzustellenden Daten gefunden.',
failedToRestore: 'Backup konnte nicht wiederhergestellt werden. Bitte überprüfen Sie das Dateiformat.',
},
// Backup Export Modal
backupExport: {
title: 'Backup exportieren',
selectData: 'Zu exportierende Daten auswählen',
selectAll: 'Alle auswählen',
selectNone: 'Keine auswählen',
categoryDescriptions: {
settings: 'Sprache, Theme, Update-Einstellungen',
notifications: 'ntfy, Pushover, Discord, usw.',
templates: 'Benutzerdefinierte Nachrichtenvorlagen',
smartPlugs: 'Tasmota-Plug-Konfigurationen',
externalLinks: 'Seitenleiste Links zu externen Diensten',
printers: 'Druckerinformationen (Zugangscodes ausgeschlossen)',
plateDetection: 'Leere Platten-Referenzbilder',
filaments: 'Filamenttypen und -kosten',
maintenance: 'Benutzerdefinierte Wartungspläne',
archives: 'Alle Druckdaten + Dateien (3MF, Thumbnails, Fotos)',
projects: 'Projekte, BOM-Elemente und Anhänge',
pendingUploads: 'Virtueller Drucker-Uploads zur Überprüfung',
apiKeys: 'Webhook-API-Schlüssel (neue Schlüssel bei Import generiert)',
},
requiresPrinters: 'Drucker müssen ausgewählt sein',
zipFileWarning: 'ZIP-Datei wird erstellt.',
zipFileDescription: 'Enthält alle 3MF-Dateien, Thumbnails, Zeitraffer und Fotos. Dies kann eine Weile dauern und zu einer großen Datei führen.',
includeAccessCodes: 'Zugangscodes einschließen',
includeAccessCodesDescription: 'Für die Übertragung auf eine andere Maschine',
includeAccessCodesWarning: 'Zugangscodes werden im Klartext eingeschlossen. Bewahren Sie diese Backup-Datei sicher auf!',
categoriesSelected: '{{selectedCount}} Kategorien ausgewählt',
},
// Pending Uploads Panel
pendingUploads: {
placeholders: {
notes: 'Notizen zu diesem Druck hinzufügen...',
},
discardUpload: 'Upload verwerfen',
archiveAllUploads: 'Alle Uploads archivieren',
discardAllUploads: 'Alle Uploads verwerfen',
archive: 'Archivieren',
timeAgo: {
justNow: 'Gerade eben',
minutesAgo: 'vor {{minutes}}m',
hoursAgo: 'vor {{hours}}h',
daysAgo: 'vor {{days}}d',
},
},
// API Browser
apiBrowser: {
placeholders: {
requestBody: 'JSON-Anforderungstext...',
searchEndpoints: 'Endpunkte suchen...',
},
},
// Configure AMS Slot Modal
configureAmsSlot: {
searchPresets: 'Voreinstellungen suchen...',
colorPlaceholder: 'Farbname oder Hex (z.B. braun, FF8800)',
clearCustomColor: 'Benutzerdefinierte Farbe löschen',
noCloudPresets: 'Keine Cloud-Voreinstellungen. Melden Sie sich bei Bambu Cloud an, um zu synchronisieren.',
noMatchingPresets: 'Keine passenden Voreinstellungen gefunden.',
custom: 'Benutzerdefiniert',
settingsSentToPrinter: 'Einstellungen an Drucker gesendet',
filamentProfile: 'Filamentprofil',
},
// GitHub Backup Settings
githubBackup: {
title: 'GitHub-Backup',
history: 'Verlauf',
downloadBackup: 'Backup herunterladen',
restoreBackup: 'Backup wiederherstellen',
noBackupsYet: 'Noch keine Backups',
},
// Email Settings
emailSettings: {
placeholders: {
fromName: 'BamBuddy',
},
},
// Tag Management Modal
tagManagement: {
searchTags: 'Tags suchen...',
renameTag: 'Tag umbenennen',
deleteTag: 'Tag löschen',
},
// Notification Template Editor
notificationTemplates: {
placeholders: {
title: 'Benachrichtigungstitel...',
body: 'Benachrichtigungstext...',
},
},
// Batch Tag Modal
batchTag: {
placeholders: {
newTag: 'Neuen Tag eingeben...',
},
},
// Photo Gallery Modal
photoGallery: {
deletePhoto: 'Foto löschen',
},
// Filament Hover Card
filamentHoverCard: {
copySpoolUuid: 'Spulen-UUID kopieren',
},
// K Profiles View
kProfilesView: {
hasNote: 'Hat Notiz',
copyProfile: 'Profil kopieren',
},
// Layout/Navigation
layout: {
openMenu: 'Menü öffnen',
noPermissionSystemInfo: 'Sie haben keine Berechtigung zum Anzeigen von Systeminformationen',
},
// Dashboard
dashboard: {
dragToReorder: 'Ziehen zum Neuordnen',
hideWidget: 'Widget ausblenden',
},
// Notification Provider Card
notificationProviderCard: {
deleteNotificationProvider: 'Benachrichtigungsanbieter löschen',
},
// File Manager Modal
fileManagerModal: {
closeFileManager: 'Dateimanager schließen',
sortFiles: 'Dateien sortieren',
goToParentFolder: 'Zum übergeordneten Ordner gehen',
threeView: '3D-Ansicht',
},
// Embedded Camera Viewer
embeddedCameraViewer: {
refreshStream: 'Stream aktualisieren',
close: 'Schließen',
zoomOut: 'Verkleinern',
resetZoom: 'Zoom zurücksetzen',
zoomIn: 'Vergrößern',
dragToResize: 'Ziehen zum Größe ändern',
},
// Timelapse Viewer
timelapseViewer: {
skipBack5s: '5s zurückspringen',
skipForward5s: '5s vorspringen',
},
// Notification Providers
notificationProviders: {
descriptions: {
email: 'SMTP-E-Mail-Benachrichtigungen',
telegram: 'Benachrichtigungen über Telegram-Bot',
discord: 'An Discord-Kanal über Webhook senden',
ntfy: 'Kostenlose, selbst hostbare Push-Benachrichtigungen',
pushover: 'Einfache, zuverlässige Push-Benachrichtigungen',
callmebot: 'Kostenlose WhatsApp-Benachrichtigungen über CallMeBot',
webhook: 'Generischer HTTP POST zu beliebiger URL',
},
},
// Log Viewer
logViewer: {
searchPlaceholder: 'Nachricht oder Logger-Name suchen...',
noLogEntries: 'Keine Logeinträge gefunden',
},
// Switchbar Popover
switchbarPopover: {
noSwitchesInSwitchbar: 'Keine Schalter in Schalterleiste',
},
// Project Page Modal
projectPageModal: {
placeholders: {
title: 'Titel',
designer: 'Designer',
license: 'Lizenz',
description: 'Beschreibung eingeben...',
profileTitle: 'Profil-Titel',
profileDescription: 'Profilbeschreibung...',
},
},
// Spoolman Settings
spoolmanSettings: {},
};
+372
View File
@@ -1030,6 +1030,30 @@ export default {
feature2: 'Users can login with username or email',
feature3: 'Forgot password feature is available',
feature4: 'Admins can reset user passwords via email',
// Error messages
errors: {
requiredFields: 'Please fill in all required fields',
usernameRequired: 'Username is required when authentication is enabled',
enterTestEmail: 'Please enter a test email address',
smtpServerAndEmail: 'Please fill in SMTP Server and From Email before testing',
usernamePasswordRequired: 'Username and Password are required when authentication is enabled',
configureSmtpFirst: 'Please configure and test SMTP settings first',
},
// Success messages
success: {
settingsSaved: 'SMTP settings saved successfully',
},
// Security options
securityOptions: {
starttls: 'STARTTLS (Port 587)',
ssl: 'SSL/TLS (Port 465)',
none: 'None (Port 25)',
},
// Authentication options
authOptions: {
enabled: 'Enabled',
disabled: 'Disabled',
},
},
appearance: 'Appearance',
notifications: 'Notifications',
@@ -2286,6 +2310,9 @@ export default {
noPrintersAvailable: 'No printers available',
printerBusy: 'Printer is busy',
printerOffline: 'Printer is offline',
sameTypeDifferentColor: 'Same type, different color',
filamentTypeNotLoaded: 'Filament type not loaded',
openCalendar: 'Open calendar',
},
// Backup
@@ -2338,6 +2365,7 @@ export default {
},
// Edit archive modal
// Edit Archive Modal
editArchive: {
title: 'Edit Archive',
name: 'Name',
@@ -2640,4 +2668,348 @@ export default {
replaceCarbonFilter: 'Replace activated carbon filter',
lubricateLeftNozzleRail: 'Lubricate left nozzle rail (H2 series)',
},
// Smart Plugs
smartPlugs: {
offline: 'Offline',
admin: 'Admin',
openPlugAdminPage: 'Open plug admin page',
deleteSmartPlug: 'Delete Smart Plug',
turnOnSmartPlug: 'Turn On Smart Plug',
turnOffSmartPlug: 'Turn Off Smart Plug',
turnOn: 'Turn On',
turnOff: 'Turn Off',
addSmartPlug: {
scanningNetwork: 'Scanning network...',
chooseEntity: 'Choose an entity...',
connectionFailed: 'Connection failed',
searchEntities: 'Search entities...',
searchPowerSensors: 'Search power sensors...',
searchEnergySensors: 'Search energy sensors...',
placeholders: {
plugName: 'Living Room Plug',
mqttStateOnValue: 'ON, true, 1',
mqttSameAsPower: 'Same as power topic, or different',
},
},
},
// Rich Text Editor
richTextEditor: {
bold: 'Bold',
italic: 'Italic',
underline: 'Underline',
bulletList: 'Bullet List',
numberedList: 'Numbered List',
alignLeft: 'Align Left',
alignCenter: 'Align Center',
alignRight: 'Align Right',
addLink: 'Add Link',
removeLink: 'Remove Link',
},
// External Links
externalLinks: {
noLinksConfigured: 'No external links configured',
deleteLink: 'Delete Link',
removeCustomIcon: 'Remove custom icon',
placeholders: {
linkName: 'My Link',
},
},
// Keyboard Shortcuts Modal
keyboardShortcuts: {
title: 'Keyboard Shortcuts',
navigation: 'Navigation',
archivesSection: 'Archives',
kProfilesSection: 'K-Profiles',
generalSection: 'General',
shortcuts: {
goToPrinters: 'Go to Printers',
goToArchives: 'Go to Archives',
goToQueue: 'Go to Queue',
goToStats: 'Go to Statistics',
goToProfiles: 'Go to Cloud Profiles',
goToSettings: 'Go to Settings',
focusSearch: 'Focus search',
openUploadModal: 'Open upload modal',
clearSelection: 'Clear selection / blur input',
contextMenu: 'Context menu on cards',
refreshProfiles: 'Refresh profiles',
newProfile: 'New profile',
exitSelectionMode: 'Exit selection mode',
showHelp: 'Show this help',
},
footer: 'Press Esc or click outside to close',
},
// Notification Log
notificationLog: {
title: 'Notification Log',
events: {
printStarted: 'Print Started',
printComplete: 'Print Complete',
printFailed: 'Print Failed',
printStopped: 'Print Stopped',
progress: 'Progress',
printerOffline: 'Printer Offline',
printerError: 'Printer Error',
lowFilament: 'Low Filament',
maintenanceDue: 'Maintenance Due',
test: 'Test',
},
timeAgo: {
justNow: 'Just now',
minutesAgo: '{{minutes}}m ago',
hoursAgo: '{{hours}}h ago',
},
},
// Restore/Backup Modal
restoreBackup: {
title: 'Restore Backup',
restoring: 'Restoring...',
restoreComplete: 'Restore Complete',
restoreFailed: 'Restore Failed',
importSettings: 'Import settings from a backup file',
pleaseWait: 'Please wait while your data is being restored',
clickToSelect: 'Click to select backup file (.json or .zip)',
howDuplicateHandling: 'How duplicate handling works:',
categories: {
printers: 'Printers',
smartPlugs: 'Smart Plugs',
notificationProviders: 'Notification Providers',
filaments: 'Filaments',
archives: 'Archives',
pendingUploads: 'Pending Uploads',
settingsTemplates: 'Settings & Templates',
},
matchingInfo: {
printers: 'matched by serial number',
smartPlugs: 'matched by IP address',
notificationProviders: 'matched by name',
filaments: 'matched by name + type + brand',
archives: 'matched by content hash',
pendingUploads: 'matched by filename',
settingsTemplates: 'always overwritten',
},
replaceExisting: 'Replace existing data',
keepExisting: 'Keep existing data',
replaceDescription: 'Overwrite items that already exist with backup data',
keepDescription: 'Only restore items that don\'t already exist',
caution: 'Caution:',
cautionText: 'Overwriting will replace your current configurations with backup data. Printer access codes are never overwritten for security.',
itemsRestored: 'Items Restored',
itemsSkipped: 'Items Skipped',
restored: 'Restored',
skipped: 'Skipped (already exist)',
filesLabel: 'Files (3MF, thumbnails, etc.)',
newApiKeysGenerated: 'New API Keys Generated',
newApiKeysWarning: 'These keys are only shown once. Copy them now!',
processingBackup: 'Processing backup file...',
noDataFound: 'No data was found to restore in the backup file.',
failedToRestore: 'Failed to restore backup. Please check the file format.',
},
// Backup Export Modal
backupExport: {
title: 'Export Backup',
selectData: 'Select data to include',
selectAll: 'Select All',
selectNone: 'Select None',
categoryDescriptions: {
settings: 'Language, theme, update preferences',
notifications: 'ntfy, Pushover, Discord, etc.',
templates: 'Custom message templates',
smartPlugs: 'Tasmota plug configurations',
externalLinks: 'Sidebar links to external services',
printers: 'Printer info (access codes excluded)',
plateDetection: 'Empty plate reference images',
filaments: 'Filament types and costs',
maintenance: 'Custom maintenance schedules',
archives: 'All print data + files (3MF, thumbnails, photos)',
projects: 'Projects, BOM items, and attachments',
pendingUploads: 'Virtual printer uploads awaiting review',
apiKeys: 'Webhook API keys (new keys generated on import)',
},
requiresPrinters: 'Requires Printers to be selected',
zipFileWarning: 'ZIP file will be created.',
zipFileDescription: 'Includes all 3MF files, thumbnails, timelapses, and photos. This may take a while and result in a large file.',
includeAccessCodes: 'Include Access Codes',
includeAccessCodesDescription: 'For transferring to another machine',
includeAccessCodesWarning: 'Access codes will be included in plain text. Keep this backup file secure!',
categoriesSelected: '{{selectedCount}} categories selected',
},
// Pending Uploads Panel
pendingUploads: {
placeholders: {
notes: 'Add notes about this print...',
},
discardUpload: 'Discard Upload',
archiveAllUploads: 'Archive All Uploads',
discardAllUploads: 'Discard All Uploads',
archive: 'Archive',
timeAgo: {
justNow: 'Just now',
minutesAgo: '{{minutes}}m ago',
hoursAgo: '{{hours}}h ago',
daysAgo: '{{days}}d ago',
},
},
// API Browser
apiBrowser: {
placeholders: {
requestBody: 'JSON request body...',
searchEndpoints: 'Search endpoints...',
},
},
// Configure AMS Slot Modal
configureAmsSlot: {
searchPresets: 'Search presets...',
colorPlaceholder: 'Color name or hex (e.g., brown, FF8800)',
clearCustomColor: 'Clear custom color',
noCloudPresets: 'No cloud presets. Login to Bambu Cloud to sync.',
noMatchingPresets: 'No matching presets found.',
custom: 'Custom',
settingsSentToPrinter: 'Settings sent to printer',
filamentProfile: 'Filament Profile',
},
// GitHub Backup Settings
githubBackup: {
title: 'GitHub Backup',
history: 'History',
downloadBackup: 'Download Backup',
restoreBackup: 'Restore Backup',
noBackupsYet: 'No backups yet',
},
// Email Settings
emailSettings: {
placeholders: {
fromName: 'BamBuddy',
},
},
// Tag Management Modal
tagManagement: {
searchTags: 'Search tags...',
renameTag: 'Rename tag',
deleteTag: 'Delete tag',
},
// Notification Template Editor
notificationTemplates: {
placeholders: {
title: 'Notification title...',
body: 'Notification body...',
},
},
// Batch Tag Modal
batchTag: {
placeholders: {
newTag: 'Enter new tag...',
},
},
// Photo Gallery Modal
photoGallery: {
deletePhoto: 'Delete Photo',
},
// Filament Hover Card
filamentHoverCard: {
copySpoolUuid: 'Copy spool UUID',
},
// K Profiles View
kProfilesView: {
hasNote: 'Has note',
copyProfile: 'Copy profile',
},
// Layout/Navigation
layout: {
openMenu: 'Open menu',
noPermissionSystemInfo: 'You do not have permission to view system information',
},
// Dashboard
dashboard: {
dragToReorder: 'Drag to reorder',
hideWidget: 'Hide widget',
},
// Notification Provider Card
notificationProviderCard: {
deleteNotificationProvider: 'Delete Notification Provider',
},
// File Manager Modal
fileManagerModal: {
closeFileManager: 'Close file manager',
sortFiles: 'Sort files',
goToParentFolder: 'Go to parent folder',
threeView: '3D View',
},
// Embedded Camera Viewer
embeddedCameraViewer: {
refreshStream: 'Refresh stream',
close: 'Close',
zoomOut: 'Zoom out',
resetZoom: 'Reset zoom',
zoomIn: 'Zoom in',
dragToResize: 'Drag to resize',
},
// Timelapse Viewer
timelapseViewer: {
skipBack5s: 'Skip back 5s',
skipForward5s: 'Skip forward 5s',
},
// Notification Providers
notificationProviders: {
descriptions: {
email: 'SMTP email notifications',
telegram: 'Notifications via Telegram bot',
discord: 'Send to Discord channel via webhook',
ntfy: 'Free, self-hostable push notifications',
pushover: 'Simple, reliable push notifications',
callmebot: 'Free WhatsApp notifications via CallMeBot',
webhook: 'Generic HTTP POST to any URL',
},
},
// Log Viewer
logViewer: {
searchPlaceholder: 'Search message or logger name...',
noLogEntries: 'No log entries found',
},
// Switchbar Popover
switchbarPopover: {
noSwitchesInSwitchbar: 'No switches in switchbar',
},
// Project Page Modal
projectPageModal: {
placeholders: {
title: 'Title',
designer: 'Designer',
license: 'License',
description: 'Enter description...',
profileTitle: 'Profile Title',
profileDescription: 'Profile description...',
},
},
// Spoolman Settings
spoolmanSettings: {},
};
+338
View File
@@ -1182,6 +1182,30 @@ export default {
feature2: 'ユーザーはユーザー名またはメールでログインできます',
feature3: 'パスワード忘れ機能が利用可能です',
feature4: '管理者はメールでユーザーパスワードをリセットできます',
// Error messages
errors: {
requiredFields: 'すべての必須フィールドに入力してください',
usernameRequired: '認証が有効な場合、ユーザー名は必須です',
enterTestEmail: 'テストメールアドレスを入力してください',
smtpServerAndEmail: 'テストする前にSMTPサーバーと送信元メールを入力してください',
usernamePasswordRequired: '認証が有効な場合、ユーザー名とパスワードは必須です',
configureSmtpFirst: '最初にSMTP設定を構成してテストしてください',
},
// Success messages
success: {
settingsSaved: 'SMTP設定を保存しました',
},
// Security options
securityOptions: {
starttls: 'STARTTLS (ポート 587)',
ssl: 'SSL/TLS (ポート 465)',
none: 'なし (ポート 25)',
},
// Authentication options
authOptions: {
enabled: '有効',
disabled: '無効',
},
},
// General - Date/Time
@@ -1801,6 +1825,20 @@ export default {
ams_humidity_high: 'AMS湿度高',
ams_temperature_high: 'AMS温度高',
test: 'テスト',
printStarted: '印刷開始',
printComplete: '印刷完了',
printFailed: '印刷失敗',
printStopped: '印刷停止',
progress: '進捗',
printerOffline: 'プリンターオフライン',
printerError: 'プリンターエラー',
lowFilament: 'フィラメント残量少',
maintenanceDue: 'メンテナンス期限',
},
timeAgo: {
justNow: 'たった今',
minutesAgo: '{{minutes}}分前',
hoursAgo: '{{hours}}時間前',
},
},
@@ -2078,6 +2116,7 @@ export default {
selectAModel: 'モデルを選択...',
locationFilterLabel: 'ロケーションフィルター(任意)',
anyLocation: 'すべてのロケーション',
openCalendar: 'カレンダーを開く',
},
// ログインページ
@@ -2514,6 +2553,19 @@ export default {
discardedCount: '{{count}}ファイルを破棄しました',
archiveAllFailed: 'すべてのアーカイブに失敗しました',
discardAllFailed: 'すべての破棄に失敗しました',
placeholders: {
tags: '例: 機能的、プロトタイプ、ギフト',
notes: 'この印刷についてのメモを追加...',
},
discardUpload: 'アップロードを破棄',
archiveAllUploads: 'すべてのアップロードをアーカイブ',
discardAllUploads: 'すべてのアップロードを破棄',
timeAgo: {
justNow: 'たった今',
minutesAgo: '{{minutes}}分前',
hoursAgo: '{{hours}}時間前',
daysAgo: '{{days}}日前',
},
},
// キーボードショートカット
@@ -2558,6 +2610,7 @@ export default {
emptyLog: 'ログファイルが空またはクリアされています',
autoRefreshing: '2秒ごとに自動更新中',
clickStart: '開始をクリックしてライブログストリーミングを有効にする',
noLogEntries: 'ログエントリが見つかりません',
},
// アーカイブ編集モーダル
@@ -3097,6 +3150,10 @@ export default {
collapseAll: 'すべて折りたたむ',
swaggerUI: 'Swagger UI',
endpointCount: '{{categories}}カテゴリー内{{count}}エンドポイント',
placeholders: {
requestBody: 'JSONリクエストボディ...',
searchEndpoints: 'エンドポイントを検索...',
},
},
githubBackup: {
title: 'GitHubバックアップ',
@@ -3190,4 +3247,285 @@ export default {
unsupportedFormat: 'サポートされていないファイル形式です',
},
},
// Maintenance type descriptions (built-in)
maintenanceDescriptions: {
lubricateRails: 'リニアレールに潤滑剤を塗布してスムーズな動きを実現',
cleanNozzle: 'ホットエンドとノズルを清掃して詰まりを防止',
checkBelts: 'ベルトの張力を確認して正確な印刷を実現',
cleanBuildPlate: 'ビルドプレートを清掃して接着力を向上',
checkExtruder: 'エクストルーダーギアの摩耗を検査',
checkCooling: '冷却ファンが正常に動作していることを確認',
generalInspection: 'プリンターの一般的な点検',
cleanCarbonRods: 'カーボンロッドを清掃して摩擦を軽減',
checkPtfeTube: 'PTFEチューブの摩耗や損傷を検査',
replaceHepaFilter: 'HEPAフィルターを交換して空気品質を向上',
replaceCarbonFilter: '活性炭フィルターを交換',
lubricateLeftNozzleRail: '左ノズルレールに潤滑剤を塗布(H2シリーズ)',
},
// Smart Plugs
smartPlugs: {
offline: 'オフライン',
admin: '管理',
openPlugAdminPage: 'プラグ管理ページを開く',
deleteSmartPlug: 'スマートプラグを削除',
turnOnSmartPlug: 'スマートプラグをオンにする',
turnOffSmartPlug: 'スマートプラグをオフにする',
turnOn: 'オンにする',
turnOff: 'オフにする',
addSmartPlug: {
scanningNetwork: 'ネットワークをスキャン中...',
chooseEntity: 'エンティティを選択...',
connectionFailed: '接続失敗',
searchEntities: 'エンティティを検索...',
searchPowerSensors: '電力センサーを検索...',
searchEnergySensors: 'エネルギーセンサーを検索...',
placeholders: {
plugName: 'リビングルームプラグ',
mqttStateOnValue: 'ON, true, 1',
mqttSameAsPower: '電力トピックと同じ、または異なる',
},
},
},
// External Links
externalLinks: {
noLinksConfigured: '外部リンクが設定されていません',
deleteLink: 'リンクを削除',
removeCustomIcon: 'カスタムアイコンを削除',
placeholders: {
linkName: 'マイリンク',
},
},
// Keyboard Shortcuts Modal
keyboardShortcuts: {
title: 'キーボードショートカット',
navigation: 'ナビゲーション',
archivesSection: 'アーカイブ',
kProfilesSection: 'Kプロファイル',
generalSection: '全般',
shortcuts: {
goToPrinters: 'プリンターへ移動',
goToArchives: 'アーカイブへ移動',
goToQueue: 'キューへ移動',
goToStats: '統計へ移動',
goToProfiles: 'クラウドプロファイルへ移動',
goToSettings: '設定へ移動',
focusSearch: '検索にフォーカス',
openUploadModal: 'アップロードモーダルを開く',
clearSelection: '選択をクリア / 入力をぼかす',
contextMenu: 'カードのコンテキストメニュー',
refreshProfiles: 'プロファイルを更新',
newProfile: '新しいプロファイル',
exitSelectionMode: '選択モードを終了',
showHelp: 'このヘルプを表示',
},
footer: 'Escキーを押すか外側をクリックして閉じます',
},
// Keyboard Shortcuts Modal
restoreBackup: {
title: 'バックアップを復元',
restoring: '復元中...',
restoreComplete: '復元完了',
restoreFailed: '復元失敗',
importSettings: 'バックアップファイルから設定をインポート',
pleaseWait: 'データの復元中です。しばらくお待ちください',
clickToSelect: 'クリックしてバックアップファイルを選択(.jsonまたは.zip)',
howDuplicateHandling: '重複の処理方法:',
categories: {
printers: 'プリンター',
smartPlugs: 'スマートプラグ',
notificationProviders: '通知プロバイダー',
filaments: 'フィラメント',
archives: 'アーカイブ',
pendingUploads: '保留中のアップロード',
settingsTemplates: '設定とテンプレート',
},
matchingInfo: {
printers: 'シリアル番号で照合',
smartPlugs: 'IPアドレスで照合',
notificationProviders: '名前で照合',
filaments: '名前+タイプ+ブランドで照合',
archives: 'コンテンツハッシュで照合',
pendingUploads: 'ファイル名で照合',
settingsTemplates: '常に上書き',
},
replaceExisting: '既存データを置き換え',
keepExisting: '既存データを保持',
replaceDescription: '既に存在するアイテムをバックアップデータで上書き',
keepDescription: 'まだ存在しないアイテムのみを復元',
caution: '注意:',
cautionText: '上書きすると現在の構成がバックアップデータに置き換えられます。セキュリティ上の理由から、プリンターのアクセスコードは上書きされません。',
itemsRestored: '復元されたアイテム',
itemsSkipped: 'スキップされたアイテム',
restored: '復元済み',
skipped: 'スキップ(既に存在)',
filesLabel: 'ファイル(3MF、サムネイルなど)',
newApiKeysGenerated: '新しいAPIキーが生成されました',
newApiKeysWarning: 'これらのキーは一度だけ表示されます。今すぐコピーしてください!',
processingBackup: 'バックアップファイルを処理中...',
noDataFound: 'バックアップファイルに復元するデータが見つかりませんでした。',
failedToRestore: 'バックアップの復元に失敗しました。ファイル形式を確認してください。',
},
// Backup Export Modal
backupExport: {
title: 'バックアップをエクスポート',
selectData: '含めるデータを選択',
selectAll: 'すべて選択',
selectNone: 'なし',
categoryDescriptions: {
settings: '言語、テーマ、更新設定',
notifications: 'ntfy、Pushover、Discordなど',
templates: 'カスタムメッセージテンプレート',
smartPlugs: 'Tasmotaプラグ設定',
externalLinks: 'サイドバーの外部サービスへのリンク',
printers: 'プリンター情報(アクセスコード除外)',
plateDetection: '空プレート参照画像',
filaments: 'フィラメントの種類とコスト',
maintenance: 'カスタムメンテナンススケジュール',
archives: 'すべての印刷データ+ファイル(3MF、サムネイル、写真)',
projects: 'プロジェクト、BOMアイテム、添付ファイル',
pendingUploads: '仮想プリンターアップロード待機中',
apiKeys: 'Webhook APIキー(インポート時に新しいキーが生成されます)',
},
requiresPrinters: 'プリンターを選択する必要があります',
zipFileWarning: 'ZIPファイルが作成されます。',
zipFileDescription: 'すべての3MFファイル、サムネイル、タイムラプス、写真が含まれます。これには時間がかかり、大きなファイルになる可能性があります。',
includeAccessCodes: 'アクセスコードを含める',
includeAccessCodesDescription: '別のマシンへの転送用',
includeAccessCodesWarning: 'アクセスコードはプレーンテキストで含まれます。このバックアップファイルを安全に保管してください!',
categoriesSelected: '{{selectedCount}}カテゴリー選択済み',
},
// Configure AMS Slot Modal
configureAmsSlot: {
searchPresets: 'プリセットを検索...',
colorPlaceholder: '色名またはHex(例: 茶色、FF8800)',
clearCustomColor: 'カスタム色をクリア',
noCloudPresets: 'クラウドプリセットがありません。Bambu Cloudにログインして同期してください。',
noMatchingPresets: '一致するプリセットが見つかりません。',
custom: 'カスタム',
settingsSentToPrinter: '設定をプリンターに送信しました',
filamentProfile: 'フィラメントプロファイル',
},
// GitHub Backup Settings (additional keys)
githubBackupSettings: {},
// Email Settings
emailSettings: {
placeholders: {
fromName: 'BamBuddy',
},
},
// Tag Management Modal
tagManagement: {
searchTags: 'タグを検索...',
renameTag: 'タグ名を変更',
deleteTag: 'タグを削除',
},
// Notification Template Editor
notificationTemplates: {
placeholders: {
title: '通知タイトル...',
body: '通知本文...',
},
},
// Batch Tag Modal
batchTag: {
placeholders: {
newTag: '新しいタグを入力...',
},
},
// Photo Gallery Modal
photoGallery: {
deletePhoto: '写真を削除',
},
// Filament Hover Card
filamentHoverCard: {
copySpoolUuid: 'スプールUUIDをコピー',
},
// K Profiles View
kProfilesView: {
hasNote: 'メモあり',
copyProfile: 'プロファイルをコピー',
},
// Layout/Navigation
layout: {
openMenu: 'メニューを開く',
noPermissionSystemInfo: 'システム情報を表示する権限がありません',
},
// Notification Provider Card
notificationProviderCard: {
deleteNotificationProvider: '通知プロバイダーを削除',
},
// File Manager Modal
fileManagerModal: {
closeFileManager: 'ファイルマネージャーを閉じる',
sortFiles: 'ファイルを並べ替え',
goToParentFolder: '親フォルダーへ移動',
threeView: '3Dビュー',
},
// Embedded Camera Viewer
embeddedCameraViewer: {
refreshStream: 'ストリームを更新',
close: '閉じる',
zoomOut: 'ズームアウト',
resetZoom: 'ズームをリセット',
zoomIn: 'ズームイン',
dragToResize: 'ドラッグしてサイズ変更',
},
// Timelapse Viewer
timelapseViewer: {
skipBack5s: '5秒戻る',
skipForward5s: '5秒進む',
},
// Notification Providers
notificationProviders: {
descriptions: {
email: 'SMTP電子メール通知',
telegram: 'Telegramボット経由の通知',
discord: 'Webhookを介してDiscordチャンネルに送信',
ntfy: '無料でセルフホスト可能なプッシュ通知',
pushover: 'シンプルで信頼性の高いプッシュ通知',
callmebot: 'CallMeBot経由の無料WhatsApp通知',
webhook: '任意のURLへのジェネリックHTTP POST',
},
},
// Switchbar Popover
switchbarPopover: {
noSwitchesInSwitchbar: 'スイッチバーにスイッチがありません',
},
// Project Page Modal
projectPageModal: {
placeholders: {
title: 'タイトル',
designer: 'デザイナー',
license: 'ライセンス',
description: '説明を入力...',
profileTitle: 'プロファイルタイトル',
profileDescription: 'プロファイルの説明...',
},
},
// Spoolman Settings
spoolmanSettings: {},
};
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -23,7 +23,7 @@
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-HOR_-s_H.js"></script>
<script type="module" crossorigin src="/assets/index-QQNcmTSY.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BwfbnBQ9.css">
</head>
<body>