Aller au contenu principal
Recette numéro 170

Recettes · Chapitre 12 · Manuels scolaires

Opérations posées comme les écrit chaque pays

Une fiche de calcul où chaque opération est une ligne - 864 ÷ 4 du Markdown, posée chiffre par chiffre en cases, la division à la manière de chaque pays.

Sur cette page
Niveau
Avancé
Postext
Testé avec Postext 1.59.0
Nécessite ≥ 1.59.0 · postext-pdf ≥ 1.59.0
Licence
Mis à jour le 24 oct. 2026
Code MIT · Texte CC BY 4.0
  • Format 210 × 297 mm
  • 1 colonne
  • Fira Sans 12/18
  • Lexend
  • 4 pages
  • Niveau
  • Postext 1.59.0
  • Mis en page en 55 ms
  • 118 lignes de code

En bref

Une page de calcul pour des enfants de neuf ans, en espagnol, en anglais, en français et en allemand. Chaque pays pose la division à sa façon et la fiche suit ; un interrupteur affiche la version de l’enseignant avec toutes les réponses.

Ce que vous allez composer

L’unité 3 d’un cahier de calcul de CM1, Les quatre opérations, en quatre éditions. Une rangée de calcul mental sur trois colonnes, puis des additions, des soustractions et des multiplications posées, un chiffre par case, avec une rangée de cases pour le résultat, enfin des divisions et un problème sur papier quadrillé. C’est à la division que les éditions se séparent : la fiche anglaise met le diviseur à l’extérieur du crochet ⟌ et le quotient au-dessus ; l’espagnole et la française placent le diviseur dans une potence à droite du dividende et le quotient dessous ; l’allemande écrit 864 : 4 = sur une ligne, avec de la place dessous pour les calculs intermédiaires, et note ses produits avec un point. La virgule ou le point décimal du calcul mental suit aussi la langue. Un interrupteur au-dessus des pages change la fiche de l’élève en version de l’enseignant, chaque réponse imprimée en orange dans sa case.

Cette recette répond à

  • Comment composer la division posée comme l'écrivent les écoles de chaque pays ?
  • Comment tirer le livre du professeur, réponses imprimées à leur place, du livre de l'élève ?

La réponse courte

script.js · lignes 26–42dans le code complet
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
  id: 'calculo',
  number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
  instruction: { bold: true, color: col('ink') },
  grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
    color: col('ink') },
  arithmetic: { columns: 4,
    division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
  blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
  area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
  answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
  marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};

Ingrédients

Typographie
Fira Sans, Lexend (SIL OFL 1.1)
Ressources
Aucune : chaque image est dessinée en code

Préparation

#1 · Écrire les opérations comme des lignes du Markdown

script.js · lignes 26–42dans le code complet
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
  id: 'calculo',
  number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
  instruction: { bold: true, color: col('ink') },
  grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
    color: col('ink') },
  arithmetic: { columns: 4,
    division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
  blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
  area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
  answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
  marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};

Un :::exercise{type="arithmetic"} prend une opération par élément de liste, - 864 ÷ 4, avec les signes qu’écrit son pays (÷, :, ×, ·). Le moteur calcule le résultat, le quotient et le reste, et le style décide du dessin de l’opération : des cases de 7,2 mm, et une arithmetic.division choisie pour chaque édition avec t(). Une rangée de calcul mental est un exercice à trous ordinaire dont la liste se trouve dans un groupe :::columns{count=3}, chaque [[70]] donnant une case de la même largeur que les autres.

#2 · Composer l’en-tête de la fiche

script.js · lignes 46–67dans le code complet
const at = (to, edge, x = 0, y = 0, size) => ({ anchor: { to, edge },
  offset: { x: mm(x), y: mm(y) }, ...(size && { size }) });
const field = (id, attr, x, width) => [
  { kind: 'text', id, content: `{attr.${attr}}`, fontFamily: LABEL, fontSize: pt(9.5),
    fontWeight: 600, color: col('muted'), align: 'left',
    placement: at('container', 'top-left', x, 26) },
  { kind: 'rule', id: `${id}-line`, direction: 'horizontal', thickness: pt(0.75),
    color: col('rule'), placement: at('container', 'top-left', x + 17, 31, { width: mm(width) }) },
];
const head = { enabled: true, minHeight: mm(36), slot: { elements: [
  { kind: 'box', id: 'band', style: { backgroundColor: col('accent'), borderRadius: mm(3) },
    placement: at('container', 'top-left', 0, 0, { width: 'fill', height: mm(19) }) },
  { kind: 'text', id: 'unit', content: '{attr.unidad}', fontFamily: LABEL, fontSize: pt(9),
    fontWeight: 700, color: col('accent'), align: 'center', verticalAlign: 'middle',
    textTransform: 'uppercase', letterSpacing: pt(1.2), lineHeight: 1.1,
    box: { backgroundColor: col('paper'), borderRadius: mm(3.5) },
    placement: at('container', 'top-left', 5, 5, { width: mm(26), height: mm(9) }) },
  { kind: 'text', id: 'title', content: '{titleText}', fontFamily: LABEL, fontSize: pt(21),
    fontWeight: 700, color: col('paper'), align: 'left', lineHeight: 1.1,
    placement: at('container', 'top-left', 37, 5.2) },
  ...field('name', 'nombre', 0, 100), ...field('date', 'fecha', 124, 38),
] } };

