Files
volumen/internal/i18n/i18n.go
T
petrbalvin f8ed33df83
Test / test (push) Successful in 7m5s
Release / gates (push) Successful in 7m28s
Release / build (amd64, freebsd) (push) Successful in 2m52s
Release / build (amd64, linux) (push) Successful in 2m46s
Release / build (arm64, freebsd) (push) Successful in 2m22s
Release / build (arm64, linux) (push) Successful in 2m38s
Release / build (loong64, linux) (push) Successful in 2m7s
Release / build (riscv64, linux) (push) Successful in 2m17s
Release / release (push) Successful in 1m0s
Initial commit
Assisted-by: GLM 5.3
2026-09-29 10:03:32 +02:00

832 lines
48 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Package i18n holds the admin interface strings in every language the
// UI ships. Simple messages are keyed by their English text, so the
// template keeps its meaning and an untranslated key falls back to
// English rather than an identifier. Messages with a numeral use an
// explicit id and per-language plural forms, because Czech declines
// the counted noun where English does not.
//
// The catalogue never stores markup: sentences with <code>, <strong> and
// friends stay in the template, split into fragments, so every string
// the funcs return can take the template engine's escaping. The one
// exception is trh, for static sentences that only make sense whole.
//
// Some keys never appear literally outside this file: the editor
// matches payloads validation errors against the catalogue at runtime
// ("Slug is required." and friends), and the page scripts read their
// strings from the JSON dump, so a key being absent from the templates
// does not mean it is dead.
package i18n
import (
"slices"
"strconv"
"strings"
)
// Languages the admin interface ships, in the order the settings
// switch lists them.
var Languages = []string{"en", "cs"}
// Cookie carries the interface language across the login screen, where
// no account is known yet.
const Cookie = "volumen_admin_lang"
// Valid reports whether the value is a shipped language.
func Valid(lang string) bool {
return slices.Contains(Languages, lang)
}
// Normalize maps a language tag, which may carry a region ("cs-CZ"),
// onto a shipped language, or "" when nothing matches.
func Normalize(tag string) string {
tag = strings.ToLower(strings.TrimSpace(tag))
for _, l := range Languages {
if tag == l || strings.HasPrefix(tag, l+"-") {
return l
}
}
return ""
}
// pluralSet holds the counted forms of one message: one for exactly
// one, few for the Czech "2 to 4" class (22 to 24 included), other for
// the rest. English never uses few.
type pluralSet struct {
one, few, other string
}
// pluralForms are the messages that carry a numeral. Every language
// defines one and other; few exists for Czech alone.
var pluralForms = map[string]map[string]pluralSet{
"posts.total": {
"en": {one: "%d post in total", other: "%d posts in total"},
"cs": {one: "Celkem %d publikace", few: "Celkem %d publikace", other: "Celkem %d publikací"},
},
"media.count": {
"en": {one: "%d file uploaded", other: "%d files uploaded"},
"cs": {one: "Nahraný %d soubor", few: "Nahrané %d soubory", other: "Nahraných %d souborů"},
},
"revisions.count": {
"en": {one: "%d archived version", other: "%d archived versions"},
"cs": {one: "Archivovaná %d verze", few: "Archivované %d verze", other: "Archivovaných %d verzí"},
},
"posts.published": {
"en": {one: "%d post published.", other: "%d posts published."},
"cs": {one: "Zveřejněna %d publikace.", few: "Zveřejněny %d publikace.", other: "Zveřejněno %d publikací."},
},
"posts.drafted": {
"en": {one: "%d post moved to draft.", other: "%d posts moved to draft."},
"cs": {one: "Přesunuta %d publikace do konceptu.", few: "Přesunuty %d publikace do konceptu.", other: "Přesunuto %d publikací do konceptu."},
},
"posts.deleted": {
"en": {one: "%d post deleted.", other: "%d posts deleted."},
"cs": {one: "Smazána %d publikace.", few: "Smazány %d publikace.", other: "Smazáno %d publikací."},
},
"diff.unchanged": {
"en": {one: "%d unchanged line", other: "%d unchanged lines"},
"cs": {one: "%d nezměněný řádek", few: "%d nezměněné řádky", other: "%d nezměněných řádků"},
},
"password.min": {
"en": {one: "Password must be at least %d character long.", other: "Password must be at least %d characters long."},
"cs": {one: "Heslo musí mít nejméně %d znak.", few: "Heslo musí mít nejméně %d znaky.", other: "Heslo musí mít nejméně %d znaků."},
},
"password.max": {
"en": {one: "Password must be at most %d character long.", other: "Password must be at most %d characters long."},
"cs": {one: "Heslo musí mít nejvýše %d znak.", few: "Heslo musí mít nejvýše %d znaky.", other: "Heslo musí mít nejvýše %d znaků."},
},
"editor.words": {
"en": {one: "%d word", other: "%d words"},
"cs": {one: "%d slovo", few: "%d slova", other: "%d slov"},
},
"refs.count": {
"en": {one: "%d reference", other: "%d references"},
"cs": {one: "%d reference", few: "%d reference", other: "%d referencí"},
},
"editor.chars": {
"en": {one: "%d char", other: "%d chars"},
"cs": {one: "%d znak", few: "%d znaky", other: "%d znaků"},
},
"editor.reading": {
"en": {one: "%d min read", other: "%d min read"},
"cs": {one: "%d min čtení", few: "%d min čtení", other: "%d min čtení"},
},
"bulk.selected": {
"en": {one: "%d selected", other: "%d selected"},
"cs": {one: "Vybráno %d", few: "Vybráno %d", other: "Vybráno %d"},
},
"login.seconds": {
"en": {one: "Too many login attempts. Try again in %d second.", other: "Too many login attempts. Try again in %d seconds."},
"cs": {one: "Příliš mnoho pokusů o přihlášení. Zkuste to znovu za %d s.", few: "Příliš mnoho pokusů o přihlášení. Zkuste to znovu za %d s.", other: "Příliš mnoho pokusů o přihlášení. Zkuste to znovu za %d s."},
},
"deliveries.attempts": {
"en": {one: "failed (%d attempt)", other: "failed (%d attempts)"},
"cs": {one: "selhalo (%d pokus)", few: "selhalo (%d pokusy)", other: "selhalo (%d pokusů)"},
},
"posts.count": {
"en": {one: "%d post", other: "%d posts"},
"cs": {one: "%d publikace", few: "%d publikace", other: "%d publikací"},
},
"backup.files": {
"en": {one: "Backup restored (%d file).", other: "Backup restored (%d files)."},
"cs": {one: "Záloha obnovena (%d soubor).", few: "Záloha obnovena (%d soubory).", other: "Záloha obnovena (%d souborů)."},
},
}
// cs translates the simple messages, keyed by the English text the
// templates and handlers use. Markup stays out: where the template
// carries <code> or <strong>, the sentence is split into fragments.
var cs = map[string]string{
// Layout: sidebar, topbar, mobile sheet, shared dialogs.
"Content": "Obsah",
"Configure": "Nastavení",
"Posts": "Publikace",
"New post": "Nová publikace",
"Import": "Import",
"Media": "Média",
"Settings": "Nastavení",
"Log out": "Odhlásit se",
"Menu": "Nabídka",
"Main menu": "Hlavní nabídka",
"Collapse sidebar": "Sbalit postranní panel",
"Expand sidebar": "Rozbalit postranní panel",
"administration": "administrace",
"Skip to content": "Přejít na obsah",
"Breadcrumb": "Navigace",
"Colour mode": "Režim barev",
"Follow system": "Podle systému",
"Light": "Světlý",
"Dark": "Tmavý",
"Update now": "Aktualizovat",
"Details": "Podrobnosti",
"is available; you are running": "je k dispozici; provozujete",
"Update to %s now?": "Aktualizovat na %s hned?",
"The server will restart.": "Server se restartuje.",
"Are you sure?": "Opravdu?",
"Continue": "Pokračovat",
"URL": "URL",
"OK": "Budiž",
// The admin 404 page.
"Page not found": "Stránka nenalezena",
"The address does not exist; it may have been moved or deleted.": "Tato adresa neexistuje; možná byla přesunuta nebo zrušena.",
"Back to dashboard": "Zpět na přehled",
// Login page.
"Volumen · administration": "Volumen · administrace",
"Sign in": "Přihlásit se",
"Welcome back. Sign in to manage your posts.": "Vítejte zpět. Přihlaste se ke správě publikací.",
"Username": "Uživatel",
"Password": "Heslo",
"Show password": "Zobrazit heslo",
"Hide password": "Skrýt heslo",
"Invalid username or password.": "Neplatné uživatelské jméno nebo heslo.",
"Auto-unlock in {} s.": "Odemčení za {} s.",
" You can try again now.": " Můžete to zkusit znovu.",
// First-run wizard.
"Welcome to Volumen": "Vítejte ve Volumenu",
"Set up Volumen": "Nastavení Volumenu",
"Set up the administrator account to open this installation.": "Nastavte účet správce, tím se instalace otevře.",
"The page takes the colours as you choose.": "Stránka mění barvy podle vaší volby.",
"Create account": "Vytvořit účet",
"The users file cannot be read; repair it before setting up.": "Soubor uživatelů nelze přečíst; před nastavením ho opravte.",
"The account could not be created: %s": "Účet se nepodařilo vytvořit: %s",
"Weak": "Slabé",
"Fair": "Dostatečné",
"Good": "Dobré",
"Strong": "Silné",
// Posts list.
"Published": "Publikované",
"Drafts": "Koncepty",
"Scheduled": "Naplánované",
"Total": "Celkem",
"Recent published": "Nedávno publikované",
"Search title, slug, tag...": "Hledat v titulku, slagu, značce…",
"Select all posts": "Vybrat všechny publikace",
"All": "Vše",
"Filter by status": "Filtrovat podle stavu",
"Filter by tag": "Filtrovat podle značky",
"Publish": "Publikovat",
"Move to draft": "Přesunout do konceptu",
"Delete": "Smazat",
"Cancel": "Zrušit",
"Two-factor authentication": "Dvoufázové přihlášení",
"Two-factor code": "Kód dvoufázového přihlášení",
"The password is accepted; answer the second question.": "Heslo přijato; odpovězte na druhou otázku.",
"Verification code": "Ověřovací kód",
"six digits, or a recovery code": "šest číslic, nebo záložní kód",
"Six digits from your application, or one of your recovery codes.": "Šest číslic z vaší aplikace, nebo jeden ze záložních kódů.",
"Back to sign in": "Zpět na přihlášení",
"Your sign-in asks for a code from your application after the password.": "Po přihlášení heslem se žádá ještě kód z vaší aplikace.",
"Current code": "Současný kód",
"Regenerate recovery codes": "Vygenerovat záložní kódy znovu",
"Turn two-factor off? Your application will no longer be asked.": "Vypnout dvoufázové přihlášení? Vaše aplikace se už nebude dotazovat.",
"Turn off": "Vypnout",
"Scan the code with your authenticator application, or enter the secret by hand, then confirm with the code it shows.": "Naskenujte kód svou aplikací pro ověřování, nebo zadejte tajný klíč ručně, a potvrďte kódem, který ukáže.",
"Secret": "Tajný klíč",
"Verify and enable": "Ověřit a zapnout",
"Ask for a code from your authenticator application after the password. Voluntary: nothing changes until you finish the setup.": "Po hesle se bude žádat o kód z vaší ověřovací aplikace. Dobrovolné: nic se nezmění, dokud nastavení nedokončíte.",
"Set up two-factor": "Nastavit dvoufázové přihlášení",
"Wrong or expired code.": "Nesprávný nebo propadlý kód.",
"That code did not match; start again.": "Kód nesouhlasil; začněte znovu.",
"Two-factor is already on.": "Dvoufázové přihlášení už je zapnuté.",
"Two-factor could not be enabled: %s": "Dvoufázové přihlášení nešlo zapnout: %s",
"Two-factor could not be disabled: %s": "Dvoufázové přihlášení nešlo vypnout: %s",
"The codes could not be replaced: %s": "Záložní kódy nešlo vyměnit: %s",
"Two-factor is off.": "Dvoufázové přihlášení je vypnuté.",
"Two-factor is on. Store these recovery codes now; they will not be shown again.": "Dvoufázové přihlášení je zapnuté. Uschovejte si tyto záložní kódy; znovu se neukážou.",
"New recovery codes. Store them now; they will not be shown again.": "Nové záložní kódy. Uschovejte si je; znovu se neukážou.",
"No posts yet": "Zatím žádné publikace",
"Create your first post to get started.": "Začněte vytvořením první publikace.",
"Create post": "Vytvořit publikaci",
"No posts match your search": "Žádná publikace neodpovídá hledání",
"Try a different search term or status filter.": "Zkuste jiné hledané slovo nebo jiný filtr stavu.",
"Clear filters": "Vymazat filtry",
"Draft": "Koncept",
"Edit": "Upravit",
"Delete post": "Smazat publikaci",
"Delete %s?": "Smazat %s?",
"Post created.": "Publikace vytvořena.",
"Post saved.": "Publikace uložena.",
"Post deleted.": "Publikace smazána.",
"Post duplicated.": "Publikace zkopírována.",
"Post restored.": "Publikace obnovena.",
"Could not restore the post; it may already be back.": "Publikaci se nepodařilo obnovit; možná už je zpět.",
"The post could not be duplicated.": "Publikaci se nepodařilo zdvojit.",
"Undo": "Zpět",
"Undo failed.": "Obnovení se nezdařilo.",
"Delete the selected posts?": "Smazat vybrané publikace?",
"Delete this post?": "Smazat tuto publikaci?",
// Editor.
"Draft a new article in Markdown.": "Napište nový článek v Markdownu.",
"Edit post": "Úprava publikace",
"Update and publish this post.": "Upravte a zveřejněte tuto publikaci.",
"Draft, not visible to the public": "Koncept, veřejnosti nezobrazovaný",
"Scheduled for %s": "Naplánováno na %s",
"Scheduled for later": "Naplánováno na později",
"Preview": "Náhled",
"Download": "Stáhnout",
"History": "Historie",
"Duplicate": "Zkopírovat",
"Duplicate as draft": "Zkopírovat jako koncept",
"Duplicate this post as a draft?": "Zkopírovat tuto publikaci jako koncept?",
"Save": "Uložit",
"Save (Ctrl+S)": "Uložit (Ctrl+S)",
"Revision restored. The previous content was archived; see": "Verze obnovena. Předchozí obsah byl archivován; viz",
"Duplicated as draft. The new slug is": "Zkopírováno jako koncept. Nový slug je",
", adjust the title and body, then publish.": ", upravte titulek a obsah a publikujte.",
"Template": "Šablona",
"Blank": "Prázdná",
"Restore": "Obnovit",
"Discard": "Zahodit",
"Title, slug, and publishing options": "Titulek, slug a volby publikování",
"Title": "Titulek",
"A clear, descriptive title": "Výstižný, popisný titulek",
"Slug": "Slug",
"my-post-slug": "moje-publikace",
"Language": "Jazyk",
"Author": "Autor",
"Author name": "Jméno autora",
"Fediverse creator": "Autor na fediverse",
"@user@instance.tld": "@uzivatel@instance.tld",
"DOI": "DOI",
"Author ORCID": "ORCID autora",
"10.5281/zenodo.1234567": "10.5281/zenodo.1234567",
"0000-0002-1825-0097": "0000-0002-1825-0097",
"Digital Object Identifier; a doi.org URL is stored as the bare 10.… form.": "Digital Object Identifier; URL na doi.org se uloží jako holý tvar 10.…",
"The author's Open Researcher and Contributor ID, checked against its own digit.": "Open Researcher and Contributor ID autora, kontroluje se i kontrolní číslice.",
"DOI must look like 10.xxxx/suffix.": "DOI musí mít tvar 10.xxxx/sufix.",
"Bibliography": "Bibliografie",
"The numbered reference list; cite entries as [n] in the body": "Číslovaný seznam literatury; v textu citujte jako [n]",
"No references yet.": "Zatím žádné reference.",
"Add reference": "Přidat referenci",
"Insert [[refs]] marker into the body": "Vložit do textu značku [[refs]]",
"Fill the verbatim citation line, or the structured fields; the marker places the list in the body and without it the list is appended.": "Vyplňte doslovný citovaný řádek nebo strukturovaná pole; značka umístí seznam do textu a bez něj se seznam připojí na konec.",
"Move up": "Posunout výš",
"Move down": "Posunout níž",
"Remove reference": "Odebrat referenci",
"Verbatim citation": "Doslovná citace",
"Structured fields": "Strukturovaná pole",
"One author per line, optionally with [orcid:0000-0002-1825-0097]": "Každý autor na vlastním řádku, volitelně s [orcid:0000-0002-1825-0097]",
"Authors": "Autoři",
"Journal or proceedings": "Časopis nebo sborník",
"Venue": "Místo publikace",
"Year": "Rok",
"Volume": "Ročník",
"Pages": "Strany",
"arXiv": "arXiv",
"Author, title, venue, year": "Autor, titul, kde vyšlo, rok",
"Publish date": "Datum publikace",
"Schedule for": "Naplánovat na",
"Pick a date": "Vyberte datum",
"Leave empty to publish immediately. Date is interpreted as your local timezone.": "Necháte-li prázdné, publikuje se hned. Datum se interpretuje v místním časovém pásmu.",
"Markdown": "Markdown",
"Visual": "Vizuální",
"Tags": "Značky",
"comma, separated": "čárkami, oddělené",
"Series": "Série",
"e.g. rust-tutorial": "např. rust-tutorial",
"Group multi-part posts; leave empty for standalone posts": "Sdružuje díly publikací; pro samostatné nechte prázdné",
"Part number": "Číslo dílu",
"Order within the series": "Pořadí v sérii",
"Excerpt": "Perex",
"Auto-generated from the first paragraph if left empty": "Nevyplněno: vygeneruje se z prvního odstavce",
"Available in all languages": "Dostupné ve všech jazycích",
"Cover image": "Úvodní obrázek",
"Header image shown on the article page": "Obrázek v záhlaví stránky článku",
"/media/… or https://…": "/media/… nebo https://…",
"Upload": "Nahrát",
"Clear": "Vymazat",
"Today": "Dnes",
"ALT text (for accessibility)": "ALT text (pro přístupnost)",
"Caption (e.g. 'Generated by AI')": "Popisek (např. „Vygenerováno AI“)",
"Write your post in Markdown…": "Pište publikaci v Markdownu…",
"Drop image to upload": "Pusťte obrázek a nahrajte",
"Bold (Ctrl+B)": "Tučně (Ctrl+B)",
"Italic (Ctrl+I)": "Kurzíva (Ctrl+I)",
"Heading 2": "Nadpis 2",
"Heading 3": "Nadpis 3",
"Link (Ctrl+K)": "Odkaz (Ctrl+K)",
"Bullet list": "Odrážky",
"Numbered list": "Číslovaný seznam",
"Quote": "Citace",
"Code": "Kód",
"Image": "Obrázek",
"Toggle preview": "Přepnout náhled",
"✓ saved": "✓ uloženo",
"Keyboard shortcuts": "Klávesové zkratky",
"Bold": "Tučně",
"Italic": "Kurzíva",
"Link": "Odkaz",
"Save post": "Uložit publikaci",
"Show this help": "Zobrazit tuto nápovědu",
"Close modal": "Zavřít okno",
"Editor": "Editor",
"Unsaved changes from %s are available.": "K dispozici jsou neuložené změny z %s.",
"Slug is available.": "Slug je volný.",
"Already used by “%s”.": "Už ho používá „%s“.",
"Will be published immediately (date is today or earlier).": "Publikuje se okamžitě (datum je dnešní nebo dřívější).",
"Link URL": "Adresa odkazu",
"Only WebP, AVIF and SVG images are accepted (got “%s”).": "Přijímají se jen obrázky WebP, AVIF a SVG (obdrženo „%s“).",
"Upload failed:\n\n%s": "Nahrání selhalo:\n\n%s",
// History.
"Back to editor": "Zpět do editoru",
"No revisions yet": "Zatím žádné verze",
"Every time this post is saved, the previous version is archived here.": "Při každém uložení publikace se předchozí verze archivuje tady.",
"Saved": "Uloženo",
"Size": "Velikost",
"Actions": "Akce",
"Restore this revision? The current content will be archived first.": "Obnovit tuto verzi? Současný obsah se nejdřív archivuje.",
"Compare": "Porovnat",
"Back to history": "Zpět do historie",
"Changes": "Změny",
"Archived version": "Archivovaná verze",
"compared with the current content.": "srovnáno se současným obsahem.",
"No differences from the current content.": "Žádné rozdíly oproti současnému obsahu.",
"removed": "odebráno",
"added": "přidáno",
"Upcoming": "Nadcházející",
// Import.
"Import post": "Import publikace",
"frontmatter": "hlavička",
"Bring a post written anywhere: a Markdown file with optional TOML frontmatter.": "Přineste publikaci psanou kdekoliv: soubor Markdown s volitelnou TOML hlavičkou.",
"Drop your post here": "Pusťte sem svou publikaci",
"or click to browse": "nebo klikněte a vyberte",
"Remove": "Odebrat",
"No frontmatter found; the slug will be derived from the file name.": "Hlavička nenalezena; slug se odvodí z názvu souboru.",
"Only .md files are accepted, got “%s”": "Přijímají se jen soubory .md, obdrženo „%s“",
// Media.
"No media yet": "Zatím žádná média",
"Upload an image to use as a cover or inline content. WebP, AVIF and SVG are supported.": "Nahrajte obrázek jako úvodní nebo do obsahu. Podporovány jsou WebP, AVIF a SVG.",
"You can also paste or drop an image directly into the editor body.": "Obrázek můžete také vložit nebo přetáhnout přímo do těla editoru.",
"Upload images": "Nahrát obrázky",
"Drop images here, or click to browse": "Pusťte sem obrázky, nebo klikněte a vyberte",
"WebP, AVIF or SVG, up to 10 MB each.": "WebP, AVIF nebo SVG, každý nejvýše 10 MB.",
"Search files...": "Hledat soubory…",
"No files match your search.": "Žádný soubor neodpovídá hledání.",
"Copy link": "Kopírovat odkaz",
"Open in new tab": "Otevřít v nové kartě",
"Link copied.": "Odkaz zkopírován.",
"Copy the link:": "Zkopírujte odkaz:",
"Upload failed: %s": "Nahrání selhalo: %s",
"Upload complete.": "Nahrání dokončeno.",
"Uploading %s…": "Nahrávám %s…",
// Settings, shared.
"Manage your account and users": "Spravujte svůj účet a uživatele",
"Account": "Účet",
"Users": "Uživatelé",
"Templates": "Šablony",
"Backup": "Záloha",
"Version": "Verze",
"Webhooks": "Webhooky",
"API tokens": "API tokeny",
"Signed in as": "Přihlášen jako",
// Account section.
"Profile photo": "Profilová fotka",
"WebP, AVIF or SVG, max 10 MB. Shown in the sidebar.": "WebP, AVIF nebo SVG, nejvýše 10 MB. Zobrazuje se v postranní liště.",
"Identity": "Identita",
"Display name": "Zobrazované jméno",
"Your real name": "Vaše skutečné jméno",
"Save name": "Uložit jméno",
"Fediverse handle": "Fediverse účet",
"Save handle": "Uložit účet",
"Security": "Zabezpečení",
"Change your password and username. You can also lock yourself out.": "Změňte heslo i uživatelské jméno. Můžete si i sami zablokovat přístup.",
"Current password": "Současné heslo",
"New password": "Nové heslo",
"Update password": "Změnit heslo",
"Update username": "Změnit uživatele",
"Language version": "Jazyková verze",
"The interface language of your account. The login screen follows your last choice.": "Jazyk rozhraní vašeho účtu. Přihlašovací stránka se řídí poslední volbou.",
"Unsupported language.": "Nepodporovaný jazyk.",
"The language could not be saved: %s": "Jazyk nešlo uložit: %s",
"Colour scheme": "Barevné schéma",
"The colour scheme of your account. The login screen follows your last choice.": "Barevné schéma vašeho účtu. Přihlašovací stránka se řídí poslední volbou.",
"Unsupported colour scheme.": "Nepodporované barevné schéma.",
"The colour scheme could not be saved: %s": "Barevné schéma nešlo uložit: %s",
"The colour scheme is set.": "Barevné schéma je nastaveno.",
// Users section.
"Add or remove admin and editor accounts": "Přidávejte a odstraňujte účty správců a autorů",
"you": "vy",
"Remove this user?": "Odebrat tohoto uživatele?",
"Add user": "Přidat uživatele",
"Role": "Role",
"jane-doe": "jana-novakova",
// Templates section.
"Post templates": "Šablony publikací",
"Pre-fill new posts with a reusable structure": "Předvyplňují nové publikace opakovaně použitelnou strukturou",
"No templates yet. Templates pre-fill the new-post form so you can keep your favourite structure on hand.": "Zatím žádné šablony. Předvyplňují formulář nové publikace, abyste měli svou oblíbenou strukturu po ruce.",
"Name": "Název",
"Fields to pre-fill": "Předvyplněná pole",
"Extra editor inputs as TOML key = value lines, one per line, strings quoted: author, lang, doi, orcid, series, series_order, cover, excerpt.": "Doplňující hodnoty editoru jako řádky TOML key = value, jeden na řádek, řetězce v uvozovkách: author, lang, doi, orcid, series, series_order, cover, excerpt.",
"Template fields must be key = value TOML lines.": "Pole šablony musí být řádky TOML key = value.",
"Unknown template field %s.": "Neznámé pole šablony %s.",
"Default title": "Výchozí titulek",
"Optional": "Volitelné",
"Default slug": "Výchozí slug",
"Tags (comma-separated)": "Značky (oddělené čárkou)",
"Body template (Markdown)": "Šablona obsahu (Markdown)",
"e.g. Review": "např. Recenze",
"Add template": "Přidat šablonu",
// Backup section.
"Backup & restore": "Záloha a obnova",
"Export or import all posts, media, users, and templates": "Exportujte nebo importujte všechny publikace, média, uživatele i šablony",
"Export": "Export",
"Download backup": "Stáhnout zálohu",
"Restore from a previously exported archive. Overwrites existing data.": "Obnova z dříve exportovaného archivu. Přepíše existující data.",
"This will overwrite existing posts and users. Continue?": "Tím se přepíšou existující publikace i uživatelé. Pokračovat?",
"Restore backup": "Obnovit ze zálohy",
// Version section.
"Keep Volumen up to date": "Udržujte Volumen aktuální",
"Installed version": "Nainstalovaná verze",
"Running": "Provozuji",
"latest": "nejnovější",
"Update to %s": "Aktualizovat na %s",
"Check for updates": "Zkontrolovat aktualizace",
// Webhooks section.
"Notify external services when posts change": "Upozorněte externí služby na změny publikací",
"Endpoints": "Koncové body",
"Signed JSON payloads are POSTed on post changes. Changes apply without a restart.": "Podepsané zprávy JSON se posílají při změnách publikací. Změny se projeví bez restartu.",
"Events": "Události",
"Send test": "Poslat test",
"disabled": "vypnuto",
"signed": "podepsáno",
"from config": "z konfigurace",
"Add webhook": "Přidat webhook",
"Endpoint URL": "URL koncového bodu",
"Signing secret (optional)": "Podpisový tajný klíč (nepovinný)",
"Events (comma-separated, empty for all)": "Události (oddělené čárkou, prázdné znamená všechny)",
"Enabled": "Zapnuto",
"Add": "Přidat",
"Enable": "Zapnout",
"Disable": "Vypnout",
"Remove this webhook?": "Odebrat tento webhook?",
"Webhook added.": "Webhook přidán.",
"Webhook updated.": "Webhook uložen.",
"Webhook removed.": "Webhook odebrán.",
"That URL is not a valid http(s) endpoint.": "Tato URL není platný koncový bod http(s).",
"That URL is already configured.": "Tato URL už je nastavená.",
"The webhook store could not be read: %s": "Soubor webhooků se nepodařilo přečíst: %s",
"The webhook could not be saved: %s": "Webhook se nepodařilo uložit: %s",
"Recent deliveries": "Nedávná doručení",
"Kept in memory; cleared on restart.": "Uchovaná v paměti; po restartu smazána.",
"When": "Kdy",
"Event": "Událost",
"Endpoint": "Kam",
"Result": "Výsledek",
// Tokens section.
"Programmatic write access to the public API": "Programový zápis do veřejného API",
"Access tokens": "Přístupové tokeny",
"Copy this token now; it will never be shown again.": "Token si zkopírujte hned; znovu se nezobrazí.",
"No tokens yet. Create one to publish posts from scripts or CI.": "Zatím žádné tokeny. Vytvořte si jeden pro publikování ze skriptů nebo CI.",
"Created": "Vytvořeno",
"Last used": "Naposledy",
"Revoke token “%s”? Scripts using it will stop working.": "Odvolat token „%s“? Skripty, které ho používají, přestanou fungovat.",
"Revoke": "Odvolat",
"Token name": "Název tokenu",
"e.g. deploy-script": "např. deploy-script",
"Scopes": "Oprávnění",
"Write": "Zápis",
"Write creates and edits posts; delete removes them. Read endpoints are public, so no scope is needed for them. Selecting neither grants full access.": "Zápis vytváří a upravuje publikace; mazání je odstraňuje. Čtení je veřejné, oprávnění nepotřebuje. Bez výběru platí plný přístup.",
"Create token": "Vytvořit token",
// Update page.
"The server is restarting. This page will reload automatically.": "Server se restartuje. Tato stránka se obnoví sama.",
"Server is back; reloading.": "Server je zpět; obnovuji.",
"The server did not come back within 3 minutes. Check the service manually.": "Server se do 3 minut nevrátil. Zkontrolujte službu ručně.",
// Date picker.
"Previous month": "Předchozí měsíc",
"Next month": "Další měsíc",
// Editor page actions and crumbs.
"Select %s": "Vybrat: %s",
"Updated to": "Aktualizováno na",
"Short summary for listings and previews": "Krátké shrnutí pro výčty a náhledy",
"Volumen admin": "Volumen administrace",
// Editor crumbs and roles.
"Untitled": "Bez názvu",
"%d of %d": "%d z %d",
"admin": "administrátor",
"author": "autor",
"date must be an ISO 8601 date.": "Datum musí být ve tvaru ISO 8601 (RRRR-MM-DD).",
"publish_at must be an ISO 8601 date.": "Datum publikace musí být ve tvaru ISO 8601 (RRRR-MM-DD).",
// Go handler messages: posts.
"No file selected.": "Nevybrán žádný soubor.",
"No file was uploaded.": "Nevybrán žádný soubor.",
"The upload could not be stored.": "Nahraný soubor nešlo uložit.",
"Only .md files are accepted.": "Přijímají se jen soubory .md.",
"File is too large.": "Soubor je příliš velký.",
"The file could not be read as a post: %s": "Soubor nešlo přečíst jako publikaci: %s",
"Import failed.": "Import selhal.",
"The file could not be read (limit %s bytes).": "Soubor nešlo přečíst (limit %s bajtů).",
"Only WebP, AVIF and SVG images are supported.": "Podporovány jsou jen obrázky WebP, AVIF a SVG.",
"The post could not be saved: %s": "Publikaci nešlo uložit: %s",
"The post could not be deleted: %s": "Publikaci nešlo smazat: %s",
"Slug is required.": "Slug je povinný.",
"Invalid slug.": "Neplatný slug.",
"Invalid language.": "Neplatný jazyk.",
"A post with that slug already exists.": "Publikace s tímto slugem už existuje.",
"Fediverse creator must look like @user@host.": "Autor fediverse musí mít tvar @uzivatel@hostitel.",
// Go handler messages: login and security.
"Invalid CSRF token": "Neplatný CSRF token",
// Go handler messages: settings, account.
"Current password is incorrect.": "Současné heslo není správné.",
"New password cannot be empty.": "Nové heslo nesmí být prázdné.",
"The new password could not be saved: %s": "Nové heslo nešlo uložit: %s",
"Password updated.": "Heslo změněno.",
"Username cannot be empty.": "Uživatelské jméno nesmí být prázdné.",
"Username may use letters, numbers, dot, dash, underscore.": "Uživatelské jméno smí používat písmena, čísla, tečku, pomlčku a podtržítko.",
"Username unchanged.": "Uživatelské jméno nezměněno.",
"The username could not be changed: %s": "Uživatelské jméno nešlo změnit: %s",
"Username updated.": "Uživatelské jméno změněno.",
"The display name could not be saved: %s": "Zobrazované jméno nešlo uložit: %s",
"Display name cleared.": "Zobrazované jméno vymazáno.",
"Display name updated.": "Zobrazované jméno uloženo.",
"The handle could not be saved: %s": "Fediverse účet nešlo uložit: %s",
"Fediverse handle cleared.": "Fediverse účet vymazán.",
"Fediverse handle must look like @user@host.": "Fediverse účet musí mít tvar @uzivatel@hostitel.",
"Fediverse handle updated.": "Fediverse účet uložen.",
"ORCID iD": "ORCID iD",
"Save ORCID": "Uložit ORCID",
"ORCID updated.": "ORCID uložen.",
"ORCID cleared.": "ORCID vymazán.",
"The ORCID could not be saved: %s": "ORCID nešlo uložit: %s",
"ORCID must look like 0000-0002-1825-0097.": "ORCID musí mít tvar 0000-0002-1825-0097.",
"Your Open Researcher and Contributor ID; it pre-fills the author field of new publications.": "Váš Open Researcher and Contributor ID; předvyplňuje pole autora nových publikací.",
"Display name pre-fills the author field. Fediverse handle pre-fills the creator, and the ORCID pre-fills the author identifier of new publications.": "Zobrazované jméno předvyplňuje pole autora, fediverse účet tvůrce a ORCID identifikátor autora nových publikací.",
"The photo could not be stored.": "Fotku nešlo uložit.",
"The profile photo could not be saved: %s": "Profilovou fotku nešlo uložit: %s",
"Profile photo updated.": "Profilová fotka uložena.",
"The profile photo could not be removed: %s": "Profilovou fotku nešlo odstranit: %s",
"Profile photo removed.": "Profilová fotka odstraněna.",
"The interface language is set.": "Jazyk rozhraní je nastaven.",
// Go handler messages: settings, users.
"Username and password are required.": "Uživatelské jméno a heslo jsou povinné.",
"That user could not be added: %s": "Uživatele nešlo přidat: %s",
"User added.": "Uživatel přidán.",
"You cannot change your own role.": "Vlastní roli nelze změnit.",
"The role could not be changed: %s": "Roli nešlo změnit: %s",
"Role updated.": "Role uložena.",
"You cannot delete your own account.": "Vlastní účet nelze smazat.",
"The user could not be removed: %s": "Uživatele nešlo odebrat: %s",
"User removed.": "Uživatel odebrán.",
"Reset password": "Resetovat heslo",
"You cannot reset your own password here.": "Vlastní heslo tady resetovat nemůžete.",
"That user was not found.": "Takový uživatel nebyl nalezen.",
"Password reset; that user's sessions were signed out.": "Heslo resetováno; relace toho uživatele byly odhlášeny.",
"Reset this user's password? Their sessions will be signed out.": "Resetovat heslo tohoto uživatele? Jeho relace budou odhlášeny.",
// Go handler messages: settings, templates and tokens.
"Template name is required.": "Název šablony je povinný.",
"That template could not be added: %s": "Šablonu nešlo přidat: %s",
"Template added.": "Šablona přidána.",
"The template could not be deleted: %s": "Šablonu nešlo smazat: %s",
"Template deleted.": "Šablona smazána.",
"The token could not be created: %s": "Token nešlo vytvořit: %s",
"Token revoked.": "Token odvolán.",
"That token was not found.": "Token nenalezen.",
// Go handler messages: settings, webhooks, backup and version.
"No webhooks configured.": "Žádné webhooky nenastaveny.",
"Webhook not found.": "Webhook nenalezen.",
"Test delivery sent.": "Testovací doručení odesláno.",
"Test delivery failed.": "Testovací doručení selhalo.",
"No backup file selected.": "Nevybrán žádný soubor zálohy.",
"Could not restore backup: %s": "Zálohu nešlo obnovit: %s",
"The archive holds no files this deployment recognises.": "Archiv neobsahuje žádné soubory, které by tahle instalace poznala.",
"Update checks are not available in this build.": "Kontrola aktualizací není v tomto buildu dostupná.",
"Update check failed: %s": "Kontrola aktualizací selhala: %s",
"volumen %s is already the latest release.": "Volumen %s je už nejnovější vydání.",
"volumen %s is available.": "Volumen %s je k dispozici.",
"Self-update is not available in this build.": "Automatická aktualizace není v tomto buildu dostupná.",
"The upgrade failed: %s": "Aktualizace selhala: %s",
"Upgrade to %s failed: %s": "Aktualizace na %s selhala: %s",
}
// csHTML translates the static sentences that only make sense with
// their markup whole. They never carry an interpolated value, so
// returning them unescaped is safe.
var csHTML = map[string]string{
"On macOS use <kbd>Cmd</kbd> instead of <kbd>Ctrl</kbd>.": "Na macOS použijte <kbd>Cmd</kbd> místo <kbd>Ctrl</kbd>.",
"Download a <code>.tar.gz</code> archive of your entire site.": "Stáhněte <code>.tar.gz</code> archiv celého webu.",
"No webhooks yet. Add an endpoint below, or declare <code>[[webhooks]]</code> blocks in <code>config.toml</code> (those are read-only here):": "Žádné webhooky. Přidejte koncový bod níže, nebo deklarujte bloky <code>[[webhooks]]</code> v <code>config.toml</code> (ty tady jsou jen ke čtení):",
"Send a token as <code>Authorization: Bearer &lt;token&gt;</code> on <code>POST/PUT/DELETE /api/volumen/posts</code>.": "Token posílejte jako <code>Authorization: Bearer &lt;token&gt;</code> na <code>POST/PUT/DELETE /api/volumen/posts</code>.",
}
// Catalog translates the admin interface.
type Catalog struct{}
// Admin is the catalogue the binary ships.
var Admin = Catalog{}
// T translates a simple message. The key is the English text; an
// unknown key or the "en" language returns the key itself, so English
// needs no table and a missing translation degrades to English rather
// than to an identifier.
func (Catalog) T(lang, s string) string {
if lang != "cs" {
return s
}
if out, ok := cs[s]; ok && out != "" {
return out
}
return s
}
// TH translates a static sentence that carries its own markup. The
// sentences are authored here, never interpolated, so returning them
// unescaped cannot smuggle request data into the page.
func (Catalog) TH(lang, s string) string {
if lang != "cs" {
return s
}
if out, ok := csHTML[s]; ok {
return out
}
return s
}
// Tf translates a simple message with one %s value. The result stays a
// plain string, so the template engine escapes the interpolated value.
func (c Catalog) Tf(lang, s, arg string) string {
t := c.T(lang, s)
if before, after, ok := strings.Cut(t, "%s"); ok {
return before + arg + after
}
return t
}
// Tf2 translates a simple message with two %s values.
func (c Catalog) Tf2(lang, s, first, second string) string {
t := c.T(lang, s)
for _, arg := range []string{first, second} {
if i := strings.Index(t, "%s"); i >= 0 {
t = t[:i] + arg + t[i+2:]
}
}
return t
}
// N translates a numbered message, picking the form the language's
// cardinal rule asks for. Czech follows CLDR: one for 1, few for the
// 2 to 4 class except 12 to 14, other otherwise.
func (c Catalog) N(lang, id string, n int) string {
forms, ok := pluralForms[id]
if !ok {
return id
}
set := forms["en"]
if lang != "en" {
if l := forms[lang]; l.one != "" || l.other != "" {
set = l
}
}
var form string
switch {
case n == 1:
form = set.one
case lang == "cs" && n%10 >= 2 && n%10 <= 4 && (n%100 < 12 || n%100 > 14):
form = set.few
default:
form = set.other
}
// A plural set without a few form (an id added with English forms
// only) would otherwise render an empty string for the 2 to 4 class.
if form == "" {
form = set.other
}
num := strconv.Itoa(n)
if i := strings.Index(form, "%d"); i >= 0 {
return form[:i] + num + form[i+2:]
}
return form
}
// JS returns the strings the page scripts need, as a map ready for
// JSON encoding into the page. Plural messages carry their three
// forms; the client picks one with the same cardinal rule as N.
func (c Catalog) JS(lang string) map[string]any {
if lang == "" {
lang = "en"
}
out := map[string]any{}
for _, id := range []string{
"editor.words", "editor.chars", "editor.reading",
"bulk.selected", "posts.count", "refs.count",
} {
set := pluralForms[id]["en"]
if lang != "en" {
if l := pluralForms[id][lang]; l.one != "" || l.other != "" {
set = l
}
}
out[id] = []string{set.one, set.few, set.other}
}
plain := map[string]string{
"post.created": c.T(lang, "Post created."),
"post.updated": c.T(lang, "Post saved."),
"post.deleted": c.T(lang, "Post deleted."),
"post.duplicated": c.T(lang, "Post duplicated."),
"post.undone": c.T(lang, "Post restored."),
"post.undelete_failed": c.T(lang, "Could not restore the post; it may already be back."),
"post.duplicate_failed": c.T(lang, "The post could not be duplicated."),
"undo": c.T(lang, "Undo"),
"undo.failed": c.T(lang, "Undo failed."),
"autosave.available": c.T(lang, "Unsaved changes from %s are available."),
"slug.ok": c.T(lang, "Slug is available."),
"slug.taken": c.T(lang, "Already used by “%s”."),
"upload.prefix": c.T(lang, "Upload failed:\n\n%s"),
"upload.rejected": c.T(lang, "Only WebP, AVIF and SVG images are accepted (got “%s”)."),
"link.prompt": c.T(lang, "Link URL"),
"Show password": c.T(lang, "Show password"),
"Hide password": c.T(lang, "Hide password"),
"Collapse sidebar": c.T(lang, "Collapse sidebar"),
"Expand sidebar": c.T(lang, "Expand sidebar"),
"login.unlock": c.T(lang, "Auto-unlock in {} s."),
"login.retry": c.T(lang, " You can try again now."),
"update.reload": c.T(lang, "Server is back; reloading."),
"update.gaveup": c.T(lang, "The server did not come back within 3 minutes. Check the service manually."),
"datepicker.prev": c.T(lang, "Previous month"),
"datepicker.next": c.T(lang, "Next month"),
"Pick a date": c.T(lang, "Pick a date"),
"Clear": c.T(lang, "Clear"),
"Today": c.T(lang, "Today"),
"filter.of": c.T(lang, "%d of %d"),
"import.rejected": c.T(lang, "Only .md files are accepted, got “%s”"),
"media.uploading": c.T(lang, "Uploading %s…"),
"media.upload_failed": c.T(lang, "Upload failed: %s"),
"media.copied": c.T(lang, "Link copied."),
"media.copy_prompt": c.T(lang, "Copy the link:"),
"upload.complete": c.T(lang, "Upload complete."),
"pw.weak": c.T(lang, "Weak"),
"pw.fair": c.T(lang, "Fair"),
"pw.good": c.T(lang, "Good"),
"pw.strong": c.T(lang, "Strong"),
}
for id, v := range plain {
out[id] = v
}
return out
}