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:
@@ -20,7 +20,7 @@ else:
|
|||||||
"cutAtLine": True, "namePrefix": "S",
|
"cutAtLine": True, "namePrefix": "S",
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
ps = rhinopanel.load_project_settings(doc)
|
ps = rhinopanel.load_project_settings(doc)
|
||||||
d = (ps or {}).get("defaults", {})
|
d = (ps or {}).get("defaults", {})
|
||||||
defaults["depthBack"] = float(d.get("schnittDepthBack", 8.0))
|
defaults["depthBack"] = float(d.get("schnittDepthBack", 8.0))
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ def _run():
|
|||||||
# gestaltung fuer Fill-Re-Apply
|
# gestaltung fuer Fill-Re-Apply
|
||||||
_g = None
|
_g = None
|
||||||
try:
|
try:
|
||||||
import gestaltung as _gmod; _g = _gmod
|
import styles as _gmod; _g = _gmod
|
||||||
except Exception as iex:
|
except Exception as iex:
|
||||||
print("[SMART-JOIN] gestaltung import:", iex)
|
print("[SMART-JOIN] gestaltung import:", iex)
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ def _run():
|
|||||||
_replicate_hatch(doc, nobj, hatch_props)
|
_replicate_hatch(doc, nobj, hatch_props)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
import gestaltung as _gmod
|
import styles as _gmod
|
||||||
for nid in new_ids:
|
for nid in new_ids:
|
||||||
nobj = doc.Objects.FindId(nid)
|
nobj = doc.Objects.FindId(nid)
|
||||||
if nobj is not None:
|
if nobj is not None:
|
||||||
|
|||||||
@@ -556,7 +556,7 @@ class AusschnittBridge(panel_base.BaseBridge):
|
|||||||
kombi = (snap.get("layerCombination") or "").strip()
|
kombi = (snap.get("layerCombination") or "").strip()
|
||||||
if kombi:
|
if kombi:
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel.apply_layer_preset_by_name(doc, kombi)
|
rhinopanel.apply_layer_preset_by_name(doc, kombi)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[AUSSCHNITTE] kombi-apply '{}':".format(kombi), ex)
|
print("[AUSSCHNITTE] kombi-apply '{}':".format(kombi), ex)
|
||||||
@@ -565,7 +565,7 @@ class AusschnittBridge(panel_base.BaseBridge):
|
|||||||
_apply_layers_global(doc, snap.get("layers", []))
|
_apply_layers_global(doc, snap.get("layers", []))
|
||||||
# Eigene Sichtbarkeit → active_comb_name clearen
|
# Eigene Sichtbarkeit → active_comb_name clearen
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel.set_active_comb_name(doc, None)
|
rhinopanel.set_active_comb_name(doc, None)
|
||||||
rhinopanel._notify_oberleiste_combs()
|
rhinopanel._notify_oberleiste_combs()
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
@@ -785,7 +785,7 @@ class AusschnittBridge(panel_base.BaseBridge):
|
|||||||
# Listen fuer Dropdowns
|
# Listen fuer Dropdowns
|
||||||
display_modes = []
|
display_modes = []
|
||||||
try:
|
try:
|
||||||
import oberleiste
|
import toolbar as oberleiste
|
||||||
display_modes = oberleiste._list_display_modes()
|
display_modes = oberleiste._list_display_modes()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[AUSSCHNITTE] display_modes:", ex)
|
print("[AUSSCHNITTE] display_modes:", ex)
|
||||||
@@ -797,7 +797,7 @@ class AusschnittBridge(panel_base.BaseBridge):
|
|||||||
print("[AUSSCHNITTE] overrides_presets:", ex)
|
print("[AUSSCHNITTE] overrides_presets:", ex)
|
||||||
layer_kombis = []
|
layer_kombis = []
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
layer_kombis = rhinopanel.list_layer_preset_names(d)
|
layer_kombis = rhinopanel.list_layer_preset_names(d)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[AUSSCHNITTE] layer_kombis:", ex)
|
print("[AUSSCHNITTE] layer_kombis:", ex)
|
||||||
|
|||||||
+12
-12
@@ -771,7 +771,7 @@ def _find_ebene_sublayer_name(doc, keywords, default_code, default_name,
|
|||||||
print("[ELEMENTE] build_layers nach auto-add:", ex)
|
print("[ELEMENTE] build_layers nach auto-add:", ex)
|
||||||
# Ebenen-Manager UI mit-informieren via broadcast_state
|
# Ebenen-Manager UI mit-informieren via broadcast_state
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] broadcast_state:", ex)
|
print("[ELEMENTE] broadcast_state:", ex)
|
||||||
@@ -866,7 +866,7 @@ def _ensure_referenz_child_in_doc(doc, parent_code, parent_keywords,
|
|||||||
z_raw = doc.Strings.GetValue("dossier_zeichnungsebenen")
|
z_raw = doc.Strings.GetValue("dossier_zeichnungsebenen")
|
||||||
zlist = json.loads(z_raw) if z_raw else []
|
zlist = json.loads(z_raw) if z_raw else []
|
||||||
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
|
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] _ensure_referenz_child:", ex)
|
print("[ELEMENTE] _ensure_referenz_child:", ex)
|
||||||
@@ -953,7 +953,7 @@ def _ensure_oeff_ebenen_in_doc(doc):
|
|||||||
z_raw = doc.Strings.GetValue("dossier_zeichnungsebenen")
|
z_raw = doc.Strings.GetValue("dossier_zeichnungsebenen")
|
||||||
zlist = json.loads(z_raw) if z_raw else []
|
zlist = json.loads(z_raw) if z_raw else []
|
||||||
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
|
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] _ensure_oeff_ebenen_in_doc build:", ex)
|
print("[ELEMENTE] _ensure_oeff_ebenen_in_doc build:", ex)
|
||||||
@@ -3641,7 +3641,7 @@ def _get_all_materials(doc):
|
|||||||
merged[n].setdefault("uvScaleM", 1.0)
|
merged[n].setdefault("uvScaleM", 1.0)
|
||||||
merged[n].setdefault("textures", {})
|
merged[n].setdefault("textures", {})
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
ps = rhinopanel.load_project_settings(doc) if doc else None
|
ps = rhinopanel.load_project_settings(doc) if doc else None
|
||||||
if isinstance(ps, dict):
|
if isinstance(ps, dict):
|
||||||
for m in ps.get("materials", []):
|
for m in ps.get("materials", []):
|
||||||
@@ -3657,7 +3657,7 @@ def _get_all_wand_styles(doc):
|
|||||||
"""Liefert alle Wand-Stile aus den Project-Settings. Wenn keine
|
"""Liefert alle Wand-Stile aus den Project-Settings. Wenn keine
|
||||||
konfiguriert (auch keine Defaults greifbar), leere Liste."""
|
konfiguriert (auch keine Defaults greifbar), leere Liste."""
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
ps = rhinopanel.load_project_settings(doc) if doc else None
|
ps = rhinopanel.load_project_settings(doc) if doc else None
|
||||||
if isinstance(ps, dict):
|
if isinstance(ps, dict):
|
||||||
return list(ps.get("wand_styles", []) or [])
|
return list(ps.get("wand_styles", []) or [])
|
||||||
@@ -13337,7 +13337,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
# Projekt-Adresse als Vorschlag fuer die Adress-Suche
|
# Projekt-Adresse als Vorschlag fuer die Adress-Suche
|
||||||
project_address = ""
|
project_address = ""
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
ps = rhinopanel.load_project_settings(doc) if doc else None
|
ps = rhinopanel.load_project_settings(doc) if doc else None
|
||||||
if isinstance(ps, dict):
|
if isinstance(ps, dict):
|
||||||
project_address = (ps.get("project", {}) or {}).get("address") or ""
|
project_address = (ps.get("project", {}) or {}).get("address") or ""
|
||||||
@@ -14223,7 +14223,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
zlist = json.loads(z_raw) if z_raw else []
|
zlist = json.loads(z_raw) if z_raw else []
|
||||||
if zlist:
|
if zlist:
|
||||||
layer_builder.build_layers(doc, zlist, ebenen)
|
layer_builder.build_layers(doc, zlist, ebenen)
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._push_log(" swisstopo-ebenen build: {}".format(ex))
|
self._push_log(" swisstopo-ebenen build: {}".format(ex))
|
||||||
@@ -14317,7 +14317,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
# UI informieren — broadcast_state schickt STATE_SYNC an
|
# UI informieren — broadcast_state schickt STATE_SYNC an
|
||||||
# ebenen_bridge_ref + zeichnungsebenen_bridge_ref
|
# ebenen_bridge_ref + zeichnungsebenen_bridge_ref
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._push_log("broadcast_state: {}".format(ex))
|
self._push_log("broadcast_state: {}".format(ex))
|
||||||
@@ -14660,7 +14660,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
if zlist:
|
if zlist:
|
||||||
import layer_builder
|
import layer_builder
|
||||||
layer_builder.build_layers(doc, zlist, ebenen)
|
layer_builder.build_layers(doc, zlist, ebenen)
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._push_log("osm-ebenen build: {}".format(ex))
|
self._push_log("osm-ebenen build: {}".format(ex))
|
||||||
@@ -16679,7 +16679,7 @@ def _migrate_plangrafik_60_to_80_once(doc):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] build_layers nach Plangrafik-Migration:", ex)
|
print("[ELEMENTE] build_layers nach Plangrafik-Migration:", ex)
|
||||||
try:
|
try:
|
||||||
import rhinopanel as _rp
|
import layers_panel as _rp
|
||||||
_rp._broadcast_state(doc)
|
_rp._broadcast_state(doc)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
@@ -16789,7 +16789,7 @@ def _migrate_layer_caps_once(doc):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[ELEMENTE] build_layers nach CAPS-Migration:", ex)
|
print("[ELEMENTE] build_layers nach CAPS-Migration:", ex)
|
||||||
try:
|
try:
|
||||||
import rhinopanel as _rp
|
import layers_panel as _rp
|
||||||
_rp._broadcast_state(doc)
|
_rp._broadcast_state(doc)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
@@ -16874,7 +16874,7 @@ def _migrate_referenz_layer_once(doc):
|
|||||||
# nicht neu angelegt hat (z.B. weil er schon existiert) wird das
|
# nicht neu angelegt hat (z.B. weil er schon existiert) wird das
|
||||||
# Panel sonst nicht neu gerendert.
|
# Panel sonst nicht neu gerendert.
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
|||||||
@@ -2204,7 +2204,7 @@ class EbenenBridge(panel_base.BaseBridge):
|
|||||||
# geaendert hat (nicht bei reinen Name/Farb-Aenderungen, die das
|
# geaendert hat (nicht bei reinen Name/Farb-Aenderungen, die das
|
||||||
# Settings-Dialog auch triggern koennte).
|
# Settings-Dialog auch triggern koennte).
|
||||||
try:
|
try:
|
||||||
import gestaltung
|
import styles as gestaltung
|
||||||
if fill_changed:
|
if fill_changed:
|
||||||
gestaltung.refresh_layer_fills(doc)
|
gestaltung.refresh_layer_fills(doc)
|
||||||
else:
|
else:
|
||||||
+1
-1
@@ -664,7 +664,7 @@ def import_material(doc, item):
|
|||||||
"uvScaleM", "textures"):
|
"uvScaleM", "textures"):
|
||||||
if k in data: new_mat[k] = data[k]
|
if k in data: new_mat[k] = data[k]
|
||||||
# Lazy-Import um Zyklen zu vermeiden
|
# Lazy-Import um Zyklen zu vermeiden
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
settings = rhinopanel.load_project_settings(doc)
|
settings = rhinopanel.load_project_settings(doc)
|
||||||
mats = list(settings.get("materials", []))
|
mats = list(settings.get("materials", []))
|
||||||
for m in mats:
|
for m in mats:
|
||||||
|
|||||||
+17
-1
@@ -20,6 +20,21 @@ import scriptcontext as sc
|
|||||||
|
|
||||||
_HERE = os.path.dirname(os.path.abspath(__file__))
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
_DIST = os.path.join(_HERE, "..", "dist", "index.html")
|
_DIST = os.path.join(_HERE, "..", "dist", "index.html")
|
||||||
|
_SETTINGS_PATH = os.path.expanduser(
|
||||||
|
"~/Library/Application Support/ch.gabrielevarano.Dossier/dossier_settings.json")
|
||||||
|
|
||||||
|
|
||||||
|
def _read_lang():
|
||||||
|
"""Liest die UI-Sprache aus dossier_settings.json. Default: 'de'."""
|
||||||
|
try:
|
||||||
|
if os.path.isfile(_SETTINGS_PATH):
|
||||||
|
with open(_SETTINGS_PATH, "rb") as f:
|
||||||
|
d = json.loads(f.read().decode("utf-8"))
|
||||||
|
lang = d.get("lang", "de")
|
||||||
|
return lang if lang in ("de", "en") else "de"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return "de"
|
||||||
|
|
||||||
|
|
||||||
# --- Timing-Instrumentierung ------------------------------------------------
|
# --- Timing-Instrumentierung ------------------------------------------------
|
||||||
@@ -317,7 +332,8 @@ def load_inline(wv, mode, params=None):
|
|||||||
_INLINE_TEMPLATE = (sig, tmpl)
|
_INLINE_TEMPLATE = (sig, tmpl)
|
||||||
|
|
||||||
# Per-Mount: nur das Mode-Script-Snippet bauen
|
# Per-Mount: nur das Mode-Script-Snippet bauen
|
||||||
parts = ['window.PANEL_MODE="{}";'.format(mode)]
|
parts = ['window.PANEL_MODE="{}";'.format(mode),
|
||||||
|
'window.DOSSIER_LANG="{}";'.format(_read_lang())]
|
||||||
if params is not None:
|
if params is not None:
|
||||||
try:
|
try:
|
||||||
parts.append('window.PANEL_PARAMS=' + json.dumps(params, ensure_ascii=False) + ';')
|
parts.append('window.PANEL_PARAMS=' + json.dumps(params, ensure_ascii=False) + ';')
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ def _update_linePts(doc, schnitt_id, new_p1, new_p2):
|
|||||||
# Panel-Broadcast (linePts haben sich geaendert, Ebenen-Panel will
|
# Panel-Broadcast (linePts haben sich geaendert, Ebenen-Panel will
|
||||||
# ggf. mit-rendern)
|
# ggf. mit-rendern)
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
rhinopanel._broadcast_state(doc)
|
rhinopanel._broadcast_state(doc)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try: doc.Views.Redraw()
|
try: doc.Views.Redraw()
|
||||||
|
|||||||
+1
-1
@@ -609,7 +609,7 @@ def pick_schnitt_interactive(doc, defaults=None):
|
|||||||
# Project-Defaults als 2-stufiges Fallback (defaults > project > hardcoded)
|
# Project-Defaults als 2-stufiges Fallback (defaults > project > hardcoded)
|
||||||
proj_d = {}
|
proj_d = {}
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
ps = rhinopanel.load_project_settings(doc) or {}
|
ps = rhinopanel.load_project_settings(doc) or {}
|
||||||
proj_d = ps.get("defaults", {}) or {}
|
proj_d = ps.get("defaults", {}) or {}
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|||||||
+6
-6
@@ -44,13 +44,13 @@ _UI_FILE = os.path.join(_HERE, "DOSSIERUI.rhw")
|
|||||||
# Muss synchron sein mit launcher/modules.json. Wenn neue Module dazukommen,
|
# Muss synchron sein mit launcher/modules.json. Wenn neue Module dazukommen,
|
||||||
# beide Stellen pflegen.
|
# beide Stellen pflegen.
|
||||||
_MODULE_TO_PY = {
|
_MODULE_TO_PY = {
|
||||||
"ebenen": "rhinopanel",
|
"ebenen": "layers_panel",
|
||||||
"oberleiste": "oberleiste",
|
"oberleiste": "toolbar",
|
||||||
"ausschnitte": "ausschnitte",
|
"ausschnitte": "ausschnitte",
|
||||||
"gestaltung": "gestaltung",
|
"gestaltung": "styles",
|
||||||
"werkzeuge": "werkzeuge",
|
"werkzeuge": "tools",
|
||||||
"overrides": "overrides_panel",
|
"overrides": "overrides_panel",
|
||||||
"dimensionen": "dimensionen",
|
"dimensionen": "dimensions",
|
||||||
"layouts": "layouts",
|
"layouts": "layouts",
|
||||||
"elemente": "elemente",
|
"elemente": "elemente",
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ def _check_doc_unit(doc):
|
|||||||
return
|
return
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try:
|
try:
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
target_unit_str = rhinopanel.get_project_unit(doc)
|
target_unit_str = rhinopanel.get_project_unit(doc)
|
||||||
target_unit_enum = rhinopanel.get_project_unit_enum(doc)
|
target_unit_enum = rhinopanel.get_project_unit_enum(doc)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ if _HERE not in sys.path:
|
|||||||
import panel_base
|
import panel_base
|
||||||
import massstab
|
import massstab
|
||||||
import overrides
|
import overrides
|
||||||
import rhinopanel
|
import layers_panel as rhinopanel
|
||||||
|
|
||||||
PANEL_GUID_STR = "7e1f6a5b-8e2f-4f3c-d5e6-f70819203b51"
|
PANEL_GUID_STR = "7e1f6a5b-8e2f-4f3c-d5e6-f70819203b51"
|
||||||
OVERRIDES_PANEL_GUID_STR = "8f2a7b6c-9f3a-4f4d-e6f7-08192a3c4d62"
|
OVERRIDES_PANEL_GUID_STR = "8f2a7b6c-9f3a-4f4d-e6f7-08192a3c4d62"
|
||||||
@@ -1849,13 +1849,17 @@ class OberleisteBridge(panel_base.BaseBridge):
|
|||||||
|
|
||||||
# --- Settings + Window-Layout -----------------------------------
|
# --- Settings + Window-Layout -----------------------------------
|
||||||
elif t == "OPEN_SETTINGS":
|
elif t == "OPEN_SETTINGS":
|
||||||
# Primaerweg: Dossier-Launcher (Tauri-App) oeffnen, dort lebt das
|
_open_dossier_settings_panel()
|
||||||
# echte Settings-UI. Wenn der Launcher nicht installiert ist,
|
|
||||||
# faellt es auf den Eto-Dialog zurueck.
|
|
||||||
if not _launch_dossier_app():
|
|
||||||
open_settings_dialog()
|
|
||||||
elif t == "GET_SETTINGS":
|
elif t == "GET_SETTINGS":
|
||||||
self._send_settings_state()
|
self._send_settings_state()
|
||||||
|
elif t == "SAVE_LANG":
|
||||||
|
lang = (p.get("lang") or "de")
|
||||||
|
if lang not in ("de", "en"):
|
||||||
|
lang = "de"
|
||||||
|
cfg = _settings_load()
|
||||||
|
cfg["lang"] = lang
|
||||||
|
_settings_save(cfg)
|
||||||
|
_reload_all_panel_langs()
|
||||||
elif t == "APPLY_LAYOUT":
|
elif t == "APPLY_LAYOUT":
|
||||||
name = (p.get("name") or "").strip()
|
name = (p.get("name") or "").strip()
|
||||||
if name: _apply_window_layout(name)
|
if name: _apply_window_layout(name)
|
||||||
@@ -2195,6 +2199,53 @@ class OberleisteBridge(panel_base.BaseBridge):
|
|||||||
self._send_state(force=False)
|
self._send_state(force=False)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Dossier-Settings-Panel -------------------------------------------------
|
||||||
|
|
||||||
|
def _open_dossier_settings_panel():
|
||||||
|
"""Oeffnet das Dossier-Settings-Fenster (Rhino-hosted Eto-Satellite)."""
|
||||||
|
existing = sc.sticky.get("_dossier_settings_form")
|
||||||
|
if existing is not None:
|
||||||
|
try:
|
||||||
|
existing.BringToFront()
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
sc.sticky["_dossier_settings_form"] = None
|
||||||
|
|
||||||
|
cfg = _settings_load()
|
||||||
|
launcher_ok = os.path.isfile(_LAUNCHER_PATH)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import panel_base
|
||||||
|
form = panel_base.open_satellite_window(
|
||||||
|
"dossier_settings",
|
||||||
|
params={
|
||||||
|
"lang": cfg.get("lang", "de"),
|
||||||
|
"launcherOk": launcher_ok,
|
||||||
|
},
|
||||||
|
title="Dossier-Einstellungen",
|
||||||
|
size=(340, 320),
|
||||||
|
)
|
||||||
|
sc.sticky["_dossier_settings_form"] = form
|
||||||
|
except Exception as ex:
|
||||||
|
print("[OBERLEISTE] open_dossier_settings_panel:", ex)
|
||||||
|
|
||||||
|
|
||||||
|
def _reload_all_panel_langs():
|
||||||
|
"""Laedt alle registrierten Panel-WebViews neu (Sprache geaendert)."""
|
||||||
|
try:
|
||||||
|
import panel_base
|
||||||
|
for key, val in list(sc.sticky.items()):
|
||||||
|
if (key.endswith("_bridge") or key.endswith("_bridge_ref")) \
|
||||||
|
and hasattr(val, "_wv") and val._wv is not None \
|
||||||
|
and hasattr(val, "mode"):
|
||||||
|
try:
|
||||||
|
panel_base.load_inline(val._wv, val.mode)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[OBERLEISTE] reload_lang ({}): {}".format(key, ex))
|
||||||
|
except Exception as ex:
|
||||||
|
print("[OBERLEISTE] _reload_all_panel_langs:", ex)
|
||||||
|
|
||||||
|
|
||||||
# --- Listener-Hookup --------------------------------------------------------
|
# --- Listener-Hookup --------------------------------------------------------
|
||||||
|
|
||||||
def _install_listeners(bridge):
|
def _install_listeners(bridge):
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useState, useEffect, useMemo } from 'react'
|
import { useState, useEffect, useMemo } from 'react'
|
||||||
import EbenenManager from './components/EbenenManager'
|
import EbenenManager from './components/LayerManager'
|
||||||
import {
|
import {
|
||||||
applyAll, setActiveEbene,
|
applyAll, setActiveEbene,
|
||||||
onMessage, notifyReady, applyVisibility,
|
onMessage, notifyReady, applyVisibility,
|
||||||
|
|||||||
@@ -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
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useState, useEffect, useMemo } from 'react'
|
import { useState, useEffect, useMemo } from 'react'
|
||||||
import GeschossManager from './components/GeschossManager'
|
import GeschossManager from './components/FloorManager'
|
||||||
import {
|
import {
|
||||||
applyAll, setActiveZeichnungsebene,
|
applyAll, setActiveZeichnungsebene,
|
||||||
onMessage, notifyReady, applyVisibility,
|
onMessage, notifyReady, applyVisibility,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import GeschossDialog from './components/GeschossDialog'
|
import GeschossDialog from './components/FloorDialog'
|
||||||
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
|
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
|
||||||
|
|
||||||
// recalcOkff direkt hier — gleiche Logik wie in ZeichnungsebenenApp.jsx,
|
// recalcOkff direkt hier — gleiche Logik wie in ZeichnungsebenenApp.jsx,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import GeschossSettingsDialog from './components/GeschossSettingsDialog'
|
import GeschossSettingsDialog from './components/FloorSettingsDialog'
|
||||||
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
|
import { notifyReady, send as bridgeSend } from './lib/rhinoBridge'
|
||||||
|
|
||||||
export default function GeschossSettingsApp() {
|
export default function GeschossSettingsApp() {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import AusschnittLayerDialog from './components/AusschnittLayerDialog'
|
import AusschnittLayerDialog from './components/ViewportLayerDialog'
|
||||||
import { onMessage, notifyReady } from './lib/rhinoBridge'
|
import { onMessage, notifyReady } from './lib/rhinoBridge'
|
||||||
|
|
||||||
function send(type, payload) {
|
function send(type, payload) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useEffect, useState, useRef } from 'react'
|
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'
|
import { notifyReady, onMessage, send as bridgeSend } from './lib/rhinoBridge'
|
||||||
|
|
||||||
export default function EbenenSettingsApp() {
|
export default function EbenenSettingsApp() {
|
||||||
+16
-18
@@ -3,6 +3,7 @@
|
|||||||
import { useEffect, useState, useRef } from 'react'
|
import { useEffect, useState, useRef } from 'react'
|
||||||
import Icon from './components/Icon'
|
import Icon from './components/Icon'
|
||||||
import ContextMenu from './components/ContextMenu'
|
import ContextMenu from './components/ContextMenu'
|
||||||
|
import { t } from './i18n/index.js'
|
||||||
import { BarButton, BarCombo, BAR_H } from './components/BarControls'
|
import { BarButton, BarCombo, BAR_H } from './components/BarControls'
|
||||||
import {
|
import {
|
||||||
onMessage, notifyReady,
|
onMessage, notifyReady,
|
||||||
@@ -181,69 +182,66 @@ export default function LayoutsApp() {
|
|||||||
|
|
||||||
// Kontextmenue-Items pro Layout
|
// Kontextmenue-Items pro Layout
|
||||||
const layoutCtxItems = (l) => [
|
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) },
|
onClick: () => activateLayout(l.id) },
|
||||||
{ label: 'Umbenennen', icon: 'edit',
|
{ label: t('common.rename'), icon: 'edit',
|
||||||
onClick: () => setRenamingId(l.id) },
|
onClick: () => setRenamingId(l.id) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Als PDF exportieren', icon: 'picture_as_pdf',
|
{ label: t('layouts.export_pdf'), icon: 'picture_as_pdf',
|
||||||
onClick: () => exportPdf(l.id, 300) },
|
onClick: () => exportPdf(l.id, 300) },
|
||||||
{ label: 'Papierformat ändern', icon: 'aspect_ratio',
|
{ label: t('layouts.change_paper'), icon: 'aspect_ratio',
|
||||||
onClick: () => openLayoutDialog('edit', {
|
onClick: () => openLayoutDialog('edit', {
|
||||||
id: l.id, name: l.name, width: l.widthMm, height: l.heightMm,
|
id: l.id, name: l.name, width: l.widthMm, height: l.heightMm,
|
||||||
}) },
|
}) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
...(folders.length > 0 ? [
|
...(folders.length > 0 ? [
|
||||||
...folders.map(f => ({
|
...folders.map(f => ({
|
||||||
label: `Verschieben → ${f}`,
|
label: t('layouts.move_to', { folder: f }),
|
||||||
icon: 'folder',
|
icon: 'folder',
|
||||||
disabled: l.folder === f,
|
disabled: l.folder === f,
|
||||||
onClick: () => setLayoutFolder(l.id, f),
|
onClick: () => setLayoutFolder(l.id, f),
|
||||||
})),
|
})),
|
||||||
{ label: 'Aus Ordner entfernen',
|
{ label: t('layouts.remove_from_folder'),
|
||||||
icon: 'folder_off',
|
icon: 'folder_off',
|
||||||
disabled: !l.folder,
|
disabled: !l.folder,
|
||||||
onClick: () => setLayoutFolder(l.id, '') },
|
onClick: () => setLayoutFolder(l.id, '') },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
] : []),
|
] : []),
|
||||||
{ label: 'Löschen', icon: 'delete', danger: true,
|
{ label: t('common.delete'), icon: 'delete', danger: true,
|
||||||
onClick: () => {
|
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 folderCtxItems = (folderName) => {
|
||||||
const items = grouped[folderName] || []
|
const items = grouped[folderName] || []
|
||||||
return [
|
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',
|
icon: collapsedFolders.has(folderName) ? 'expand_more' : 'expand_less',
|
||||||
onClick: () => toggleFolderCollapse(folderName) },
|
onClick: () => toggleFolderCollapse(folderName) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Alle ankreuzen / abwählen',
|
{ label: t('layouts.check_all'),
|
||||||
icon: 'check_box',
|
icon: 'check_box',
|
||||||
onClick: () => checkAllInFolder(items) },
|
onClick: () => checkAllInFolder(items) },
|
||||||
{ label: `Ordner als PDF (${items.length})`,
|
{ label: t('layouts.folder_pdf', { count: items.length }),
|
||||||
icon: 'picture_as_pdf',
|
icon: 'picture_as_pdf',
|
||||||
disabled: items.length === 0,
|
disabled: items.length === 0,
|
||||||
onClick: () => handleExportFolder(folderName) },
|
onClick: () => handleExportFolder(folderName) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Ordner umbenennen',
|
{ label: t('common.rename_folder'),
|
||||||
icon: 'edit',
|
icon: 'edit',
|
||||||
onClick: () => {
|
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) {
|
if (next && next.trim() && next !== folderName) {
|
||||||
// Atomar via Server-Side waere besser; simpler: alle Layouts
|
|
||||||
// umhaengen + alten loeschen + neuen anlegen.
|
|
||||||
addLayoutFolder(next.trim())
|
addLayoutFolder(next.trim())
|
||||||
items.forEach(l => setLayoutFolder(l.id, next.trim()))
|
items.forEach(l => setLayoutFolder(l.id, next.trim()))
|
||||||
removeLayoutFolder(folderName)
|
removeLayoutFolder(folderName)
|
||||||
}
|
}
|
||||||
} },
|
} },
|
||||||
{ label: 'Ordner loeschen',
|
{ label: t('common.delete_folder'),
|
||||||
icon: 'folder_off', danger: true,
|
icon: 'folder_off', danger: true,
|
||||||
onClick: () => {
|
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)
|
removeLayoutFolder(folderName)
|
||||||
} },
|
} },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState, useEffect, useMemo } from 'react'
|
import { useState, useEffect, useMemo } from 'react'
|
||||||
import Icon from './components/Icon'
|
import Icon from './components/Icon'
|
||||||
import ContextMenu from './components/ContextMenu'
|
import ContextMenu from './components/ContextMenu'
|
||||||
|
import { t } from './i18n/index.js'
|
||||||
import {
|
import {
|
||||||
onMessage, notifyReady,
|
onMessage, notifyReady,
|
||||||
listAusschnitte, saveAusschnitt, updateAusschnitt,
|
listAusschnitte, saveAusschnitt, updateAusschnitt,
|
||||||
@@ -287,25 +288,25 @@ export default function AusschnitteApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAddFolder = () => {
|
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())
|
if (name && name.trim()) addAusschnittFolder(name.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctxItems = (id) => [
|
const ctxItems = (id) => [
|
||||||
{ label: 'Wiederherstellen', icon: 'restore', onClick: () => restoreAusschnitt(id) },
|
{ label: t('viewports.restore'), icon: 'restore', onClick: () => restoreAusschnitt(id) },
|
||||||
{ label: 'Auf Detail anwenden', icon: 'crop_landscape', onClick: () => applyAusschnittToDetail(id) },
|
{ label: t('viewports.apply_to_detail'),icon: 'crop_landscape', onClick: () => applyAusschnittToDetail(id) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Ausschnittseinstellungen…', icon: 'tune', onClick: () => openAusschnittSettings(id) },
|
{ label: t('viewports.settings'), icon: 'tune', onClick: () => openAusschnittSettings(id) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicateAusschnitt(id) },
|
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicateAusschnitt(id) },
|
||||||
{ label: 'Aktualisieren', icon: 'sync', onClick: () => updateAusschnitt(id) },
|
{ label: t('viewports.update'), icon: 'sync', onClick: () => updateAusschnitt(id) },
|
||||||
{ divider: true },
|
{ 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) => [
|
const folderCtxItems = (folderName) => [
|
||||||
{ label: 'Ordner umbenennen', icon: 'edit', onClick: () => {
|
{ label: t('common.rename_folder'), icon: 'edit', onClick: () => {
|
||||||
const newName = window.prompt('Neuer Ordnername:', folderName)
|
const newName = window.prompt(t('common.new_folder_name'), folderName)
|
||||||
if (newName && newName.trim() && newName !== folderName) {
|
if (newName && newName.trim() && newName !== folderName) {
|
||||||
snaps.filter(s => s.folder === folderName).forEach(s => setAusschnittFolder(s.id, newName.trim()))
|
snaps.filter(s => s.folder === folderName).forEach(s => setAusschnittFolder(s.id, newName.trim()))
|
||||||
addAusschnittFolder(newName.trim())
|
addAusschnittFolder(newName.trim())
|
||||||
@@ -313,8 +314,8 @@ export default function AusschnitteApp() {
|
|||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Ordner löschen', icon: 'folder_off', danger: true, onClick: () => {
|
{ label: t('common.delete_folder'), icon: 'folder_off', danger: true, onClick: () => {
|
||||||
if (window.confirm(`Ordner "${folderName}" löschen? Ausschnitte werden zur Wurzel verschoben.`)) {
|
if (window.confirm(`${t('common.delete_folder')} "${folderName}"? ${t('viewports.delete_folder_confirm')}`)) {
|
||||||
removeAusschnittFolder(folderName)
|
removeAusschnittFolder(folderName)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Icon from './Icon'
|
import Icon from './Icon'
|
||||||
import ContextMenu from './ContextMenu'
|
import ContextMenu from './ContextMenu'
|
||||||
|
import { t } from '../i18n/index.js'
|
||||||
import { BarCombo, BarButton } from './BarControls'
|
import { BarCombo, BarButton } from './BarControls'
|
||||||
import { openGeschossSettings, openGeschossDialog, createSchnitt } from '../lib/rhinoBridge'
|
import { openGeschossSettings, openGeschossDialog, createSchnitt } from '../lib/rhinoBridge'
|
||||||
|
|
||||||
@@ -150,12 +151,12 @@ function ZeichnungsebeneRow({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODES = [
|
const MODES = () => [
|
||||||
{ value: 'all_force', label: 'Alle anzeigen' },
|
{ value: 'all_force', label: t('layers.show_all_mode') },
|
||||||
{ value: 'all', label: 'Ausgewählte' },
|
{ value: 'all', label: t('layers.selected_mode') },
|
||||||
{ value: 'active', label: 'Nur aktive' },
|
{ value: 'active', label: t('layers.active_only_mode') },
|
||||||
{ value: 'grey', label: 'Andere grau' },
|
{ value: 'grey', label: t('layers.others_gray') },
|
||||||
{ value: 'grey_locked', label: 'Andere grau & gesperrt' },
|
{ value: 'grey_locked', label: t('layers.others_gray_locked') },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function GeschossManager({
|
export default function GeschossManager({
|
||||||
@@ -443,11 +444,11 @@ export default function GeschossManager({
|
|||||||
const z = zeichnungsebenen.find(x => x.id === id)
|
const z = zeichnungsebenen.find(x => x.id === id)
|
||||||
if (!z) return []
|
if (!z) return []
|
||||||
return [
|
return [
|
||||||
{ label: 'Einstellungen…', icon: 'settings', onClick: () => openGeschossSettings(z) },
|
{ label: t('common.settings') + '…', icon: 'settings', onClick: () => openGeschossSettings(z) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicate(id) },
|
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicate(id) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Löschen', icon: 'delete', danger: true,
|
{ label: t('common.delete'), icon: 'delete', danger: true,
|
||||||
disabled: zeichnungsebenen.length <= 1,
|
disabled: zeichnungsebenen.length <= 1,
|
||||||
onClick: () => remove(id) },
|
onClick: () => remove(id) },
|
||||||
]
|
]
|
||||||
@@ -461,22 +462,22 @@ export default function GeschossManager({
|
|||||||
background: 'var(--bg-section)',
|
background: 'var(--bg-section)',
|
||||||
borderBottom: '1px solid var(--border-light)',
|
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%' }}>
|
<div style={{ display: 'flex', width: '100%' }}>
|
||||||
<BarCombo
|
<BarCombo
|
||||||
stretch
|
stretch
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
value={mode}
|
value={mode}
|
||||||
onChange={onModeChange}
|
onChange={onModeChange}
|
||||||
title="Sichtbarkeits-Modus"
|
title={t('layers.visibility_mode')}
|
||||||
onGear={() => openGeschossDialog(zeichnungsebenen)}
|
onGear={() => openGeschossDialog(zeichnungsebenen)}
|
||||||
gearIcon="settings"
|
gearIcon="settings"
|
||||||
gearTitle="Einstellungen"
|
gearTitle={t('common.settings')}
|
||||||
onSecond={openAddMenu}
|
onSecond={openAddMenu}
|
||||||
secondIcon="add"
|
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>
|
<option key={m.value} value={m.value}>{m.label}</option>
|
||||||
))}
|
))}
|
||||||
</BarCombo>
|
</BarCombo>
|
||||||
@@ -501,8 +502,7 @@ export default function GeschossManager({
|
|||||||
if (mode === 'active' || mode === 'all_force') onModeChange('all')
|
if (mode === 'active' || mode === 'all_force') onModeChange('all')
|
||||||
}}
|
}}
|
||||||
title={zeichnungsebenen.every(z => z.visible !== false)
|
title={zeichnungsebenen.every(z => z.visible !== false)
|
||||||
? 'Alle Zeichnungsebenen ausblenden'
|
? t('floors.hide_all') : t('floors.show_all')}
|
||||||
: 'Alle Zeichnungsebenen einblenden'}
|
|
||||||
style={{ width: 16, height: 16,
|
style={{ width: 16, height: 16,
|
||||||
opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
|
opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
|
||||||
>
|
>
|
||||||
@@ -519,8 +519,7 @@ export default function GeschossManager({
|
|||||||
onChange(zeichnungsebenen.map(z => ({ ...z, locked: !anyLocked })))
|
onChange(zeichnungsebenen.map(z => ({ ...z, locked: !anyLocked })))
|
||||||
}}
|
}}
|
||||||
title={zeichnungsebenen.every(z => z.locked === true)
|
title={zeichnungsebenen.every(z => z.locked === true)
|
||||||
? 'Alle Zeichnungsebenen entsperren'
|
? t('floors.unlock_all') : t('floors.lock_all')}
|
||||||
: 'Alle Zeichnungsebenen sperren'}
|
|
||||||
style={{ width: 14, height: 14 }}
|
style={{ width: 14, height: 14 }}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
@@ -2,19 +2,20 @@
|
|||||||
// Copyright (C) 2026 Karim Gabriele Varano
|
// Copyright (C) 2026 Karim Gabriele Varano
|
||||||
import { useState, useRef, useMemo, useEffect } from 'react'
|
import { useState, useRef, useMemo, useEffect } from 'react'
|
||||||
import Icon from './Icon'
|
import Icon from './Icon'
|
||||||
import ConfirmDeleteEbene from './ConfirmDeleteEbene'
|
import ConfirmDeleteEbene from './ConfirmDeleteLayer'
|
||||||
import ContextMenu from './ContextMenu'
|
import ContextMenu from './ContextMenu'
|
||||||
import { BarCombo, BarButton } from './BarControls'
|
import { BarCombo, BarButton } from './BarControls'
|
||||||
import { setLayerStyle, deleteEbene, moveSelectionToEbene, openEbenenSettings,
|
import { setLayerStyle, deleteEbene, moveSelectionToEbene, openEbenenSettings,
|
||||||
pickLayerCombination, saveLayerCombination, deleteLayerCombination,
|
pickLayerCombination, saveLayerCombination, deleteLayerCombination,
|
||||||
openLayerCombinationsDialog } from '../lib/rhinoBridge'
|
openLayerCombinationsDialog } from '../lib/rhinoBridge'
|
||||||
|
import { t } from '../i18n/index.js'
|
||||||
|
|
||||||
const MODES = [
|
const MODES = () => [
|
||||||
{ value: 'all_force', label: 'Alle anzeigen' },
|
{ value: 'all_force', label: t('layers.show_all_mode') },
|
||||||
{ value: 'all', label: 'Ausgewählte' },
|
{ value: 'all', label: t('layers.selected_mode') },
|
||||||
{ value: 'active', label: 'Nur aktive' },
|
{ value: 'active', label: t('layers.active_only_mode') },
|
||||||
{ value: 'grey', label: 'Andere grau' },
|
{ value: 'grey', label: t('layers.others_gray') },
|
||||||
{ value: 'grey_locked', label: 'Andere grau & gesperrt' },
|
{ 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]
|
const LW_PRESETS = [0.02, 0.10, 0.13, 0.18, 0.25, 0.35, 0.50, 0.70, 1.00]
|
||||||
@@ -532,19 +533,19 @@ export default function EbenenManager({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ctxItems = (code) => [
|
const ctxItems = (code) => [
|
||||||
{ label: 'Ebeneneinstellungen…', icon: 'settings', onClick: () => {
|
{ label: t('layers.settings'), icon: 'settings', onClick: () => {
|
||||||
const target = _findInTree(ebenen, code)
|
const target = _findInTree(ebenen, code)
|
||||||
if (target) openEbenenSettings(target, hatchPatterns)
|
if (target) openEbenenSettings(target, hatchPatterns)
|
||||||
} },
|
} },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Sub-Ebene hinzufügen…', icon: 'add', onClick: () => addChild(code) },
|
{ label: t('layers.add_sub'), icon: 'add', onClick: () => addChild(code) },
|
||||||
{ label: 'Selektion hierher übertragen', icon: 'move_down', onClick: () => moveSelectionToEbene(code) },
|
{ label: t('layers.move_selection'), icon: 'move_down', onClick: () => moveSelectionToEbene(code) },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicateEbene(code) },
|
{ label: t('common.duplicate'), icon: 'content_copy', onClick: () => duplicateEbene(code) },
|
||||||
{ label: 'Eigenschaften kopieren', icon: 'colorize', onClick: () => copyProps(code) },
|
{ label: t('layers.copy_props'), icon: 'colorize', onClick: () => copyProps(code) },
|
||||||
{ label: 'Eigenschaften einfügen', icon: 'format_paint', onClick: () => pasteProps(code), disabled: !clipboard },
|
{ label: t('layers.paste_props'), icon: 'format_paint', onClick: () => pasteProps(code), disabled: !clipboard },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ label: 'Löschen', icon: 'delete', onClick: () => handleDelete(code), danger: true,
|
{ label: t('common.delete'), icon: 'delete', onClick: () => handleDelete(code), danger: true,
|
||||||
disabled: ebenen.length <= 1 },
|
disabled: ebenen.length <= 1 },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -556,7 +557,7 @@ export default function EbenenManager({
|
|||||||
background: 'var(--bg-section)',
|
background: 'var(--bg-section)',
|
||||||
borderBottom: '1px solid var(--border-light)',
|
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%' }}>
|
<div style={{ display: 'flex', width: '100%' }}>
|
||||||
<BarCombo
|
<BarCombo
|
||||||
stretch
|
stretch
|
||||||
@@ -582,21 +583,21 @@ export default function EbenenManager({
|
|||||||
pickLayerCombination(v === '__none__' ? null : v)
|
pickLayerCombination(v === '__none__' ? null : v)
|
||||||
}}
|
}}
|
||||||
title={activeKombi
|
title={activeKombi
|
||||||
? `Aktive Kombi: ${activeKombi}`
|
? `${t('layers.combination')}: ${activeKombi}`
|
||||||
: 'Keine Kombination — manuelle Sichtbarkeit'}
|
: t('layers.no_combination')}
|
||||||
onGear={openLayerCombinationsDialog}
|
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 => (
|
{layerCombinations.map(n => (
|
||||||
<option key={n} value={n}>{n}</option>
|
<option key={n} value={n}>{n}</option>
|
||||||
))}
|
))}
|
||||||
<option disabled>──────────</option>
|
<option disabled>──────────</option>
|
||||||
<option value="__save__">+ Aktuelle speichern…</option>
|
<option value="__save__">{t('layers.save_current')}</option>
|
||||||
{activeKombi && (
|
{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>
|
</BarCombo>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -607,19 +608,19 @@ export default function EbenenManager({
|
|||||||
background: 'var(--bg-section)',
|
background: 'var(--bg-section)',
|
||||||
borderBottom: '1px solid var(--border-light)',
|
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%' }}>
|
<div style={{ display: 'flex', width: '100%' }}>
|
||||||
<BarCombo
|
<BarCombo
|
||||||
stretch
|
stretch
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
value={mode}
|
value={mode}
|
||||||
onChange={onModeChange}
|
onChange={onModeChange}
|
||||||
title="Sichtbarkeits-Modus"
|
title={t('layers.visibility_mode')}
|
||||||
onSecond={addNew}
|
onSecond={addNew}
|
||||||
secondIcon="add"
|
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>
|
</BarCombo>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -642,7 +643,7 @@ export default function EbenenManager({
|
|||||||
if (mode === 'active' || mode === 'all_force') onModeChange('all')
|
if (mode === 'active' || mode === 'all_force') onModeChange('all')
|
||||||
}}
|
}}
|
||||||
title={ebenen.every(e => e.visible !== false)
|
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,
|
style={{ width: 16, height: 16,
|
||||||
opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
|
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)
|
const anyLocked = ebenen.some(e => e.locked === true)
|
||||||
onChange(ebenen.map(e => ({ ...e, locked: !anyLocked })))
|
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 }}
|
style={{ width: 14, height: 14 }}
|
||||||
>
|
>
|
||||||
<Icon name={ebenen.every(e => e.locked === true) ? 'lock' : 'lock_open'} size={11} />
|
<Icon name={ebenen.every(e => e.locked === true) ? 'lock' : 'lock_open'} size={11} />
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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
@@ -3,63 +3,71 @@
|
|||||||
import { StrictMode } from 'react'
|
import { StrictMode } from 'react'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import './index.css'
|
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 App from './App.jsx'
|
||||||
import ZeichnungsebenenApp from './ZeichnungsebenenApp.jsx'
|
import DrawingLevelsApp from './DrawingLevelsApp.jsx'
|
||||||
import GeschossSettingsApp from './GeschossSettingsApp.jsx'
|
import FloorSettingsApp from './FloorSettingsApp.jsx'
|
||||||
|
import FloorDialogApp from './FloorDialogApp.jsx'
|
||||||
import ProjectSettingsApp from './ProjectSettingsApp.jsx'
|
import ProjectSettingsApp from './ProjectSettingsApp.jsx'
|
||||||
|
import DossierSettingsApp from './DossierSettingsApp.jsx'
|
||||||
import LibraryApp from './LibraryApp.jsx'
|
import LibraryApp from './LibraryApp.jsx'
|
||||||
import SymbolPickerApp from './SymbolPickerApp.jsx'
|
import SymbolPickerApp from './SymbolPickerApp.jsx'
|
||||||
import EbenenSettingsApp from './EbenenSettingsApp.jsx'
|
import LayerSettingsApp from './LayerSettingsApp.jsx'
|
||||||
import GeschossDialogApp from './GeschossDialogApp.jsx'
|
|
||||||
import LayerCombinationsApp from './LayerCombinationsApp.jsx'
|
import LayerCombinationsApp from './LayerCombinationsApp.jsx'
|
||||||
import AusschnittSettingsApp from './AusschnittSettingsApp.jsx'
|
import ViewportSettingsApp from './ViewportSettingsApp.jsx'
|
||||||
import LayoutDialogApp from './LayoutDialogApp.jsx'
|
import LayoutDialogApp from './LayoutDialogApp.jsx'
|
||||||
import SwisstopoApp from './SwisstopoApp.jsx'
|
import SwisstopoApp from './SwisstopoApp.jsx'
|
||||||
import OsmApp from './OsmApp.jsx'
|
import OsmApp from './OsmApp.jsx'
|
||||||
import KameraApp from './KameraApp.jsx'
|
import CameraApp from './CameraApp.jsx'
|
||||||
import MasseSettingsApp from './MasseSettingsApp.jsx'
|
import UnitsSettingsApp from './UnitsSettingsApp.jsx'
|
||||||
import AboutApp from './AboutApp.jsx'
|
import AboutApp from './AboutApp.jsx'
|
||||||
import TextEditorApp from './TextEditorApp.jsx'
|
import TextEditorApp from './TextEditorApp.jsx'
|
||||||
import GestaltungApp from './GestaltungApp.jsx'
|
import StylesApp from './StylesApp.jsx'
|
||||||
import AusschnitteApp from './AusschnitteApp.jsx'
|
import ViewportsApp from './ViewportsApp.jsx'
|
||||||
import MassstabApp from './MassstabApp.jsx'
|
import ScaleApp from './ScaleApp.jsx'
|
||||||
import WerkzeugeApp from './WerkzeugeApp.jsx'
|
import ToolsApp from './ToolsApp.jsx'
|
||||||
import OberleisteApp from './OberleisteApp.jsx'
|
import ToolbarApp from './ToolbarApp.jsx'
|
||||||
import OverridesApp from './OverridesApp.jsx'
|
import OverridesApp from './OverridesApp.jsx'
|
||||||
import DimensionenApp from './DimensionenApp.jsx'
|
import DimensionsApp from './DimensionsApp.jsx'
|
||||||
import LayoutsApp from './LayoutsApp.jsx'
|
import LayoutsApp from './LayoutsApp.jsx'
|
||||||
import ElementeApp from './ElementeApp.jsx'
|
import ElementeApp from './ElementeApp.jsx'
|
||||||
import ElementeUebersichtApp from './ElementeUebersichtApp.jsx'
|
import ElementsOverviewApp from './ElementsOverviewApp.jsx'
|
||||||
import ElementePropertiesApp from './ElementePropertiesApp.jsx'
|
import ElementPropertiesApp from './ElementPropertiesApp.jsx'
|
||||||
|
|
||||||
const mode = (typeof window !== 'undefined' && window.PANEL_MODE) || 'ebenen'
|
const mode = (typeof window !== 'undefined' && window.PANEL_MODE) || 'ebenen'
|
||||||
const RootApp = mode === 'gestaltung' ? GestaltungApp
|
const RootApp = mode === 'gestaltung' ? StylesApp
|
||||||
: mode === 'ausschnitte' ? AusschnitteApp
|
: mode === 'ausschnitte' ? ViewportsApp
|
||||||
: mode === 'massstab' ? MassstabApp
|
: mode === 'massstab' ? ScaleApp
|
||||||
: mode === 'werkzeuge' ? WerkzeugeApp
|
: mode === 'werkzeuge' ? ToolsApp
|
||||||
: mode === 'oberleiste' ? OberleisteApp
|
: mode === 'oberleiste' ? ToolbarApp
|
||||||
: mode === 'overrides' ? OverridesApp
|
: mode === 'overrides' ? OverridesApp
|
||||||
: mode === 'dimensionen' ? DimensionenApp
|
: mode === 'dimensionen' ? DimensionsApp
|
||||||
: mode === 'layouts' ? LayoutsApp
|
: mode === 'layouts' ? LayoutsApp
|
||||||
: mode === 'elemente' ? ElementeApp
|
: mode === 'elemente' ? ElementeApp
|
||||||
: mode === 'zeichnungsebenen' ? ZeichnungsebenenApp
|
: mode === 'zeichnungsebenen' ? DrawingLevelsApp
|
||||||
: mode === 'geschoss_settings' ? GeschossSettingsApp
|
: mode === 'geschoss_settings' ? FloorSettingsApp
|
||||||
: mode === 'project_settings' ? ProjectSettingsApp
|
: mode === 'project_settings' ? ProjectSettingsApp
|
||||||
|
: mode === 'dossier_settings' ? DossierSettingsApp
|
||||||
: mode === 'library' ? LibraryApp
|
: mode === 'library' ? LibraryApp
|
||||||
: mode === 'symbol_picker' ? SymbolPickerApp
|
: mode === 'symbol_picker' ? SymbolPickerApp
|
||||||
: mode === 'ebenen_settings' ? EbenenSettingsApp
|
: mode === 'ebenen_settings' ? LayerSettingsApp
|
||||||
: mode === 'geschoss_dialog' ? GeschossDialogApp
|
: mode === 'geschoss_dialog' ? FloorDialogApp
|
||||||
: mode === 'layer_combinations' ? LayerCombinationsApp
|
: mode === 'layer_combinations' ? LayerCombinationsApp
|
||||||
: mode === 'ausschnitt_settings' ? AusschnittSettingsApp
|
: mode === 'ausschnitt_settings' ? ViewportSettingsApp
|
||||||
: mode === 'layout_dialog' ? LayoutDialogApp
|
: mode === 'layout_dialog' ? LayoutDialogApp
|
||||||
: mode === 'swisstopo' ? SwisstopoApp
|
: mode === 'swisstopo' ? SwisstopoApp
|
||||||
: mode === 'osm' ? OsmApp
|
: mode === 'osm' ? OsmApp
|
||||||
: mode === 'kamera' ? KameraApp
|
: mode === 'kamera' ? CameraApp
|
||||||
: mode === 'masse_settings' ? MasseSettingsApp
|
: mode === 'masse_settings' ? UnitsSettingsApp
|
||||||
: mode === 'about' ? AboutApp
|
: mode === 'about' ? AboutApp
|
||||||
: mode === 'text_editor' ? TextEditorApp
|
: mode === 'text_editor' ? TextEditorApp
|
||||||
: mode === 'elemente_uebersicht' ? ElementeUebersichtApp
|
: mode === 'elemente_uebersicht' ? ElementsOverviewApp
|
||||||
: mode === 'elemente_properties' ? ElementePropertiesApp
|
: mode === 'elemente_properties' ? ElementPropertiesApp
|
||||||
: App
|
: App
|
||||||
|
|
||||||
document.addEventListener('contextmenu', e => e.preventDefault(), true)
|
document.addEventListener('contextmenu', e => e.preventDefault(), true)
|
||||||
|
|||||||
Reference in New Issue
Block a user