Zum Hauptinhalt springen
Rezept Nummer 178

Rezepte · Kapitel 10 · Ausgabe und Integration

Ein Entwurf für drei Sprachausgaben

Ein Heft auf Englisch, Spanisch und Arabisch aus allgemeinen Einstellungen, mit Abweichungen nur für das, was jeder Sprache gehört: Schriften, Grade, Sperrung.

Auf dieser Seite
Gattung
Kataloge
Ausgabe
Canvas · PDF
Postext
Getestet mit Postext 1.65.0
Erfordert ≥ 1.65.0 · postext-pdf ≥ 1.65.0
Lizenz
Aktualisiert am 31. Okt. 2026
Code MIT · Text CC BY 4.0

S. 1 von 4

  • Englisches Beispiel: noch keine deutsche Ausgabe
  • Endformat 148 × 210 mm
  • 1 Spalte
  • Source Serif 4 10/14
  • Source Sans 3
  • 4 Seiten
  • Stufe
  • Postext 1.65.0
  • In 223 ms gesetzt
  • 205 Zeilen Code

Kurz gesagt

Ein Heft über drei alte Astrolabien, gedruckt auf Englisch, Spanisch und Arabisch. Alle drei teilen einen Entwurf; nur die arabische Ausgabe ändert Schriften und Größen.

Was Sie setzen

Ein Heft von vier A5-Seiten über drei Astrolabien im Metropolitan Museum of Art: eines 1291 im Jemen gebaut, eines 1654 in Iran, eines 1462 in Europa. Der Verlag bringt es auf Englisch, Spanisch und Arabisch heraus, und die drei Ausgaben sind ein Entwurf. Umschlagfoto, messingfarbene Zwischentitel, der Kasten mit seiner Linie, die umflossenen Abbildungen und der dunkle Tabellenkopf kommen aus denselben Einstellungen. Die arabische Ausgabe ändert, was zu ihrer Schrift gehört: Amiri und IBM Plex Sans Arabic statt Source Serif und Source Sans, einen größeren Grad und Beschriftungen ohne Versalien und Sperrung. Sie liest sich von rechts und wird rechts gebunden, ohne eine einzige eigene Koordinate.

Dieses Rezept beantwortet

  • Wie teile ich eine Gestaltung zwischen den Ausgaben eines Buchs in mehreren Sprachen und ändere nur Schriften, Silbentrennung, Anführungszeichen und Beschriftungen jeder Sprache?
  • Wie veröffentliche ich dasselbe Buch aus einem Projekt in zwei Sprachen?

Die kurze Antwort

script.js · Zeilen 114–141im vollständigen Code
const ARABIC_LABEL = { fontFamily: 'IBM Plex Sans Arabic', letterSpacing: pt(0),
  textTransform: 'none' }; // Arabic letters join: never tracked, and they have no capitals
// English and Spanish need nothing more than their locale: it picks the hyphenation patterns
// and the words of the figure and table labels. Arabic sets the faces of its script.
const overrides = {
  ar: {
    bodyText: { fontFamily: 'Amiri', fontSize: pt(12), lineHeight: pt(19),
      firstLineIndent: em(1.5) },
    headings: { fontFamily: 'Amiri', fontWeight: 700,
      levels: [{ level: 2, fontSize: pt(15), lineHeight: pt(24) }] },
    // Lists keyed by id merge entry by entry: only these fields of these elements change.
    headingStyles: [{ id: 'cover', advancedDesign: { slot: { elements: [
      { id: 'kicker', ...ARABIC_LABEL, fontSize: pt(10) },
      { id: 'title', fontFamily: 'Amiri', fontWeight: 700, fontSize: pt(50), lineHeight: 1.25 },
      { id: 'facts', ...ARABIC_LABEL, fontSize: pt(9.5) },
    ] } } }],
    header: { elements: ['verso-folio', 'verso-title', 'recto-title', 'recto-folio']
      .map((id) => ({ id, ...ARABIC_LABEL, fontSize: pt(9) })) },
    calloutStyles: [{ id: 'note', titleStyle: { ...ARABIC_LABEL, fontSize: pt(10) },
      body: { fontSize: pt(11.5), lineHeight: pt(19) } }],
    tableStyle: { headerFontFamily: 'IBM Plex Sans Arabic', headerFontSize: pt(9),
      bodyFontFamily: 'IBM Plex Sans Arabic', bodyFontSize: pt(9.4) },
    captionStyle: { fontFamily: 'IBM Plex Sans Arabic', fontSize: pt(9) },
    paragraphStyles: [{ id: 'colophon', fontFamily: 'IBM Plex Sans Arabic', fontSize: pt(8.4),
      lineHeight: pt(13) }],
  },
};
const edition = mergeConfigLayers(config, overrides[LANG]); // config itself for en and es

