487 lines
24 KiB
JavaScript
487 lines
24 KiB
JavaScript
// UI strings for both languages. Keys are grouped by the view they belong to;
|
||
// {placeholders} are filled by t().
|
||
const STRINGS = {
|
||
de: {
|
||
"common.cancel": "Abbrechen",
|
||
"common.save": "Speichern",
|
||
"common.create": "Anlegen",
|
||
"common.request": "Anfragen",
|
||
"common.search": "Suchen",
|
||
"common.all": "Alle",
|
||
"common.none": "Keine",
|
||
"common.close": "Schließen",
|
||
"common.edit": "Bearbeiten",
|
||
"common.delete": "Löschen",
|
||
"common.link": "Verbinden",
|
||
"common.createAndLink": "Anlegen & verbinden",
|
||
"common.selectAll": "Alle auswählen",
|
||
"common.removeSelected": "Ausgewählte entfernen",
|
||
"common.removeSelectedN": "Ausgewählte entfernen ({n})",
|
||
"common.library": "Library",
|
||
"common.type": "Typ",
|
||
"common.title": "Titel",
|
||
"common.authors": "Autor(en)",
|
||
"common.author": "Autor",
|
||
"common.narrator": "Sprecher",
|
||
"common.series": "Serie",
|
||
"common.volume": "Band",
|
||
"common.year": "Jahr",
|
||
"common.name": "Name",
|
||
"common.path": "Pfad",
|
||
"common.language": "Sprache",
|
||
"common.score": "Score",
|
||
"common.status": "Status",
|
||
"common.noLibrary": "— keine Library —",
|
||
"common.nothingHere": "Nichts hier.",
|
||
"common.optionalForAll": "optional, für alle",
|
||
"common.optional": "optional",
|
||
"common.needLibraryFirst": "Erst eine Library für diesen Typ anlegen (Tab Libraries)",
|
||
"common.creating": "Lege an…",
|
||
"lang.german": "Deutsch",
|
||
"lang.english": "Englisch",
|
||
|
||
"nav.search": "Suche",
|
||
"nav.missing": "Missing",
|
||
"nav.imported": "Importiert",
|
||
"nav.import": "Import",
|
||
"nav.settings": "Libraries",
|
||
"nav.langToggle": "Switch to English",
|
||
|
||
"search.languageTitle": "Sprache der Ausgabe — filtert Ebook- und Audiobook-Suche",
|
||
"search.allLanguages": "Alle Sprachen",
|
||
"search.placeholder": "Titel, Autor oder ISBN…",
|
||
"search.manual": "Manuell anlegen",
|
||
"search.running": "Suche…",
|
||
"search.wholeSeries": "Ganze Serie…",
|
||
"search.requested": "✓ Angefragt",
|
||
"search.emptyEbook": "Keine Treffer. Tipp: ISBN ohne Bindestriche oder Titel + Autor versuchen — und ggf. „Alle Sprachen“ wählen.",
|
||
"search.emptyAudiobook": "Keine Treffer. Tipp: EAN/ISBN funktioniert bei Audible nicht — nach Titel/Autor suchen.",
|
||
"search.emptyComic": "Keine Treffer bei AniList (Manga). Westliche Comics per „Manuell anlegen“ erfassen.",
|
||
|
||
"manual.heading": "Manuell anfragen",
|
||
"manual.volumeTo": "bis Band (Bulk, optional)",
|
||
"manual.bulkHint": "Legt pro Band/Folge eine Anfrage an, z.B. 1 bis 300",
|
||
"manual.externalId": "ISBN/ID",
|
||
"manual.noLibraryChosen": "Keine Library gewählt",
|
||
"manual.needStartVolume": "Für Bulk bitte Start-Band angeben",
|
||
"manual.created": "Anfrage angelegt",
|
||
"manual.createdN": "{n} Anfragen angelegt",
|
||
|
||
"series.fallbackTitle": "Serie",
|
||
"series.from": "von Nr.",
|
||
"series.to": "bis Nr.",
|
||
"series.loading": "{unit} werden gesucht…",
|
||
"series.unitVolumes": "Bände",
|
||
"series.unitEpisodes": "Folgen",
|
||
"series.found": "{n} {unit} gefunden",
|
||
"series.range": " (Nr. {from}–{to})",
|
||
"series.noteEbook": ". Bände ohne Ausgabe in der gewählten Sprache stehen mit ihrem Originaltitel da.",
|
||
"series.noteAudiobook": ". Audible hat keine Serien-Abfrage — einzelne Folgen können fehlen.",
|
||
"series.gapVolumes": "… {n} Bände nicht bei Hardcover gefunden ({from}–{to})",
|
||
"series.gapVolume": "… {n} Band nicht bei Hardcover gefunden ({from}–{to})",
|
||
"series.gapEpisodes": "… {n} Folgen nicht bei Audible gefunden ({from}–{to})",
|
||
"series.gapEpisode": "… {n} Folge nicht bei Audible gefunden ({from}–{to})",
|
||
"series.requestN": "{n} anfragen",
|
||
"series.needLibrary": "Erst eine {type}-Library anlegen (Tab Libraries)",
|
||
"series.createdN": "{n} Anfragen angelegt",
|
||
"series.skippedN": ", {n} bereits vorhanden",
|
||
|
||
"list.allTypes": "Alle Typen",
|
||
"list.allLibraries": "Alle Libraries",
|
||
"list.filterPlaceholder": "Filtern (Titel/Autor/Serie)…",
|
||
"list.view": "Ansicht",
|
||
"list.viewList": "Liste",
|
||
"list.viewSmall": "Kleine Symbole",
|
||
"list.viewLarge": "Große Symbole",
|
||
"list.confirmDeleteRequests": "{n} Anfrage(n) entfernen?",
|
||
"list.confirmDeleteImported": "{n} Eintrag/Einträge entfernen? Die importierten Dateien in der Library bleiben erhalten.",
|
||
"list.deletedN": "{n} entfernt",
|
||
|
||
"detail.statusMissing": "fehlt noch",
|
||
"detail.statusImported": "importiert",
|
||
"detail.externalId": "ISBN/ASIN",
|
||
"detail.retag": "Speichern & neu taggen",
|
||
"detail.relocate": "Speichern & neu ablegen",
|
||
"detail.relocateTitle": "Ordner und Dateinamen nach dem Schema der Library neu anlegen",
|
||
"detail.relocating": "Lege ab…",
|
||
"detail.relocated": "Neu abgelegt: {dest}",
|
||
"detail.alreadyPlaced": "Liegt bereits richtig",
|
||
"detail.retagging": "Tagge…",
|
||
"detail.retagged": "{n} Datei(en) neu getaggt",
|
||
"detail.saved": "Anfrage gespeichert",
|
||
"detail.duplicateConfirm": "Trotzdem anlegen?",
|
||
|
||
"import.scan": "Download-Ordner scannen",
|
||
"import.splitDirs": "Ordner als Einzeldateien behandeln (z.B. Folgen-Sammlungen)",
|
||
"import.scanning": "Scanne…",
|
||
"import.candidates": "{n} Kandidat(en) in {dir}",
|
||
"import.remaining": "{n} Kandidat(en) übrig — für den aktuellen Stand erneut scannen",
|
||
"import.filterPlaceholder": "Filtern (Name/Pfad)…",
|
||
"import.modeSuggested": "Nur mit Vorschlag",
|
||
"import.modeUnassigned": "Nur ohne Zuordnung",
|
||
"import.modeConflict": "Nur Konflikte",
|
||
"import.formatTitle": "Nur Einträge mit diesem Dateiformat zeigen",
|
||
"import.allFormats": "Alle Formate",
|
||
"import.sortScan": "Reihenfolge: Scan",
|
||
"import.sortScore": "Score absteigend",
|
||
"import.sortName": "Name A–Z",
|
||
"import.selectSuggested": "Alle mit Vorschlag auswählen",
|
||
"import.selectAllTitle": "Alle Einträge der aktuellen Ansicht auswählen, auch ohne Zuordnung",
|
||
"import.selectPage": "Diese Seite auswählen",
|
||
"import.selectPageTitle": "Nur die Einträge dieser Seite auswählen, alle anderen abwählen",
|
||
"import.deselectAll": "Alle abwählen",
|
||
"import.merge": "Ausgewählte zusammenfassen",
|
||
"import.mergeTitle": "Mehrteiler: ausgewählte Einträge als ein Hörbuch importieren",
|
||
"import.fromNames": "Anfragen aus Ordnernamen",
|
||
"import.fromNamesTitle": "Für ausgewählte Einträge ohne Zuordnung Anfragen aus den Ordnernamen anlegen",
|
||
"import.colFile": "Datei/Ordner",
|
||
"import.colAssignment": "Zuordnung",
|
||
"import.prev": "← Zurück",
|
||
"import.next": "Weiter →",
|
||
"import.run": "Ausgewählte importieren",
|
||
"import.skip": "— überspringen —",
|
||
"import.appendGroup": "Bereits importiert — Teile anhängen",
|
||
"import.quickTitle": "Metadaten suchen und Anfrage direkt verbinden",
|
||
"import.unmerge": "Zusammenfassung wieder auflösen",
|
||
"import.splitDir": "Ordner in einzelne Titel aufteilen",
|
||
"import.parts": "{parts} Teile · {files} Dateien",
|
||
"import.maybeSeparate": "{n} Titel?",
|
||
"import.maybeSeparateTitle": "Die {n} Dateien tragen verschiedene Titel und sind je groß genug für ein ganzes Buch — mit ✂️ aufteilen",
|
||
"import.libraryCellTitle": "Ziel-Library dieser Anfrage ändern",
|
||
"import.conflict": "⚠ Konflikt",
|
||
"import.conflictTitle": "Mehrere Einträge zeigen auf dieselbe Anfrage",
|
||
"import.running": "läuft…",
|
||
"import.done": "✓ importiert",
|
||
"import.failed": "✗ Fehler",
|
||
"import.pageInfo": "Seite {page}/{pages} · {total} Einträge{filtered} · {selected} ausgewählt",
|
||
"import.filtered": " (gefiltert: {n})",
|
||
"import.movedToLibrary": "„{title}\" → {library}",
|
||
"import.selectedN": "{n} Einträge {what} ausgewählt",
|
||
"import.selectedWithout": ", davon {n} ohne Zuordnung",
|
||
"import.thisPage": "dieser Seite",
|
||
"import.inTotal": "insgesamt",
|
||
"import.nothingSelected": "Nichts ausgewählt",
|
||
"import.needTwo": "Mindestens zwei Einträge auswählen",
|
||
"import.sameTypeOnly": "Nur Einträge desselben Typs lassen sich zusammenfassen",
|
||
"import.differentFolders": "Die Einträge liegen in verschiedenen Ordnern",
|
||
"import.mergedN": "{n} Einträge als „{name}\" zusammengefasst ({files} Dateien)",
|
||
"import.splitN": "„{name}\" in {n} Einzeltitel aufgeteilt",
|
||
"import.nothingImported": "Nichts importiert: alle ausgewählten Einträge waren mehreren Anfragen zugeordnet — Filter „Nur Konflikte\" zeigt sie.",
|
||
"import.summary": "{n} importiert",
|
||
"import.summaryFailed": ", {n} Fehler",
|
||
"import.summarySkipped": "{n} Anfrage(n) waren mehreren Einträgen zugeordnet und wurden übersprungen — Filter „Nur Konflikte\" zeigt sie.",
|
||
"import.finished": "Import fertig",
|
||
"import.finishedFailed": "Import fertig, {n} Fehler",
|
||
"import.progressDone": "{total}/{total} · fertig",
|
||
|
||
"names.heading": "Anfragen aus Ordnernamen",
|
||
"names.intro": "{n} Einträge ohne Zuordnung ({type}). Titel und Folgennummer kommen aus dem Ordnernamen; Serie und Autor gelten für alle.",
|
||
"names.more": "… und {n} weitere",
|
||
"names.noneWithout": "Keine ausgewählten Einträge ohne Zuordnung",
|
||
"names.result": "{created} Anfragen angelegt{skipped}, {linked} Einträge verbunden",
|
||
"names.existed": ", {n} gab es schon",
|
||
|
||
"conflict.heading": "Mehrfach zugeordnete Anfragen",
|
||
"conflict.intro": "{n} Anfrage(n) sind mehreren Einträgen zugeordnet. Gehören die Einträge zusammen (Mehrteiler), lassen sie sich als ein Hörbuch importieren — sonst überspringst du sie, korrigierst die Zuordnung und importierst sie später.",
|
||
"conflict.merge": "Als je ein Hörbuch zusammenfassen",
|
||
"conflict.skip": "Konflikte überspringen, Rest importieren",
|
||
|
||
"quick.heading": "Suchen & Anfragen",
|
||
"quick.placeholder": "Titel/Serie suchen…",
|
||
"quick.targetLibrary": "Ziel-Library",
|
||
"quick.openRequests": "Offene Anfragen",
|
||
"quick.reqFilter": "nach Titel, Autor, Serie filtern…",
|
||
"quick.manualSummary": "Nicht bei Audible? Manuell anlegen",
|
||
"quick.editSummary": "Felder anpassen",
|
||
"quick.episodeVolume": "Folge/Band",
|
||
"quick.searching": "Suche läuft…",
|
||
"quick.episodeNote": "Folge {n} — nicht mitgesucht",
|
||
"quick.matchingOpen": "Passende offene Requests:",
|
||
"quick.hits": "{shown} von {total} Treffern ({open} offen)",
|
||
"quick.noHits": "Kein Treffer unter {open} offenen Anfragen",
|
||
"quick.linked": "Mit bestehendem Request verbunden",
|
||
"quick.editTitle": "Felder vor dem Anlegen anpassen (z.B. Serie)",
|
||
"quick.pickTitle": "Anfrage anlegen und mit diesem Eintrag verbinden",
|
||
"quick.basedOn": "Übernommen von Audible: „{title}\" — Sprecher, Cover, Jahr und ASIN bleiben erhalten.",
|
||
"quick.requestedAndLinked": "„{title}\" angefragt und verbunden",
|
||
"quick.needTitle": "Titel angeben",
|
||
|
||
"lib.heading": "Libraries",
|
||
"lib.folderTemplate": "Ordner-Schema",
|
||
"lib.fileTemplate": "Datei-Schema",
|
||
"lib.new": "Neue Library",
|
||
"lib.edit": "Library „{name}“ bearbeiten",
|
||
"lib.namePlaceholder": "Name (z.B. Kids)",
|
||
"lib.folderPlaceholder": "Ordner-Schema (optional)",
|
||
"lib.filePlaceholder": "Datei-Schema (optional)",
|
||
"lib.languageTitle": "Sprache der Ausgaben in dieser Library — filtert die Metadaten-Suche",
|
||
"lib.anyLanguage": "Sprache: egal",
|
||
"lib.placeholders": "Platzhalter: {Author} {Authors} {Narrator} {Narrators} {Title} {Year} {Series} {Volume} — {Author}/{Narrator} nennen den ersten Namen, {Authors}/{Narrators} alle. Leere Werte fallen samt Trenner weg.",
|
||
"lib.confirmDelete": "Library löschen?",
|
||
"lib.saved": "Library gespeichert — gilt für künftige Importe",
|
||
"lib.created": "Library angelegt",
|
||
},
|
||
|
||
en: {
|
||
"common.cancel": "Cancel",
|
||
"common.save": "Save",
|
||
"common.create": "Create",
|
||
"common.request": "Request",
|
||
"common.search": "Search",
|
||
"common.all": "All",
|
||
"common.none": "None",
|
||
"common.close": "Close",
|
||
"common.edit": "Edit",
|
||
"common.delete": "Delete",
|
||
"common.link": "Link",
|
||
"common.createAndLink": "Create & link",
|
||
"common.selectAll": "Select all",
|
||
"common.removeSelected": "Remove selected",
|
||
"common.removeSelectedN": "Remove selected ({n})",
|
||
"common.library": "Library",
|
||
"common.type": "Type",
|
||
"common.title": "Title",
|
||
"common.authors": "Author(s)",
|
||
"common.author": "Author",
|
||
"common.narrator": "Narrator",
|
||
"common.series": "Series",
|
||
"common.volume": "Volume",
|
||
"common.year": "Year",
|
||
"common.name": "Name",
|
||
"common.path": "Path",
|
||
"common.language": "Language",
|
||
"common.score": "Score",
|
||
"common.status": "Status",
|
||
"common.noLibrary": "— no library —",
|
||
"common.nothingHere": "Nothing here.",
|
||
"common.optionalForAll": "optional, for all",
|
||
"common.optional": "optional",
|
||
"common.needLibraryFirst": "Create a library for this type first (Libraries tab)",
|
||
"common.creating": "Creating…",
|
||
"lang.german": "German",
|
||
"lang.english": "English",
|
||
|
||
"nav.search": "Search",
|
||
"nav.missing": "Missing",
|
||
"nav.imported": "Imported",
|
||
"nav.import": "Import",
|
||
"nav.settings": "Libraries",
|
||
"nav.langToggle": "Auf Deutsch umschalten",
|
||
|
||
"search.languageTitle": "Edition language — filters the ebook and audiobook search",
|
||
"search.allLanguages": "All languages",
|
||
"search.placeholder": "Title, author or ISBN…",
|
||
"search.manual": "Add manually",
|
||
"search.running": "Searching…",
|
||
"search.wholeSeries": "Whole series…",
|
||
"search.requested": "✓ Requested",
|
||
"search.emptyEbook": "No hits. Try the ISBN without dashes, or title + author — and maybe pick “All languages”.",
|
||
"search.emptyAudiobook": "No hits. EAN/ISBN does not work on Audible — search by title/author.",
|
||
"search.emptyComic": "No hits on AniList (manga). Add western comics via “Add manually”.",
|
||
|
||
"manual.heading": "Request manually",
|
||
"manual.volumeTo": "to volume (bulk, optional)",
|
||
"manual.bulkHint": "Creates one request per volume/episode, e.g. 1 to 300",
|
||
"manual.externalId": "ISBN/ID",
|
||
"manual.noLibraryChosen": "No library chosen",
|
||
"manual.needStartVolume": "Bulk needs a starting volume",
|
||
"manual.created": "Request created",
|
||
"manual.createdN": "{n} requests created",
|
||
|
||
"series.fallbackTitle": "Series",
|
||
"series.from": "from no.",
|
||
"series.to": "to no.",
|
||
"series.loading": "Looking for {unit}…",
|
||
"series.unitVolumes": "volumes",
|
||
"series.unitEpisodes": "episodes",
|
||
"series.found": "{n} {unit} found",
|
||
"series.range": " (no. {from}–{to})",
|
||
"series.noteEbook": ". Volumes without an edition in the chosen language keep their original title.",
|
||
"series.noteAudiobook": ". Audible has no series query — single episodes can be missing.",
|
||
"series.gapVolumes": "… {n} volumes not found on Hardcover ({from}–{to})",
|
||
"series.gapVolume": "… {n} volume not found on Hardcover ({from}–{to})",
|
||
"series.gapEpisodes": "… {n} episodes not found on Audible ({from}–{to})",
|
||
"series.gapEpisode": "… {n} episode not found on Audible ({from}–{to})",
|
||
"series.requestN": "Request {n}",
|
||
"series.needLibrary": "Create an {type} library first (Libraries tab)",
|
||
"series.createdN": "{n} requests created",
|
||
"series.skippedN": ", {n} already there",
|
||
|
||
"list.allTypes": "All types",
|
||
"list.allLibraries": "All libraries",
|
||
"list.filterPlaceholder": "Filter (title/author/series)…",
|
||
"list.view": "View",
|
||
"list.viewList": "List",
|
||
"list.viewSmall": "Small icons",
|
||
"list.viewLarge": "Large icons",
|
||
"list.confirmDeleteRequests": "Remove {n} request(s)?",
|
||
"list.confirmDeleteImported": "Remove {n} entr(y/ies)? The imported files stay in the library.",
|
||
"list.deletedN": "{n} removed",
|
||
|
||
"detail.statusMissing": "still missing",
|
||
"detail.statusImported": "imported",
|
||
"detail.externalId": "ISBN/ASIN",
|
||
"detail.retag": "Save & re-tag",
|
||
"detail.relocate": "Save & re-file",
|
||
"detail.relocateTitle": "Rebuild folder and file names from the library's scheme",
|
||
"detail.relocating": "Filing…",
|
||
"detail.relocated": "Re-filed: {dest}",
|
||
"detail.alreadyPlaced": "Already in the right place",
|
||
"detail.retagging": "Tagging…",
|
||
"detail.retagged": "{n} file(s) re-tagged",
|
||
"detail.saved": "Request saved",
|
||
"detail.duplicateConfirm": "Create anyway?",
|
||
|
||
"import.scan": "Scan download folder",
|
||
"import.splitDirs": "Treat folders as single files (e.g. episode collections)",
|
||
"import.scanning": "Scanning…",
|
||
"import.candidates": "{n} candidate(s) in {dir}",
|
||
"import.remaining": "{n} candidate(s) left — scan again for the current state",
|
||
"import.filterPlaceholder": "Filter (name/path)…",
|
||
"import.modeSuggested": "With suggestion only",
|
||
"import.modeUnassigned": "Unassigned only",
|
||
"import.modeConflict": "Conflicts only",
|
||
"import.formatTitle": "Show only entries with this file format",
|
||
"import.allFormats": "All formats",
|
||
"import.sortScan": "Order: scan",
|
||
"import.sortScore": "Score descending",
|
||
"import.sortName": "Name A–Z",
|
||
"import.selectSuggested": "Select all with a suggestion",
|
||
"import.selectAllTitle": "Select every entry of the current view, unassigned ones too",
|
||
"import.selectPage": "Select this page",
|
||
"import.selectPageTitle": "Select only this page's entries, deselect all others",
|
||
"import.deselectAll": "Deselect all",
|
||
"import.merge": "Merge selected",
|
||
"import.mergeTitle": "Multi-part title: import the selected entries as one audiobook",
|
||
"import.fromNames": "Requests from folder names",
|
||
"import.fromNamesTitle": "Create requests from the folder names of the selected unassigned entries",
|
||
"import.colFile": "File/folder",
|
||
"import.colAssignment": "Assignment",
|
||
"import.prev": "← Back",
|
||
"import.next": "Next →",
|
||
"import.run": "Import selected",
|
||
"import.skip": "— skip —",
|
||
"import.appendGroup": "Already imported — append parts",
|
||
"import.quickTitle": "Search metadata and link the request right away",
|
||
"import.unmerge": "Undo the merge",
|
||
"import.splitDir": "Split the folder into single titles",
|
||
"import.parts": "{parts} parts · {files} files",
|
||
"import.maybeSeparate": "{n} titles?",
|
||
"import.maybeSeparateTitle": "The {n} files carry different titles and are each big enough for a whole book — split with ✂️",
|
||
"import.libraryCellTitle": "Change this request's target library",
|
||
"import.conflict": "⚠ Conflict",
|
||
"import.conflictTitle": "Several entries point at the same request",
|
||
"import.running": "running…",
|
||
"import.done": "✓ imported",
|
||
"import.failed": "✗ Error",
|
||
"import.pageInfo": "Page {page}/{pages} · {total} entries{filtered} · {selected} selected",
|
||
"import.filtered": " (filtered: {n})",
|
||
"import.movedToLibrary": "“{title}” → {library}",
|
||
"import.selectedN": "{n} entries {what} selected",
|
||
"import.selectedWithout": ", {n} of them unassigned",
|
||
"import.thisPage": "on this page",
|
||
"import.inTotal": "in total",
|
||
"import.nothingSelected": "Nothing selected",
|
||
"import.needTwo": "Select at least two entries",
|
||
"import.sameTypeOnly": "Only entries of the same type can be merged",
|
||
"import.differentFolders": "The entries live in different folders",
|
||
"import.mergedN": "{n} entries merged as “{name}” ({files} files)",
|
||
"import.splitN": "“{name}” split into {n} single titles",
|
||
"import.nothingImported": "Nothing imported: every selected entry was assigned to several requests — the “Conflicts only” filter shows them.",
|
||
"import.summary": "{n} imported",
|
||
"import.summaryFailed": ", {n} failed",
|
||
"import.summarySkipped": "{n} request(s) were assigned to several entries and were skipped — the “Conflicts only” filter shows them.",
|
||
"import.finished": "Import finished",
|
||
"import.finishedFailed": "Import finished, {n} failed",
|
||
"import.progressDone": "{total}/{total} · done",
|
||
|
||
"names.heading": "Requests from folder names",
|
||
"names.intro": "{n} unassigned entries ({type}). Title and episode number come from the folder name; series and author apply to all of them.",
|
||
"names.more": "… and {n} more",
|
||
"names.noneWithout": "No selected entries without an assignment",
|
||
"names.result": "{created} requests created{skipped}, {linked} entries linked",
|
||
"names.existed": ", {n} already existed",
|
||
|
||
"conflict.heading": "Requests assigned more than once",
|
||
"conflict.intro": "{n} request(s) are assigned to several entries. If those entries belong together (a multi-part title), they can be imported as one audiobook — otherwise skip them, fix the assignment and import them later.",
|
||
"conflict.merge": "Merge each into one audiobook",
|
||
"conflict.skip": "Skip conflicts, import the rest",
|
||
|
||
"quick.heading": "Search & request",
|
||
"quick.placeholder": "Search title/series…",
|
||
"quick.targetLibrary": "Target library",
|
||
"quick.openRequests": "Open requests",
|
||
"quick.reqFilter": "filter by title, author, series…",
|
||
"quick.manualSummary": "Not on Audible? Add manually",
|
||
"quick.editSummary": "Adjust the fields",
|
||
"quick.episodeVolume": "Episode/volume",
|
||
"quick.searching": "Searching…",
|
||
"quick.episodeNote": "Episode {n} — not part of the search",
|
||
"quick.matchingOpen": "Matching open requests:",
|
||
"quick.hits": "{shown} of {total} hits ({open} open)",
|
||
"quick.noHits": "No hit among {open} open requests",
|
||
"quick.linked": "Linked to the existing request",
|
||
"quick.editTitle": "Adjust the fields before creating (e.g. the series)",
|
||
"quick.pickTitle": "Create the request and link it to this entry",
|
||
"quick.basedOn": "Taken from Audible: “{title}” — narrator, cover, year and ASIN are kept.",
|
||
"quick.requestedAndLinked": "“{title}” requested and linked",
|
||
"quick.needTitle": "Enter a title",
|
||
|
||
"lib.heading": "Libraries",
|
||
"lib.folderTemplate": "Folder scheme",
|
||
"lib.fileTemplate": "File scheme",
|
||
"lib.new": "New library",
|
||
"lib.edit": "Edit library “{name}”",
|
||
"lib.namePlaceholder": "Name (e.g. Kids)",
|
||
"lib.folderPlaceholder": "Folder scheme (optional)",
|
||
"lib.filePlaceholder": "File scheme (optional)",
|
||
"lib.languageTitle": "Language of this library's editions — filters the metadata search",
|
||
"lib.anyLanguage": "Language: any",
|
||
"lib.placeholders": "Placeholders: {Author} {Authors} {Narrator} {Narrators} {Title} {Year} {Series} {Volume} — {Author}/{Narrator} name the first one, {Authors}/{Narrators} all of them. Empty values drop out with their separator.",
|
||
"lib.confirmDelete": "Delete library?",
|
||
"lib.saved": "Library saved — applies to future imports",
|
||
"lib.created": "Library created",
|
||
},
|
||
};
|
||
|
||
const LANG_KEY = "wordarr.lang";
|
||
|
||
function initialLang() {
|
||
try {
|
||
const saved = localStorage.getItem(LANG_KEY);
|
||
if (saved && STRINGS[saved]) return saved;
|
||
} catch {}
|
||
return (navigator.language || "en").startsWith("de") ? "de" : "en";
|
||
}
|
||
|
||
let lang = initialLang();
|
||
|
||
// {Placeholders} of the naming scheme must survive, so only known vars are replaced
|
||
function t(key, vars) {
|
||
let s = STRINGS[lang][key] ?? STRINGS.en[key] ?? key;
|
||
if (vars) {
|
||
for (const [name, value] of Object.entries(vars)) {
|
||
s = s.split("{" + name + "}").join(String(value));
|
||
}
|
||
}
|
||
return s;
|
||
}
|
||
|
||
const I18N_ATTRS = { "i18nPlaceholder": "placeholder", "i18nTitle": "title", "i18nAria": "aria-label" };
|
||
|
||
function applyI18n(root = document) {
|
||
root.querySelectorAll("[data-i18n]").forEach((el) => (el.textContent = t(el.dataset.i18n)));
|
||
for (const [data, attr] of Object.entries(I18N_ATTRS)) {
|
||
root.querySelectorAll(`[data-${data.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase())}]`)
|
||
.forEach((el) => el.setAttribute(attr, t(el.dataset[data])));
|
||
}
|
||
document.documentElement.lang = lang;
|
||
}
|
||
|
||
function setLang(next) {
|
||
lang = next;
|
||
try { localStorage.setItem(LANG_KEY, next); } catch {}
|
||
applyI18n();
|
||
if (typeof onLangChange === "function") onLangChange();
|
||
}
|