[{"content":"Diesen Beitrag gibt es nur auf Deutsch. Das ist keine unfertige Übersetzung, sondern der Zustand, auf den ein zweisprachiges Blog die meiste Zeit zuläuft: Man schreibt etwas auf, weil man es gerade gelöst hat, und in welcher Sprache das passiert, entscheidet die Situation.\nWas das Theme daraus macht Im Schriftfeld erscheint keine Zeile „Auch auf\u0026quot; — es gibt nichts zu verweisen, also wird nichts liniert. Die Sprachumschaltung oben bleibt trotzdem bedienbar und führt auf die englische Startseite, weil das die einzige ehrliche Antwort ist: Es gibt hier nichts, worauf sie zeigen könnte.\nDie englische Suche findet diesen Beitrag nicht, und im englischen Feed taucht er nicht auf. Beide Indizes sind sprachgetrennt, und das ist Absicht — wer auf /en/ liest, soll keine Treffer bekommen, die er nicht lesen kann.\nWarum das kein Sonderfall sein sollte Ein Theme, das Übersetzungspaare als Normalfall behandelt, drängt dazu, halbfertige Übersetzungen zu veröffentlichen, nur damit die Struktur aufgeht. Umgekehrt ist es richtig: Das Paar ist der Sonderfall, der einzelne Beitrag der Normalfall.\nHinweis\nDrei Beiträge dieser Demo gibt es in nur einer Sprache: diesen hier sowie The Zone Rail und Writing with Shortcodes auf der englischen Seite. Die Sprachumschaltung verhält sich auf allen dreien gleich.","permalink":"/felix/vellum/de/posts/nur-auf-deutsch/","summary":"Dieser Beitrag hat kein englisches Gegenstück — und demonstriert damit, was das Theme in genau diesem Fall tut.","title":"Nur auf Deutsch"},{"content":"Diese Demo läuft auf Englisch und Deutsch. Nicht Englisch mit deutschem Anstrich: Jede Sprache hat ihr eigenes Inhaltsverzeichnis, ihr eigenes Menü, ihren eigenen Suchindex, ihren eigenen Feed und ihre eigenen Tags. Ein Beitrag darf in einer Sprache existieren und in der anderen nicht — das ist der Normalfall, keine Lücke, für die man sich entschuldigt.\nDer Aufbau defaultContentLanguage = \u0026#34;en\u0026#34; defaultContentLanguageInSubdir = true [languages.en] languageName = \u0026#34;English\u0026#34; contentDir = \u0026#34;content/en\u0026#34; weight = 1 [languages.de] languageName = \u0026#34;Deutsch\u0026#34; contentDir = \u0026#34;content/de\u0026#34; weight = 2 defaultContentLanguageInSubdir stellt jede Sprache unter ein Präfix, Englisch eingeschlossen. Damit landet nichts im Veröffentlichungswurzelverzeichnis — und genau deshalb bringt das Theme das Ausgabeformat ROOT404 mit, damit der Webserver überhaupt ein Fehlerdokument ausliefern kann.\nWichtig\nROOT404 gehört ausschließlich in die Standardsprache. Gibt man es beiden, streiten sie sich um /404.html, und die Build-Reihenfolge entscheidet.\nÜbersetzungen paaren Zwei Beiträge werden über einen gemeinsamen translationKey zu Übersetzungen voneinander. Damit bleiben Dateiname und URL in jeder Sprache idiomatisch:\ntranslationKey = \u0026#34;multilingual-by-design\u0026#34; Im Schriftfeld erscheint dann die Zeile Auch auf, und die Sprachumschaltung im Kopf führt auf das Gegenstück dieser Seite statt auf die Startseite. Wo es kein Gegenstück gibt — wie bei zwei Beiträgen dieser Demo — fällt sie auf die Startseite der anderen Sprache zurück. Das ist die ehrliche Antwort.\nParameter je Sprache Alles unter [languages.xx.params] erreicht die Templates als site.Params, bereits für die aktuelle Sprache aufgelöst. Erst das macht einen wirklich sprachabhängigen editPost-Link möglich:\n[languages.de.params.editPost] URL = \u0026#34;https://example.org/-/edit/main/content/de\u0026#34; appendFilePath = true .File.Path ist relativ zum contentDir der jeweiligen Sprache — eine einzige seitenweite URL könnte also immer nur für eine der beiden stimmen.\nDatumsangaben DateFormat = \u0026quot;:date_long\u0026quot; statt einer Go-Layout-Zeichenkette. Ein Layout wie 2. January 2006 friert den Monatsnamen in einer Sprache ein und schreibt auf einer deutschen Seite bereitwillig January; die Kurzform löst pro Sprache auf.","permalink":"/felix/vellum/de/posts/mehrsprachig-von-anfang-an/","summary":"Zwei Sprachen, von denen keine eine Übersetzungsschicht über der anderen ist — und was das an Konfiguration kostet.","title":"Mehrsprachig von Anfang an"},{"content":"Die Lesespalte dieses Themes ist aus genau einem Grund 92 Zeichen breit: Eine aus einem 80 Zeichen breiten Terminal kopierte Zeile soll hineinpassen, ohne umzubrechen. Alles andere an der Behandlung von Code folgt aus dieser Entscheidung.\nSyntaxhervorhebung Chroma gibt Klassennamen statt Inline-Styles aus. Nur deshalb lassen sich die Syntaxfarben über dieselben light-dark()-Tokens auflösen wie der Rest der Seite. Die einbindende Site muss das allerdings aktiv einschalten:\npygmentsUseClasses = true [markup.highlight] noClasses = false Fehlt eines von beidem, backt Hugo eine Hell-Palette fest ins HTML — und die Codeblöcke bleiben auf einer dunklen Seite hell.\nEin Beispiel 1\nDer folgende Ausschnitt ist ein Beispiel, kein Auszug aus dem Theme — er zeigt, worauf es beim Fehlertext ankommt, nicht wie tokens.html tatsächlich gebaut ist. Diese Passage trägt deshalb einen Randstrich: Sie ist mit Unterstützung entstanden, und der Änderungsvermerk am Blattfuß sagt, womit.\n// tokens.html liest vier Werte zur Build-Zeit aus 00-tokens.css, weil ein // sizes-Attribut ohne Element-Kontext ausgewertet wird und kein var() kennt. func measure(css string) (int, error) { m := regexp.MustCompile(`--content-width:\\s*(\\d+)px`).FindStringSubmatch(css) if m == nil { return 0, fmt.Errorf(\u0026#34;--content-width fehlt: Layout und responsive \u0026#34;+ \u0026#34;Bilder wären sich stillschweigend uneinig\u0026#34;) } return strconv.Atoi(m[1]) } Bemerkenswert ist weniger der Code als der Fehlertext. Ein fehlendes Token bringt hier nichts zum Absturz — es sorgt nur dafür, dass jedes Bild eine falsche sizes-Angabe ausliefert. Solche Fehler überleben Monate.\nLange Ausgaben Vollständige Build-Ausgabe $ hugo --source exampleSite --themesDir ../.. --printPathWarnings Start building sites … hugo v0.165.0+extended linux/amd64 │ EN │ DE ───────────────────┼────┼──── Pages │ 24 │ 21 Paginator pages │ 2 │ 1 Non-page files │ 4 │ 2 Processed images │ 6 │ 6 Aliases │ 4 │ 3 Total in 284 ms Wenn eine Ausgabe über hunderte Zeilen läuft, gehört sie in einen collapse-Shortcode — gefaltet, aber vollständig. Gekürzte Logs sind das Einzige, was Lesende nicht rekonstruieren können.\nTipp\nShowCodeCopyButtons = true setzt auf jeden Block eine Kopierschaltfläche. Sie erscheint bei Hover und bei Tastaturfokus und wird im Druck unterdrückt — auf Papier gibt es nichts zu kopieren.","permalink":"/felix/vellum/de/posts/code-und-terminalausgabe/","summary":"Codeblöcke sind der eigentliche Inhalt eines technischen Beitrags, nicht sein Beiwerk — entsprechend werden sie gesetzt.","title":"Code und Terminalausgabe"},{"content":"Jede Seite dieses Themes ist ein Zeichnungsblatt. Der linierte Block unter dem Titel ist das Schriftfeld: Auf einer echten technischen Zeichnung steht darin, was das Blatt zeigt, wer es gezeichnet hat, wann, und in welchem Änderungsstand. Hier trägt es dieselben Felder — als wirkliche Tabelle mit Rahmen, nicht als graue Bildunterschrift, über die der Blick ohnehin hinweggeht.\nWas im Schriftfeld steht Jede Zeile speist sich aus genau einem Front-Matter-Schlüssel. Eine Zeile, die nichts zu sagen hat, wird gar nicht erst liniert — ein leeres Feld ist auf einer Zeichnung ein Mangel, kein Platzhalter.\nDieser Beitrag hat ein lastmod, das mehr als einen Tag nach date liegt — deshalb erscheint die Zeile Änderung. Nimmt man den Schlüssel heraus, verschwindet die Zeile und der Block schließt sich darüber.\nFeld Quelle Erscheint Ausgabe date immer Änderung Lastmod bei mehr als einem Tag Unterschied zu date Umfang Lesezeit, Wortzahl wenn die Schalter an sind Von author wenn gesetzt Thema tags wenn der Beitrag Tags hat Auch auf Übersetzungen wenn es den Beitrag in einer anderen Sprache gibt Die Lesespalte Die Spalte fasst bei 20px Grundschrift 92 Zeichen — deutlich mehr als die klassische Empfehlung von 65 bis 75. Das ist ein bewusster Tausch für technische Texte, deren eigentlicher Inhalt Befehle und Terminalausgaben sind, die nicht umbrechen sollen:\n$ hugo --gc --minify Start building sites … │ EN │ DE ──────────────────┼────┼──── Pages │ 24 │ 21 Processed images │ 6 │ 6 Total in 211 ms Den Preis dafür trägt die Zeilenhöhe: Bei 1.75 bleibt auch eine 92 Zeichen lange Zeile verfolgbar, und der Rücksprung landet zuverlässig in der richtigen Reihe. Beide Werte sind an einer gesetzten Zeile gemessen, nicht geschätzt — eine Hochrechnung über Zeichen pro Pixel geht verlässlich daneben.\nHinweis\nGeschrieben als gewöhnliches Markdown-Zitat, das mit [!NOTE] beginnt. Kein Shortcode und kein rohes HTML — was deshalb zählt, weil Goldmarks unsafe ausgeschaltet ist.\nDie Zonenleiste Der Streifen mit den Buchstaben am linken Rahmenrand ist keine Zierde. Jeder Buchstabe steht für eine Überschrift erster Ebene in diesem Beitrag, und jeder ist ein Link. Auf einer Seite, die nichts zu indizieren hat, wird die Leiste nicht gezeichnet — ein beschriftetes leeres Feld wäre eine Behauptung über die Zeichnung, die nicht stimmt.\nWarnung\nBreite Tabellen scrollen in einem eigenen Container, statt die ganze Seite seitwärts zu schieben. Probiere die Tabelle oben in einem schmalen Fenster aus.","permalink":"/felix/vellum/de/posts/ein-blatt-lesen/","summary":"Was das Schriftfeld festhält, warum die Lesespalte breiter ist als üblich empfohlen — und wann das Blatt gar nichts zeichnet.","title":"Ein Blatt lesen"}]