Le titre de niveau 1 de l’unité dessine le bandeau orange, la pastille et le titre, ainsi que les champs du prénom et de la date à partir de ses attributs (nombre="Name" fecha="Date") : chaque édition les intitule donc dans sa langue.

#3 · Passer de la fiche de l’élève à la version de l’enseignant

script.js · lignes 180–194dans le code complet
const form = document.getElementById('controls');
const labels = t({ es: ['Alumno', 'Profesor'], en: ['Pupil', 'Teacher'],
  fr: ['Élève', 'Enseignant'], de: ['Schüler', 'Lehrkraft'] });
form.querySelectorAll('label span').forEach((span, k) => { span.textContent = labels[k]; });
function render() {
  // The same config, edited in place: the next build sees the edition the form asks for.
  config.exercises.edition = form.elements.edition.value;
  const doc = buildDocument({ markdown }, config); // the faces are loaded by now
  showPages(doc, { title });
  document.querySelectorAll('#pt-actions a, [data-postext-pdf]').forEach((old) => old.remove());
  offerPdf(() => renderToPdf(doc, { fontProvider: fontsourceProvider }),
    `${RECIPE}-${LANG}-${config.exercises.edition}.pdf`);
}
form.addEventListener('change', render);
render();

exercises.edition: 'teacher' imprime chaque réponse à sa place, dans la couleur que donne answers.color, ici celle d’accent : les cases du calcul mental, les chiffres de chaque résultat, le quotient et le reste, la réponse modèle du problème. Le formulaire au-dessus des pages modifie la configuration sur place et relance la composition ; les polices sont déjà chargées, si bien que buildDocument suffit. La capture compose d’abord les deux fiches, et les pages publiées montrent la fiche de l’élève, puis celle de l’enseignant.

La recette complète

Sandbox
// ═══ Postext Cookbook · Nº 170 · Column arithmetic as each country writes it ═══════
// https://postext.dev/en/cookbook/column-arithmetic-by-country
// Code: MIT · Text: original (CC BY 4.0) · Pictures: none
// Fonts: Fira Sans, Lexend (SIL OFL 1.1) · Needs postext ≥ 1.59.0
import { buildDocumentWithFonts, buildDocument, renderPageToCanvas } from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'fr'; // @lang: the language of the worksheet ('es' | 'en' | 'fr' | 'de')
const RECIPE = 'column-arithmetic-by-country';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: ink, one orange accent, a pale tint, the grey of squared paper
const palette = {
  ink: '#1f2328', accent: '#c4511c', tint: '#fbeee6', rule: '#b9c0c8', muted: '#5f6670',
  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.accent, model: 'hex' } },
];
// #endregion
const [TEXT, LABEL] = ['Fira Sans', 'Lexend'];

// #region answer: operations in squares, long division as the edition's schools set it
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
  id: 'calculo',
  number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
  instruction: { bold: true, color: col('ink') },
  grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
    color: col('ink') },
  arithmetic: { columns: 4,
    division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
  blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
  area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
  answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
  marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};
// #endregion

// #region head: the unit pill, the title and the lines for a name and a date
const at = (to, edge, x = 0, y = 0, size) => ({ anchor: { to, edge },
  offset: { x: mm(x), y: mm(y) }, ...(size && { size }) });
const field = (id, attr, x, width) => [

Le script.js composé s’exécute tel quel : collez-le dans le script de module de n’importe quelle page, ou ouvrez la recette sur CodePen. Dossier de la recette sur GitHub ↗ (s’ouvre dans un nouvel onglet)

Variantes

#Mettre les solutions à l’envers en pied de page

Une habitude des cahiers de jeux : le corrigé de chaque exercice, retourné à 180° sous l’exercice.

-  exercises: { edition: 'student' }, // the switch above the pages sets 'teacher'
+  exercises: { edition: 'student', solutions: { placement: 'inverted', layout: 'key' } },

#Poser la division sous le crochet dans toutes les éditions

Les écoles japonaises et chinoises utilisent aussi le crochet ; une langue que vous ne nommez pas garde sa propre disposition.

-    division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
+    division: 'bracket' },

Erreurs fréquentes

  • Les opérations portent sur des nombres entiers : une opération avec des décimales comme 12,5 + 3,75 n’est pas lue et s’imprime telle qu’elle est écrite. Gardez les nombres décimaux dans les trous du calcul mental, où la réponse est du texte.

Crédits

Texte
Texte original, CC BY 4.0
Polices
Fira Sans (SIL OFL 1.1) · Lexend (SIL OFL 1.1)
SandboxPDF