Merge: i18n fallback fix + missing projekte.* translations
This commit is contained in:
@@ -728,6 +728,113 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"dezernat.add": "Hinzuf\u00fcgen",
|
||||
"dezernat.remove": "Entfernen",
|
||||
"dezernat.confirm_remove": "Mitglied entfernen?",
|
||||
"projekte.title": "Projekte \u2014 Paliad",
|
||||
"projekte.heading": "Projekte",
|
||||
"projekte.subtitle": "Mandanten, Streitsachen, Patente und F\u00e4lle \u2014 hierarchisch organisiert.",
|
||||
"projekte.new": "Neues Projekt",
|
||||
"projekte.search.placeholder": "Titel, Referenz oder ClientMatter...",
|
||||
"projekte.filter.type": "Typ",
|
||||
"projekte.filter.type.all": "Alle Typen",
|
||||
"projekte.filter.status": "Status",
|
||||
"projekte.filter.status.all": "Alle Status",
|
||||
"projekte.filter.status.active": "Aktiv",
|
||||
"projekte.filter.status.archived": "Archiviert",
|
||||
"projekte.filter.status.closed": "Abgeschlossen",
|
||||
"projekte.filter.view": "Ansicht",
|
||||
"projekte.view.flat": "Flache Liste",
|
||||
"projekte.view.roots": "Nur Wurzeln",
|
||||
"projekte.unavailable": "Projektverwaltung zurzeit nicht verf\u00fcgbar \u2014 bitte Administrator kontaktieren.",
|
||||
"projekte.col.title": "Titel",
|
||||
"projekte.col.type": "Typ",
|
||||
"projekte.col.reference": "Referenz",
|
||||
"projekte.col.clientmatter": "ClientMatter",
|
||||
"projekte.col.status": "Status",
|
||||
"projekte.col.updated": "Zuletzt ge\u00e4ndert",
|
||||
"projekte.empty.title": "Noch kein Projekt angelegt",
|
||||
"projekte.empty.hint": "Starten Sie \u00fcber \u201eNeues Projekt\u201c \u2014 legen Sie zuerst einen Mandanten an, darunter Streitsachen, Patente und F\u00e4lle.",
|
||||
"projekte.empty.filtered": "Keine Treffer f\u00fcr diese Filter.",
|
||||
"projekte.cancel": "Abbrechen",
|
||||
"projekte.submit": "Projekt anlegen",
|
||||
"projekte.neu.title": "Neues Projekt \u2014 Paliad",
|
||||
"projekte.neu.heading": "Neues Projekt anlegen",
|
||||
"projekte.neu.subtitle": "Mandant, Streitsache, Patent, Verfahren oder generisches Projekt \u2014 hierarchisch einordnen. Sichtbarkeit folgt dem Team (Sie werden als \u201eLead\u201c automatisch hinzugef\u00fcgt).",
|
||||
"projekte.field.type": "Typ",
|
||||
"projekte.field.parent": "\u00dcbergeordnetes Projekt",
|
||||
"projekte.field.parent.placeholder": "Titel eingeben, um ein \u00dcberprojekt zu suchen...",
|
||||
"projekte.field.parent.hint": "Leer lassen f\u00fcr ein Wurzel-Projekt (typisch: Mandant).",
|
||||
"projekte.field.title": "Titel",
|
||||
"projekte.field.title.placeholder": "z.B. Siemens AG | Siemens v. Huawei | EP 1 234 567",
|
||||
"projekte.field.reference": "Interne Referenz (optional)",
|
||||
"projekte.field.reference.placeholder": "z.B. HL-2026-0042",
|
||||
"projekte.field.client_number": "Client-Nr. (7 Ziffern)",
|
||||
"projekte.field.matter_number": "Matter-Nr. (7 Ziffern)",
|
||||
"projekte.field.clientmatter.hint": "HLC-Billing-Nummern. Format CCCCCCC.MMMMMMM. Client-Nr. wird an Unterprojekte vererbt (\u00fcberschreibbar).",
|
||||
"projekte.field.netdocuments_url": "netDocuments-URL (optional)",
|
||||
"projekte.field.industry": "Branche",
|
||||
"projekte.field.country": "Land (ISO-2)",
|
||||
"projekte.field.billing_reference": "Billing-Referenz",
|
||||
"projekte.field.patent_number": "Patentnummer",
|
||||
"projekte.field.filing_date": "Anmeldetag",
|
||||
"projekte.field.grant_date": "Erteilungstag",
|
||||
"projekte.field.court": "Gericht",
|
||||
"projekte.field.case_number": "Aktenzeichen (Gericht)",
|
||||
"projekte.field.status": "Status",
|
||||
"projekte.error.title_required": "Titel erforderlich",
|
||||
"projekte.detail.title": "Projekt \u2014 Paliad",
|
||||
"projekte.detail.back": "\u2190 Zur\u00fcck zur \u00dcbersicht",
|
||||
"projekte.detail.loading": "L\u00e4dt\u2026",
|
||||
"projekte.detail.notfound": "Projekt nicht gefunden oder keine Berechtigung.",
|
||||
"projekte.detail.edit": "Bearbeiten",
|
||||
"projekte.detail.save": "Speichern",
|
||||
"projekte.detail.tab.verlauf": "Verlauf",
|
||||
"projekte.detail.tab.team": "Team",
|
||||
"projekte.detail.tab.kinder": "Untergeordnet",
|
||||
"projekte.detail.tab.parteien": "Parteien",
|
||||
"projekte.detail.tab.fristen": "Fristen",
|
||||
"projekte.detail.tab.termine": "Termine",
|
||||
"projekte.detail.tab.notizen": "Notizen",
|
||||
"projekte.detail.tab.checklisten": "Checklisten",
|
||||
"projekte.detail.verlauf.empty": "Noch keine Ereignisse aufgezeichnet.",
|
||||
"projekte.detail.verlauf.loadMore": "Mehr laden",
|
||||
"projekte.detail.team.form.user": "Benutzer",
|
||||
"projekte.detail.team.form.role": "Rolle",
|
||||
"projekte.detail.team.form.cancel": "Abbrechen",
|
||||
"projekte.detail.team.form.submit": "Hinzuf\u00fcgen",
|
||||
"projekte.detail.team.col.name": "Name",
|
||||
"projekte.detail.team.col.role": "Rolle",
|
||||
"projekte.detail.team.col.source": "Herkunft",
|
||||
"projekte.detail.kinder.add": "Untervorhaben anlegen",
|
||||
"projekte.detail.kinder.empty": "Keine untergeordneten Projekte.",
|
||||
"projekte.detail.parteien.add": "Partei hinzuf\u00fcgen",
|
||||
"projekte.detail.parteien.form.name": "Name",
|
||||
"projekte.detail.parteien.form.role": "Rolle",
|
||||
"projekte.detail.parteien.form.rep": "Vertreter (optional)",
|
||||
"projekte.detail.parteien.form.cancel": "Abbrechen",
|
||||
"projekte.detail.parteien.form.submit": "Hinzuf\u00fcgen",
|
||||
"projekte.detail.parteien.role.claimant": "Kl\u00e4ger",
|
||||
"projekte.detail.parteien.role.defendant": "Beklagter",
|
||||
"projekte.detail.parteien.role.thirdparty": "Streitverk\u00fcndeter / Drittpartei",
|
||||
"projekte.detail.parteien.col.name": "Name",
|
||||
"projekte.detail.parteien.col.role": "Rolle",
|
||||
"projekte.detail.parteien.col.rep": "Vertreter",
|
||||
"projekte.detail.parteien.empty": "Noch keine Parteien eingetragen.",
|
||||
"projekte.detail.fristen.add": "Frist hinzuf\u00fcgen",
|
||||
"projekte.detail.fristen.empty": "F\u00fcr dieses Projekt sind noch keine Fristen erfasst.",
|
||||
"projekte.detail.termine.add": "Termin hinzuf\u00fcgen",
|
||||
"projekte.detail.termine.form.cancel": "Abbrechen",
|
||||
"projekte.detail.termine.form.submit": "Hinzuf\u00fcgen",
|
||||
"projekte.detail.termine.empty": "F\u00fcr dieses Projekt sind noch keine Termine erfasst.",
|
||||
"projekte.detail.checklisten.empty": "F\u00fcr dieses Projekt sind noch keine Checklisten-Instanzen erfasst.",
|
||||
"projekte.detail.checklisten.col.template": "Vorlage",
|
||||
"projekte.detail.checklisten.col.name": "Name",
|
||||
"projekte.detail.checklisten.col.progress": "Fortschritt",
|
||||
"projekte.detail.checklisten.col.created": "Angelegt",
|
||||
"projekte.detail.checklisten.hint": "Instanzen werden auf der Vorlagen-Seite unter Checklisten angelegt.",
|
||||
"projekte.detail.delete": "Projekt archivieren",
|
||||
"projekte.detail.delete.confirm.title": "Projekt wirklich archivieren?",
|
||||
"projekte.detail.delete.confirm.body": "Das Projekt wird archiviert. Es kann nicht direkt wiederhergestellt werden.",
|
||||
"projekte.detail.delete.confirm.cancel": "Abbrechen",
|
||||
"projekte.detail.delete.confirm.ok": "Archivieren",
|
||||
"projekte.type.client": "Mandant",
|
||||
"projekte.type.litigation": "Streitsache",
|
||||
"projekte.type.patent": "Patent",
|
||||
@@ -1622,6 +1729,113 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"dezernat.add": "Add",
|
||||
"dezernat.remove": "Remove",
|
||||
"dezernat.confirm_remove": "Remove member?",
|
||||
"projekte.title": "Projects \u2014 Paliad",
|
||||
"projekte.heading": "Projects",
|
||||
"projekte.subtitle": "Clients, litigations, patents and cases \u2014 organised hierarchically.",
|
||||
"projekte.new": "New project",
|
||||
"projekte.search.placeholder": "Title, reference or ClientMatter...",
|
||||
"projekte.filter.type": "Type",
|
||||
"projekte.filter.type.all": "All types",
|
||||
"projekte.filter.status": "Status",
|
||||
"projekte.filter.status.all": "All statuses",
|
||||
"projekte.filter.status.active": "Active",
|
||||
"projekte.filter.status.archived": "Archived",
|
||||
"projekte.filter.status.closed": "Closed",
|
||||
"projekte.filter.view": "View",
|
||||
"projekte.view.flat": "Flat list",
|
||||
"projekte.view.roots": "Roots only",
|
||||
"projekte.unavailable": "Project management is currently unavailable \u2014 please contact an administrator.",
|
||||
"projekte.col.title": "Title",
|
||||
"projekte.col.type": "Type",
|
||||
"projekte.col.reference": "Reference",
|
||||
"projekte.col.clientmatter": "ClientMatter",
|
||||
"projekte.col.status": "Status",
|
||||
"projekte.col.updated": "Last modified",
|
||||
"projekte.empty.title": "No projects yet",
|
||||
"projekte.empty.hint": "Start via \u201cNew project\u201d \u2014 create a client first, then litigations, patents and cases underneath.",
|
||||
"projekte.empty.filtered": "No matches for these filters.",
|
||||
"projekte.cancel": "Cancel",
|
||||
"projekte.submit": "Create project",
|
||||
"projekte.neu.title": "New project \u2014 Paliad",
|
||||
"projekte.neu.heading": "Create a new project",
|
||||
"projekte.neu.subtitle": "Client, litigation, patent, case or generic project \u2014 place it in the hierarchy. Visibility follows the team (you are auto-added as \u201cLead\u201d).",
|
||||
"projekte.field.type": "Type",
|
||||
"projekte.field.parent": "Parent project",
|
||||
"projekte.field.parent.placeholder": "Type to search for a parent project...",
|
||||
"projekte.field.parent.hint": "Leave blank for a root project (typically a client).",
|
||||
"projekte.field.title": "Title",
|
||||
"projekte.field.title.placeholder": "e.g. Siemens AG | Siemens v. Huawei | EP 1 234 567",
|
||||
"projekte.field.reference": "Internal reference (optional)",
|
||||
"projekte.field.reference.placeholder": "e.g. HL-2026-0042",
|
||||
"projekte.field.client_number": "Client no. (7 digits)",
|
||||
"projekte.field.matter_number": "Matter no. (7 digits)",
|
||||
"projekte.field.clientmatter.hint": "HLC billing numbers. Format CCCCCCC.MMMMMMM. Client no. is inherited by sub-projects (overridable).",
|
||||
"projekte.field.netdocuments_url": "netDocuments URL (optional)",
|
||||
"projekte.field.industry": "Industry",
|
||||
"projekte.field.country": "Country (ISO-2)",
|
||||
"projekte.field.billing_reference": "Billing reference",
|
||||
"projekte.field.patent_number": "Patent number",
|
||||
"projekte.field.filing_date": "Filing date",
|
||||
"projekte.field.grant_date": "Grant date",
|
||||
"projekte.field.court": "Court",
|
||||
"projekte.field.case_number": "Case number (court)",
|
||||
"projekte.field.status": "Status",
|
||||
"projekte.error.title_required": "Title required",
|
||||
"projekte.detail.title": "Project \u2014 Paliad",
|
||||
"projekte.detail.back": "\u2190 Back to overview",
|
||||
"projekte.detail.loading": "Loading\u2026",
|
||||
"projekte.detail.notfound": "Project not found or no access.",
|
||||
"projekte.detail.edit": "Edit",
|
||||
"projekte.detail.save": "Save",
|
||||
"projekte.detail.tab.verlauf": "Activity",
|
||||
"projekte.detail.tab.team": "Team",
|
||||
"projekte.detail.tab.kinder": "Sub-projects",
|
||||
"projekte.detail.tab.parteien": "Parties",
|
||||
"projekte.detail.tab.fristen": "Deadlines",
|
||||
"projekte.detail.tab.termine": "Appointments",
|
||||
"projekte.detail.tab.notizen": "Notes",
|
||||
"projekte.detail.tab.checklisten": "Checklists",
|
||||
"projekte.detail.verlauf.empty": "No events recorded yet.",
|
||||
"projekte.detail.verlauf.loadMore": "Load more",
|
||||
"projekte.detail.team.form.user": "User",
|
||||
"projekte.detail.team.form.role": "Role",
|
||||
"projekte.detail.team.form.cancel": "Cancel",
|
||||
"projekte.detail.team.form.submit": "Add",
|
||||
"projekte.detail.team.col.name": "Name",
|
||||
"projekte.detail.team.col.role": "Role",
|
||||
"projekte.detail.team.col.source": "Source",
|
||||
"projekte.detail.kinder.add": "Create sub-project",
|
||||
"projekte.detail.kinder.empty": "No sub-projects.",
|
||||
"projekte.detail.parteien.add": "Add party",
|
||||
"projekte.detail.parteien.form.name": "Name",
|
||||
"projekte.detail.parteien.form.role": "Role",
|
||||
"projekte.detail.parteien.form.rep": "Representative (optional)",
|
||||
"projekte.detail.parteien.form.cancel": "Cancel",
|
||||
"projekte.detail.parteien.form.submit": "Add",
|
||||
"projekte.detail.parteien.role.claimant": "Claimant",
|
||||
"projekte.detail.parteien.role.defendant": "Defendant",
|
||||
"projekte.detail.parteien.role.thirdparty": "Third-party / intervenor",
|
||||
"projekte.detail.parteien.col.name": "Name",
|
||||
"projekte.detail.parteien.col.role": "Role",
|
||||
"projekte.detail.parteien.col.rep": "Representative",
|
||||
"projekte.detail.parteien.empty": "No parties recorded yet.",
|
||||
"projekte.detail.fristen.add": "Add deadline",
|
||||
"projekte.detail.fristen.empty": "No deadlines recorded for this project.",
|
||||
"projekte.detail.termine.add": "Add appointment",
|
||||
"projekte.detail.termine.form.cancel": "Cancel",
|
||||
"projekte.detail.termine.form.submit": "Add",
|
||||
"projekte.detail.termine.empty": "No appointments recorded for this project.",
|
||||
"projekte.detail.checklisten.empty": "No checklist instances recorded for this project.",
|
||||
"projekte.detail.checklisten.col.template": "Template",
|
||||
"projekte.detail.checklisten.col.name": "Name",
|
||||
"projekte.detail.checklisten.col.progress": "Progress",
|
||||
"projekte.detail.checklisten.col.created": "Created",
|
||||
"projekte.detail.checklisten.hint": "Instances are created on the template page under Checklists.",
|
||||
"projekte.detail.delete": "Archive project",
|
||||
"projekte.detail.delete.confirm.title": "Archive project?",
|
||||
"projekte.detail.delete.confirm.body": "The project will be archived. It cannot be directly restored.",
|
||||
"projekte.detail.delete.confirm.cancel": "Cancel",
|
||||
"projekte.detail.delete.confirm.ok": "Archive",
|
||||
"projekte.type.client": "Client",
|
||||
"projekte.type.litigation": "Litigation",
|
||||
"projekte.type.patent": "Patent",
|
||||
@@ -1803,6 +2017,12 @@ export function t(key: string): string {
|
||||
return translations[currentLang][key] ?? translations.de[key] ?? key;
|
||||
}
|
||||
|
||||
// tOrEmpty returns the translation if present, else "" — so callers that
|
||||
// want to fall back to the existing default text in the DOM can do so.
|
||||
function tOrEmpty(key: string): string {
|
||||
return translations[currentLang][key] ?? translations.de[key] ?? "";
|
||||
}
|
||||
|
||||
export function getLang(): Lang {
|
||||
return currentLang;
|
||||
}
|
||||
@@ -1822,17 +2042,22 @@ export function setLang(lang: Lang) {
|
||||
}
|
||||
|
||||
function applyTranslations() {
|
||||
// When a key is missing from every locale, preserve whatever static text
|
||||
// the HTML was authored with — never overwrite with the raw key string.
|
||||
document.querySelectorAll<HTMLElement>("[data-i18n]").forEach((el) => {
|
||||
const key = el.getAttribute("data-i18n")!;
|
||||
el.textContent = t(key);
|
||||
const val = tOrEmpty(key);
|
||||
if (val !== "") el.textContent = val;
|
||||
});
|
||||
document.querySelectorAll<HTMLElement>("[data-i18n-placeholder]").forEach((el) => {
|
||||
const key = el.getAttribute("data-i18n-placeholder")!;
|
||||
(el as HTMLInputElement).placeholder = t(key);
|
||||
const val = tOrEmpty(key);
|
||||
if (val !== "") (el as HTMLInputElement).placeholder = val;
|
||||
});
|
||||
document.querySelectorAll<HTMLElement>("[data-i18n-title]").forEach((el) => {
|
||||
const key = el.getAttribute("data-i18n-title")!;
|
||||
el.setAttribute("title", t(key));
|
||||
const val = tOrEmpty(key);
|
||||
if (val !== "") el.setAttribute("title", val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user