Vai al contenuto principale
Ricetta numero 171

Ricettario · Capitolo 12 · Libri di testo

Un quaderno di esercizi cinese, per alunno e insegnante

Un 练习册 di cinese e matematica: sezioni 一、二、, parentesi ( ), 田字格 e operazioni in colonna, composto due volte da un solo testo, per l’alunno e l’insegnante.

In questa pagina
Output
Canvas · PDF
Livello
Intermedio
Postext
Provata con Postext 1.59.0
Richiede ≥ 1.59.0 · postext-pdf ≥ 1.59.0
Licenza
Aggiornata il 24 ott 2026
Codice MIT · Testo CC BY 4.0
  • Esempio in lingua straniera: non c’è ancora un’edizione italiana
  • Formato 184 × 260 mm
  • 1 colonna
  • Noto Serif SC 10,5/21
  • LXGW WenKai TC
  • Noto Sans SC
  • 8 pagine
  • Livello
  • Postext 1.59.0
  • Impaginato in 124 ms
  • 162 righe di codice

In breve

Un quaderno di esercizi di una primaria cinese: due unità di lingua e di matematica. Lo stesso testo dà la copia dell’alunno, con spazi vuoti e soluzioni in fondo, e quella dell’insegnante, con ogni risposta in rosso al suo posto.

Che cosa comporrai

Due unità di un 练习册 di seconda elementare in formato 16开: un’unità di lingua, 春天来了, e una di matematica su addizioni e sottrazioni entro il 100. Ognuna si apre con una fascia ad acquerello, una linguetta con la materia e una riga per classe, nome e punteggio, poi passa per le sezioni che stampa un quaderno cinese: 看拼音写词语, letture da cerchiare, 选择题 con una ( ) dopo il testo e A. B. C. D. in fila, 判断题 con una parentesi a fine riga, frasi da completare, 连线 tra classificatori e oggetti, una frase da scrivere nei 田字格, 口算 su quattro colonne, 竖式 con una casella per cifra e un problema. I punti stanno in ogni consegna, dove li legge l’alunno. Lo stesso Markdown si compone due volte: il libro dell’alunno, con il 参考答案 alla fine di ogni unità, e quello dell’insegnante, con ogni risposta scritta in Kai rosso al suo posto.

Questa ricetta risponde a

  • Come compongo domande d'esame cinesi: una parentesi ( ) dopo la domanda e le opzioni A. B. C. D. in fila?
  • Come ricavo la guida per l'insegnante, con le risposte al loro posto, dal libro dell'alunno?
  • Come do a una domanda aperta la rigatura Seyès, i quadretti o le caselle 田字格 per scrivere?
  • Come compongo la divisione in colonna come la scrivono le scuole di ogni paese?

La risposta breve

script.js · righe 36–65nel codice completo
// The exercise style is the form; the Markdown holds every word, the points included. The
// same text builds both editions: `edition: 'teacher'` writes each answer into its blank,
// bracket and square in red Kai, rings the right options and draws the matching lines.
const lianxi = {
  id: 'lianxi',
  number: { format: 'simp-chinese-informal', suffix: '、', fontFamily: HEI, color: col('green') },
  instruction: { fontFamily: HEI, bold: false }, // 黑体, not bold: the points stay quiet
  // 选择题: A. B. C. D. in a row, a ( ) after the stem for the letter.
  options: { labels: 'alpha-upper', suffix: '.', layout: 'row', bracket: true },
  trueFalse: { look: 'bracket' }, // 判断题: ( ) at the end of the line, √ or ×
  blank: { look: 'line', color: col('ink') },
  area: { kind: 'tianzige', color: col('rule') }, // 写话 on 田字格
  match: { color: col('green') },
  grid: { fontFamily: SONG, rule: col('rule') },
  answers: { color: col('red'), fontFamily: KAI },
  solutions: { box: 'daan' },
  marginTop: em(1.2), marginBottom: em(0.6),
};
const exerciseStyles = [
  lianxi,
  // 看拼音写词语: a box under each syllable, as wide as its word.
  { id: 'pinyin', extends: 'lianxi', blank: { look: 'box', width: 'answer', color: col('rule') } },
  // 在( )里填: the bracket is in the text, the blank inside it draws nothing.
  { id: 'kuohao', extends: 'lianxi', blank: { look: 'none', width: 'answer' } },
];
let edition = 'student'; // the second build below prints the teacher's book
// The pupil's book: 参考答案 where a :::solutions line stands, at the end of each unit.
// The teacher's book: every answer on the page, so no key at the end.
const exercises = () => ({ edition,
  solutions: { placement: edition === 'teacher' ? 'none' : 'directive' } });

Ingredienti

Tipo
Noto Serif SC, Noto Sans SC, LXGW WenKai TC (SIL OFL 1.1)
Risorse
  • market-1600.jpg
  • spring-1600.jpg
  • A Chinese village in early spring: willows, swallows, peach blossom and two children on a path between rice fields. (Generated With Diffusion Models, originale)
  • Two children count oranges, apples and pears at a grandmother's fruit stall, a cat on a stool beside them. (Generated With Diffusion Models, originale)

