本文へスキップ
レシピ番号171

レシピ集 · 第12章 · 教科書

中国語の練習帳(练习册)、児童用と教師用

国語と算数の练习册。一、二、の大問、( )のかっこ、田字格、筆算の竖式を、ひとつのテキストから児童用と教師用の2回組みます。

このページの内容
出力
Canvas · PDF
レベル
中級
Postext
Postext 1.59.0で検証済み
1.59.0以上が必要 · postext-pdf ≥ 1.59.0
ライセンス
2026年10月24日更新
コードMIT · 本文CC BY 4.0

1ページ(全8ページ)

  • 外国語の見本:日本語版はまだありません
  • 仕上がり184 × 260 mm
  • 1段
  • Noto Serif SC 10.5/21
  • LXGW WenKai TC
  • Noto Sans SC
  • 8ページ
  • レベル
  • Postext 1.59.0
  • 組版時間124 ms
  • コード162行

かんたんな説明

中国の小学校の練習帳です。国語と算数の2単元があります。同じテキストから、空欄があり単元末に解答が付く児童用と、すべての答えを赤字でその場に書いた教師用を作ります。

できあがり

小学2年生向けの练习册から2単元を、16开の判型で組みます。国語の単元「春天来了」と、100までのたし算とひき算を扱う算数の単元です。各単元は水彩画の帯、教科のタブ、クラスと名前と点数の行で始まり、中国の練習帳が刷る大問が続きます。看拼音写词语、丸で囲む読み、問いのあとに( )があり A. B. C. D. を1行に並べる选择题、行末にかっこがある判断题、穴埋め、量詞と物を結ぶ连线、田字格に書く一文、4列の口算、1桁に1マスの竖式、そして文章題です。配点は各問題の指示文の中にあり、児童はそこで読みます。同じ Markdown を2回組みます。児童用は各単元の終わりに参考答案を付け、教師用はすべての答えを赤い楷書体でその場所に書きます。

このレシピが答える質問

  • 中国語の選択問題(問の後の( )と一行に並ぶ A. B. C. D.)はどう組む?
  • 生徒用から、答えを欄に刷り込んだ教師用を作るには?
  • 記述問題の解答欄をセイエス罫、方眼、田字格にするには?
  • わり算の筆算を国ごとの学校の書き方で組むには?

手短な答え

script.js · 36〜65行コード全体で見る
// 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' } });

材料

種類
Noto Serif SC, Noto Sans SC, LXGW WenKai TC (SIL OFL 1.1)
素材
  • 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, オリジナル)
  • Two children count oranges, apples and pears at a grandmother's fruit stall, a cat on a stool beside them. (Generated With Diffusion Models, オリジナル)

作り方

#1 · すべての大問をひとつのスタイルで

コードは上の手短な答えにあります。大問は漢数字に全角の「、」を付けて数えるので、番号のあとに語間スペースは入りません。指示文は黒体で、太字にしません。かっこ内の配点が指示文の一部として読めるようにするためです。options.bracket が各問いのあとに( )を書き、教師用では正しい記号がその中に入ります。2つの小さなスタイルはメインのスタイルを拡張します。pinyin は空欄ごとに語と同じ幅の枠を描き、kuohao は何も描きません。「在( )里填」のかっこはテキストの中にあるからです。

#2 · 児童用と教師用をひとつのテキストから

script.js · 334〜338行コード全体で見る
const build = () => withLoadedFonts(() => buildDocument({ markdown, resources }, config()),
  { ...kitFonts(FONTS), text: markdown });
const pupil = await build();
edition = 'teacher';
const docs = [pupil, await build()];

設定は関数なので、組むたびに別のオブジェクトができ、Sandbox のバンドルには児童用の設定が残ります。edition: 'teacher' は answers の色と書体で答えを書きます。語は枠に、記号はかっこに、判断题には √ と × を、竖式のマスには数字を、例文は1マスに1字ずつ書きます。児童用は各単元の終わりにある :::solutions の行に解答を刷ります。教師用には要りません。

#3 · 絵の入った単元の扉

script.js · 69〜87行コード全体で見る
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' } } },
] } };

絵はページに固定されるので、奇数ページでも偶数ページでも上端まで届きます。教科のタブと題は版面の上端から配置し、絵の下端より下に来ます。2つの単元は同じデザインを使い、違うのは見出しの属性 kicker と pic だけです。

#4 · ノンブルは下に

script.js · 91〜101行コード全体で見る
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' }),
] };

中国の練習帳はノンブルをページの下に置きます。シリーズ名は Markdown のフロントマター({title})から、単元名は見出し({chapterTitle})から取ります。

レシピの全体

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') },

組み立てたscript.jsはそのまま動きます。任意のページのモジュールスクリプトに貼り付けるか、レシピをCodePenで開いてください。 GitHub上のレシピのフォルダー ↗ (新しいタブで開きます)

アレンジ

#解答を章末に刷る

:::solutions の行がなければ、chapterEnd が各単元の解答を次のレベル1の見出しの前にまとめます。

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

#空欄のそばに読みを書く

ピンインの入門読本は、字の上にピンインをルビとして載せます。空欄にはまだ載せられません。

よくあるつまずき

つまずき

中国語の書体はcjkブロックを通じてスライス単位で読み込む

Fontsourceは中国語、日本語、韓国語のファミリーを、ウェイトごとに約100個のファイルとして配信し、各ファイルが文字の範囲を受け持ちます。loadFontsが取得するのはlatinファイルだけなので、画面では漢字がシステムの書体で出て計測が狂い、fontsourceProviderはPDFにそのlatinファイルを渡すため、漢字が空の四角で印字されます。キットのcjkブロックを挙げ、loadFontsのあとにloadCjkFonts(FONTS, markdown)を呼び(本で複数のCJK書体を使うときは、それぞれの書体で組むテキストを渡して書体ごとに1回)、renderToPdfにfontProvider: cjkPdfProviderを渡してください。どちらもテキストの文字を含むファイルを取得します。 中国語・日本語・韓国語のフォント →

  • 空欄の上にはまだ読みを置けません。[[…]] の中のルビは隠れた答えの一部になり、田字格の領域は行の幅いっぱいを占めます。看拼音写词语の大問では、音節を1行ずつ置いてその下に枠を置き、:::columns のグループで1行に4つ並べます。
  • 楷書体は答えだけを組むので、空欄と模範解答の字だけを読み込みます。ほかの場所でこの書体を使う字があれば、そのテキストに加えてください。

クレジット

レシピ
Ignacio Ferro
本文
書き下ろしの文章, CC BY 4.0
画像
  • A Chinese village in early spring: willows, swallows, peach blossom and two children on a path between rice fields. · Generated With Diffusion Models · オリジナル
  • Two children count oranges, apples and pears at a grandmother's fruit stall, a cat on a stool beside them. · Generated With Diffusion Models · オリジナル
フォント
Noto Serif SC (SIL OFL 1.1) · Noto Sans SC (SIL OFL 1.1) · LXGW WenKai TC (SIL OFL 1.1)
Sandbox