Zutaten

Schrift
Source Serif 4, Source Sans 3, Amiri, IBM Plex Sans Arabic (SIL OFL 1.1)
Dateien
  • mashhad-800.jpg
  • rasulid-cover-1400.jpg
  • regiomontanus-800.jpg
  • Astrolabe of ʿUmar ibn Yusuf, Yemen, 1291 (the cover; background extended at the top and darkened) (The Metropolitan Museum of Art, CC0 1.0)
  • Muhammad Zaman, planispheric astrolabe, Iran, 1654–55 (cropped) (The Metropolitan Museum of Art, CC0 1.0)
  • Astrolabe attributed to Regiomontanus, 1462 (cropped) (The Metropolitan Museum of Art, CC0 1.0)

Zubereitung

#1 · Allgemeine Einstellungen und drei kleine Abweichungen

Der Code steht in der kurzen Antwort oben. config enthält die allgemeinen Einstellungen; mergeConfigLayers legt die Abweichung einer Ausgabe Feld für Feld darüber. Englisch und Spanisch haben keine Abweichung: ihr locale wählt die Trennmuster und die Wörter Figure und Table, Figura und Tabla. Die arabische Abweichung nennt nur einzelne Felder: bodyText.fontFamily ändert die Schrift und behält Farbe, Ausrichtung und Silbentrennung, und das Element kicker des Umschlags ändert Schrift und Sperrung und behält Anker, Farbe und Größe. Eine Änderung an Palette oder Rändern in config erreicht alle drei Ausgaben.

#2 · Seiten nach der Schreibrichtung benannt

script.js · Zeilen 59–72im vollständigen Code
// An even page's outer edge is its start side in either direction (the left of an English
// verso, the right of an Arabic one), an odd page's its end side.
const head = (id, content, parity, edge, x, extra = {}) => ({ kind: 'text', id, content,
  parity, pages: 'body', fontFamily: LABEL, fontSize: pt(7.5), fontWeight: 600,
  letterSpacing: pt(1.1), textTransform: 'uppercase', color: col('muted'),
  align: edge.endsWith('start') ? 'start' : 'end',
  placement: { anchor: { to: 'page', edge }, offset: { x: mm(x), y: mm(12) } }, ...extra });
const folio = { fontWeight: 700, color: col('brass') };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-start', 16, folio),
  head('verso-title', '{title}', 'even', 'top-start', 24),
  head('recto-title', '{subtitle}', 'odd', 'top-end', -24),
  head('recto-folio', '{pageNumber}', 'odd', 'top-end', -16, folio),
] };

Der Außenrand einer geraden Seite ist in beiden Richtungen der Zeilenanfang, der einer ungeraden das Zeilenende; top-start und top-end setzen die Seitenzahlen deshalb auf einer englischen wie auf einer arabischen linken Seite außen. Die Linie des Kastens ist side: 'start', und der Umschlagtext hängt an top-start: keines braucht eine Abweichung.

#3 · Abbildungen am Zeilenende, vom Text umflossen

script.js · Zeilen 195–219im vollständigen Code
const photo = (id, file, w, h, extra = {}) => ({ id, typeId: 'figure', kind: 'bitmap',
  createdAt: 0, updatedAt: 0, ...extra,
  bitmap: { fileId: file, format: 'jpeg', width: w, height: h } });
// 'end' is the right of an English column and the left of an Arabic one.
const wrapped = { position: 'here', wrap: 'end', width: 0.38 };
const note = (n) => `The Met, ${n}, CC0`;
const resources = [
  photo('rasulid', 'rasulid-cover-1400.jpg', 1400, 1985),
  photo('mashhad', 'mashhad-800.jpg', 800, 1187, { placement: wrapped, note: note('63.166a–j'),
    caption: t({ en: 'Planispheric astrolabe, Iran, 1654–55. Brass and steel.',
      es: 'Astrolabio planisférico, Irán, 1654-1655. Latón y acero.',
      ar: 'أسطرلاب مسطّح، إيران، ١٠٦٥\u00a0هـ / ١٦٥٤–١٦٥٥\u00a0م. نحاس أصفر وفولاذ.' }),
    altText: t({ en: 'A brass astrolabe whose rete is a lattice of leaves and scrolls',
      es: 'Un astrolabio de latón cuya red es un enrejado de hojas y volutas',
      ar: 'أسطرلاب من النحاس الأصفر عنكبوته شبكة من الأوراق والأغصان الملتفّة' }) }),
  photo('regiomontanus', 'regiomontanus-800.jpg', 800, 1083,
    { placement: wrapped,
    note: note('2025.347a–j'),
    caption: t({ en: 'Astrolabe attributed to Regiomontanus, 1462. Copper alloy.',
      es: 'Astrolabio atribuido a Regiomontano, 1462. Aleación de cobre.',
      ar: 'أسطرلاب يُنسب إلى ريجيومونتانوس، ١٤٦٢\u00a0م. سبيكة نحاسية.' }),
    altText: t({ en: 'A round brass astrolabe with Latin star names on its rete',
      es: 'Un astrolabio redondo de latón con nombres latinos de estrellas en la red',
      ar: 'أسطرلاب مستدير من النحاس عليه أسماء نجوم لاتينية' }) }),
];