Preparazione

#1 · Un solo stile per tutte le sezioni

Il codice è nella risposta breve qui sopra. Le sezioni si contano con numerali cinesi seguiti da un 、 a larghezza piena, quindi dopo il numero non c’è spazio; la consegna è in Hei senza grassetto, così i punti tra parentesi si leggono come parte di essa. options.bracket scrive la ( ) dopo ogni testo, e nel libro dell’insegnante la lettera giusta ci va dentro. I due stili piccoli estendono quello principale: pinyin disegna ogni spazio vuoto come una casella larga quanto la sua parola, kuohao non disegna nulla, perché la parentesi di 在( )里填 è già nel testo.

#2 · Il libro dell’alunno e quello dell’insegnante da un solo testo

script.js · righe 334–338nel codice completo
const build = () => withLoadedFonts(() => buildDocument({ markdown, resources }, config()),
  { ...kitFonts(FONTS), text: markdown });
const pupil = await build();
edition = 'teacher';
const docs = [pupil, await build()];

La configurazione è una funzione, quindi ogni composizione riceve il suo oggetto e il pacchetto del Sandbox conserva quello dell’alunno. edition: 'teacher' scrive le risposte nel colore e nel carattere di answers: le parole nelle loro caselle, le lettere nelle loro parentesi, √ e × nei 判断题, le cifre nelle caselle dei 竖式, la frase modello con un carattere per quadretto. Il libro dell’alunno tiene le soluzioni per la riga :::solutions alla fine di ogni unità; quello dell’insegnante non ne ha bisogno.

#3 · Un’apertura di unità con il suo dipinto

script.js · righe 69–87nel codice completo
const BAND = 184 / 2.4; // mm: the painting's height at the page's width
const opener = { enabled: true, minHeight: mm(BAND - 22 + 23), slot: { elements: [
  { kind: 'image', id: 'picture', resourceId: '{attr.pic}', decorative: true, reserve: false,
    placement: { anchor: { to: 'page', edge: 'top-left' },
      size: { width: mm(184), height: mm(BAND) } } },
  { kind: 'text', id: 'subject', content: '{attr.kicker}', fontFamily: HEI, fontSize: pt(11),
    fontWeight: 700, color: col('paper'), letterSpacing: pt(2), align: 'center',
    box: { backgroundColor: col('green'), borderRadius: mm(1.5),
      padding: { top: mm(0.8), bottom: mm(0.8), left: mm(2.4), right: mm(2) } },
    placement: { anchor: { to: 'container', edge: 'top-left' },
      offset: { x: mm(0), y: mm(BAND - 22 + 6) } } },
  { kind: 'text', id: 'title', content: '{titleText}', fontFamily: HEI, fontSize: pt(24),
    fontWeight: 700, color: col('ink'), align: 'left',
    placement: { anchor: { to: '#subject', edge: 'right-of' },
      offset: { x: mm(4), y: mm(-2.6) } } },
  { kind: 'rule', id: 'rule', direction: 'horizontal', thickness: pt(1.2), color: col('green'),
    placement: { anchor: { to: 'container', edge: 'top-left' },
      offset: { x: mm(0), y: mm(BAND - 22 + 19) }, size: { width: 'fill' } } },
] } };

Il dipinto è ancorato alla pagina, quindi arriva al bordo superiore sia su un recto sia su un verso; la linguetta e il titolo si collocano dall’alto della gabbia di testo, sotto il piede del dipinto. Le due unità condividono il progetto grafico e cambiano solo negli attributi del titolo, kicker e pic.

#4 · Numeri di pagina al piede

script.js · righe 91–101nel codice completo
const foot = (id, content, parity, edge, x, extra = {}) => ({ kind: 'text', id, content,
  parity, fontFamily: HEI, fontSize: pt(8), color: col('muted'),
  placement: { anchor: { to: 'page', edge }, offset: { x: mm(x), y: mm(-10) } }, ...extra });
const footer = { elements: [
  foot('folio-v', '{pageNumber}', 'even', 'bottom-left', 16,
    { fontWeight: 700, color: col('green') }),
  foot('series', '{title}', 'even', 'bottom-left', 24),
  foot('unit', '{chapterTitle}', 'odd', 'bottom-right', -24, { align: 'right' }),
  foot('folio-r', '{pageNumber}', 'odd', 'bottom-right', -16,
    { fontWeight: 700, color: col('green'), align: 'right' }),
] };

I quaderni cinesi mettono il numero di pagina al piede. Il titolo della collana viene dal front matter del Markdown ({title}), quello dell’unità dal suo titolo ({chapterTitle}).

La ricetta completa

