i18n DE/EN + DossierSettings panel + English file renames

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

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

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

Python module renames:
- rhinopanel.py → layers_panel.py
- oberleiste.py → toolbar.py
- gestaltung.py → styles.py
- werkzeuge.py → tools.py
- dimensionen.py → dimensions.py
- startup.py _MODULE_TO_PY updated, all cross-imports fixed
This commit is contained in:
2026-06-06 11:09:33 +02:00
parent 92b4baa285
commit 375487c10c
45 changed files with 998 additions and 148 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ else:
"cutAtLine": True, "namePrefix": "S",
}
try:
import rhinopanel
import layers_panel as rhinopanel
ps = rhinopanel.load_project_settings(doc)
d = (ps or {}).get("defaults", {})
defaults["depthBack"] = float(d.get("schnittDepthBack", 8.0))
+1 -1
View File
@@ -392,7 +392,7 @@ def _run():
# gestaltung fuer Fill-Re-Apply
_g = None
try:
import gestaltung as _gmod; _g = _gmod
import styles as _gmod; _g = _gmod
except Exception as iex:
print("[SMART-JOIN] gestaltung import:", iex)
+1 -1
View File
@@ -233,7 +233,7 @@ def _run():
_replicate_hatch(doc, nobj, hatch_props)
else:
try:
import gestaltung as _gmod
import styles as _gmod
for nid in new_ids:
nobj = doc.Objects.FindId(nid)
if nobj is not None:
+4 -4
View File
@@ -556,7 +556,7 @@ class AusschnittBridge(panel_base.BaseBridge):
kombi = (snap.get("layerCombination") or "").strip()
if kombi:
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel.apply_layer_preset_by_name(doc, kombi)
except Exception as ex:
print("[AUSSCHNITTE] kombi-apply '{}':".format(kombi), ex)
@@ -565,7 +565,7 @@ class AusschnittBridge(panel_base.BaseBridge):
_apply_layers_global(doc, snap.get("layers", []))
# Eigene Sichtbarkeit → active_comb_name clearen
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel.set_active_comb_name(doc, None)
rhinopanel._notify_oberleiste_combs()
except Exception: pass
@@ -785,7 +785,7 @@ class AusschnittBridge(panel_base.BaseBridge):
# Listen fuer Dropdowns
display_modes = []
try:
import oberleiste
import toolbar as oberleiste
display_modes = oberleiste._list_display_modes()
except Exception as ex:
print("[AUSSCHNITTE] display_modes:", ex)
@@ -797,7 +797,7 @@ class AusschnittBridge(panel_base.BaseBridge):
print("[AUSSCHNITTE] overrides_presets:", ex)
layer_kombis = []
try:
import rhinopanel
import layers_panel as rhinopanel
layer_kombis = rhinopanel.list_layer_preset_names(d)
except Exception as ex:
print("[AUSSCHNITTE] layer_kombis:", ex)
+12 -12
View File
@@ -771,7 +771,7 @@ def _find_ebene_sublayer_name(doc, keywords, default_code, default_name,
print("[ELEMENTE] build_layers nach auto-add:", ex)
# Ebenen-Manager UI mit-informieren via broadcast_state
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as 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")
zlist = json.loads(z_raw) if z_raw else []
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as 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")
zlist = json.loads(z_raw) if z_raw else []
if zlist: layer_builder.build_layers(doc, zlist, ebenen)
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as 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("textures", {})
try:
import rhinopanel
import layers_panel as rhinopanel
ps = rhinopanel.load_project_settings(doc) if doc else None
if isinstance(ps, dict):
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
konfiguriert (auch keine Defaults greifbar), leere Liste."""
try:
import rhinopanel
import layers_panel as rhinopanel
ps = rhinopanel.load_project_settings(doc) if doc else None
if isinstance(ps, dict):
return list(ps.get("wand_styles", []) or [])
@@ -13337,7 +13337,7 @@ class ElementeBridge(panel_base.BaseBridge):
# Projekt-Adresse als Vorschlag fuer die Adress-Suche
project_address = ""
try:
import rhinopanel
import layers_panel as rhinopanel
ps = rhinopanel.load_project_settings(doc) if doc else None
if isinstance(ps, dict):
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 []
if zlist:
layer_builder.build_layers(doc, zlist, ebenen)
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as 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
# ebenen_bridge_ref + zeichnungsebenen_bridge_ref
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as ex:
self._push_log("broadcast_state: {}".format(ex))
@@ -14660,7 +14660,7 @@ class ElementeBridge(panel_base.BaseBridge):
if zlist:
import layer_builder
layer_builder.build_layers(doc, zlist, ebenen)
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception as 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:
print("[ELEMENTE] build_layers nach Plangrafik-Migration:", ex)
try:
import rhinopanel as _rp
import layers_panel as _rp
_rp._broadcast_state(doc)
except Exception: pass
@@ -16789,7 +16789,7 @@ def _migrate_layer_caps_once(doc):
except Exception as ex:
print("[ELEMENTE] build_layers nach CAPS-Migration:", ex)
try:
import rhinopanel as _rp
import layers_panel as _rp
_rp._broadcast_state(doc)
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
# Panel sonst nicht neu gerendert.
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception: pass
except Exception as ex:
@@ -2204,7 +2204,7 @@ class EbenenBridge(panel_base.BaseBridge):
# geaendert hat (nicht bei reinen Name/Farb-Aenderungen, die das
# Settings-Dialog auch triggern koennte).
try:
import gestaltung
import styles as gestaltung
if fill_changed:
gestaltung.refresh_layer_fills(doc)
else:
+1 -1
View File
@@ -664,7 +664,7 @@ def import_material(doc, item):
"uvScaleM", "textures"):
if k in data: new_mat[k] = data[k]
# Lazy-Import um Zyklen zu vermeiden
import rhinopanel
import layers_panel as rhinopanel
settings = rhinopanel.load_project_settings(doc)
mats = list(settings.get("materials", []))
for m in mats:
+17 -1
View File
@@ -20,6 +20,21 @@ import scriptcontext as sc
_HERE = os.path.dirname(os.path.abspath(__file__))
_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 ------------------------------------------------
@@ -317,7 +332,8 @@ def load_inline(wv, mode, params=None):
_INLINE_TEMPLATE = (sig, tmpl)
# 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:
try:
parts.append('window.PANEL_PARAMS=' + json.dumps(params, ensure_ascii=False) + ';')
+1 -1
View File
@@ -155,7 +155,7 @@ def _update_linePts(doc, schnitt_id, new_p1, new_p2):
# Panel-Broadcast (linePts haben sich geaendert, Ebenen-Panel will
# ggf. mit-rendern)
try:
import rhinopanel
import layers_panel as rhinopanel
rhinopanel._broadcast_state(doc)
except Exception: pass
try: doc.Views.Redraw()
+1 -1
View File
@@ -609,7 +609,7 @@ def pick_schnitt_interactive(doc, defaults=None):
# Project-Defaults als 2-stufiges Fallback (defaults > project > hardcoded)
proj_d = {}
try:
import rhinopanel
import layers_panel as rhinopanel
ps = rhinopanel.load_project_settings(doc) or {}
proj_d = ps.get("defaults", {}) or {}
except Exception: pass
+6 -6
View File
@@ -44,13 +44,13 @@ _UI_FILE = os.path.join(_HERE, "DOSSIERUI.rhw")
# Muss synchron sein mit launcher/modules.json. Wenn neue Module dazukommen,
# beide Stellen pflegen.
_MODULE_TO_PY = {
"ebenen": "rhinopanel",
"oberleiste": "oberleiste",
"ebenen": "layers_panel",
"oberleiste": "toolbar",
"ausschnitte": "ausschnitte",
"gestaltung": "gestaltung",
"werkzeuge": "werkzeuge",
"gestaltung": "styles",
"werkzeuge": "tools",
"overrides": "overrides_panel",
"dimensionen": "dimensionen",
"dimensionen": "dimensions",
"layouts": "layouts",
"elemente": "elemente",
}
@@ -209,7 +209,7 @@ def _check_doc_unit(doc):
return
except Exception: pass
try:
import rhinopanel
import layers_panel as rhinopanel
target_unit_str = rhinopanel.get_project_unit(doc)
target_unit_enum = rhinopanel.get_project_unit_enum(doc)
except Exception as ex:
+57 -6
View File
@@ -22,7 +22,7 @@ if _HERE not in sys.path:
import panel_base
import massstab
import overrides
import rhinopanel
import layers_panel as rhinopanel
PANEL_GUID_STR = "7e1f6a5b-8e2f-4f3c-d5e6-f70819203b51"
OVERRIDES_PANEL_GUID_STR = "8f2a7b6c-9f3a-4f4d-e6f7-08192a3c4d62"
@@ -1849,13 +1849,17 @@ class OberleisteBridge(panel_base.BaseBridge):
# --- Settings + Window-Layout -----------------------------------
elif t == "OPEN_SETTINGS":
# Primaerweg: Dossier-Launcher (Tauri-App) oeffnen, dort lebt das
# echte Settings-UI. Wenn der Launcher nicht installiert ist,
# faellt es auf den Eto-Dialog zurueck.
if not _launch_dossier_app():
open_settings_dialog()
_open_dossier_settings_panel()
elif t == "GET_SETTINGS":
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":
name = (p.get("name") or "").strip()
if name: _apply_window_layout(name)
@@ -2195,6 +2199,53 @@ class OberleisteBridge(panel_base.BaseBridge):
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 --------------------------------------------------------
def _install_listeners(bridge):