wrap: 'end' setzt jedes Foto rechts in eine englische und links in eine arabische Spalte, und der Text läuft daneben. Bildunterschriften und Alternativtexte stehen in der Sprache der Ausgabe; die arabischen nennen zuerst das Hidschra-Datum.

#4 · Die Tabelle in den Wörtern und Ziffern jeder Ausgabe

script.js · Zeilen 223–241im vollständigen Code
const row = (...cells) => cells.map((content) => ({ content }));
const head2 = (...cells) => cells.map((content) => ({ content, isHeader: true }));
resources.push({ id: 'three', typeId: 'table', kind: 'table', createdAt: 0, updatedAt: 0,
  placement: { position: 'here' },
  caption: t({ en: 'The three instruments.', es: 'Los tres instrumentos.',
    ar: 'الأدوات الثلاث.' }),
  table: { model: { headerRowCount: 1, columnWidths: [1.15, 1.1, 1.2, 1.1], rows: t({
    en: [head2('Made', 'Where', 'Maker', 'Size'),
      row('1291', 'Yemen', 'ʿUmar ibn Yūsuf', '15.6 cm wide'),
      row('1654–55', 'Iran, Mashhad?', 'Muhammad Zaman', '21.6 cm high'),
      row('1462', 'Germany or Italy', 'Regiomontanus', '13.5 cm high')],
    es: [head2('Fecha', 'Lugar', 'Autor', 'Tamaño'),
      row('1291', 'Yemen', 'ʿUmar ibn Yūsuf', '15,6 cm de ancho'),
      row('1654-1655', 'Irán, ¿Mashhad?', 'Muhammad Zaman', '21,6 cm de alto'),
      row('1462', 'Alemania o Italia', 'Regiomontano', '13,5 cm de alto')],
    ar: [head2('التاريخ', 'المكان', 'الصانع', 'المقاس'),
      row('٦٩٠\u00a0هـ / ١٢٩١\u00a0م', 'اليمن', 'عمر بن يوسف', 'عرضه ١٥٫٦\u00a0سم'),
      row('١٠٦٥\u00a0هـ / ١٦٥٤\u00a0م', 'إيران، مشهد؟', 'محمد زمان', 'ارتفاعه ٢١٫٦\u00a0سم'),
      row('١٤٦٢\u00a0م', 'ألمانيا أو إيطاليا', 'ريجيومونتانوس', 'ارتفاعه ١٣٫٥\u00a0سم')] }) } } });

Die Tabellendaten sind Inhalt und wechseln mit der Ausgabe: arabisch-indische Ziffern und das arabische Dezimaltrennzeichen in der arabischen Ausgabe, ein Dezimalkomma in der spanischen. Ihr Stil ist allgemein: die Abweichung setzt nur die arabische Schrift und ihren Grad.

Das ganze Rezept

Sandbox
// ═══ Postext Cookbook · Nº 178 · One design for three language editions ═══════════
// https://postext.dev/en/cookbook/shared-design-per-language
// Code: MIT · Text: original (CC BY 4.0) · Photographs: The Met, Open Access (CC0)
// Fonts: Source Serif 4, Source Sans 3, Amiri, IBM Plex Sans Arabic (OFL) · Needs postext ≥ 1.65.0
import {
  buildDocument, withLoadedFonts, renderPageToCanvas, registerResourceImage, mergeConfigLayers,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'en'; // @lang: the edition: 'en' | 'es' | 'ar'
const RECIPE = 'shared-design-per-language';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: night ink, the brass of the instruments, a parchment tint
const palette = {
  ink: '#1f2230', // text: a blue near-black
  brass: '#80561c', // the one accent: kickers, rules, the box stripe (6.2:1 on paper)
  tint: '#f4eee2', // the box ground
  rule: '#cfc5b2', // hairlines
  muted: '#6a655c', // running heads, credits
  paper: '#ffffff',
};
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
  ...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
  { id: 'main-color', name: 'brass (defaults)', value: { hex: palette.brass, model: 'hex' } },
];
// #endregion
const [TEXT, LABEL] = ['Source Serif 4', 'Source Sans 3'];
const PAGE = { w: 148, h: 210 }; // mm: an A5 booklet
const LEAD = 14; // pt

