i18n DE/EN + DossierSettings panel + English file renames

i18n:
- src/i18n/de.json + en.json: 200+ keys covering all main panels
- src/i18n/index.js: t(key, vars) reads window.DOSSIER_LANG
- panel_base.py: injects window.DOSSIER_LANG from dossier_settings.json
- EbenenManager, GeschossManager, AusschnitteApp, LayoutsApp: all
  context menus and main labels use t()

DossierSettings panel:
- DossierSettingsApp.jsx: language toggle (DE/EN pill) + launcher status
- toolbar.py: OPEN_SETTINGS opens new Rhino-hosted satellite window,
  SAVE_LANG writes lang to dossier_settings.json + reloads all panels

File renames (JSX → English):
- ZeichnungsebenenApp → DrawingLevelsApp
- GeschossManager/Dialog/Settings → Floor*
- AusschnitteApp/Settings → Viewports*
- EbenenManager/Settings → Layer*
- GestaltungApp → StylesApp, OberleisteApp → ToolbarApp
- WerkzeugeApp → ToolsApp, DimensionenApp → DimensionsApp
- MassstabApp → ScaleApp, KameraApp → CameraApp
- MasseSettingsApp → UnitsSettingsApp
- ConfirmDeleteEbene → ConfirmDeleteLayer
- AusschnittLayerDialog → ViewportLayerDialog