Sandbox
// ═══ Postext Cookbook · Nº 171 · A Chinese exercise book, pupil's and teacher's ═══
// https://postext.dev/en/cookbook/chinese-exercise-book
// Code: MIT · Text: original (CC BY 4.0) · Pictures: generated with diffusion models
// Fonts: Noto Serif SC, Noto Sans SC, LXGW WenKai TC (SIL OFL 1.1) · Needs postext ≥ 1.59.0
import {
  buildDocument, withLoadedFonts, renderPageToCanvas, registerResourceImage,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'zh'; // @lang: the language of the frame; the exercise book is Chinese in all
const RECIPE = 'chinese-exercise-book';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: a green exercise book, and the red of the teacher's pen
const palette = {
  ink: '#1f2523', // text: a green-tinted near-black
  green: '#2c7350', // the one accent: section numbers, the subject tab, the squares
  red: '#d0352c', // the teacher's answers
  tint: '#e6f2ea', // the subject tab's ground, the answers box
  rule: '#8fb9a2', // 田字格, the matching dots' lines
  muted: '#68736d', // folios, the series line
  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: 'accent (defaults)', value: { hex: palette.green, model: 'hex' } },
];
// #endregion
// 宋 for the text, 黑 for the instructions and labels, 楷 for what the teacher writes.
const [SONG, HEI, KAI] = ['Noto Serif SC', 'Noto Sans SC', 'LXGW WenKai TC'];
const CHARS = 40; // characters per line: 40 × 10.5 pt = 148 mm
const SIZE = 10.5; // pt: 五号, the size of a school book's text

// #region answer: sections 一、二、 that print the pupil's book or the teacher's
// The exercise style is the form; the Markdown holds every word, the points included. The
// same text builds both editions: `edition: 'teacher'` writes each answer into its blank,
// bracket and square in red Kai, rings the right options and draws the matching lines.
const lianxi = {
  id: 'lianxi',
  number: { format: 'simp-chinese-informal', suffix: '、', fontFamily: HEI, color: col('green') },
  instruction: { fontFamily: HEI, bold: false }, // 黑体, not bold: the points stay quiet
  // 选择题: A. B. C. D. in a row, a ( ) after the stem for the letter.
  options: { labels: 'alpha-upper', suffix: '.', layout: 'row', bracket: true },
  trueFalse: { look: 'bracket' }, // 判断题: ( ) at the end of the line, √ or ×
  blank: { look: 'line', color: col('ink') },
  area: { kind: 'tianzige', color: col('rule') }, // 写话 on 田字格
  match: { color: col('green') },

Lo script.js composto funziona così com’è: incollalo nello script modulo di qualsiasi pagina, oppure apri la ricetta su CodePen. Cartella della ricetta su GitHub ↗ (si apre in una nuova scheda)

Varianti

#Stampa le soluzioni a fine capitolo

Senza righe :::solutions, chapterEnd raccoglie le soluzioni di ogni unità prima del titolo di livello 1 successivo.

-  solutions: { placement: edition === 'teacher' ? 'none' : 'directive' } });
+  solutions: { placement: edition === 'teacher' ? 'none' : 'chapterEnd' } });

#Scrivi le letture accanto agli spazi vuoti

L’abbecedario in pinyin mette il pinyin sopra i suoi caratteri come ruby, cosa che uno spazio vuoto non può ancora contenere.

Errori frequenti

Errore frequente

I caratteri cinesi si caricano a fette, tramite il blocco cjk

Fontsource serve una famiglia cinese, giapponese o coreana come un centinaio di file per peso, ognuno dei quali copre un intervallo di caratteri. loadFonts scarica solo il file latin, così a schermo i caratteri Han vengono da un font di sistema e sono misurati male, e fontsourceProvider passa al PDF quel file latin, che li stampa come riquadri vuoti. Elenca il blocco cjk del kit, chiama loadCjkFonts(FONTS, markdown) dopo loadFonts (una volta per voce tipografica, con il testo che compone, quando il libro usa più caratteri CJK) e passa a renderToPdf fontProvider: cjkPdfProvider: entrambi prendono i file che contengono i caratteri del testo. Font cinesi, giapponesi e coreani →

  • Una lettura non può ancora stare sopra uno spazio vuoto: un ruby dentro [[…]] fa parte della risposta nascosta, e un’area di 田字格 occupa tutta la giustezza. La sezione 看拼音写词语 mette ogni sillaba su una riga sua e la casella sotto, quattro per fila in un gruppo :::columns.
  • Il carattere Kai compone solo le risposte, quindi carica soltanto i caratteri degli spazi vuoti e delle risposte modello; se compone un carattere altrove, va aggiunto a quel testo.

Crediti

Testo
Testo originale, CC BY 4.0
Immagini
  • A Chinese village in early spring: willows, swallows, peach blossom and two children on a path between rice fields. · Generated With Diffusion Models · originale
  • Two children count oranges, apples and pears at a grandmother's fruit stall, a cat on a stool beside them. · Generated With Diffusion Models · originale
Font
Noto Serif SC (SIL OFL 1.1) · Noto Sans SC (SIL OFL 1.1) · LXGW WenKai TC (SIL OFL 1.1)
Sandbox