refactor: localize UI labels and store filenames

This commit is contained in:
Marcel Peterkau
2026-06-21 18:25:58 +02:00
parent 80d4d5ef90
commit e7962f77e1
9 changed files with 87 additions and 29 deletions
+1
View File
@@ -24,6 +24,7 @@
"Der Hausmeister-Tab zeigt den vollständigen Inhalt eines markierten Vorgangs in einem mehrzeiligen Detailbereich.",
"Hausmeister-Tasks lassen sich manuell löschen; Einträge entfernter Mitgliederakten werden beim nächsten Lauf bereinigt.",
"Forderungen besitzen eigene Tabs mit Positionen, Teilzahlungen, GnuCash-Referenzen, Zahlungszuordnungen, Mahnungen und Gebühren.",
"Dropdowns zeigen deutsche Begriffe bei weiterhin englischen Speicher-Keys; der Hausmeisterstatus liegt einheitlich in housekeeper.json.",
"Hausmeister um konfigurierbare Geburtstags- und Mitgliedsjubiläumsmeldungen erweitert.",
"Statusänderungen werden mit altem und neuem Klartextwert in der Mitgliederchronik protokolliert.",
"Fensterposition, normaler Fensterzustand und Maximierung werden gespeichert; der Splash startet auf dem zuletzt verwendeten Monitor.",
+8 -5
View File
@@ -51,8 +51,8 @@ class Housekeeper:
def __init__(self, repository: MemberRepository, settings: HousekeeperSettings | None = None):
self.repository = repository
self.settings = settings or HousekeeperSettings()
self.state_path = repository.root / "hausmeister.json"
self.lock_path = repository.root / ".hausmeister.lock"
self.state_path = repository.root / "housekeeper.json"
self.lock_path = repository.root / ".housekeeper.lock"
def run(self, today: date | None = None) -> list[HousekeeperFinding]:
current_date = today or date.today()
@@ -125,7 +125,7 @@ class Housekeeper:
"items": sorted(items.values(), key=lambda item: str(item.get("key", ""))),
}
)
write_json_atomic(self.state_path, working)
self._write_state(working)
return _open_findings(working["items"])
def delete_task(self, key: str) -> list[HousekeeperFinding]:
@@ -142,7 +142,7 @@ class Housekeeper:
raise RepositoryError("Nur Hausmeister-Tasks können manuell gelöscht werden.")
del items[selected_key]
state["items"] = sorted(items.values(), key=lambda value: str(value.get("key", "")))
write_json_atomic(self.state_path, state)
self._write_state(state)
return _open_findings(state["items"])
@staticmethod
@@ -343,7 +343,10 @@ class Housekeeper:
raise ValueError("ungültige Struktur")
return state
except (OSError, ValueError, TypeError, json.JSONDecodeError) as exc:
raise RepositoryError(f"hausmeister.json konnte nicht gelesen werden: {exc}") from exc
raise RepositoryError(f"housekeeper.json konnte nicht gelesen werden: {exc}") from exc
def _write_state(self, state: dict[str, Any]) -> None:
write_json_atomic(self.state_path, state)
def _items_by_key(state: dict[str, Any]) -> dict[str, dict[str, Any]]:
+5 -4
View File
@@ -19,6 +19,7 @@ from ccma.domain.contributions import (
)
from ccma.domain.dates import date_input_hint, format_date_for_display
from ccma.storage.repository import MemberRepository, RepositoryError
from ccma.ui.labels import CLAIM_ITEM_TYPE_LABELS, display_label, storage_key
class ClaimTab(ttk.Frame):
@@ -181,7 +182,7 @@ class ClaimTab(ttk.Frame):
"end",
iid=str(item.get("item_id", "")),
values=(
item.get("type", ""),
display_label(CLAIM_ITEM_TYPE_LABELS, str(item.get("type", ""))),
item.get("description", ""),
item.get("quantity", "1"),
item.get("unit_price", item.get("amount", "")),
@@ -294,7 +295,7 @@ class ItemDialog(_Dialog):
def __init__(self, master, repository, member_id, claim_id, on_saved):
super().__init__(master, "Forderungsposition hinzufügen", on_saved)
self.repository, self.member_id, self.claim_id = repository, member_id, claim_id
self.type_var = tk.StringVar(value="correction")
self.type_var = tk.StringVar(value=CLAIM_ITEM_TYPE_LABELS["correction"])
self.description_var = tk.StringVar()
self.quantity_var = tk.StringVar(value="1")
self.unit_var = tk.StringVar()
@@ -310,7 +311,7 @@ class ItemDialog(_Dialog):
ttk.Combobox(
self.frame,
textvariable=variable,
values=("base", "product", "service", "fee", "discount", "credit", "correction"),
values=list(CLAIM_ITEM_TYPE_LABELS.values()),
state="readonly",
width=32,
).grid(row=row, column=1, sticky="ew", pady=5)
@@ -326,7 +327,7 @@ class ItemDialog(_Dialog):
description=self.description_var.get(),
quantity=self.quantity_var.get(),
unit_price=self.unit_var.get(),
item_type=self.type_var.get(),
item_type=storage_key(CLAIM_ITEM_TYPE_LABELS, self.type_var.get()),
)
except RepositoryError as exc:
messagebox.showerror("Position konnte nicht gespeichert werden", str(exc), parent=self)
+26
View File
@@ -0,0 +1,26 @@
from __future__ import annotations
from collections.abc import Mapping
THEME_LABELS = {
"dark": "Dunkel",
"light": "Hell",
}
CLAIM_ITEM_TYPE_LABELS = {
"base": "Grundposition",
"product": "Produkt",
"service": "Dienstleistung",
"fee": "Gebühr",
"discount": "Rabatt",
"credit": "Gutschrift",
"correction": "Korrektur",
}
def display_label(labels: Mapping[str, str], key: str) -> str:
return labels.get(key, key)
def storage_key(labels: Mapping[str, str], label: str) -> str:
return next((key for key, value in labels.items() if value == label), label)
+10 -3
View File
@@ -12,6 +12,7 @@ from ccma.domain.dates import age_label, date_input_hint, format_date_for_displa
from ccma.domain.models import MEMBERSHIP_STATUS_LABELS as STATUS_LABELS
from ccma.domain.models import Event
from ccma.storage.repository import MemberRepository, RepositoryError
from ccma.ui.labels import display_label, storage_key
class MemberTab(ttk.Frame):
@@ -121,7 +122,7 @@ class MemberTab(ttk.Frame):
ttk.Combobox(
data_tab,
textvariable=self.variables["status"],
values=list(STATUS_LABELS),
values=list(STATUS_LABELS.values()),
state="readonly",
width=39,
).grid(row=len(fields), column=1, sticky="ew", pady=5)
@@ -196,7 +197,10 @@ class MemberTab(ttk.Frame):
date_fields = {"birth_date", "accepted_at", "membership_started_at"}
for key, variable in self.variables.items():
value = getattr(self.member, key)
variable.set(format_date_for_display(value) if key in date_fields else value)
if key == "status":
variable.set(display_label(STATUS_LABELS, str(value)))
else:
variable.set(format_date_for_display(value) if key in date_fields else value)
self._refresh_events()
self._refresh_contributions()
self._refresh_documents()
@@ -248,7 +252,10 @@ class MemberTab(ttk.Frame):
def _save(self) -> None:
for key, variable in self.variables.items():
setattr(self.member, key, variable.get().strip())
value = variable.get().strip()
if key == "status":
value = storage_key(STATUS_LABELS, value)
setattr(self.member, key, value)
try:
self.repository.save_member(self.member)
except RepositoryError as exc:
+4 -3
View File
@@ -13,6 +13,7 @@ from ccma.services.intervals import (
from ccma.storage.repository import MemberRepository, RepositoryError, validate_member_number_pattern
from ccma.ui.changelog_view import ChangelogView
from ccma.ui.icons import IconStore
from ccma.ui.labels import THEME_LABELS, display_label, storage_key
class OptionsDialog(tk.Toplevel):
@@ -30,7 +31,7 @@ class OptionsDialog(tk.Toplevel):
self.icons = IconStore(self)
self.store_var = tk.StringVar(value=config.store_path)
self.gnucash_var = tk.StringVar(value=config.gnucash_path)
self.theme_var = tk.StringVar(value=config.theme_mode)
self.theme_var = tk.StringVar(value=display_label(THEME_LABELS, config.theme_mode))
self.housekeeper_var = tk.BooleanVar(value=config.run_housekeeper_on_startup)
self.birthday_before_var = tk.StringVar(value=str(config.birthday_days_before))
self.birthday_after_var = tk.StringVar(value=str(config.birthday_days_after))
@@ -137,7 +138,7 @@ class OptionsDialog(tk.Toplevel):
ttk.Combobox(
parent,
textvariable=self.theme_var,
values=("dark", "light"),
values=list(THEME_LABELS.values()),
state="readonly",
width=18,
).grid(row=0, column=1, sticky="w", pady=6)
@@ -339,7 +340,7 @@ class OptionsDialog(tk.Toplevel):
store_changed = old_store != store
self.config_obj.store_path = str(store)
self.config_obj.gnucash_path = str(gnucash) if gnucash else ""
self.config_obj.theme_mode = self.theme_var.get()
self.config_obj.theme_mode = storage_key(THEME_LABELS, self.theme_var.get())
self.config_obj.run_housekeeper_on_startup = self.housekeeper_var.get()
self.config_obj.birthday_days_before = birthday_before
self.config_obj.birthday_days_after = birthday_after