Python module renames:
- rhinopanel.py → layers_panel.py
- oberleiste.py → toolbar.py
- gestaltung.py → styles.py
- werkzeuge.py → tools.py
- dimensionen.py → dimensions.py
- startup.py _MODULE_TO_PY updated, all cross-imports fixed
This commit is contained in:
2026-06-06 11:09:33 +02:00
parent 92b4baa285
commit 375487c10c
45 changed files with 998 additions and 148 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect, useMemo } from 'react'
import EbenenManager from './components/EbenenManager'
import EbenenManager from './components/LayerManager'
import {
applyAll, setActiveEbene,
onMessage, notifyReady, applyVisibility,
+178
View File
@@ -0,0 +1,178 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect } from 'react'
import { notifyReady, send as bridgeSend, onMessage } from './lib/rhinoBridge'
import Icon from './components/Icon'
const LANGS = [
{ id: 'de', label: 'Deutsch' },
{ id: 'en', label: 'English' },
]
export default function DossierSettingsApp() {
const initial = (typeof window !== 'undefined' && window.PANEL_PARAMS) || {}
const [lang, setLang] = useState(initial.lang || 'de')
const [launcherOk, setLauncherOk] = useState(initial.launcherOk ?? null)
const [saved, setSaved] = useState(false)
useEffect(() => {
notifyReady()
onMessage('SETTINGS', (p) => {
if (p.lang) setLang(p.lang)
if (p.launcherOk != null) setLauncherOk(p.launcherOk)
})
}, [])
function handleLang(id) {
setLang(id)
bridgeSend('SAVE_LANG', { lang: id })
setSaved(true)
setTimeout(() => setSaved(false), 1800)
}
const label = (de, en) => lang === 'en' ? en : de
return (
<div style={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
background: 'var(--bg-base)',
color: 'var(--text-primary)',
fontFamily: 'var(--font)',
fontSize: 12,
overflow: 'hidden',
}}>
{/* Header */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '14px 16px 10px',
borderBottom: '1px solid var(--border-light)',
flexShrink: 0,
}}>
<span style={{ fontWeight: 600, fontSize: 13, letterSpacing: '0.01em' }}>
{label('Dossier-Einstellungen', 'Dossier Settings')}
</span>
{saved && (
<span style={{
fontSize: 10,
color: 'var(--accent)',
display: 'flex',
alignItems: 'center',
gap: 4,
}}>
<Icon name="check_circle" size={13} />
{label('Gespeichert', 'Saved')}
</span>
)}
</div>
{/* Body */}
<div style={{ flex: 1, overflowY: 'auto', padding: '16px' }}>
{/* Language */}
<Section label={label('Sprache', 'Language')} icon="language">
<div style={{ display: 'flex', gap: 6 }}>
{LANGS.map(l => (
<button
key={l.id}
onClick={() => handleLang(l.id)}
style={{
flex: 1,
padding: '7px 0',
borderRadius: 999,
border: lang === l.id
? '1.5px solid var(--accent)'
: '1px solid var(--border)',
background: lang === l.id ? 'var(--accent-dim)' : 'var(--bg-item)',
color: lang === l.id ? 'var(--accent)' : 'var(--text-secondary)',
fontFamily: 'var(--font)',
fontSize: 11,
fontWeight: lang === l.id ? 600 : 400,
cursor: 'pointer',
transition: 'all 120ms ease',
letterSpacing: '0.02em',
}}
>
{l.label}
</button>
))}
</div>
<p style={{ marginTop: 8, fontSize: 10, color: 'var(--text-muted)', lineHeight: 1.4 }}>
{label('Gilt für alle Panels — Rhino neu laden um alle anzuwenden.', 'Applies to all panels — reload Rhino to apply everywhere.')}
</p>
</Section>
{/* Launcher status */}
<Section label={label('Launcher', 'Launcher')} icon="hub">
<div style={{
display: 'flex',
alignItems: 'center',
gap: 8,
padding: '8px 10px',
borderRadius: 8,
background: 'var(--bg-item)',
border: '1px solid var(--border-light)',
}}>
<div style={{
width: 7, height: 7, borderRadius: '50%', flexShrink: 0,
background: launcherOk === true
? 'var(--accent)'
: launcherOk === false
? 'var(--danger)'
: 'var(--text-muted)',
}} />
<span style={{ fontSize: 11, color: 'var(--text-secondary)' }}>
{launcherOk === true
? label('Launcher verbunden', 'Launcher connected')
: launcherOk === false
? label('Launcher nicht gefunden', 'Launcher not found')
: label('Unbekannt', 'Unknown')}
</span>
</div>
</Section>
</div>
{/* Footer */}
<div style={{
padding: '10px 16px',
borderTop: '1px solid var(--border-light)',
display: 'flex',
justifyContent: 'flex-end',
flexShrink: 0,
}}>
<button
className="btn-outlined"
onClick={() => bridgeSend('CANCEL', {})}
>
{label('Schließen', 'Close')}
</button>
</div>
</div>
)
}
function Section({ label, icon, children }) {
return (
<div style={{ marginBottom: 20 }}>
<div style={{
display: 'flex',
alignItems: 'center',
gap: 6,
marginBottom: 10,
color: 'var(--text-muted)',
fontSize: 10,
fontWeight: 600,
letterSpacing: '0.08em',
textTransform: 'uppercase',
}}>
{icon && <Icon name={icon} size={13} />}
{label}
</div>
{children}
</div>
)
}
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect, useMemo } from 'react'
import GeschossManager from './components/GeschossManager'
import GeschossManager from './components/FloorManager'
import {
applyAll, setActiveZeichnungsebene,
onMessage, notifyReady, applyVisibility,
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useEffect } from 'react'
import GeschossDialog from './components/GeschossDialog'
import GeschossDialog from './components/FloorDialog'
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
// recalcOkff direkt hier gleiche Logik wie in ZeichnungsebenenApp.jsx,
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useEffect } from 'react'
import GeschossSettingsDialog from './components/GeschossSettingsDialog'
import GeschossSettingsDialog from './components/FloorSettingsDialog'
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
export default function GeschossSettingsApp() {
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect } from 'react'
import AusschnittLayerDialog from './components/AusschnittLayerDialog'
import AusschnittLayerDialog from './components/ViewportLayerDialog'
import { onMessage, notifyReady } from './lib/rhinoBridge'
function send(type, payload) {
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useEffect, useState, useRef } from 'react'
import EbenenSettingsDialog from './components/EbenenSettingsDialog'
import EbenenSettingsDialog from './components/LayerSettingsDialog'
import { notifyReady, onMessage, send as bridgeSend } from './lib/rhinoBridge'
export default function EbenenSettingsApp() {
+16 -18
View File
@@ -3,6 +3,7 @@
import { useEffect, useState, useRef } from 'react'
import Icon from './components/Icon'
import ContextMenu from './components/ContextMenu'
import { t } from './i18n/index.js'
import { BarButton, BarCombo, BAR_H } from './components/BarControls'
import {
onMessage, notifyReady,
@@ -181,69 +182,66 @@ export default function LayoutsApp() {
// Kontextmenue-Items pro Layout
const layoutCtxItems = (l) => [
{ label: 'In Rhino oeffnen', icon: 'open_in_new',
{ label: t('layouts.open_in_rhino'), icon: 'open_in_new',
onClick: () => activateLayout(l.id) },
{ label: 'Umbenennen', icon: 'edit',
{ label: t('common.rename'), icon: 'edit',
onClick: () => setRenamingId(l.id) },
{ divider: true },
{ label: 'Als PDF exportieren', icon: 'picture_as_pdf',
{ label: t('layouts.export_pdf'), icon: 'picture_as_pdf',
onClick: () => exportPdf(l.id, 300) },
{ label: 'Papierformat ändern', icon: 'aspect_ratio',
{ label: t('layouts.change_paper'), icon: 'aspect_ratio',
onClick: () => openLayoutDialog('edit', {
id: l.id, name: l.name, width: l.widthMm, height: l.heightMm,
}) },
{ divider: true },
...(folders.length > 0 ? [
...folders.map(f => ({
label: `Verschieben → ${f}`,
label: t('layouts.move_to', { folder: f }),
icon: 'folder',
disabled: l.folder === f,
onClick: () => setLayoutFolder(l.id, f),
})),
{ label: 'Aus Ordner entfernen',
{ label: t('layouts.remove_from_folder'),
icon: 'folder_off',
disabled: !l.folder,
onClick: () => setLayoutFolder(l.id, '') },
{ divider: true },
] : []),
{ label: 'Löschen', icon: 'delete', danger: true,
{ label: t('common.delete'), icon: 'delete', danger: true,
onClick: () => {
if (window.confirm(`Layout "${l.name}" löschen?`)) deleteLayout(l.id)
if (window.confirm(`${t('common.delete')} "${l.name}"?`)) deleteLayout(l.id)
} },
]
// Kontextmenue-Items pro Ordner
const folderCtxItems = (folderName) => {
const items = grouped[folderName] || []
return [
{ label: collapsedFolders.has(folderName) ? 'Aufklappen' : 'Einklappen',
{ label: collapsedFolders.has(folderName) ? t('common.expand') : t('common.collapse'),
icon: collapsedFolders.has(folderName) ? 'expand_more' : 'expand_less',
onClick: () => toggleFolderCollapse(folderName) },
{ divider: true },
{ label: 'Alle ankreuzen / abwählen',
{ label: t('layouts.check_all'),
icon: 'check_box',
onClick: () => checkAllInFolder(items) },
{ label: `Ordner als PDF (${items.length})`,
{ label: t('layouts.folder_pdf', { count: items.length }),
icon: 'picture_as_pdf',
disabled: items.length === 0,
onClick: () => handleExportFolder(folderName) },
{ divider: true },
{ label: 'Ordner umbenennen',
{ label: t('common.rename_folder'),
icon: 'edit',
onClick: () => {
const next = window.prompt('Neuer Ordner-Name:', folderName)
const next = window.prompt(t('layouts.new_folder_name'), folderName)
if (next && next.trim() && next !== folderName) {
// Atomar via Server-Side waere besser; simpler: alle Layouts
// umhaengen + alten loeschen + neuen anlegen.
addLayoutFolder(next.trim())
items.forEach(l => setLayoutFolder(l.id, next.trim()))
removeLayoutFolder(folderName)
}
} },
{ label: 'Ordner loeschen',
{ label: t('common.delete_folder'),
icon: 'folder_off', danger: true,
onClick: () => {
if (window.confirm(`Ordner "${folderName}" loeschen? Layouts werden zur Wurzel verschoben.`))
if (window.confirm(`${t('common.delete_folder')} "${folderName}"? ${t('layouts.delete_folder_confirm')}`))
removeLayoutFolder(folderName)
} },
]
+12 -11
View File
@@ -3,6 +3,7 @@
import { useState, useEffect, useMemo } from 'react'
import Icon from './components/Icon'
import ContextMenu from './components/ContextMenu'
import { t } from './i18n/index.js'
import {
onMessage, notifyReady,
listAusschnitte, saveAusschnitt, updateAusschnitt,
@@ -287,25 +288,25 @@ export default function AusschnitteApp() {
}
const handleAddFolder = () => {
const name = window.prompt('Name für neuen Ordner:')
const name = window.prompt(t('viewports.new_folder_name'))
if (name && name.trim()) addAusschnittFolder(name.trim())
}
const ctxItems = (id) => [
{ label: 'Wiederherstellen', icon: 'restore', onClick: () => restoreAusschnitt(id) },
{ label: 'Auf Detail anwenden', icon: 'crop_landscape', onClick: () => applyAusschnittToDetail(id) },
{ label: t('viewports.restore'), icon: 'restore', onClick: () => restoreAusschnitt(id) },
{ label: t('viewports.apply_to_detail'),icon: 'crop_landscape', onClick: () => applyAusschnittToDetail(id) },
{ divider: true },
{ label: 'Ausschnittseinstellungen…', icon: 'tune', onClick: () => openAusschnittSettings(id) },
{ label: t('viewports.settings'), icon: 'tune', onClick: () => openAusschnittSettings(id) },
{ divider: true },
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicateAusschnitt(id) },
{ label: 'Aktualisieren', icon: 'sync', onClick: () => updateAusschnitt(id) },
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicateAusschnitt(id) },
{ label: t('viewports.update'), icon: 'sync', onClick: () => updateAusschnitt(id) },
{ divider: true },
{ label: 'Löschen', icon: 'delete', danger: true, onClick: () => deleteAusschnitt(id) },
{ label: t('common.delete'), icon: 'delete', danger: true, onClick: () => deleteAusschnitt(id) },
]
const folderCtxItems = (folderName) => [
{ label: 'Ordner umbenennen', icon: 'edit', onClick: () => {
const newName = window.prompt('Neuer Ordnername:', folderName)
{ label: t('common.rename_folder'), icon: 'edit', onClick: () => {
const newName = window.prompt(t('common.new_folder_name'), folderName)
if (newName && newName.trim() && newName !== folderName) {
snaps.filter(s => s.folder === folderName).forEach(s => setAusschnittFolder(s.id, newName.trim()))
addAusschnittFolder(newName.trim())
@@ -313,8 +314,8 @@ export default function AusschnitteApp() {
}
}},
{ divider: true },
{ label: 'Ordner löschen', icon: 'folder_off', danger: true, onClick: () => {
if (window.confirm(`Ordner "${folderName}" löschen? Ausschnitte werden zur Wurzel verschoben.`)) {
{ label: t('common.delete_folder'), icon: 'folder_off', danger: true, onClick: () => {
if (window.confirm(`${t('common.delete_folder')} "${folderName}"? ${t('viewports.delete_folder_confirm')}`)) {
removeAusschnittFolder(folderName)
}
}},
@@ -3,6 +3,7 @@
import { useState } from 'react'
import Icon from './Icon'
import ContextMenu from './ContextMenu'
import { t } from '../i18n/index.js'
import { BarCombo, BarButton } from './BarControls'
import { openGeschossSettings, openGeschossDialog, createSchnitt } from '../lib/rhinoBridge'
@@ -150,12 +151,12 @@ function ZeichnungsebeneRow({
)
}
const MODES = [
{ value: 'all_force', label: 'Alle anzeigen' },
{ value: 'all', label: 'Ausgewählte' },
{ value: 'active', label: 'Nur aktive' },
{ value: 'grey', label: 'Andere grau' },
{ value: 'grey_locked', label: 'Andere grau & gesperrt' },
const MODES = () => [
{ value: 'all_force', label: t('layers.show_all_mode') },
{ value: 'all', label: t('layers.selected_mode') },
{ value: 'active', label: t('layers.active_only_mode') },
{ value: 'grey', label: t('layers.others_gray') },
{ value: 'grey_locked', label: t('layers.others_gray_locked') },
]
export default function GeschossManager({
@@ -443,11 +444,11 @@ export default function GeschossManager({
const z = zeichnungsebenen.find(x => x.id === id)
if (!z) return []
return [
{ label: 'Einstellungen…', icon: 'settings', onClick: () => openGeschossSettings(z) },
{ label: t('common.settings') + '…', icon: 'settings', onClick: () => openGeschossSettings(z) },
{ divider: true },
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicate(id) },
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicate(id) },
{ divider: true },
{ label: 'Löschen', icon: 'delete', danger: true,
{ label: t('common.delete'), icon: 'delete', danger: true,
disabled: zeichnungsebenen.length <= 1,
onClick: () => remove(id) },
]
@@ -461,22 +462,22 @@ export default function GeschossManager({
background: 'var(--bg-section)',
borderBottom: '1px solid var(--border-light)',
}}>
<span className="label-xs">Sichtbarkeit</span>
<span className="label-xs">{t('layers.visibility_mode')}</span>
<div style={{ display: 'flex', width: '100%' }}>
<BarCombo
stretch
icon="visibility"
value={mode}
onChange={onModeChange}
title="Sichtbarkeits-Modus"
title={t('layers.visibility_mode')}
onGear={() => openGeschossDialog(zeichnungsebenen)}
gearIcon="settings"
gearTitle="Einstellungen"
gearTitle={t('common.settings')}
onSecond={openAddMenu}
secondIcon="add"
secondTitle="Hinzufuegen: Geschoss / Schnitt / Zeichnung"
secondTitle={t('floors.add')}
>
{MODES.map(m => (
{MODES().map(m => (
<option key={m.value} value={m.value}>{m.label}</option>
))}
</BarCombo>
@@ -501,8 +502,7 @@ export default function GeschossManager({
if (mode === 'active' || mode === 'all_force') onModeChange('all')
}}
title={zeichnungsebenen.every(z => z.visible !== false)
? 'Alle Zeichnungsebenen ausblenden'
: 'Alle Zeichnungsebenen einblenden'}
? t('floors.hide_all') : t('floors.show_all')}
style={{ width: 16, height: 16,
opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
>
@@ -519,8 +519,7 @@ export default function GeschossManager({
onChange(zeichnungsebenen.map(z => ({ ...z, locked: !anyLocked })))
}}
title={zeichnungsebenen.every(z => z.locked === true)
? 'Alle Zeichnungsebenen entsperren'
: 'Alle Zeichnungsebenen sperren'}
? t('floors.unlock_all') : t('floors.lock_all')}
style={{ width: 14, height: 14 }}
>
<Icon
@@ -2,19 +2,20 @@
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useRef, useMemo, useEffect } from 'react'
import Icon from './Icon'
import ConfirmDeleteEbene from './ConfirmDeleteEbene'
import ConfirmDeleteEbene from './ConfirmDeleteLayer'
import ContextMenu from './ContextMenu'
import { BarCombo, BarButton } from './BarControls'
import { setLayerStyle, deleteEbene, moveSelectionToEbene, openEbenenSettings,
pickLayerCombination, saveLayerCombination, deleteLayerCombination,
openLayerCombinationsDialog } from '../lib/rhinoBridge'
import { t } from '../i18n/index.js'
const MODES = [
{ value: 'all_force', label: 'Alle anzeigen' },
{ value: 'all', label: 'Ausgewählte' },
{ value: 'active', label: 'Nur aktive' },
{ value: 'grey', label: 'Andere grau' },
{ value: 'grey_locked', label: 'Andere grau & gesperrt' },
const MODES = () => [
{ value: 'all_force', label: t('layers.show_all_mode') },
{ value: 'all', label: t('layers.selected_mode') },
{ value: 'active', label: t('layers.active_only_mode') },
{ value: 'grey', label: t('layers.others_gray') },
{ value: 'grey_locked', label: t('layers.others_gray_locked') },
]
const LW_PRESETS = [0.02, 0.10, 0.13, 0.18, 0.25, 0.35, 0.50, 0.70, 1.00]
@@ -532,20 +533,20 @@ export default function EbenenManager({
}
const ctxItems = (code) => [
{ label: 'Ebeneneinstellungen…', icon: 'settings', onClick: () => {
{ label: t('layers.settings'), icon: 'settings', onClick: () => {
const target = _findInTree(ebenen, code)
if (target) openEbenenSettings(target, hatchPatterns)
} },
{ divider: true },
{ label: 'Sub-Ebene hinzufügen…', icon: 'add', onClick: () => addChild(code) },
{ label: 'Selektion hierher übertragen', icon: 'move_down', onClick: () => moveSelectionToEbene(code) },
{ label: t('layers.add_sub'), icon: 'add', onClick: () => addChild(code) },
{ label: t('layers.move_selection'), icon: 'move_down', onClick: () => moveSelectionToEbene(code) },
{ divider: true },
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicateEbene(code) },
{ label: 'Eigenschaften kopieren', icon: 'colorize', onClick: () => copyProps(code) },
{ label: 'Eigenschaften einfügen', icon: 'format_paint', onClick: () => pasteProps(code), disabled: !clipboard },
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicateEbene(code) },
{ label: t('layers.copy_props'), icon: 'colorize', onClick: () => copyProps(code) },
{ label: t('layers.paste_props'), icon: 'format_paint', onClick: () => pasteProps(code), disabled: !clipboard },
{ divider: true },
{ label: 'Löschen', icon: 'delete', onClick: () => handleDelete(code), danger: true,
disabled: ebenen.length <= 1 },
{ label: t('common.delete'), icon: 'delete', onClick: () => handleDelete(code), danger: true,
disabled: ebenen.length <= 1 },
]
return (
@@ -556,7 +557,7 @@ export default function EbenenManager({
background: 'var(--bg-section)',
borderBottom: '1px solid var(--border-light)',
}}>
<span className="label-xs">Ebenenkombination</span>
<span className="label-xs">{t('layers.combination')}</span>
<div style={{ display: 'flex', width: '100%' }}>
<BarCombo
stretch
@@ -582,21 +583,21 @@ export default function EbenenManager({
pickLayerCombination(v === '__none__' ? null : v)
}}
title={activeKombi
? `Aktive Kombi: ${activeKombi}`
: 'Keine Kombination — manuelle Sichtbarkeit'}
? `${t('layers.combination')}: ${activeKombi}`
: t('layers.no_combination')}
onGear={openLayerCombinationsDialog}
gearTitle="Ebenenkombinationen bearbeiten"
gearTitle={t('layers.edit_combinations')}
>
<option value="__none__"> Eigene </option>
<option value="__none__">{t('layers.custom')}</option>
{layerCombinations.map(n => (
<option key={n} value={n}>{n}</option>
))}
<option disabled></option>
<option value="__save__">+ Aktuelle speichern</option>
<option value="__save__">{t('layers.save_current')}</option>
{activeKombi && (
<option value="__delete__">🗑 Aktuelle löschen</option>
<option value="__delete__">🗑 {t('layers.delete_current')}</option>
)}
<option value="__configure__">Bearbeiten</option>
<option value="__configure__">{t('common.edit')}</option>
</BarCombo>
</div>
</div>
@@ -607,19 +608,19 @@ export default function EbenenManager({
background: 'var(--bg-section)',
borderBottom: '1px solid var(--border-light)',
}}>
<span className="label-xs">Sichtbarkeit</span>
<span className="label-xs">{t('layers.visibility_mode')}</span>
<div style={{ display: 'flex', width: '100%' }}>
<BarCombo
stretch
icon="visibility"
value={mode}
onChange={onModeChange}
title="Sichtbarkeits-Modus"
title={t('layers.visibility_mode')}
onSecond={addNew}
secondIcon="add"
secondTitle="Ebene hinzufügen"
secondTitle={t('layers.add')}
>
{MODES.map(m => <option key={m.value} value={m.value}>{m.label}</option>)}
{MODES().map(m => <option key={m.value} value={m.value}>{m.label}</option>)}
</BarCombo>
</div>
</div>
@@ -642,7 +643,7 @@ export default function EbenenManager({
if (mode === 'active' || mode === 'all_force') onModeChange('all')
}}
title={ebenen.every(e => e.visible !== false)
? 'Alle Ebenen ausblenden' : 'Alle Ebenen einblenden'}
? t('layers.hide_all') : t('layers.show_all')}
style={{ width: 16, height: 16,
opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
>
@@ -658,7 +659,7 @@ export default function EbenenManager({
const anyLocked = ebenen.some(e => e.locked === true)
onChange(ebenen.map(e => ({ ...e, locked: !anyLocked })))
}}
title={ebenen.every(e => e.locked === true) ? 'Alle Ebenen entsperren' : 'Alle Ebenen sperren'}
title={ebenen.every(e => e.locked === true) ? t('layers.unlock_all') : t('layers.lock_all')}
style={{ width: 14, height: 14 }}
>
<Icon name={ebenen.every(e => e.locked === true) ? 'lock' : 'lock_open'} size={11} />
+290
View File
@@ -0,0 +1,290 @@
{
"common.save": "Speichern",
"common.cancel": "Abbrechen",
"common.delete": "Löschen",
"common.duplicate": "Duplizieren",
"common.rename": "Umbenennen",
"common.settings": "Einstellungen",
"common.edit": "Bearbeiten",
"common.add": "Hinzufügen",
"common.expand": "Aufklappen",
"common.collapse": "Einklappen",
"common.show": "Einblenden",
"common.hide": "Ausblenden",
"common.lock": "Sperren",
"common.unlock": "Entsperren",
"common.refresh": "Aktualisieren",
"common.close": "Schließen",
"common.apply": "Anwenden",
"common.new_folder": "Neuer Ordner",
"common.rename_folder": "Ordner umbenennen",
"common.delete_folder": "Ordner löschen",
"common.new_folder_name": "Neuer Ordnername:",
"lang.de": "Deutsch",
"lang.en": "English",
"lang.label": "Sprache",
"settings.title": "Dossier-Einstellungen",
"settings.language": "Sprache",
"settings.language_hint": "Gilt für alle Panels",
"settings.launcher_sync": "Launcher-Einstellungen",
"settings.launcher_available": "Launcher verbunden",
"settings.launcher_missing": "Launcher nicht gefunden",
"settings.window_layout": "Fenster-Layout",
"settings.apply_layout": "Layout automatisch anwenden",
"settings.saved": "Gespeichert",
"layers.title": "Ebenen",
"layers.settings": "Ebeneneinstellungen…",
"layers.add_sub": "Sub-Ebene hinzufügen…",
"layers.move_selection": "Selektion hierher übertragen",
"layers.copy_props": "Eigenschaften kopieren",
"layers.paste_props": "Eigenschaften einfügen",
"layers.add": "Ebene hinzufügen",
"layers.hide_all": "Alle Ebenen ausblenden",
"layers.show_all": "Alle Ebenen einblenden",
"layers.lock_all": "Alle Ebenen sperren",
"layers.unlock_all": "Alle Ebenen entsperren",
"layers.visibility_mode": "Sichtbarkeits-Modus",
"layers.show_all_mode": "Alle anzeigen",
"layers.selected_mode": "Ausgewählte",
"layers.active_only_mode": "Nur aktive",
"layers.others_gray": "Andere grau",
"layers.others_gray_locked": "Andere grau & gesperrt",
"layers.combination": "Ebenenkombination",
"layers.no_combination": "Keine Kombination — manuelle Sichtbarkeit",
"layers.edit_combinations": "Ebenenkombinationen bearbeiten",
"layers.save_current": "+ Aktuelle speichern…",
"layers.delete_current": "Aktuelle löschen",
"layers.custom": "— Eigene —",
"layers.dblclick_edit": "Doppelklick zum Bearbeiten",
"layers.dblclick_rename": "Doppelklick zum Umbenennen",
"floors.title": "Zeichnungsebenen",
"floors.add": "Hinzufügen: Geschoss / Schnitt / Zeichnung",
"floors.floor": "Geschoss",
"floors.section": "Schnitt / Ansicht",
"floors.drawing": "Zeichnung",
"floors.new_floor": "Neues Geschoss",
"floors.position_relative": "Position relativ zu",
"floors.none": "— keins —",
"floors.insert_above": "Über dem Anker einfügen",
"floors.insert_below": "Unter dem Anker einfügen",
"floors.height": "Höhe (m)",
"floors.section_height": "Schnitt (m)",
"floors.section_height_hint": "Höhe der horizontalen Schnitt-Plane über OKFF",
"floors.hide_all": "Alle Zeichnungsebenen ausblenden",
"floors.show_all": "Alle Zeichnungsebenen einblenden",
"floors.lock_all": "Alle Zeichnungsebenen sperren",
"floors.unlock_all": "Alle Zeichnungsebenen entsperren",
"floors.clipping_off": "Clipping Plane ausschalten",
"floors.clipping_on": "Clipping Plane einschalten",
"floors.copy_suffix": "Kopie",
"floors.confirm_delete": "wirklich löschen?",
"viewports.title": "Ausschnitte",
"viewports.save": "Ausschnitt speichern",
"viewports.new_name": "Name für neuen Ausschnitt…",
"viewports.restore": "Wiederherstellen",
"viewports.apply_to_detail": "Auf Detail anwenden",
"viewports.settings": "Ausschnittseinstellungen…",
"viewports.update": "Aktualisieren",
"viewports.empty": "Noch keine Ausschnitte.",
"viewports.empty_hint": "Oben einen Namen eingeben und klicken.",
"viewports.empty_folder": "Leer — Ausschnitte hier ablegen.",
"viewports.drop_root": "Hier ablegen für Wurzel",
"viewports.folder_actions": "Ordner-Aktionen",
"viewports.new_folder_name": "Name für neuen Ordner:",
"viewports.delete_folder_confirm": "Ausschnitte werden zur Wurzel verschoben.",
"viewports.scale_hint": "Doppelklick um Maßstab einzutragen (z.B. 1:50)",
"viewports.footer_hint": "Drag & Drop auf Ordner-Card zum Verschieben · Doppelklick = bearbeiten · ⋮ für Aktionen",
"layouts.title": "Layouts",
"layouts.landscape": "Querformat",
"layouts.portrait": "Hochformat",
"layouts.untitled": "(unbenannt)",
"layouts.empty": "Noch keine Layouts.",
"layouts.empty_hint": "Unten klicken um ein neues Layout anzulegen.",
"layouts.empty_folder": "Leer — Layouts hier ablegen.",
"layouts.drop_remove": "Hier ablegen um aus Ordner zu entfernen",
"layouts.new_detail": "Neues Detail (zentriert auf Seite)",
"layouts.sync_all": "Alle Details mit ihren Ausschnitten neu synchronisieren",
"layouts.no_details": "Keine Details auf diesem Layout.",
"layouts.no_details_hint": "Oben klicken um eines hinzuzufügen.",
"layouts.no_section": "— kein Ausschnitt —",
"layouts.reapply_section": "Gebundenen Ausschnitt neu anwenden",
"layouts.new": "Neues Layout erstellen",
"layouts.open_in_rhino": "In Rhino öffnen",
"layouts.export_pdf": "Als PDF exportieren",
"layouts.export_selection_pdf": "Auswahl ({count}) als ein PDF exportieren",
"layouts.export_all_pdf": "Alle Layouts als ein PDF exportieren",
"layouts.select_first": "Erst Layouts ankreuzen",
"layouts.change_paper": "Papierformat ändern",
"layouts.move_to": "Verschieben → {folder}",
"layouts.remove_from_folder": "Aus Ordner entfernen",
"layouts.check_all": "Alle ankreuzen / abwählen",
"layouts.folder_pdf": "Ordner als PDF ({count})",
"layouts.check_for_pdf": "Für PDF-Export ankreuzen",
"layouts.delete_detail_confirm": "Detail löschen?",
"layouts.new_folder_name": "Neuer Ordner-Name:",
"layouts.delete_folder_confirm": "Layouts werden zur Wurzel verschoben.",
"overrides.title": "Overrides",
"overrides.layer_name": "Layer-Name",
"overrides.object_name": "Objekt-Name",
"overrides.contains": "enthält",
"overrides.starts_with": "beginnt mit",
"overrides.ends_with": "endet mit",
"overrides.remove_condition": "Diese Bedingung entfernen",
"overrides.logic_all": "Alle Bedingungen müssen zutreffen",
"overrides.logic_any": "Mindestens eine Bedingung muss zutreffen",
"overrides.add_condition": "Weitere Bedingung hinzufügen",
"overrides.color": "Farbe",
"overrides.lineweight": "Strichstärke",
"overrides.linetype": "Linientyp",
"overrides.hatch": "Schraffur",
"overrides.hatch_scale": "Schraffur-Skala",
"overrides.hatch_hint": "Hatch-Override modifiziert nur existierende Schraffuren.",
"overrides.conditions": "Bedingungen",
"overrides.overrides": "Überschreibungen",
"overrides.combinations": "Override-Kombinationen",
"overrides.no_combination": "— neu / keine —",
"overrides.save_as_combination": "Als Kombination speichern…",
"overrides.save_changes_to": "Änderungen in \"{name}\" speichern",
"overrides.save_current_as_new": "Aktuelle Regeln als neue Kombination speichern",
"overrides.delete_combination_confirm": "Kombination \"{name}\" dauerhaft löschen?",
"overrides.delete_combination": "Gewählte Kombination dauerhaft löschen",
"overrides.insert_empty": "Leere Regel oben einfügen",
"overrides.from_template": "+ Aus Vorlage…",
"overrides.insert_from_template": "Regel aus Vorlage einfügen",
"overrides.delete_template": "Vorlage löschen",
"overrides.additive_hint": "Regeln sind additiv. Bei Konflikt gewinnt die oberste.",
"overrides.empty": "Noch keine Regeln.",
"overrides.empty_hint": "Oben klicken um eine neue Regel zu erstellen.",
"overrides.activate": "Aktivieren",
"overrides.deactivate": "Deaktivieren",
"overrides.prio_up": "Prio höher (nach oben)",
"overrides.prio_down": "Prio tiefer (nach unten)",
"overrides.save_as_template": "Als Vorlage speichern…",
"overrides.template_name": "Name für Vorlage:",
"overrides.delete_rule_confirm": "Regel \"{name}\" löschen?",
"overrides.rule_active": "Regel aktiv",
"overrides.logic_label": "Logik:",
"overrides.key": "Key",
"overrides.value": "Wert",
"overrides.condition": "Bedingung",
"overrides.empty_value": "(leer)",
"toolbar.shortcuts_hint": "Shortcuts (Shift+Klick = Über Dossier)",
"toolbar.app_settings": "Dossier-Einstellungen",
"toolbar.project_settings": "Projekt-Einstellungen",
"toolbar.overrides_on": "Grafische Overrides aktiv — klick zum Ausschalten",
"toolbar.overrides_off": "Grafische Overrides ausgeschaltet",
"toolbar.open_overrides": "Overrides-Regel-Editor öffnen",
"toolbar.zoom_snap": "Zoom auf 1:{scale} snappen",
"toolbar.zoom_select_scale": "Erst einen Massstab wählen",
"toolbar.zoom_all": "Auf gesamten Inhalt zoomen",
"toolbar.zoom_selection": "Auf Selektion zoomen",
"toolbar.refs_show": "Referenzlinien einblenden",
"toolbar.refs_hide": "Referenzlinien ausblenden",
"toolbar.osnap_on": "Object-Snap an — Klick zum Ausschalten",
"toolbar.osnap_off": "Object-Snap aus — Klick zum Einschalten",
"toolbar.grid_toggle": "Konstruktions-Raster ein-/ausblenden",
"toolbar.print_view_on": "Print-View aktiv — klick zum Ausschalten",
"toolbar.print_view_off": "Strichstärken anzeigen (Print-View)",
"toolbar.set_scale": "Gesetzter Massstab",
"toolbar.live_scale": "Aktueller Live-Massstab",
"toolbar.no_scale": "Kein Massstab gesetzt",
"toolbar.perspective_no_scale": "Perspektive — kein Massstab",
"toolbar.scale_input": "Massstab eingeben",
"toolbar.font": "Schriftart",
"toolbar.text_height": "Texthöhe (m)",
"toolbar.bold": "Fett",
"toolbar.italic": "Kursiv",
"toolbar.insert_text": "Neuen Text einfügen",
"toolbar.measures_edit": "Masse bearbeiten / neues anlegen",
"toolbar.style_save": "+ Speichern…",
"toolbar.style_delete": "Aktiven löschen",
"toolbar.bring_front": "In den Vordergrund",
"toolbar.bring_forward": "Eine Stufe hoch",
"toolbar.send_backward": "Eine Stufe runter",
"toolbar.send_back": "In den Hintergrund",
"toolbar.camera_settings": "Kamera-Einstellungen",
"toolbar.detail_level_simple": "Einfach (1:100)",
"toolbar.detail_level_standard": "Standard (1:50)",
"toolbar.detail_level_detail": "Detail (1:20)",
"tools.drawing_2d": "2D Zeichnen",
"tools.editing_2d": "2D Editieren",
"tools.modeling_3d": "3D Modellieren",
"tools.selection": "Auswahl",
"tools.line": "Linie",
"tools.polyline": "Polylinie",
"tools.rectangle": "Rechteck",
"tools.circle": "Kreis",
"tools.arc": "Bogen",
"tools.spline": "Freie Kurve (Spline)",
"tools.text": "Text",
"tools.hatch": "Schraffur",
"tools.dimension": "Linearbemaßung",
"tools.move": "Verschieben",
"tools.copy": "Kopieren",
"tools.rotate": "Drehen",
"tools.scale": "Skalieren",
"tools.mirror": "Spiegeln",
"tools.offset": "Parallelversatz",
"tools.trim": "Stutzen",
"tools.extend": "Verlängern",
"tools.join": "Verbinden",
"tools.explode": "Auflösen",
"tools.fillet": "Verrunden",
"tools.array": "Polar-Array",
"tools.extrude": "Kurve zu 3D extrudieren",
"tools.box": "Quader",
"tools.bool_union": "Boolean-Vereinigung",
"tools.bool_diff": "Boolean-Differenz",
"tools.bool_intersect": "Boolean-Schnittmenge",
"tools.close_holes": "Planare Löcher schließen",
"tools.section_lines": "Schnittlinien erzeugen",
"tools.loft": "Loft",
"tools.select_tangent": "Tangentiale Kurvenkette wählen",
"tools.select_duplicates": "Doppelte Objekte wählen",
"tools.select_closed": "Geschlossene Kurven wählen",
"tools.invert_selection": "Auswahl invertieren",
"tools.select_all": "Alle auswählen",
"tools.deselect_all": "Auswahl aufheben",
"dimensions.no_selection": "Keine Selektion",
"dimensions.no_selection_hint": "In Rhino ein oder mehrere Objekte auswählen.",
"dimensions.world_coords": "Weltkoordinaten",
"dimensions.active_cplane": "Aktive Konstruktionsebene",
"dimensions.rotate_hint": "Selektion um Z-Achse der aktiven Plane drehen",
"dimensions.rotate_ccw": "90° gegen den Uhrzeigersinn",
"dimensions.rotate_cw": "90° im Uhrzeigersinn",
"measures.title": "Masse",
"measures.subtitle": "Globale Vorgaben für Raum-Rundung und Mass-Linien",
"measures.active": "Aktiv",
"measures.new": "Neues Mass anlegen",
"measures.delete_active": "Aktives Mass löschen",
"measures.name": "Name",
"measures.room_rounding": "Raum-Rundung",
"measures.decimal_places": "Mass-Dezimalstellen",
"measures.unit": "Mass-Einheit",
"measures.hint": "Änderungen werden sofort auf alle Räume angewendet.",
"measures.delete_confirm": "Mass \"{name}\" löschen?",
"measures.min_one": "Mindestens ein Mass muss erhalten bleiben.",
"measures.new_name": "Name für neues Mass:",
"measures.new_name_placeholder": "Name für neues Mass:",
"about.tagline": "Architektur-Studio für Rhino 8",
"about.part_of": "Teil von",
"about.author": "Autor",
"about.web": "Web",
"about.license": "Lizenz · Dual",
"about.license_open": "Frei nutzbar, modifizierbar und weitergebbar unter den Bedingungen der AGPL-3.0.",
"about.license_commercial": "Kommerzielle Lizenz",
"about.license_commercial_hint": "Für proprietäre Integrationen — Kontakt: karim@gabrielevarano.ch",
"about.made_in": "made in Switzerland"
}
+290
View File
@@ -0,0 +1,290 @@
{
"common.save": "Save",
"common.cancel": "Cancel",
"common.delete": "Delete",
"common.duplicate": "Duplicate",
"common.rename": "Rename",
"common.settings": "Settings",
"common.edit": "Edit",
"common.add": "Add",
"common.expand": "Expand",
"common.collapse": "Collapse",
"common.show": "Show",
"common.hide": "Hide",
"common.lock": "Lock",
"common.unlock": "Unlock",
"common.refresh": "Refresh",
"common.close": "Close",
"common.apply": "Apply",
"common.new_folder": "New Folder",
"common.rename_folder": "Rename Folder",
"common.delete_folder": "Delete Folder",
"common.new_folder_name": "New Folder Name:",
"lang.de": "Deutsch",
"lang.en": "English",
"lang.label": "Language",
"settings.title": "Dossier Settings",
"settings.language": "Language",
"settings.language_hint": "Applies to all panels",
"settings.launcher_sync": "Launcher Settings",
"settings.launcher_available": "Launcher connected",
"settings.launcher_missing": "Launcher not found",
"settings.window_layout": "Window Layout",
"settings.apply_layout": "Auto-apply layout",
"settings.saved": "Saved",
"layers.title": "Layers",
"layers.settings": "Layer Settings…",
"layers.add_sub": "Add Sub-Layer…",
"layers.move_selection": "Move Selection Here",
"layers.copy_props": "Copy Properties",
"layers.paste_props": "Paste Properties",
"layers.add": "Add Layer",
"layers.hide_all": "Hide All Layers",
"layers.show_all": "Show All Layers",
"layers.lock_all": "Lock All Layers",
"layers.unlock_all": "Unlock All Layers",
"layers.visibility_mode": "Visibility Mode",
"layers.show_all_mode": "Show All",
"layers.selected_mode": "Selected",
"layers.active_only_mode": "Active Only",
"layers.others_gray": "Others Gray",
"layers.others_gray_locked": "Others Gray & Locked",
"layers.combination": "Layer Combination",
"layers.no_combination": "No Combination — Manual Visibility",
"layers.edit_combinations": "Edit Layer Combinations",
"layers.save_current": "+ Save Current…",
"layers.delete_current": "Delete Current",
"layers.custom": "— Custom —",
"layers.dblclick_edit": "Double-click to Edit",
"layers.dblclick_rename": "Double-click to Rename",
"floors.title": "Drawing Levels",
"floors.add": "Add: Floor / Section / Drawing",
"floors.floor": "Floor",
"floors.section": "Section / View",
"floors.drawing": "Drawing",
"floors.new_floor": "New Floor",
"floors.position_relative": "Position Relative To",
"floors.none": "— none —",
"floors.insert_above": "Insert Above Anchor",
"floors.insert_below": "Insert Below Anchor",
"floors.height": "Height (m)",
"floors.section_height": "Section (m)",
"floors.section_height_hint": "Height of Section Plane Above OKFF",
"floors.hide_all": "Hide All Drawing Levels",
"floors.show_all": "Show All Drawing Levels",
"floors.lock_all": "Lock All Drawing Levels",
"floors.unlock_all": "Unlock All Drawing Levels",
"floors.clipping_off": "Turn Off Clipping Plane",
"floors.clipping_on": "Turn On Clipping Plane",
"floors.copy_suffix": "Copy",
"floors.confirm_delete": "Really delete?",
"viewports.title": "Viewports",
"viewports.save": "Save Viewport",
"viewports.new_name": "Name for New Viewport…",
"viewports.restore": "Restore",
"viewports.apply_to_detail": "Apply to Detail",
"viewports.settings": "Viewport Settings…",
"viewports.update": "Update",
"viewports.empty": "No Viewports Yet.",
"viewports.empty_hint": "Enter a name above and click.",
"viewports.empty_folder": "Empty — Drop viewports here.",
"viewports.drop_root": "Drop here for root",
"viewports.folder_actions": "Folder Actions",
"viewports.new_folder_name": "Name for New Folder:",
"viewports.delete_folder_confirm": "Viewports will be moved to root.",
"viewports.scale_hint": "Double-click to enter scale (e.g. 1:50)",
"viewports.footer_hint": "Drag & Drop onto folder card to move · Double-click = edit · ⋮ for actions",
"layouts.title": "Layouts",
"layouts.landscape": "Landscape",
"layouts.portrait": "Portrait",
"layouts.untitled": "(Untitled)",
"layouts.empty": "No Layouts Yet.",
"layouts.empty_hint": "Click below to create a new layout.",
"layouts.empty_folder": "Empty — Drop layouts here.",
"layouts.drop_remove": "Drop here to remove from folder",
"layouts.new_detail": "New Detail (Centered on Page)",
"layouts.sync_all": "Re-sync All Details with Their Viewports",
"layouts.no_details": "No Details on This Layout.",
"layouts.no_details_hint": "Click above to add one.",
"layouts.no_section": "— no viewport —",
"layouts.reapply_section": "Re-apply Bound Viewport",
"layouts.new": "Create New Layout",
"layouts.open_in_rhino": "Open in Rhino",
"layouts.export_pdf": "Export as PDF",
"layouts.export_selection_pdf": "Export Selection ({count}) as PDF",
"layouts.export_all_pdf": "Export All Layouts as PDF",
"layouts.select_first": "Select Layouts First",
"layouts.change_paper": "Change Paper Format",
"layouts.move_to": "Move → {folder}",
"layouts.remove_from_folder": "Remove from Folder",
"layouts.check_all": "Check All / Uncheck All",
"layouts.folder_pdf": "Folder as PDF ({count})",
"layouts.check_for_pdf": "Check for PDF Export",
"layouts.delete_detail_confirm": "Delete Detail?",
"layouts.new_folder_name": "New Folder Name:",
"layouts.delete_folder_confirm": "Layouts will be moved to root.",
"overrides.title": "Overrides",
"overrides.layer_name": "Layer Name",
"overrides.object_name": "Object Name",
"overrides.contains": "contains",
"overrides.starts_with": "starts with",
"overrides.ends_with": "ends with",
"overrides.remove_condition": "Remove This Condition",
"overrides.logic_all": "All Conditions Must Be Met",
"overrides.logic_any": "At Least One Condition Must Be Met",
"overrides.add_condition": "Add Another Condition",
"overrides.color": "Color",
"overrides.lineweight": "Line Weight",
"overrides.linetype": "Line Type",
"overrides.hatch": "Hatch Pattern",
"overrides.hatch_scale": "Hatch Scale",
"overrides.hatch_hint": "Hatch Override modifies only existing hatches.",
"overrides.conditions": "Conditions",
"overrides.overrides": "Overrides",
"overrides.combinations": "Override Combinations",
"overrides.no_combination": "— new / none —",
"overrides.save_as_combination": "Save as Combination…",
"overrides.save_changes_to": "Save Changes to \"{name}\"",
"overrides.save_current_as_new": "Save Current Rules as New Combination",
"overrides.delete_combination_confirm": "Permanently delete combination \"{name}\"?",
"overrides.delete_combination": "Permanently Delete Selected Combination",
"overrides.insert_empty": "Insert Empty Rule Above",
"overrides.from_template": "+ From Template…",
"overrides.insert_from_template": "Insert Rule from Template",
"overrides.delete_template": "Delete Template",
"overrides.additive_hint": "Rules are additive. In case of conflict, the topmost wins.",
"overrides.empty": "No Rules Yet.",
"overrides.empty_hint": "Click above to create a new rule.",
"overrides.activate": "Activate",
"overrides.deactivate": "Deactivate",
"overrides.prio_up": "Higher Priority (Up)",
"overrides.prio_down": "Lower Priority (Down)",
"overrides.save_as_template": "Save as Template…",
"overrides.template_name": "Name for Template:",
"overrides.delete_rule_confirm": "Delete rule \"{name}\"?",
"overrides.rule_active": "Rule Active",
"overrides.logic_label": "Logic:",
"overrides.key": "Key",
"overrides.value": "Value",
"overrides.condition": "Condition",
"overrides.empty_value": "(empty)",
"toolbar.shortcuts_hint": "Shortcuts (Shift+Click = About Dossier)",
"toolbar.app_settings": "Dossier Settings",
"toolbar.project_settings": "Project Settings",
"toolbar.overrides_on": "Graphic Overrides Active — click to turn off",
"toolbar.overrides_off": "Graphic Overrides Off",
"toolbar.open_overrides": "Open Overrides Editor",
"toolbar.zoom_snap": "Snap Zoom to 1:{scale}",
"toolbar.zoom_select_scale": "Select a Scale First",
"toolbar.zoom_all": "Zoom to All Content",
"toolbar.zoom_selection": "Zoom to Selection",
"toolbar.refs_show": "Show Reference Lines",
"toolbar.refs_hide": "Hide Reference Lines",
"toolbar.osnap_on": "Object Snap On — click to turn off",
"toolbar.osnap_off": "Object Snap Off — click to turn on",
"toolbar.grid_toggle": "Toggle Construction Grid",
"toolbar.print_view_on": "Print View Active — click to turn off",
"toolbar.print_view_off": "Show Line Weights (Print View)",
"toolbar.set_scale": "Set Scale",
"toolbar.live_scale": "Current Live Scale",
"toolbar.no_scale": "No Scale Set",
"toolbar.perspective_no_scale": "Perspective — No Scale",
"toolbar.scale_input": "Enter Scale",
"toolbar.font": "Font",
"toolbar.text_height": "Text Height (m)",
"toolbar.bold": "Bold",
"toolbar.italic": "Italic",
"toolbar.insert_text": "Insert New Text",
"toolbar.measures_edit": "Edit Measures / Create New",
"toolbar.style_save": "+ Save…",
"toolbar.style_delete": "Delete Active",
"toolbar.bring_front": "Bring to Front",
"toolbar.bring_forward": "Bring Forward",
"toolbar.send_backward": "Send Backward",
"toolbar.send_back": "Send to Back",
"toolbar.camera_settings": "Camera Settings",
"toolbar.detail_level_simple": "Simple (1:100)",
"toolbar.detail_level_standard": "Standard (1:50)",
"toolbar.detail_level_detail": "Detail (1:20)",
"tools.drawing_2d": "2D Drawing",
"tools.editing_2d": "2D Editing",
"tools.modeling_3d": "3D Modeling",
"tools.selection": "Selection",
"tools.line": "Line",
"tools.polyline": "Polyline",
"tools.rectangle": "Rectangle",
"tools.circle": "Circle",
"tools.arc": "Arc",
"tools.spline": "Free Curve (Spline)",
"tools.text": "Text",
"tools.hatch": "Hatch",
"tools.dimension": "Linear Dimension",
"tools.move": "Move",
"tools.copy": "Copy",
"tools.rotate": "Rotate",
"tools.scale": "Scale",
"tools.mirror": "Mirror",
"tools.offset": "Offset",
"tools.trim": "Trim",
"tools.extend": "Extend",
"tools.join": "Join",
"tools.explode": "Explode",
"tools.fillet": "Fillet",
"tools.array": "Polar Array",
"tools.extrude": "Extrude Curve to 3D",
"tools.box": "Box",
"tools.bool_union": "Boolean Union",
"tools.bool_diff": "Boolean Difference",
"tools.bool_intersect": "Boolean Intersection",
"tools.close_holes": "Close Planar Holes",
"tools.section_lines": "Create Section Lines",
"tools.loft": "Loft",
"tools.select_tangent": "Select Tangent Curve Chain",
"tools.select_duplicates": "Select Duplicate Objects",
"tools.select_closed": "Select Closed Curves",
"tools.invert_selection": "Invert Selection",
"tools.select_all": "Select All",
"tools.deselect_all": "Deselect All",
"dimensions.no_selection": "No Selection",
"dimensions.no_selection_hint": "Select one or more objects in Rhino.",
"dimensions.world_coords": "World Coordinates",
"dimensions.active_cplane": "Active Construction Plane",
"dimensions.rotate_hint": "Rotate selection around Z-axis of active plane",
"dimensions.rotate_ccw": "90° Counterclockwise",
"dimensions.rotate_cw": "90° Clockwise",
"measures.title": "Measures",
"measures.subtitle": "Global defaults for room rounding and measure lines",
"measures.active": "Active",
"measures.new": "Create New Measure",
"measures.delete_active": "Delete Active Measure",
"measures.name": "Name",
"measures.room_rounding": "Room Rounding",
"measures.decimal_places": "Decimal Places",
"measures.unit": "Unit",
"measures.hint": "Changes apply immediately to all rooms.",
"measures.delete_confirm": "Delete measure \"{name}\"?",
"measures.min_one": "At least one measure must remain.",
"measures.new_name": "Name for new measure:",
"measures.new_name_placeholder": "Name for new measure:",
"about.tagline": "Architecture Studio for Rhino 8",
"about.part_of": "Part of",
"about.author": "Author",
"about.web": "Web",
"about.license": "License · Dual",
"about.license_open": "Freely usable, modifiable and distributable under AGPL-3.0.",
"about.license_commercial": "Commercial License",
"about.license_commercial_hint": "For proprietary integrations — contact: karim@gabrielevarano.ch",
"about.made_in": "made in Switzerland"
}
+18
View File
@@ -0,0 +1,18 @@
import de from './de.json'
import en from './en.json'
const _langs = { de, en }
function _getLang() {
return (typeof window !== 'undefined' && window.DOSSIER_LANG) || 'de'
}
export function t(key, vars) {
const lang = _getLang()
const dict = _langs[lang] || _langs.de
const str = dict[key] ?? _langs.de[key] ?? key
if (!vars) return str
return str.replace(/\{(\w+)\}/g, (_, k) => (vars[k] ?? `{${k}}`))
}
export function getLang() { return _getLang() }
+38 -30
View File
@@ -3,63 +3,71 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
// Set language before any component renders
if (typeof window !== 'undefined' && window.DOSSIER_LANG == null) {
window.DOSSIER_LANG = 'de'
}
import App from './App.jsx'
import ZeichnungsebenenApp from './ZeichnungsebenenApp.jsx'
import GeschossSettingsApp from './GeschossSettingsApp.jsx'
import DrawingLevelsApp from './DrawingLevelsApp.jsx'
import FloorSettingsApp from './FloorSettingsApp.jsx'
import FloorDialogApp from './FloorDialogApp.jsx'
import ProjectSettingsApp from './ProjectSettingsApp.jsx'
import DossierSettingsApp from './DossierSettingsApp.jsx'
import LibraryApp from './LibraryApp.jsx'
import SymbolPickerApp from './SymbolPickerApp.jsx'
import EbenenSettingsApp from './EbenenSettingsApp.jsx'
import GeschossDialogApp from './GeschossDialogApp.jsx'
import LayerSettingsApp from './LayerSettingsApp.jsx'
import LayerCombinationsApp from './LayerCombinationsApp.jsx'
import AusschnittSettingsApp from './AusschnittSettingsApp.jsx'
import ViewportSettingsApp from './ViewportSettingsApp.jsx'
import LayoutDialogApp from './LayoutDialogApp.jsx'
import SwisstopoApp from './SwisstopoApp.jsx'
import OsmApp from './OsmApp.jsx'
import KameraApp from './KameraApp.jsx'
import MasseSettingsApp from './MasseSettingsApp.jsx'
import CameraApp from './CameraApp.jsx'
import UnitsSettingsApp from './UnitsSettingsApp.jsx'
import AboutApp from './AboutApp.jsx'
import TextEditorApp from './TextEditorApp.jsx'
import GestaltungApp from './GestaltungApp.jsx'
import AusschnitteApp from './AusschnitteApp.jsx'
import MassstabApp from './MassstabApp.jsx'
import WerkzeugeApp from './WerkzeugeApp.jsx'
import OberleisteApp from './OberleisteApp.jsx'
import StylesApp from './StylesApp.jsx'
import ViewportsApp from './ViewportsApp.jsx'
import ScaleApp from './ScaleApp.jsx'
import ToolsApp from './ToolsApp.jsx'
import ToolbarApp from './ToolbarApp.jsx'
import OverridesApp from './OverridesApp.jsx'
import DimensionenApp from './DimensionenApp.jsx'
import DimensionsApp from './DimensionsApp.jsx'
import LayoutsApp from './LayoutsApp.jsx'
import ElementeApp from './ElementeApp.jsx'
import ElementeUebersichtApp from './ElementeUebersichtApp.jsx'
import ElementePropertiesApp from './ElementePropertiesApp.jsx'
import ElementsOverviewApp from './ElementsOverviewApp.jsx'
import ElementPropertiesApp from './ElementPropertiesApp.jsx'
const mode = (typeof window !== 'undefined' && window.PANEL_MODE) || 'ebenen'
const RootApp = mode === 'gestaltung' ? GestaltungApp
: mode === 'ausschnitte' ? AusschnitteApp
: mode === 'massstab' ? MassstabApp
: mode === 'werkzeuge' ? WerkzeugeApp
: mode === 'oberleiste' ? OberleisteApp
const RootApp = mode === 'gestaltung' ? StylesApp
: mode === 'ausschnitte' ? ViewportsApp
: mode === 'massstab' ? ScaleApp
: mode === 'werkzeuge' ? ToolsApp
: mode === 'oberleiste' ? ToolbarApp
: mode === 'overrides' ? OverridesApp
: mode === 'dimensionen' ? DimensionenApp
: mode === 'dimensionen' ? DimensionsApp
: mode === 'layouts' ? LayoutsApp
: mode === 'elemente' ? ElementeApp
: mode === 'zeichnungsebenen' ? ZeichnungsebenenApp
: mode === 'geschoss_settings' ? GeschossSettingsApp
: mode === 'zeichnungsebenen' ? DrawingLevelsApp
: mode === 'geschoss_settings' ? FloorSettingsApp
: mode === 'project_settings' ? ProjectSettingsApp
: mode === 'dossier_settings' ? DossierSettingsApp
: mode === 'library' ? LibraryApp
: mode === 'symbol_picker' ? SymbolPickerApp
: mode === 'ebenen_settings' ? EbenenSettingsApp
: mode === 'geschoss_dialog' ? GeschossDialogApp
: mode === 'ebenen_settings' ? LayerSettingsApp
: mode === 'geschoss_dialog' ? FloorDialogApp
: mode === 'layer_combinations' ? LayerCombinationsApp
: mode === 'ausschnitt_settings' ? AusschnittSettingsApp
: mode === 'ausschnitt_settings' ? ViewportSettingsApp
: mode === 'layout_dialog' ? LayoutDialogApp
: mode === 'swisstopo' ? SwisstopoApp
: mode === 'osm' ? OsmApp
: mode === 'kamera' ? KameraApp
: mode === 'masse_settings' ? MasseSettingsApp
: mode === 'kamera' ? CameraApp
: mode === 'masse_settings' ? UnitsSettingsApp
: mode === 'about' ? AboutApp
: mode === 'text_editor' ? TextEditorApp
: mode === 'elemente_uebersicht' ? ElementeUebersichtApp
: mode === 'elemente_properties' ? ElementePropertiesApp
: mode === 'elemente_uebersicht' ? ElementsOverviewApp
: mode === 'elemente_properties' ? ElementPropertiesApp
: App
document.addEventListener('contextmenu', e => e.preventDefault(), true)