Mehrsprachigkeit bearbeiten

Tragen Sie pro Seite die passenden URL-Slugs je Sprache ein. Links ist nur eine Bezeichnung (frei wählbar). Der Sprachwechsel nutzt diese Zuordnungen automatisch.

Domain:
Projekt:
Sprachen erlaubt:
Status wird geladen…
Tipp: Nutzen Sie in jeder Sprachspalte den vollständigen Pfad (z. B. /de/start). Für die Startseite wird die Zeile Start verwendet.

`; } toast("Gespeichert", "Ihre Änderungen wurden gespeichert."); updateStatus(); }catch(e){ toast("Fehler", "Speichern war nicht möglich. Bitte später erneut versuchen."); }finally{ $("#btnSave").disabled = false; $("#btnSave").textContent = "Änderungen speichern"; } } // === Init === async function init(){ state.public = getParam("public").trim(); state.domain = getParam("domain").trim().toLowerCase(); state.edit = getParam("edit").trim(); // Labels $("#publicLabel").textContent = state.public || "—"; $("#domainLabel").textContent = state.domain || "—"; // Default links if(state.public){ const configUrl = `${CDN_BASE}/config/${encodeURIComponent(state.public)}.json`; $("#configLink").href = configUrl; $("#configLink").textContent = configUrl; const healthUrl = `${state.domain ? ("https://" + state.domain) : ""}/?tf_check=1`; $("#healthLink").href = state.domain ? healthUrl : "#"; $("#healthLink").textContent = state.domain ? healthUrl : "—"; $("#snippetText").textContent = ``; } // Try load existing config let cfg = null; if(state.public){ cfg = await loadConfigIfAvailable(); } // Determine entitlement state.maxLanguages = (cfg && cfg.entitlement && Number(cfg.entitlement.maxLanguages)) || (cfg && cfg.maxLanguages && Number(cfg.maxLanguages)) || DEFAULT_MAX_LANGUAGES; $("#maxLangLabel").textContent = String(state.maxLanguages); // Determine initial languages if(cfg && Array.isArray(cfg.languages) && cfg.languages.length >= 2){ state.langCodes = cfg.languages.map(x=>String(x||"").toLowerCase()); }else{ state.langCodes = ["de","en"]; } // Determine initial rows from pagesMapping if present (best effort) // MVP: if mapping exists, we attempt to reconstruct rows by collecting unique slugs per language and grouping by shared targets. // If not, show 4 example rows. let rows = []; if(cfg && cfg.pagesMapping && typeof cfg.pagesMapping === "object"){ // Collect slugs per lang const langs = uniqLower(state.langCodes).slice(0, state.maxLanguages); const slugSets = {}; langs.forEach(l=> slugSets[l] = new Set()); for(const [srcLang, mp] of Object.entries(cfg.pagesMapping)){ if(!slugSets[srcLang]) continue; for(const srcSlug of Object.keys(mp||{})){ slugSets[srcLang].add(String(srcSlug)); } } // Build a simple row list from union by index (not perfect but usable) const maxLen = Math.max(...langs.map(l => slugSets[l].size)); const arrays = langs.map(l => Array.from(slugSets[l])); for(let i=0;i{ r.slugs[li] = arrays[li][i] ? normalizePath(arrays[li][i]) : ""; }); // give keyword from first non-empty slug tail const any = r.slugs.find(Boolean) || ""; r.keyword = any ? any.split("/").filter(Boolean).slice(-1)[0] : ""; rows.push(r); } } if(rows.length === 0){ rows = DEFAULT_EXAMPLE_ROWS.map(r => ({ keyword: r.keyword, slugs: Array(state.langCodes.length).fill(""), isExample: true })); } // Ensure at least 4 rows visible (as you want), but unlimited via + while(rows.length < 4){ rows.push({ keyword:"", slugs: Array(state.langCodes.length).fill(""), isExample:false }); } state.rows = rows; // Wire buttons $("#btnSave").addEventListener("click", saveConfig); $("#btnReload").addEventListener("click", async ()=>{ toast("Neu laden", "Konfiguration wird neu geladen…"); await init(); }); // Render buildHeader(); buildRows(); updateStatus(); // If link incomplete, show helpful message if(!state.public || !state.domain || !state.edit){ $("#statusMsg").textContent = "Dieser Link ist unvollständig. Bitte verwenden Sie den vollständigen Edit-Link, den Sie von Tintenfrei erhalten haben."; $("#statusDot").style.background = "var(--bad)"; } } init();