// #region cover: the photograph to the trim, the title on its dark head
const at = (edge, x, y, width) => ({ anchor: { to: 'page', edge },
  offset: { x: mm(x), y: mm(y) }, ...(width ? { size: { width: mm(width) } } : {}) });
const caps = { fontFamily: LABEL, fontWeight: 700, textTransform: 'uppercase',
  letterSpacing: pt(1.6) };
// Every side is named by the direction of the text: 'top-start' is the left of an English
// page and the right of an Arabic one, so the cover needs no override to turn round.
const cover = { id: 'cover',
  advancedDesign: { enabled: true, slot: { elements: [
    { kind: 'image', id: 'photo', resourceId: 'rasulid', decorative: true, fit: 'cover',
      placement: { anchor: { to: 'page', edge: 'top-left' },
        size: { width: mm(PAGE.w), height: mm(PAGE.h) } } },
    { kind: 'text', id: 'kicker', content: '{attr.kicker}', fontSize: pt(8.5), align: 'start',
      color: col('paper'), ...caps, placement: at('top-start', 17, 18) },
    { kind: 'rule', id: 'rule', direction: 'horizontal', thickness: pt(1.5), color: col('tint'),
      placement: { anchor: { to: '#kicker', edge: 'below' }, offset: { x: mm(0), y: mm(3) },

Das zusammengesetzte script.js läuft unverändert: Fügen Sie es in das Modulskript einer beliebigen Seite ein, oder öffnen Sie das Rezept auf CodePen. Ordner des Rezepts auf GitHub ↗ (öffnet sich in einem neuen Tab)

Varianten

#Die Abweichungen in ein Paket schreiben

Die .postext-Hin-und-Rückreise schreibt ein Buch in zwei Sprachen in eine Datei. Seit postext 1.58 speichert createBundle die allgemeinen Einstellungen einmal und neben den Kapiteln jeder Sprache ihre Abweichung, so wie mergeConfigLayers sie hier liest. Das Sandbox-Buch dieses Rezepts öffnet sich so: Schalten Sie das Design-Panel zwischen Alle Sprachen und der arabischen Ausgabe um, um zu sehen, welche Felder die arabische Ausgabe setzt.

#Die arabische Ausgabe für den Maghreb drucken

ar-MA behält Richtung und Bindung und schreibt die erzeugten Zahlen, Seitenzahlen und Abbildungsnummern, in europäischen Ziffern. Tippen Sie auch die Ziffern der Tabelle neu.

-  locale: t({ en: 'en-gb', es: 'es', ar: 'ar' }), // ar: right to left, bound on the right
+  locale: t({ en: 'en-gb', es: 'es', ar: 'ar-MA' }), // ar-MA: European digits

Häufige Fehler

Häufiger Fehler

Arabische Schnitte brauchen ihre arabic-Datei, über den Block arabic

Fontsource liefert Amiri, Noto Naskh Arabic oder Scheherazade New als eine Datei pro Teilmenge aus, und die arabischen Buchstaben stehen in der Datei arabic. loadFonts holt nur latin (und latin-ext), am Bildschirm stammt das Arabische also aus einer Systemschrift und wird falsch gemessen, und fontsourceProvider gibt dem PDF diese latin-Datei, die leere Kästchen druckt. Führen Sie den Kit-Block arabic auf, rufen Sie loadArabicFonts(FONTS, markdown) nach loadFonts auf, mit jeder Schriftstärke, die die Seiten auf Arabisch setzen, in FONTS aufgeführt, und geben Sie renderToPdf fontProvider: arabicPdfProvider. Arabische Schriften →

  • Arabische Buchstaben sind verbunden: Eine in den allgemeinen Einstellungen gesperrte Beschriftung muss in der arabischen Abweichung ihr letterSpacing verlieren, sonst meldet die Engine joiningScriptLetterSpacing. Dazu gehört textTransform: 'none': Arabisch hat keine Versalien.
  • Die Zeilen einer arabischen Ausgabe sind höher, ihre Seiten brechen an anderen Stellen. Jede Ausgabe wurde für sich eingepasst: Der arabische Kasten fließt an den Fuß seiner Seite (placement="bottom"), und die Schlusssätze laufen neben dem letzten Foto.

Nachweise

Text
Eigener Text, CC BY 4.0
Bilder
Schriften
Source Serif 4 (SIL OFL 1.1) · Source Sans 3 (SIL OFL 1.1) · Amiri (SIL OFL 1.1) · IBM Plex Sans Arabic (SIL OFL 1.1)
SandboxPDF