Compare commits

...

2 commits

Author SHA1 Message Date
3d3362fea0 feat(i18n): +10 langues (hu, da, fi, sk, hr, sl, lt, lv, et, nb)
Magyar, Dansk, Suomi, Slovenčina, Hrvatski, Slovenščina, Lietuvių, Latviešu,
Eesti, Norsk bokmål. 21 langues au total.

- locales.js: traductions complètes des ~50 clés (faq, legal inclus)
- index.html: boutons dropdown avec flag-icons (sl→si, et→ee, nb→no, da→dk)
- app.js: SUPPORTED_LANGS, LANG_FLAGS, LANG_NAMES

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 19:47:36 +02:00
f145188d1f fix(geocoder): band_locations.ma_id en BIGINT — débloque 62k bands
bands.ma_id est BIGINT (crawler génère jusqu'à ~3.5e9) mais band_locations.ma_id
avait été créé en INTEGER (max 2.1e9). Tout INSERT pour un band à ma_id élevé
échouait en "integer out of range", erreur avalée silencieusement par l'enqueue.
62 239 bands (sur 96 143 localisables) n'entraient donc jamais dans le pipeline,
d'où 0 llm_needed / 0 erreur trompeurs.

- migration 008: ma_id BIGINT (installs neuves)
- migration 009: ALTER COLUMN ma_id TYPE BIGINT (DB existante)
- enqueue.py: compte les inserts échoués (failed=) au lieu de les avaler
- worker.py: sync_bands_primary prend le lieu d'ORIGINE (step 0) et non la
  dernière localisation — garde les groupes européens en Europe
- admin app.js: coût LLM robuste au NaN (NUMERIC accepte la valeur spéciale NaN)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 19:47:30 +02:00
7 changed files with 405 additions and 12 deletions

View file

@ -1064,7 +1064,8 @@ async function loadGeocoding() {
const locManual = locs.find((x) => x.status === "manual")?.n || 0; const locManual = locs.find((x) => x.status === "manual")?.n || 0;
const locErr = locs.find((x) => x.status === "error")?.n || 0; const locErr = locs.find((x) => x.status === "error")?.n || 0;
const locPct = locTotal ? Math.round((locDone / locTotal) * 100) : 0; const locPct = locTotal ? Math.round((locDone / locTotal) * 100) : 0;
const llmCost = parseFloat(r.llm_cache?.total_cost_usd || 0).toFixed(4); const rawCost = Number(r.llm_cache?.total_cost_usd);
const llmCost = (Number.isFinite(rawCost) ? rawCost : 0).toFixed(4);
const locStatsEl = document.getElementById("loc-stats"); const locStatsEl = document.getElementById("loc-stats");
if (locStatsEl) locStatsEl.innerHTML = ` if (locStatsEl) locStatsEl.innerHTML = `

View file

@ -4,7 +4,7 @@
CREATE TABLE IF NOT EXISTS band_locations ( CREATE TABLE IF NOT EXISTS band_locations (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
ma_id INTEGER NOT NULL REFERENCES bands(ma_id) ON DELETE CASCADE, ma_id BIGINT NOT NULL REFERENCES bands(ma_id) ON DELETE CASCADE,
step_order SMALLINT NOT NULL DEFAULT 0, step_order SMALLINT NOT NULL DEFAULT 0,
step_label TEXT, step_label TEXT,
location_raw TEXT NOT NULL, location_raw TEXT NOT NULL,

View file

@ -0,0 +1,9 @@
-- 009_band_locations_bigint.sql
-- bands.ma_id est BIGINT (valeurs jusqu'à ~3.5e9 côté crawler), mais
-- band_locations.ma_id avait été créé en INTEGER (008). Tout INSERT pour un
-- band avec ma_id > 2147483647 échouait en "integer out of range" — l'erreur
-- était avalée silencieusement par l'enqueue, laissant ~62k bands hors pipeline.
-- On aligne le type sur bands.ma_id.
ALTER TABLE band_locations
ALTER COLUMN ma_id TYPE BIGINT;

View file

@ -43,7 +43,8 @@ def run_enqueue(cur) -> tuple[int, int, int]:
bands = cur.fetchall() bands = cur.fetchall()
print(f"[enqueue] {len(bands)} bands à parser") print(f"[enqueue] {len(bands)} bands à parser")
inserted = country_fixed = skipped = 0 inserted = country_fixed = skipped = failed = 0
err_samples: list[str] = []
for ma_id, country, location_text in bands: for ma_id, country, location_text in bands:
steps = parse_location_text(location_text, country) steps = parse_location_text(location_text, country)
@ -67,8 +68,14 @@ def run_enqueue(cur) -> tuple[int, int, int]:
if cur.rowcount > 0: if cur.rowcount > 0:
inserted += 1 inserted += 1
except Exception as exc: except Exception as exc:
failed += 1
if len(err_samples) < 5:
err_samples.append(f"ma_id={ma_id}: {exc}")
print(f"[enqueue] WARN insert ma_id={ma_id}: {exc}") print(f"[enqueue] WARN insert ma_id={ma_id}: {exc}")
if failed:
print(f"[enqueue] {failed} inserts échoués — échantillon: {err_samples}")
# Résoudre immédiatement les entrées pays-seulement # Résoudre immédiatement les entrées pays-seulement
cur.execute( cur.execute(
""" """
@ -101,7 +108,7 @@ def run_enqueue(cur) -> tuple[int, int, int]:
else: else:
print(f"[enqueue] no centroid id={loc_id} raw='{location_raw}'") print(f"[enqueue] no centroid id={loc_id} raw='{location_raw}'")
return inserted, country_fixed, skipped return inserted, country_fixed, skipped, failed
def main(): def main():
@ -141,10 +148,11 @@ def main():
print(f"[enqueue] job #{job_id} démarré") print(f"[enqueue] job #{job_id} démarré")
try: try:
inserted, country_fixed, skipped = run_enqueue(cur) inserted, country_fixed, skipped, failed = run_enqueue(cur)
summary = ( summary = (
f"[geocoder_enqueue] job #{job_id} terminé — " f"[geocoder_enqueue] job #{job_id} terminé — "
f"inserted={inserted} country_fixed={country_fixed} skipped={skipped}" f"inserted={inserted} country_fixed={country_fixed} "
f"skipped={skipped} failed={failed}"
) )
cur.execute( cur.execute(
"UPDATE job_triggers SET status='done', finished_at=now() WHERE id=%s", "UPDATE job_triggers SET status='done', finished_at=now() WHERE id=%s",

View file

@ -66,14 +66,19 @@ def geoapify_search(query: str) -> dict | None:
def sync_bands_primary(cur, ma_id: int): def sync_bands_primary(cur, ma_id: int):
"""Met à jour bands.lat/lon avec le step le plus récent géocodé.""" """Met à jour bands.lat/lon avec le lieu d'ORIGINE géocodé (step_order le plus bas).
Carte « metal from Europe » : on veut le point de formation du groupe, pas
sa dernière localisation (ex. un groupe de Thessaloniki parti à Boston doit
rester à Thessaloniki, en Europe).
"""
cur.execute( cur.execute(
""" """
SELECT lat, lon FROM band_locations SELECT lat, lon FROM band_locations
WHERE ma_id = %s WHERE ma_id = %s
AND geocode_status IN ('done', 'country_only') AND geocode_status IN ('done', 'country_only')
AND lat IS NOT NULL AND lon IS NOT NULL AND lat IS NOT NULL AND lon IS NOT NULL
ORDER BY step_order DESC, id DESC ORDER BY step_order ASC, id ASC
LIMIT 1 LIMIT 1
""", """,
(ma_id,), (ma_id,),

View file

@ -4,7 +4,7 @@
const API_BASE = "https://bm.nicolasfryder.ovh"; const API_BASE = "https://bm.nicolasfryder.ovh";
// --- i18n --- // --- i18n ---
const SUPPORTED_LANGS = ["fr", "en", "de", "es", "it", "pl", "nl", "ro", "pt", "cs", "sv"]; const SUPPORTED_LANGS = ["fr", "en", "de", "es", "it", "pl", "nl", "ro", "pt", "cs", "sv", "hu", "da", "fi", "sk", "hr", "sl", "lt", "lv", "et", "nb"];
function detectLang() { function detectLang() {
const langs = navigator.languages?.length ? navigator.languages : [navigator.language || "en"]; const langs = navigator.languages?.length ? navigator.languages : [navigator.language || "en"];
@ -1407,8 +1407,8 @@ if (window.matchMedia("(max-width: 1200px)").matches) {
} }
// Language dropdown (flag-icons custom widget) // Language dropdown (flag-icons custom widget)
const LANG_FLAGS = { en:"gb", fr:"fr", de:"de", es:"es", it:"it", pl:"pl", nl:"nl", ro:"ro", pt:"pt", cs:"cz", sv:"se" }; const LANG_FLAGS = { en:"gb", fr:"fr", de:"de", es:"es", it:"it", pl:"pl", nl:"nl", ro:"ro", pt:"pt", cs:"cz", sv:"se", hu:"hu", da:"dk", fi:"fi", sk:"sk", hr:"hr", sl:"si", lt:"lt", lv:"lv", et:"ee", nb:"no" };
const LANG_NAMES = { en:"English", fr:"Français", de:"Deutsch", es:"Español", it:"Italiano", pl:"Polski", nl:"Nederlands", ro:"Română", pt:"Português", cs:"Čeština", sv:"Svenska" }; const LANG_NAMES = { en:"English", fr:"Français", de:"Deutsch", es:"Español", it:"Italiano", pl:"Polski", nl:"Nederlands", ro:"Română", pt:"Português", cs:"Čeština", sv:"Svenska", hu:"Magyar", da:"Dansk", fi:"Suomi", sk:"Slovenčina", hr:"Hrvatski", sl:"Slovenščina", lt:"Lietuvių", lv:"Latviešu", et:"Eesti", nb:"Norsk bokmål" };
function syncLangTrigger(lang) { function syncLangTrigger(lang) {
const trigger = document.getElementById("langTrigger"); const trigger = document.getElementById("langTrigger");

View file

@ -1,4 +1,4 @@
/* locales.js — 11 langues pour Metal from Europe */ /* locales.js — 21 langues pour Metal from Europe */
(function () { (function () {
"use strict"; "use strict";
@ -463,6 +463,376 @@
], ],
}, },
hu: {
search_placeholder: "Keresés (név, műfaj, város, ország)…",
displayed: "megjelenített", total_bands: "összesen", localities: "helységek", located: "lokalizált",
view_section: "Nézet", reset_view: "Nézet alaphelyzetbe", heatmap_label: "Hőtérkép",
filters_section: "Szűrők", without_coords_btn: "Koordináták nélkül",
country_label: "Ország", all_label: "Összes", status_label: "Állapot",
genres_label: "Műfajok", subgenres_label: "Alműfajok", selection_label: "Kiválasztás",
themes_label: "Témák", timeline_label: "Idővonal (alapítás éve)",
sort_label: "Lista rendezése", sort_az: "A → Z", sort_status: "Állapot szerint",
sort_genre: "Műfaj szerint", sort_country: "Ország szerint", sort_year: "Év szerint (legújabb → legrégibb)",
list_section: "Lista", legal_link: "Jogi információk", faq_link: "GYIK",
visits_label: "Látogatások", this_month_label: "Ezen a hónapon", options_btn: "Beállítások", close_btn: "Bezárás",
all_years_label: "mind", year_data_missing: "hiányzó adatok",
year_data_unavailable: "Az éves adatok nem elérhetők", results_label: "eredmény",
loading_text: "Betöltés…", without_coords_modal: "Együttesek koordináták nélkül",
group_s: "együttes", group_p: "együttesek", location_fallback: "Helyszín",
legal_title: "Jogi információk", faq_title: "GYIK",
ed_title: "Weboldal szerkesztője", ed_name: "Szerző: Nico", ed_status: "Státusz: magánszemély", ed_contact: "Kapcsolat:",
host_title: "Tárhelyszolgáltató", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Franciaország",
ip_title: "Szellemi tulajdon",
ip_text: "A tartalmak (szövegek, képek, összesített adatok) tájékoztató jelleggel kerülnek közzétételre. A bandák logói és nevei szerzőik tulajdonai maradnak. Minden adat a __MA__ oldalról származik, a webmasterek engedélyével.",
prv_title: "Személyes adatok",
prv_text: "Ez a weboldal nem gyűjt személyes adatokat, és nem telepít nyomkövető sütiket. A tárhelyszolgáltató technikai naplókat tárolhat. A forgalom elemzése __GC__ segítségével történik (sütik nélkül).",
pub_title: "Felelős szerkesztő", pub_name: "Nico",
thanks_title: "Köszönet",
thanks_intro: "Ez a weboldal kiváló eszközökre és szolgáltatásokra támaszkodik:",
thanks_map: "Térképészet", thanks_geo: "Geokódolás", thanks_data: "Adatok",
thanks_hb: "Különös köszönet HellBlazernek (Metal Archives webmaster) a scraping engedélyéért.",
faq: [
["K: Honnan származnak az adatok?", "V: Metal Archives + automatizált földrajzi gazdagítás. Néhány kézi javítás, de ez fáradságos."],
["K: Javíthatok egy hibát?", "V: Igen, ha a weboldalt érinti, lépj kapcsolatba velem a jogi oldalon megadott e-mailben. Az adatokhoz javítsd közvetlenül a Metal Archives-on."],
["K: Miért nem láthatók egyes együttesek?", "V: Az automatikus geokódolásnak inherens hibái vannak. A helyek kézi javítása fáradságos."],
["K: Éppen létrehoztam az együttesem a Metal Archives-on, de nem jelenik meg.", "V: Jelenleg nincs automatikus szinkronizáció a Metal Archives-szal."],
["K: Nyomon követ engem a weboldal?", "V: Csak a forgalom elemzéséhez a GoatCounter segítségével (sütik nélkül). A reklámblokkolók gond nélkül blokkolják ezeket a kéréseket."],
],
},
da: {
search_placeholder: "Søg (navn, genre, by, land)…",
displayed: "vist", total_bands: "i alt", localities: "lokaliteter", located: "lokaliserede",
view_section: "Visning", reset_view: "Nulstil visning", heatmap_label: "Varmekort",
filters_section: "Filtre", without_coords_btn: "Uden koordinater",
country_label: "Land", all_label: "Alle", status_label: "Status",
genres_label: "Genrer", subgenres_label: "Undergenrer", selection_label: "Valg",
themes_label: "Temaer", timeline_label: "Tidslinje (stiftelsesår)",
sort_label: "Sorter liste", sort_az: "A → Z", sort_status: "Efter status",
sort_genre: "Efter genre", sort_country: "Efter land", sort_year: "Efter år (nyeste → ældste)",
list_section: "Liste", legal_link: "Juridisk information", faq_link: "FAQ",
visits_label: "Besøg", this_month_label: "Denne måned", options_btn: "Indstillinger", close_btn: "Luk",
all_years_label: "alle", year_data_missing: "manglende data",
year_data_unavailable: "Årsdata ikke tilgængeligt", results_label: "resultat(er)",
loading_text: "Indlæser…", without_coords_modal: "Bands uden koordinater",
group_s: "band", group_p: "bands", location_fallback: "Placering",
legal_title: "Juridisk information", faq_title: "FAQ",
ed_title: "Websiteredaktør", ed_name: "Forfatter: Nico", ed_status: "Status: privatperson", ed_contact: "Kontakt:",
host_title: "Hosting", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Frankrig",
ip_title: "Intellektuel ejendomsret",
ip_text: "Indhold (tekster, billeder, aggregerede data) leveres til informationsformål. Bandlogoer og navne forbliver deres forfatteres ejendom. Alle data stammer fra __MA__, med webmasternes tilladelse.",
prv_title: "Personlige data",
prv_text: "Dette websted indsamler ikke personoplysninger og installerer ikke sporings-cookies. Hostingudbyderen kan opbevare tekniske logs. Trafik analyseres via __GC__ (uden cookies).",
pub_title: "Ansvarlig udgiver", pub_name: "Nico",
thanks_title: "Tak til",
thanks_intro: "Dette websted bygger på fremragende værktøjer og tjenester:",
thanks_map: "Kortlægning", thanks_geo: "Geokodning", thanks_data: "Data",
thanks_hb: "Særlig tak til HellBlazer (Metal Archives webmaster) for tilladelsen til scraping.",
faq: [
["Sp: Hvor kommer dataene fra?", "Sv: Metal Archives + automatiseret geografisk berikning. Nogle manuelle rettelser, men det er kedeligt."],
["Sp: Kan jeg rette en fejl?", "Sv: Ja, hvis det vedrører webstedet, kontakt mig via e-mailen i juridisk information. For data, ret direkte på Metal Archives."],
["Sp: Hvorfor er nogle bands ikke synlige?", "Sv: Automatisk geokodning har iboende fejl. Manuel korrektion af placeringer er kedeligt."],
["Sp: Jeg oprettede netop mit band på Metal Archives, men det vises ikke.", "Sv: Ingen automatisk synkronisering med Metal Archives er i øjeblikket implementeret."],
["Sp: Sporer webstedet mig?", "Sv: Kun til trafikanalyse via GoatCounter (ingen cookies). Annonceblokkere blokerer disse anmodninger uden problemer."],
],
},
fi: {
search_placeholder: "Haku (nimi, genre, kaupunki, maa)…",
displayed: "näytetty", total_bands: "yhteensä", localities: "paikkakunnat", located: "paikannettu",
view_section: "Näkymä", reset_view: "Palauta näkymä", heatmap_label: "Lämpökartta",
filters_section: "Suodattimet", without_coords_btn: "Ilman koordinaatteja",
country_label: "Maa", all_label: "Kaikki", status_label: "Tila",
genres_label: "Genret", subgenres_label: "Alagenret", selection_label: "Valinta",
themes_label: "Teemat", timeline_label: "Aikajana (perustamisvuosi)",
sort_label: "Lajittele lista", sort_az: "A → Z", sort_status: "Tilan mukaan",
sort_genre: "Genren mukaan", sort_country: "Maan mukaan", sort_year: "Vuoden mukaan (uusin → vanhin)",
list_section: "Lista", legal_link: "Lakitiedot", faq_link: "UKK",
visits_label: "Vierailut", this_month_label: "Tässä kuussa", options_btn: "Asetukset", close_btn: "Sulje",
all_years_label: "kaikki", year_data_missing: "tiedot puuttuvat",
year_data_unavailable: "Vuosidataa ei saatavilla", results_label: "tulos/ta",
loading_text: "Ladataan…", without_coords_modal: "Bändit ilman koordinaatteja",
group_s: "bändi", group_p: "bändit", location_fallback: "Sijainti",
legal_title: "Lakitiedot", faq_title: "UKK",
ed_title: "Sivuston toimittaja", ed_name: "Tekijä: Nico", ed_status: "Asema: yksityishenkilö", ed_contact: "Yhteystiedot:",
host_title: "Palveluntarjoaja", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Ranska",
ip_title: "Immateriaalioikeudet",
ip_text: "Sisältö (tekstit, kuvat, koottu data) on tarjolla tiedotustarkoituksessa. Bändien logot ja nimet pysyvät tekijöidensä omaisuutena. Kaikki data on peräisin __MA__-sivustolta webmasterien luvalla.",
prv_title: "Henkilötiedot",
prv_text: "Tämä sivusto ei kerää henkilötietoja eikä asenna seurantaevästeitä. Palveluntarjoaja voi säilyttää teknisiä lokeja. Liikenne analysoidaan __GC__:n kautta (ilman evästeitä).",
pub_title: "Julkaisusta vastaava", pub_name: "Nico",
thanks_title: "Kiitokset",
thanks_intro: "Tämä sivusto perustuu erinomaisiin työkaluihin ja palveluihin:",
thanks_map: "Kartografia", thanks_geo: "Geokoodaus", thanks_data: "Data",
thanks_hb: "Erityiskiitos HellBlazerille (Metal Archivesi webmaster) scraping-luvasta.",
faq: [
["K: Mistä data on peräisin?", "V: Metal Archives + automatisoitu maantieteellinen rikastaminen. Joitakin manuaalisia korjauksia, mutta se on työlästä."],
["K: Voinko korjata virheen?", "V: Kyllä, jos kyse on sivustosta, ota minuun yhteyttä lakitiedoissa mainitun sähköpostin kautta. Datan osalta korjaa suoraan Metal Archivesissa."],
["K: Miksi jotkut bändit eivät näy?", "V: Automaattisella geokoodauksella on inhärentin virheitä. Sijaintien manuaalinen korjaaminen on työlästä."],
["K: Loin juuri bändini Metal Archivesiin, mutta se ei näy.", "V: Automaattista synkronointia Metal Archivesin kanssa ei ole tällä hetkellä toteutettu."],
["K: Seuraako sivusto minua?", "V: Vain liikenteen analysointiin GoatCounterin kautta (ei evästeitä). Mainosten esto estää nämä pyynnöt ongelmitta."],
],
},
sk: {
search_placeholder: "Hľadať (názov, žáner, mesto, krajina)…",
displayed: "zobrazené", total_bands: "celkom", localities: "miest", located: "lokalizované",
view_section: "Zobrazenie", reset_view: "Obnoviť zobrazenie", heatmap_label: "Tepelná mapa",
filters_section: "Filtre", without_coords_btn: "Bez súradníc",
country_label: "Krajina", all_label: "Všetko", status_label: "Stav",
genres_label: "Žánre", subgenres_label: "Podžánre", selection_label: "Výber",
themes_label: "Témy", timeline_label: "Časová os (rok vzniku)",
sort_label: "Zoradiť zoznam", sort_az: "A → Z", sort_status: "Podľa stavu",
sort_genre: "Podľa žánru", sort_country: "Podľa krajiny", sort_year: "Podľa roku (najnovší → najstarší)",
list_section: "Zoznam", legal_link: "Právne informácie", faq_link: "FAQ",
visits_label: "Návštevy", this_month_label: "Tento mesiac", options_btn: "Možnosti", close_btn: "Zatvoriť",
all_years_label: "všetko", year_data_missing: "chýbajúce údaje",
year_data_unavailable: "Ročné dáta nie sú dostupné", results_label: "výsledok/kov",
loading_text: "Načítava sa…", without_coords_modal: "Kapely bez súradníc",
group_s: "kapela", group_p: "kapely", location_fallback: "Poloha",
legal_title: "Právne informácie", faq_title: "FAQ",
ed_title: "Prevádzkovateľ webu", ed_name: "Autor: Nico", ed_status: "Stav: súkromná osoba", ed_contact: "Kontakt:",
host_title: "Hosting", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Francúzsko",
ip_title: "Duševné vlastníctvo",
ip_text: "Obsah (texty, obrázky, agregované dáta) je poskytovaný na informačné účely. Logá a názvy kapiel zostávajú majetkom ich autorov. Všetky dáta pochádzajú z __MA__, so súhlasom webmasterov.",
prv_title: "Osobné údaje",
prv_text: "Táto webstránka nezhromažďuje osobné údaje ani neinštaluje sledovacie cookies. Poskytovateľ hostingu môže uchovávať technické záznamy. Prevádzka je analyzovaná prostredníctvom __GC__ (bez cookies).",
pub_title: "Zodpovedný redaktor", pub_name: "Nico",
thanks_title: "Poďakovania",
thanks_intro: "Táto webstránka využíva vynikajúce nástroje a služby:",
thanks_map: "Kartografia", thanks_geo: "Geokódovanie", thanks_data: "Dáta",
thanks_hb: "Špeciálne poďakovanie HellBlazerovi (webmaster Metal Archives) za povolenie scrapingu.",
faq: [
["O: Odkiaľ pochádzajú dáta?", "A: Metal Archives + automatizované geografické obohatenie. Niekoľko manuálnych opráv, ale je to únavné."],
["O: Môžem opraviť chybu?", "A: Áno, ak sa týka webu, kontaktujte ma prostredníctvom e-mailu v právnych informáciách. Pri dátach opravte priamo na Metal Archives."],
["O: Prečo niektoré kapely nie sú viditeľné?", "A: Automatické geokódovanie má inherentné chyby. Manuálna oprava polohy je únavná."],
["O: Práve som vytvoril kapelu na Metal Archives, ale nezobrazuje sa.", "A: Automatická synchronizácia s Metal Archives momentálne nie je implementovaná."],
["O: Sleduje ma web?", "A: Iba na analýzu návštevnosti cez GoatCounter (bez cookies). Blokovače reklám tieto požiadavky bez problémov zablokujú."],
],
},
hr: {
search_placeholder: "Pretraži (ime, žanr, grad, država)…",
displayed: "prikazano", total_bands: "ukupno", localities: "lokaliteta", located: "locirano",
view_section: "Prikaz", reset_view: "Resetiraj prikaz", heatmap_label: "Toplinska karta",
filters_section: "Filtri", without_coords_btn: "Bez koordinata",
country_label: "Država", all_label: "Sve", status_label: "Status",
genres_label: "Žanrovi", subgenres_label: "Podžanrovi", selection_label: "Odabir",
themes_label: "Teme", timeline_label: "Vremenski trak (godina osnivanja)",
sort_label: "Sortiraj popis", sort_az: "A → Z", sort_status: "Po statusu",
sort_genre: "Po žanru", sort_country: "Po državi", sort_year: "Po godini (najnoviji → najstariji)",
list_section: "Popis", legal_link: "Pravne informacije", faq_link: "FAQ",
visits_label: "Posjeti", this_month_label: "Ovaj mjesec", options_btn: "Opcije", close_btn: "Zatvori",
all_years_label: "sve", year_data_missing: "podaci nedostaju",
year_data_unavailable: "Godišnji podaci nisu dostupni", results_label: "rezultat(a)",
loading_text: "Učitavanje…", without_coords_modal: "Bendovi bez koordinata",
group_s: "bend", group_p: "bendovi", location_fallback: "Lokacija",
legal_title: "Pravne informacije", faq_title: "FAQ",
ed_title: "Urednik stranice", ed_name: "Autor: Nico", ed_status: "Status: privatna osoba", ed_contact: "Kontakt:",
host_title: "Hosting", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Francuska",
ip_title: "Intelektualno vlasništvo",
ip_text: "Sadržaji (tekstovi, slike, agregirani podaci) pružaju se u informativne svrhe. Logotipi i nazivi bendova ostaju vlasništvo njihovih autora. Svi podaci potječu s __MA__, uz dopuštenje webmastera.",
prv_title: "Osobni podaci",
prv_text: "Ova stranica ne prikuplja osobne podatke niti instalira kolačiće za praćenje. Pružatelj usluga hostinga može čuvati tehničke zapise. Promet se analizira putem __GC__ (bez kolačića).",
pub_title: "Odgovorni urednik", pub_name: "Nico",
thanks_title: "Zahvale",
thanks_intro: "Ova stranica oslanja se na izvrsne alate i usluge:",
thanks_map: "Kartografija", thanks_geo: "Geokodiranje", thanks_data: "Podaci",
thanks_hb: "Posebna zahvala HellBlazeru (webmaster Metal Archives) za dopuštenje scrapinga.",
faq: [
["P: Odakle dolaze podaci?", "O: Metal Archives + automatizovano geografsko obogaćivanje. Neke ručne ispravke, ali je zamorno."],
["P: Mogu li ispraviti pogrešku?", "O: Da, ako se tiče stranice, kontaktirajte me putem e-maila u pravnim informacijama. Za podatke, ispravite direktno na Metal Archives."],
["P: Zašto neki bendovi nisu vidljivi?", "O: Automatsko geokodiranje ima inherentnih grešaka. Ručna ispravka lokacija je zamorna."],
["P: Upravo sam stvorio bend na Metal Archives-u, ali se ne pojavljuje.", "O: Automatska sinkronizacija s Metal Archives-om trenutno nije implementirana."],
["P: Prati li me stranica?", "O: Samo za analizu prometa putem GoatCountera (bez kolačića). Blokatori oglasa blokiraju ove zahtjeve bez problema."],
],
},
sl: {
search_placeholder: "Iskanje (ime, zvrst, mesto, država)…",
displayed: "prikazano", total_bands: "skupaj", localities: "krajev", located: "lokalizirano",
view_section: "Pogled", reset_view: "Ponastavi pogled", heatmap_label: "Toplotna karta",
filters_section: "Filtri", without_coords_btn: "Brez koordinat",
country_label: "Država", all_label: "Vse", status_label: "Status",
genres_label: "Zvrsti", subgenres_label: "Podzvrsti", selection_label: "Izbira",
themes_label: "Teme", timeline_label: "Časovnica (leto nastanka)",
sort_label: "Razvrsti seznam", sort_az: "A → Z", sort_status: "Po statusu",
sort_genre: "Po zvrsti", sort_country: "Po državi", sort_year: "Po letu (najnovejši → najstarejši)",
list_section: "Seznam", legal_link: "Pravne informacije", faq_link: "FAQ",
visits_label: "Obiski", this_month_label: "Ta mesec", options_btn: "Možnosti", close_btn: "Zapri",
all_years_label: "vsa", year_data_missing: "manjkajoči podatki",
year_data_unavailable: "Letni podatki niso na voljo", results_label: "rezultat(ov)",
loading_text: "Nalaganje…", without_coords_modal: "Bendi brez koordinat",
group_s: "bend", group_p: "bendi", location_fallback: "Lokacija",
legal_title: "Pravne informacije", faq_title: "FAQ",
ed_title: "Urednik spletišča", ed_name: "Avtor: Nico", ed_status: "Status: zasebnik", ed_contact: "Stik:",
host_title: "Gostovanje", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Francija",
ip_title: "Intelektualna lastnina",
ip_text: "Vsebine (besedila, slike, agregirani podatki) so na voljo v informativne namene. Logotipi in imena bendov ostajajo last njihovih avtorjev. Vsi podatki izvirajo iz __MA__, z dovoljenjem spletnih mojstrov.",
prv_title: "Osebni podatki",
prv_text: "To spletišče ne zbira osebnih podatkov in ne namešča sledilnih piškotkov. Ponudnik gostovanja lahko hrani tehnične dnevnike. Promet se analizira prek __GC__ (brez piškotkov).",
pub_title: "Odgovorni urednik", pub_name: "Nico",
thanks_title: "Zahvale",
thanks_intro: "To spletišče temelji na odličnih orodjih in storitvah:",
thanks_map: "Kartografija", thanks_geo: "Geokodiranje", thanks_data: "Podatki",
thanks_hb: "Posebna zahvala HellBlazerju (spletni mojster Metal Archives) za dovoljenje za scraping.",
faq: [
["V: Od kod prihajajo podatki?", "O: Metal Archives + avtomatizirano geografsko obogatitev. Nekatere ročne popravke, ampak je dolgočasno."],
["V: Ali lahko popravim napako?", "O: Da, če se nanaša na spletišče, me kontaktirajte prek e-pošte v pravnih informacijah. Za podatke, popravite neposredno na Metal Archives."],
["V: Zakaj nekateri bendi niso vidni?", "O: Avtomatsko geokodiranje ima inherentne napake. Ročno popravljanje lokacij je dolgočasno."],
["V: Ravnokar sem ustvaril bend na Metal Archives, a se ne prikaže.", "O: Avtomatska sinhronizacija z Metal Archives trenutno ni implementirana."],
["V: Me spletišče sledi?", "O: Samo za analizo prometa prek GoatCounterja (brez piškotkov). Blokirniki oglasov brez težav blokirajo te zahteve."],
],
},
lt: {
search_placeholder: "Ieškoti (pavadinimas, žanras, miestas, šalis)…",
displayed: "rodoma", total_bands: "iš viso", localities: "vietovių", located: "lokalizuota",
view_section: "Vaizdas", reset_view: "Atstatyti vaizdą", heatmap_label: "Šilumos žemėlapis",
filters_section: "Filtrai", without_coords_btn: "Be koordinačių",
country_label: "Šalis", all_label: "Visi", status_label: "Būsena",
genres_label: "Žanrai", subgenres_label: "Pažanriai", selection_label: "Pasirinkimas",
themes_label: "Temos", timeline_label: "Laiko juosta (įkūrimo metai)",
sort_label: "Rūšiuoti sąrašą", sort_az: "A → Z", sort_status: "Pagal būseną",
sort_genre: "Pagal žanrą", sort_country: "Pagal šalį", sort_year: "Pagal metus (naujausi → seniausi)",
list_section: "Sąrašas", legal_link: "Teisinė informacija", faq_link: "DUK",
visits_label: "Apsilankymai", this_month_label: "Šį mėnesį", options_btn: "Parinktys", close_btn: "Uždaryti",
all_years_label: "visi", year_data_missing: "trūksta duomenų",
year_data_unavailable: "Metų duomenys neprieinami", results_label: "rezultatas/-ų",
loading_text: "Kraunama…", without_coords_modal: "Grupės be koordinačių",
group_s: "grupė", group_p: "grupės", location_fallback: "Vieta",
legal_title: "Teisinė informacija", faq_title: "DUK",
ed_title: "Svetainės redaktorius", ed_name: "Autorius: Nico", ed_status: "Statusas: fizinis asmuo", ed_contact: "Kontaktas:",
host_title: "Priegloba", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Prancūzija",
ip_title: "Intelektinė nuosavybė",
ip_text: "Turinys (tekstai, vaizdai, apibendrinti duomenys) pateikiamas informaciniais tikslais. Grupių logotipai ir pavadinimai lieka jų autorių nuosavybe. Visi duomenys gaunami iš __MA__, gavus svetainių valdytojų leidimą.",
prv_title: "Asmens duomenys",
prv_text: "Ši svetainė nerenka asmens duomenų ir neinstaliuoja sekimo slapukų. Prieglobos paslaugų teikėjas gali saugoti techninius žurnalus. Srautas analizuojamas per __GC__ (be slapukų).",
pub_title: "Atsakingas leidėjas", pub_name: "Nico",
thanks_title: "Padėkos",
thanks_intro: "Ši svetainė remiasi puikiomis priemonėmis ir paslaugomis:",
thanks_map: "Kartografija", thanks_geo: "Geokodavimas", thanks_data: "Duomenys",
thanks_hb: "Ypatingas ačiū HellBlazer'iui (Metal Archives svetainių valdytojas) už leidimą naudoti scrapingą.",
faq: [
["K: Iš kur kilę duomenys?", "A: Metal Archives + automatizuotas geografinis praturtinimas. Keletas rankinių pataisymų, bet tai nuobodu."],
["K: Ar galiu ištaisyti klaidą?", "A: Taip, jei tai susiję su svetaine, susisiekite su manimi el. paštu teisinėje informacijoje. Duomenims taisykite tiesiogiai Metal Archives."],
["K: Kodėl kai kurios grupės nematomos?", "A: Automatinis geokodavimas turi įgimtų klaidų. Rankinis vietų taisymas yra nuobodus."],
["K: Ką tik sukūriau savo grupę Metal Archives, bet ji nerodoma.", "A: Šiuo metu nėra automatinės sinchronizacijos su Metal Archives."],
["K: Ar svetainė mane seka?", "A: Tik srauto analizei per GoatCounter (be slapukų). Reklamos blokatoriai be problemų blokuoja šias užklausas."],
],
},
lv: {
search_placeholder: "Meklēt (nosaukums, žanrs, pilsēta, valsts)…",
displayed: "rādīts", total_bands: "kopā", localities: "vietu", located: "lokalizēts",
view_section: "Skats", reset_view: "Atiestatīt skatu", heatmap_label: "Siltuma karte",
filters_section: "Filtri", without_coords_btn: "Bez koordinātām",
country_label: "Valsts", all_label: "Visi", status_label: "Statuss",
genres_label: "Žanri", subgenres_label: "Apakšžanri", selection_label: "Atlase",
themes_label: "Tēmas", timeline_label: "Laika josla (dibināšanas gads)",
sort_label: "Kārtot sarakstu", sort_az: "A → Z", sort_status: "Pēc statusa",
sort_genre: "Pēc žanra", sort_country: "Pēc valsts", sort_year: "Pēc gada (jaunākais → vecākais)",
list_section: "Saraksts", legal_link: "Juridiskā informācija", faq_link: "BUJ",
visits_label: "Apmeklējumi", this_month_label: "Šomēnes", options_btn: "Opcijas", close_btn: "Aizvērt",
all_years_label: "visi", year_data_missing: "trūkst datu",
year_data_unavailable: "Gada dati nav pieejami", results_label: "rezultāts/-i",
loading_text: "Ielāde…", without_coords_modal: "Grupas bez koordinātām",
group_s: "grupa", group_p: "grupas", location_fallback: "Atrašanās vieta",
legal_title: "Juridiskā informācija", faq_title: "BUJ",
ed_title: "Vietnes redaktors", ed_name: "Autors: Nico", ed_status: "Statuss: privātpersona", ed_contact: "Kontakts:",
host_title: "Mitināšana", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Francija",
ip_title: "Intelektuālais īpašums",
ip_text: "Saturs (teksti, attēli, apkopotie dati) tiek sniegts informatīviem nolūkiem. Grupu logotipi un nosaukumi paliek to autoru īpašumā. Visi dati nāk no __MA__, ar tīmekļa vietņu pārvaldnieku atļauju.",
prv_title: "Personas dati",
prv_text: "Šī vietne neapkopo personas datus un neinstalē izsekošanas sīkdatnes. Mitināšanas pakalpojumu sniedzējs var glabāt tehniskos žurnālus. Trafiks tiek analizēts, izmantojot __GC__ (bez sīkdatnēm).",
pub_title: "Atbildīgais izdevējs", pub_name: "Nico",
thanks_title: "Pateicības",
thanks_intro: "Šī vietne balstās uz izciliem rīkiem un pakalpojumiem:",
thanks_map: "Kartogrāfija", thanks_geo: "Geokodēšana", thanks_data: "Dati",
thanks_hb: "Īpaša pateicība HellBlazer (Metal Archives tīmekļvietnes pārvaldnieks) par atļauju veikt skrāpēšanu.",
faq: [
["J: No kurienes nāk dati?", "A: Metal Archives + automatizēta ģeogrāfiskā bagātināšana. Daži manuāli labojumi, bet tas ir nogurdinoši."],
["J: Vai es varu labot kļūdu?", "A: Jā, ja tā attiecas uz vietni, sazinieties ar mani pa e-pastu juridiskajā informācijā. Datiem labojiet tieši Metal Archives."],
["J: Kāpēc dažas grupas nav redzamas?", "A: Automātiskajai geokodēšanai ir raksturīgas kļūdas. Manuāla atrašanās vietu labošana ir nogurdinoša."],
["J: Tikko izveidoju savu grupu Metal Archives, bet tā neparādās.", "A: Pašlaik nav ieviesta automātiskā sinhronizācija ar Metal Archives."],
["J: Vai vietne mani izseko?", "A: Tikai trafika analīzei, izmantojot GoatCounter (bez sīkdatnēm). Reklāmu bloķētāji bez problēmām bloķē šos pieprasījumus."],
],
},
et: {
search_placeholder: "Otsi (nimi, žanr, linn, riik)…",
displayed: "kuvatud", total_bands: "kokku", localities: "asulatest", located: "lokaliseeritud",
view_section: "Vaade", reset_view: "Lähtesta vaade", heatmap_label: "Soojuskaart",
filters_section: "Filtrid", without_coords_btn: "Ilma koordinaatideta",
country_label: "Riik", all_label: "Kõik", status_label: "Olek",
genres_label: "Žanrid", subgenres_label: "Alažanrid", selection_label: "Valik",
themes_label: "Teemad", timeline_label: "Ajajoon (asutamisaasta)",
sort_label: "Sordi nimekirja", sort_az: "A → Z", sort_status: "Oleku järgi",
sort_genre: "Žanri järgi", sort_country: "Riigi järgi", sort_year: "Aasta järgi (uusim → vanim)",
list_section: "Nimekiri", legal_link: "Õiguslik teave", faq_link: "KKK",
visits_label: "Külastused", this_month_label: "Sel kuul", options_btn: "Valikud", close_btn: "Sulge",
all_years_label: "kõik", year_data_missing: "andmed puuduvad",
year_data_unavailable: "Aasta andmed pole saadaval", results_label: "tulemus/-t",
loading_text: "Laadimine…", without_coords_modal: "Bändid koordinaatideta",
group_s: "bänd", group_p: "bändid", location_fallback: "Asukoht",
legal_title: "Õiguslik teave", faq_title: "KKK",
ed_title: "Saidi toimetaja", ed_name: "Autor: Nico", ed_status: "Staatus: eraisik", ed_contact: "Kontakt:",
host_title: "Majutus", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Prantsusmaa",
ip_title: "Intellektuaalne omand",
ip_text: "Sisu (tekstid, pildid, koondandmed) on esitatud informatiivsetel eesmärkidel. Bändide logod ja nimed jäävad nende autorite omandisse. Kõik andmed pärinevad __MA__-lt, veebimeistrite loal.",
prv_title: "Isikuandmed",
prv_text: "See sait ei kogu isikuandmeid ega installi jälgimisküpsiseid. Majutusteenuse pakkuja võib säilitada tehnilisi logisid. Liiklust analyseeritakse __GC__ kaudu (küpsisteta).",
pub_title: "Väljaande vastutav isik", pub_name: "Nico",
thanks_title: "Tänusõnad",
thanks_intro: "See sait tugineb suurepärastele tööriistadele ja teenustele:",
thanks_map: "Kartograafia", thanks_geo: "Geokodeerimine", thanks_data: "Andmed",
thanks_hb: "Eriline tänu HellBlazerile (Metal Archivesi veebimeister) kraapimise loa eest.",
faq: [
["K: Kust andmed pärinevad?", "V: Metal Archives + automatiseeritud geograafiline rikastamine. Mõned käsitsi parandused, kuid see on tüütu."],
["K: Kas saan vea parandada?", "V: Jah, kui see puudutab saiti, võtke minuga ühendust õiguslikus teabes oleva e-posti kaudu. Andmete puhul parandage otse Metal Archivesis."],
["K: Miks mõned bändid pole nähtavad?", "V: Automaatsel geokodeerimisel on omased vead. Asukohtade käsitsi parandamine on tüütu."],
["K: Lõin just oma bändi Metal Archivesis, kuid see ei ilmu.", "V: Praegu pole Metal Archivesiga automaatset sünkroonimist rakendatud."],
["K: Kas sait jälgib mind?", "V: Ainult liikluse analüüsimiseks GoatCounteri kaudu (küpsisteta). Reklaamiblokeerijad blokeerivad need päringud probleemideta."],
],
},
nb: {
search_placeholder: "Søk (navn, sjanger, by, land)…",
displayed: "vist", total_bands: "totalt", localities: "steder", located: "lokaliserte",
view_section: "Visning", reset_view: "Tilbakestill visning", heatmap_label: "Varmekart",
filters_section: "Filtre", without_coords_btn: "Uten koordinater",
country_label: "Land", all_label: "Alle", status_label: "Status",
genres_label: "Sjangere", subgenres_label: "Undersjangere", selection_label: "Utvalg",
themes_label: "Temaer", timeline_label: "Tidslinje (stiftelsesår)",
sort_label: "Sorter liste", sort_az: "A → Z", sort_status: "Etter status",
sort_genre: "Etter sjanger", sort_country: "Etter land", sort_year: "Etter år (nyeste → eldste)",
list_section: "Liste", legal_link: "Juridisk informasjon", faq_link: "FAQ",
visits_label: "Besøk", this_month_label: "Denne måneden", options_btn: "Innstillinger", close_btn: "Lukk",
all_years_label: "alle", year_data_missing: "data mangler",
year_data_unavailable: "Årsdata ikke tilgjengelig", results_label: "resultat(er)",
loading_text: "Laster…", without_coords_modal: "Band uten koordinater",
group_s: "band", group_p: "band", location_fallback: "Sted",
legal_title: "Juridisk informasjon", faq_title: "FAQ",
ed_title: "Nettstedredaktør", ed_name: "Forfatter: Nico", ed_status: "Status: privatperson", ed_contact: "Kontakt:",
host_title: "Hosting", host_text: "OVH SAS 2 rue Kellermann - 59100 Roubaix - Frankrike",
ip_title: "Immateriell eiendom",
ip_text: "Innhold (tekster, bilder, aggregerte data) tilbys for informasjonsformål. Bandlogoer og navn forblir deres forfatteres eiendom. Alle data stammer fra __MA__, med webmasternes tillatelse.",
prv_title: "Personlige data",
prv_text: "Dette nettstedet samler ikke inn personopplysninger og installerer ikke sporingskapsler. Leverandøren av webhosting kan oppbevare tekniske logger. Trafikk analyseres via __GC__ (uten informasjonskapsler).",
pub_title: "Ansvarlig utgiver", pub_name: "Nico",
thanks_title: "Takk til",
thanks_intro: "Dette nettstedet er avhengig av utmerkede verktøy og tjenester:",
thanks_map: "Kartografi", thanks_geo: "Geokoding", thanks_data: "Data",
thanks_hb: "Spesiell takk til HellBlazer (Metal Archives webmaster) for tillatelse til scraping.",
faq: [
["Sp: Hvor kommer dataene fra?", "Sv: Metal Archives + automatisert geografisk berikelse. Noen manuelle korreksjoner, men det er kjedelig."],
["Sp: Kan jeg korrigere en feil?", "Sv: Ja, hvis det gjelder nettstedet, kontakt meg via e-posten i juridisk informasjon. For data, korriger direkte på Metal Archives."],
["Sp: Hvorfor er noen band ikke synlige?", "Sv: Automatisk geokoding har iboende feil. Manuell korreksjon av plasseringer er kjedelig."],
["Sp: Jeg opprettet nettopp bandet mitt på Metal Archives, men det vises ikke.", "Sv: Ingen automatisk synkronisering med Metal Archives er for øyeblikket implementert."],
["Sp: Sporer nettstedet meg?", "Sv: Bare for trafikkanalyse via GoatCounter (ingen informasjonskapsler). Annonseblokkere blokkerer disse forespørslene uten problemer."],
],
},
}; };
/* Build LOCALES — add legal_html + faq_html to each entry */ /* Build LOCALES — add legal_html + faq_html to each entry */