Please prepare similar similar handbook for ESL 3rd grade students with similar variety of logical questions and answers under them (not funny ) questions on remaining topic like object pronouns,demonstrative pronouns and possessive pronouns, because possessive adjectives you have already made.
cd /home/daytona/workspace/attachments/469133f1-f8b2-45f4-bccf-c1a2a94490f5/ && …
cd /home/daytona/workspace/attachments/469133f1-f8b2-45f4-bccf-c1a2a94490f5/ && …
mkdir -p /home/daytona/workspace/esl-pronouns && ls /home/daytona/workspace/esl-…
~/esl-pronouns/build_handbooks.py
"""
ESL Grade 3 Pronouns Handbooks
Builds three PDFs: Object Pronouns, Demonstrative Pronouns, Possessive Pronouns
Matches the style of the existing Possessive Adjectives handbook.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os
# ── Colours (matching the blue-teal palette of the original) ──────────────────
DARK_BLUE = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#0A7D8C")
LIGHT_TEAL = colors.HexColor("#D9F0F3")
GOLD = colors.HexColor("#F5A623")
LIGHT_GOLD = colors.HexColor("#FFF8E7")
WHITE = colors.white
GREY_BG = colors.HexColor("#F4F6F9")
DARK_TEXT = colors.HexColor("#1A1A2E")
Q_BLUE = colors.HexColor("#E8F4FD")
A_GREEN = colors.HexColor("#E8F9EE")
PAGE_W, PAGE_H = A4
# ── Helper: base doc ──────────────────────────────────────────────────────────
def make_doc(filename):
return SimpleDocTemplate(
filename,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm
)
# ── Styles ────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()
def sty(name, **kw):
base = kw.pop("parent", "Normal")
s = ParagraphStyle(name, parent=ss[base], **kw)
return s
COVER_TITLE = sty("CoverTitle", fontSize=34, leading=40, alignment=TA_CENTER,
textColor=WHITE, fontName="Helvetica-Bold")
COVER_SUB = sty("CoverSub", fontSize=16, leading=22, alignment=TA_CENTER,
textColor=LIGHT_TEAL, fontName="Helvetica")
COVER_RU = sty("CoverRu", fontSize=13, leading=18, alignment=TA_CENTER,
textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica")
COVER_BAND = sty("CoverBand", fontSize=11, leading=16, alignment=TA_CENTER,
textColor=WHITE, fontName="Helvetica")
COVER_TAGLINE = sty("CoverTag", fontSize=10, leading=14, alignment=TA_CENTER,
textColor=colors.HexColor("#FFE0A0"), fontName="Helvetica-Oblique")
SEC_HEAD = sty("SecHead", fontSize=15, leading=20, alignment=TA_CENTER,
textColor=DARK_BLUE, fontName="Helvetica-Bold")
SEC_HEAD_RU = sty("SecHeadRu", fontSize=11, leading=15, alignment=TA_CENTER,
textColor=TEAL, fontName="Helvetica-Oblique")
BODY = sty("Body", fontSize=11, leading=16, alignment=TA_JUSTIFY,
textColor=DARK_TEXT, fontName="Helvetica")
BODY_RU = sty("BodyRu", fontSize=10, leading=14, alignment=TA_JUSTIFY,
textColor=colors.HexColor("#444466"), fontName="Helvetica-Oblique")
EXAMPLE_EN = sty("ExEN", fontSize=11, leading=16, alignment=TA_LEFT,
textColor=DARK_BLUE, fontName="Helvetica-Bold")
EXAMPLE_RU = sty("ExRU", fontSize=10, leading=14, alignment=TA_LEFT,
textColor=TEAL, fontName="Helvetica-Oblique")
Q_STYLE = sty("QStyle", fontSize=11, leading=16, alignment=TA_LEFT,
textColor=DARK_BLUE, fontName="Helvetica-Bold")
A_STYLE = sty("AStyle", fontSize=11, leading=16, alignment=TA_LEFT,
textColor=colors.HexColor("#1A6B2E"), fontName="Helvetica")
RU_Q = sty("RuQ", fontSize=9, leading=13, alignment=TA_LEFT,
textColor=colors.HexColor("#555577"), fontName="Helvetica-Oblique")
RU_A = sty("RuA", fontSize=9, leading=13, alignment=TA_LEFT,
textColor=colors.HexColor("#2A7A44"), fontName="Helvetica-Oblique")
TABLE_HEADER = sty("TblHdr", fontSize=11, leading=14, alignment=TA_CENTER,
textColor=WHITE, fontName="Helvetica-Bold")
TABLE_CELL = sty("TblCell", fontSize=10, leading=13, alignment=TA_LEFT,
textColor=DARK_TEXT, fontName="Helvetica")
TABLE_RU = sty("TblRu", fontSize=9, leading=12, alignment=TA_LEFT,
textColor=colors.HexColor("#555577"), fontName="Helvetica-Oblique")
NOTE_STYLE = sty("Note", fontSize=10, leading=14, alignment=TA_CENTER,
textColor=DARK_BLUE, fontName="Helvetica-Bold")
NOTE_RU = sty("NoteRu", fontSize=9, leading=13, alignment=TA_CENTER,
textColor=TEAL, fontName="Helvetica-Oblique")
# ── Reusable page-section divider ─────────────────────────────────────────────
def divider():
return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=6, spaceBefore=6)
# ── Coloured box paragraph ────────────────────────────────────────────────────
def colour_box(content_rows, bg=LIGHT_TEAL, padding=8, col_widths=None):
"""Wrap paragraphs in a single-cell table to get a coloured background."""
inner = []
for row in content_rows:
if isinstance(row, str):
inner.append(Paragraph(row, BODY))
else:
inner.append(row)
data = [[inner]]
col_w = col_widths or [PAGE_W - 4*cm]
t = Table(data, colWidths=col_w)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROUNDEDCORNERS", [8]),
("BOX", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), padding),
("BOTTOMPADDING",(0,0),(-1,-1), padding),
("LEFTPADDING", (0,0), (-1,-1), padding),
("RIGHTPADDING",(0,0), (-1,-1), padding),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return t
# ── Cover page helper ─────────────────────────────────────────────────────────
def cover_page(story, en_title, ru_title, pronoun_list_en, pronoun_list_ru, emoji_row="📚 ✏️ 📚"):
"""Build a cover page matching the original handbook."""
# Full-width navy header box
header_data = [[
Paragraph(f"Grade 3 ESL", COVER_BAND),
]]
header_data2 = [[
Paragraph("3-й класс ЭСЛ", COVER_BAND),
]]
# Build cover as a big coloured table
cover_table_data = [
[Paragraph(emoji_row, sty("emoji", fontSize=26, leading=32, alignment=TA_CENTER, fontName="Helvetica"))],
[Spacer(1, 0.3*cm)],
[Paragraph(en_title, COVER_TITLE)],
[Paragraph(ru_title, COVER_RU)],
[Spacer(1, 0.4*cm)],
[Paragraph("Handbook – Table, Formula & Conversations", COVER_SUB)],
[Paragraph("Справочник – таблица, формула и разговоры", COVER_RU)],
[Spacer(1, 0.4*cm)],
[Paragraph(pronoun_list_en, COVER_BAND)],
[Paragraph(pronoun_list_ru, COVER_RU)],
[Spacer(1, 0.5*cm)],
[Paragraph("English ⇄ Russian", sty("lang", fontSize=13, leading=18, alignment=TA_CENTER,
textColor=GOLD, fontName="Helvetica-Bold"))],
[Paragraph("Английский ⇄ Русский", COVER_RU)],
[Spacer(1, 0.5*cm)],
[Paragraph("Made with ❤️ for young learners", COVER_TAGLINE)],
[Paragraph("Создано с ❤️ для юных учеников", COVER_TAGLINE)],
]
cover_t = Table(cover_table_data, colWidths=[PAGE_W - 4*cm])
cover_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 18),
("RIGHTPADDING", (0,0), (-1,-1), 18),
("BOX", (0,0), (-1,-1), 2, GOLD),
]))
story.append(cover_t)
story.append(Spacer(1, 0.5*cm))
# ── Q&A block ─────────────────────────────────────────────────────────────────
def qa_block(story, q_en, q_ru, a_en, a_ru, q_num):
"""Render a single Q-and-A pair in the conversation style."""
q_data = [
[Paragraph(f"❓ Q{q_num}: {q_en}", Q_STYLE)],
[Paragraph(q_ru, RU_Q)],
]
a_data = [
[Paragraph(f"✅ {a_en}", A_STYLE)],
[Paragraph(a_ru, RU_A)],
]
w = [PAGE_W - 4*cm]
qt = Table(q_data, colWidths=w)
qt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), Q_BLUE),
("BOX", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING",(0,0),(-1,-1), 8),
("RIGHTPADDING",(0,0),(-1,-1), 8),
]))
at = Table(a_data, colWidths=w)
at.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), A_GREEN),
("BOX", (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING",(0,0),(-1,-1), 8),
("RIGHTPADDING",(0,0),(-1,-1), 8),
]))
story.append(KeepTogether([qt, Spacer(1,0.15*cm), at, Spacer(1,0.3*cm)]))
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
doc = make_doc(out)
story = []
# ── Cover ────────────────────────────────────────────────────────────────
cover_page(
story,
en_title="Object\nPronouns",
ru_title="Объектные местоимения",
pronoun_list_en="Me • You • Him • Her • It • Us • Them",
pronoun_list_ru="Меня • Тебя • Его • Её • Его/Её • Нас • Их",
emoji_row="📚 ✏️ 📚"
)
# ── Page 2 – What is an Object Pronoun? ───────────────────────────────────
story.append(divider())
story.append(Paragraph("What is an Object Pronoun? 🤔", SEC_HEAD))
story.append(Paragraph("Что такое объектное местоимение?", SEC_HEAD_RU))
story.append(Spacer(1, 0.3*cm))
defn_rows = [
Paragraph("An <b>object pronoun</b> replaces the name of a person or thing that receives the action of a verb. It always comes <b>after</b> the verb or a preposition.", BODY),
Spacer(1, 0.2*cm),
Paragraph("<b>Объектное местоимение</b> заменяет имя человека или предмета, на которое направлено действие глагола. Оно всегда стоит <b>после</b> глагола или предлога.", BODY_RU),
]
story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
story.append(Spacer(1, 0.3*cm))
examples = [
("🤔 She sees <b>me</b> every morning.", "Она видит <b>меня</b> каждое утро."),
("🤔 The teacher called <b>him</b>.", "Учитель позвал <b>его</b>."),
("🤔 Can you help <b>us</b>?", "Можешь помочь <b>нам</b>?"),
]
for en, ru in examples:
story.append(Paragraph(en, EXAMPLE_EN))
story.append(Paragraph(ru, EXAMPLE_RU))
story.append(Spacer(1, 0.15*cm))
# ── Page 3 – Table ────────────────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Object Pronouns Table", SEC_HEAD))
story.append(Paragraph("Таблица объектных местоимений", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
tbl_data = [
[Paragraph("Object Pronoun (EN)\nОбъектное местоимение", TABLE_HEADER),
Paragraph("Russian Translation\nПеревод на русский", TABLE_HEADER),
Paragraph("Example Sentence\nПример предложения", TABLE_HEADER)],
[Paragraph("ME\nМЕНЯ", TABLE_CELL), Paragraph("меня / мне\nМЕНЯ / МНЕ", TABLE_RU), Paragraph("She called me.\nОна позвонила мне.", TABLE_CELL)],
[Paragraph("YOU\nТЕБЯ / ВАС", TABLE_CELL), Paragraph("тебя / вас\nТЕБЯ / ВАС", TABLE_RU), Paragraph("I see you every day.\nЯ вижу тебя каждый день.", TABLE_CELL)],
[Paragraph("HIM\nЕГО", TABLE_CELL), Paragraph("его / ему\nЕГО / ЕМУ", TABLE_RU), Paragraph("We helped him.\nМы помогли ему.", TABLE_CELL)],
[Paragraph("HER\nЕЁ", TABLE_CELL), Paragraph("её / ей\nЕЁ / ЕЙ", TABLE_RU), Paragraph("He thanked her.\nОн поблагодарил её.", TABLE_CELL)],
[Paragraph("IT\nЕГО / ЕЁ", TABLE_CELL), Paragraph("его / её\nЕГО / ЕЁ", TABLE_RU), Paragraph("I can see it clearly.\nЯ вижу его отчётливо.", TABLE_CELL)],
[Paragraph("US\nНАС", TABLE_CELL), Paragraph("нас / нам\nНАС / НАМ", TABLE_RU), Paragraph("She invited us.\nОна пригласила нас.", TABLE_CELL)],
[Paragraph("THEM\nИХ", TABLE_CELL), Paragraph("их / им\nИХ / ИМ", TABLE_RU), Paragraph("I know them well.\nЯ знаю их хорошо.", TABLE_CELL)],
]
col_w = [4*cm, 4.5*cm, 7*cm]
tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), LIGHT_TEAL),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), LIGHT_TEAL),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BACKGROUND", (0,5), (-1,5), LIGHT_TEAL),
("BACKGROUND", (0,6), (-1,6), WHITE),
("BACKGROUND", (0,7), (-1,7), LIGHT_TEAL),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(tbl)
# ── Page 4 – Formula ──────────────────────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(divider())
story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
story.append(Spacer(1, 0.2*cm))
formula_data = [[
Paragraph("SUBJECT", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("VERB", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("OBJECT PRONOUN", TABLE_HEADER),
]]
ftbl = Table(formula_data, colWidths=[3.5*cm, 0.8*cm, 3.5*cm, 0.8*cm, 5.4*cm])
ftbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), DARK_BLUE),
("BACKGROUND", (1,0), (1,0), WHITE),
("BACKGROUND", (2,0), (2,0), TEAL),
("BACKGROUND", (3,0), (3,0), WHITE),
("BACKGROUND", (4,0), (4,0), GOLD),
("BOX", (0,0), (-1,-1), 1, DARK_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(ftbl)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
story.append(Spacer(1, 0.15*cm))
formula_examples = [
("She", "sees", "me", "Она видит меня."),
("We", "helped", "him", "Мы помогли ему."),
("The teacher", "called", "them", "Учитель позвал их."),
("I", "will call", "you tomorrow", "Я позвоню тебе завтра."),
("They", "surprised", "us", "Они удивили нас."),
("He", "thanked", "her", "Он поблагодарил её."),
]
fe_data = [[Paragraph("Subject\nПодлежащее", TABLE_HEADER),
Paragraph("Verb\nГлагол", TABLE_HEADER),
Paragraph("Object Pronoun\nОбъектное мест.", TABLE_HEADER),
Paragraph("Translation\nПеревод", TABLE_HEADER)]]
for s, v, op, ru in formula_examples:
fe_data.append([Paragraph(s, TABLE_CELL), Paragraph(v, TABLE_CELL),
Paragraph(op, TABLE_CELL), Paragraph(ru, TABLE_RU)])
fetbl = Table(fe_data, colWidths=[3.5*cm, 3*cm, 4*cm, 5*cm], repeatRows=1)
fetbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(fetbl)
# ── Pages 5–7 – Conversations Q1–Q15 ─────────────────────────────────────
conversations = [
# Q, Q_ru, A, A_ru
("Who did the teacher call to the board?",
"Кого учитель вызвал к доске?",
"She called me. I walked to the board and wrote the answer.",
"Она вызвала меня. Я подошёл к доске и написал ответ."),
("Can you see the bird on the tree?",
"Ты видишь птицу на дереве?",
"Yes, I can see it. It is sitting very still on the branch.",
"Да, я вижу её. Она сидит очень тихо на ветке."),
("Did your friends invite you to the party?",
"Твои друзья пригласили тебя на вечеринку?",
"Yes, they invited me and I am very excited to go.",
"Да, они пригласили меня, и я очень рад идти."),
("Who helped Tim with his homework?",
"Кто помог Тиму с домашним заданием?",
"His older sister helped him. She explained every problem clearly.",
"Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),
("Did the coach choose Sara for the team?",
"Тренер выбрал Сару в команду?",
"Yes, the coach chose her. She is a very fast runner.",
"Да, тренер выбрал её. Она очень быстро бегает."),
("Did you and your class win the quiz?",
"Ты и твой класс выиграли викторину?",
"Yes! The principal gave us a trophy and took our photograph.",
"Да! Директор вручил нам кубок и сфотографировал нас."),
("Where are the new books? Did the librarian bring them?",
"Где новые книги? Библиотекарь принёс их?",
"Yes, she brought them this morning and put them on the shelf.",
"Да, она принесла их этим утром и поставила на полку."),
("Your dog ran away — did anyone find it?",
"Твоя собака убежала — кто-нибудь нашёл её?",
"The neighbour found it and brought it home safely.",
"Сосед нашёл её и безопасно привёл домой."),
("Did your teacher read your story?",
"Учитель прочитал твой рассказ?",
"Yes, she read it and said it was very creative.",
"Да, она прочитала его и сказала, что он очень творческий."),
("Can we sit with you at lunch?",
"Мы можем сесть с тобой на обед?",
"Of course! You can sit next to me. There is enough room.",
"Конечно! Вы можете сесть рядом со мной. Места достаточно."),
("Did the doctor check Max and Lily?",
"Врач осмотрел Макса и Лили?",
"Yes, the doctor checked them and said they are both healthy.",
"Да, врач осмотрел их и сказал, что они оба здоровы."),
("Who did you wave to at the gate?",
"Кому ты помахал у ворот?",
"I waved to her. She waved back and smiled at me.",
"Я помахал ей. Она помахала в ответ и улыбнулась мне."),
("Can your father drive us to school?",
"Твой папа может отвезти нас в школу?",
"Yes, he can drive us. He leaves at 7:30 every morning.",
"Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),
("Did the storm damage the fence?",
"Буря повредила забор?",
"Yes, it damaged it badly. My father will repair it on Saturday.",
"Да, она сильно повредила его. Мой папа починит его в субботу."),
("Why did the principal call you and Tom?",
"Почему директор вызвал тебя и Тома?",
"She called us because we won first place in the science fair.",
"Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
]
# Split into 3 pages (Q1-5, Q6-10, Q11-15)
for page_idx, start in enumerate([0, 5, 10]):
story.append(divider())
end = start + 5
story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
qa_block(story, qe, qr, ae, ar, i)
# ── Page 8 – Quick Reference ──────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
qref_data = [
[Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
Paragraph("Russian\nПо-русски", TABLE_HEADER),
Paragraph("Quick Example (EN + RU)\nПример (англ. + рус.)", TABLE_HEADER)],
[Paragraph("ME\nМЕНЯ", TABLE_CELL),
Paragraph("меня/мне", TABLE_RU),
Paragraph("She sees me.\nОна видит меня.", TABLE_CELL)],
[Paragraph("YOU\nТЕБЯ", TABLE_CELL),
Paragraph("тебя/вас", TABLE_RU),
Paragraph("I called you.\nЯ позвонил тебе.", TABLE_CELL)],
[Paragraph("HIM\nЕГО", TABLE_CELL),
Paragraph("его/ему", TABLE_RU),
Paragraph("We helped him.\nМы помогли ему.", TABLE_CELL)],
[Paragraph("HER\nЕЁ", TABLE_CELL),
Paragraph("её/ей", TABLE_RU),
Paragraph("He thanked her.\nОн поблагодарил её.", TABLE_CELL)],
[Paragraph("IT\nЕГО/ЕЁ", TABLE_CELL),
Paragraph("его/её", TABLE_RU),
Paragraph("I can see it.\nЯ вижу его.", TABLE_CELL)],
[Paragraph("US\nНАС", TABLE_CELL),
Paragraph("нас/нам", TABLE_RU),
Paragraph("She invited us.\nОна пригласила нас.", TABLE_CELL)],
[Paragraph("THEM\nИХ", TABLE_CELL),
Paragraph("их/им", TABLE_RU),
Paragraph("I know them.\nЯ знаю их.", TABLE_CELL)],
]
qref_tbl = Table(qref_data, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
qref_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(qref_tbl)
story.append(Spacer(1, 0.3*cm))
story.append(colour_box([
Paragraph("🤔 Object pronouns come AFTER the verb or preposition! • Объектные местоимения стоят ПОСЛЕ глагола или предлога!", NOTE_STYLE)
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ Created: {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
doc = make_doc(out)
story = []
# ── Cover ────────────────────────────────────────────────────────────────
cover_page(
story,
en_title="Demonstrative\nPronouns",
ru_title="Указательные местоимения",
pronoun_list_en="This • That • These • Those",
pronoun_list_ru="Этот/Эта/Это • Тот/Та/То • Эти • Те",
emoji_row="📚 ✏️ 📚"
)
# ── Page 2 – What is a Demonstrative Pronoun? ─────────────────────────────
story.append(divider())
story.append(Paragraph("What is a Demonstrative Pronoun? 🤔", SEC_HEAD))
story.append(Paragraph("Что такое указательное местоимение?", SEC_HEAD_RU))
story.append(Spacer(1, 0.3*cm))
defn_rows = [
Paragraph("A <b>demonstrative pronoun</b> points to a specific person or thing. <b>This</b> and <b>these</b> are used for things that are <b>near</b>. <b>That</b> and <b>those</b> are used for things that are <b>far away</b>.", BODY),
Spacer(1, 0.2*cm),
Paragraph("<b>Указательное местоимение</b> указывает на конкретного человека или предмет. <b>This/These</b> — для близких предметов. <b>That/Those</b> — для далёких.", BODY_RU),
]
story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
story.append(Spacer(1, 0.3*cm))
examples = [
("🤔 <b>This</b> is my pencil. (near me)", "<b>Это</b> мой карандаш. (рядом со мной)"),
("🤔 <b>That</b> is a tall building. (far away)", "<b>То</b> — высокое здание. (далеко)"),
("🤔 <b>These</b> are my books.", "<b>Эти</b> — мои книги."),
("🤔 <b>Those</b> are his shoes.", "<b>Те</b> — его туфли."),
]
for en, ru in examples:
story.append(Paragraph(en, EXAMPLE_EN))
story.append(Paragraph(ru, EXAMPLE_RU))
story.append(Spacer(1, 0.15*cm))
# ── Page 3 – Table ────────────────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Demonstrative Pronouns Table", SEC_HEAD))
story.append(Paragraph("Таблица указательных местоимений", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
tbl_data = [
[Paragraph("Demonstrative\nУказательное", TABLE_HEADER),
Paragraph("Number / Distance\nЧисло / Расстояние", TABLE_HEADER),
Paragraph("Russian\nПо-русски", TABLE_HEADER),
Paragraph("Example Sentence\nПример", TABLE_HEADER)],
[Paragraph("THIS\nЭТО", TABLE_CELL),
Paragraph("Singular / Near\nЕд.ч. / Близко", TABLE_RU),
Paragraph("этот / эта / это", TABLE_RU),
Paragraph("This is my bag.\nЭта сумка — моя.", TABLE_CELL)],
[Paragraph("THAT\nТО", TABLE_CELL),
Paragraph("Singular / Far\nЕд.ч. / Далеко", TABLE_RU),
Paragraph("тот / та / то", TABLE_RU),
Paragraph("That is a big tree.\nТо — большое дерево.", TABLE_CELL)],
[Paragraph("THESE\nЭТИ", TABLE_CELL),
Paragraph("Plural / Near\nМн.ч. / Близко", TABLE_RU),
Paragraph("эти", TABLE_RU),
Paragraph("These are my crayons.\nЭти — мои карандаши.", TABLE_CELL)],
[Paragraph("THOSE\nТЕ", TABLE_CELL),
Paragraph("Plural / Far\nМн.ч. / Далеко", TABLE_RU),
Paragraph("те", TABLE_RU),
Paragraph("Those are her books.\nТе — её книги.", TABLE_CELL)],
]
col_w = [3*cm, 4*cm, 4*cm, 5.5*cm]
tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), LIGHT_TEAL),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), LIGHT_TEAL),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(tbl)
# Near vs Far visual note
story.append(Spacer(1, 0.3*cm))
near_far_data = [
[Paragraph("📍 NEAR (близко)", sty("nf1", fontSize=11, leading=14, alignment=TA_CENTER,
textColor=DARK_BLUE, fontName="Helvetica-Bold")),
Paragraph("📍 FAR (далеко)", sty("nf2", fontSize=11, leading=14, alignment=TA_CENTER,
textColor=DARK_BLUE, fontName="Helvetica-Bold"))],
[Paragraph("Singular: <b>THIS</b> (ед.ч.)\nPlural: <b>THESE</b> (мн.ч.)", TABLE_CELL),
Paragraph("Singular: <b>THAT</b> (ед.ч.)\nPlural: <b>THOSE</b> (мн.ч.)", TABLE_CELL)],
]
nf_tbl = Table(near_far_data, colWidths=[7.75*cm, 7.75*cm])
nf_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), colors.HexColor("#DFF5E1")),
("BACKGROUND", (1,0), (1,-1), colors.HexColor("#FFF0D0")),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
]))
story.append(nf_tbl)
# ── Page 4 – Formula ──────────────────────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(divider())
story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
story.append(Spacer(1, 0.2*cm))
formula_data = [[
Paragraph("DEM. PRONOUN", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("IS / ARE", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("REST OF SENTENCE", TABLE_HEADER),
]]
ftbl = Table(formula_data, colWidths=[4.5*cm, 0.8*cm, 3*cm, 0.8*cm, 5.4*cm])
ftbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), DARK_BLUE),
("BACKGROUND", (1,0), (1,0), WHITE),
("BACKGROUND", (2,0), (2,0), TEAL),
("BACKGROUND", (3,0), (3,0), WHITE),
("BACKGROUND", (4,0), (4,0), GOLD),
("BOX", (0,0), (-1,-1), 1, DARK_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(ftbl)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
story.append(Spacer(1, 0.15*cm))
formula_examples = [
("This", "is", "my notebook.", "Это мой блокнот."),
("That", "is", "a very old bridge.", "То — очень старый мост."),
("These", "are", "fresh apples.", "Эти — свежие яблоки."),
("Those", "are", "my father's tools.", "Те — инструменты моего папы."),
("This", "is", "the correct answer.", "Это правильный ответ."),
("Those", "are", "wild birds.", "Те — дикие птицы."),
]
fe_data = [[Paragraph("Dem. Pronoun\nУказат. мест.", TABLE_HEADER),
Paragraph("Verb\nГлагол", TABLE_HEADER),
Paragraph("Rest\nОстаток", TABLE_HEADER),
Paragraph("Translation\nПеревод", TABLE_HEADER)]]
for dp, v, rest, ru in formula_examples:
fe_data.append([Paragraph(dp, TABLE_CELL), Paragraph(v, TABLE_CELL),
Paragraph(rest, TABLE_CELL), Paragraph(ru, TABLE_RU)])
fetbl = Table(fe_data, colWidths=[3.5*cm, 2.5*cm, 5*cm, 4.5*cm], repeatRows=1)
fetbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(fetbl)
# ── Conversations Q1–Q15 ──────────────────────────────────────────────────
conversations = [
("What is that tall building near the park?",
"Что это за высокое здание у парка?",
"That is the new library. It opened last month and has many books.",
"То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),
("Are these your colour pencils on the table?",
"Это твои цветные карандаши на столе?",
"Yes, these are mine. I use them for my art class every Friday.",
"Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),
("What is this small animal in the box?",
"Что это за маленькое животное в коробке?",
"This is a hamster. This is my pet and its name is Peanut.",
"Это хомяк. Это моё домашнее животное, его зовут Пинат."),
("Whose shoes are those by the front door?",
"Чьи это туфли у парадной двери?",
"Those are my father's shoes. He always leaves them there after work.",
"Те — туфли моего папы. Он всегда оставляет их там после работы."),
("Is this the right classroom for Grade 3?",
"Это правильный класс для 3-го класса?",
"Yes, this is the right one. Our teacher is already inside.",
"Да, это правильный. Наш учитель уже внутри."),
("What are those colourful flags on the wall?",
"Что это за разноцветные флаги на стене?",
"Those are country flags. Our teacher put them up for a geography lesson.",
"Те — флаги стран. Наш учитель повесил их для урока географии."),
("Is this water safe to drink?",
"Эта вода безопасна для питья?",
"Yes, this is clean drinking water from the school filter.",
"Да, это чистая питьевая вода из школьного фильтра."),
("What are these papers on your desk?",
"Что это за бумаги на твоём столе?",
"These are my test results. I got a high score in all subjects.",
"Это мои результаты тестов. Я получил высокий балл по всем предметам."),
("Can you see those children in the yard?",
"Ты видишь тех детей во дворе?",
"Yes, I can see them. Those are my classmates playing football.",
"Да, я вижу их. Те — мои одноклассники, они играют в футбол."),
("Whose drawing is this on the board?",
"Чей это рисунок на доске?",
"This is Anna's drawing. She drew it during free time today.",
"Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),
("Are those mountains real or in a picture?",
"Те горы настоящие или на картинке?",
"Those are real mountains. We can see them from the school roof.",
"Те горы настоящие. Мы можем видеть их с крыши школы."),
("What is this sweet smell in the kitchen?",
"Что это за сладкий запах на кухне?",
"This is the smell of fresh bread. The cook baked it this morning.",
"Это запах свежего хлеба. Повар испёк его этим утром."),
("Are these apples from your garden?",
"Эти яблоки из вашего сада?",
"Yes, these are from our garden. My mother picked them yesterday.",
"Да, эти — из нашего сада. Мама сорвала их вчера."),
("What are those bright lights in the sky?",
"Что это за яркие огни в небе?",
"Those are stars. On a clear night you can count hundreds of them.",
"Те — звёзды. В ясную ночь можно сосчитать сотни из них."),
("Is this the book you wanted to borrow?",
"Это та книга, которую ты хотел взять?",
"Yes, this is the one! I have been looking for it all week.",
"Да, это она! Я искал её всю неделю."),
]
for start in [0, 5, 10]:
end = start + 5
story.append(divider())
story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
qa_block(story, qe, qr, ae, ar, i)
# ── Quick Reference Card ──────────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
qref_data = [
[Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
Paragraph("Use\nКогда", TABLE_HEADER),
Paragraph("Russian\nПо-русски", TABLE_HEADER),
Paragraph("Quick Example (EN + RU)\nПример", TABLE_HEADER)],
[Paragraph("THIS\nЭТО", TABLE_CELL),
Paragraph("Singular / Near\nЕд.ч./Близко", TABLE_RU),
Paragraph("этот/эта/это", TABLE_RU),
Paragraph("This is my pen.\nЭто моя ручка.", TABLE_CELL)],
[Paragraph("THAT\nТО", TABLE_CELL),
Paragraph("Singular / Far\nЕд.ч./Далеко", TABLE_RU),
Paragraph("тот/та/то", TABLE_RU),
Paragraph("That is a cloud.\nТо — облако.", TABLE_CELL)],
[Paragraph("THESE\nЭТИ", TABLE_CELL),
Paragraph("Plural / Near\nМн.ч./Близко", TABLE_RU),
Paragraph("эти", TABLE_RU),
Paragraph("These are my boots.\nЭти — мои сапоги.", TABLE_CELL)],
[Paragraph("THOSE\nТЕ", TABLE_CELL),
Paragraph("Plural / Far\nМн.ч./Далеко", TABLE_RU),
Paragraph("те", TABLE_RU),
Paragraph("Those are tall trees.\nТе — высокие деревья.", TABLE_CELL)],
]
qref_tbl = Table(qref_data, colWidths=[3*cm, 3.5*cm, 3.5*cm, 5.5*cm], repeatRows=1)
qref_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(qref_tbl)
story.append(Spacer(1, 0.3*cm))
story.append(colour_box([
Paragraph("🤔 THIS/THESE = near you • THAT/THOSE = far away • THIS/THAT = singular • THESE/THOSE = plural", NOTE_STYLE),
Paragraph("THIS/THESE = рядом • THAT/THOSE = далеко • THIS/THAT = ед. число • THESE/THOSE = мн. число", NOTE_RU),
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ Created: {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
doc = make_doc(out)
story = []
# ── Cover ────────────────────────────────────────────────────────────────
cover_page(
story,
en_title="Possessive\nPronouns",
ru_title="Притяжательные местоимения (самостоятельные)",
pronoun_list_en="Mine • Yours • His • Hers • Ours • Theirs",
pronoun_list_ru="Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их",
emoji_row="📚 ✏️ 📚"
)
# ── Page 2 – What is a Possessive Pronoun? ────────────────────────────────
story.append(divider())
story.append(Paragraph("What is a Possessive Pronoun? 🤔", SEC_HEAD))
story.append(Paragraph("Что такое притяжательное местоимение (самостоятельное)?", SEC_HEAD_RU))
story.append(Spacer(1, 0.3*cm))
defn_rows = [
Paragraph("A <b>possessive pronoun</b> shows that something belongs to someone. Unlike possessive adjectives (my, your, his…), possessive pronouns <b>stand alone</b> — they do not come before a noun.", BODY),
Spacer(1, 0.2*cm),
Paragraph("<b>Притяжательное местоимение</b> показывает принадлежность. В отличие от притяжательных прилагательных (my, your, his…), оно стоит <b>самостоятельно</b> — без существительного.", BODY_RU),
]
story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
story.append(Spacer(1, 0.3*cm))
examples = [
("🤔 This pencil is <b>mine</b>.", "Этот карандаш — <b>мой</b>."),
("🤔 That red bag is <b>hers</b>.", "Та красная сумка — <b>её</b>."),
("🤔 The blue umbrella is <b>ours</b>.", "Синий зонт — <b>наш</b>."),
("🤔 Those books are <b>theirs</b>.", "Те книги — <b>их</b>."),
]
for en, ru in examples:
story.append(Paragraph(en, EXAMPLE_EN))
story.append(Paragraph(ru, EXAMPLE_RU))
story.append(Spacer(1, 0.15*cm))
# ── Possessive Adjective vs Pronoun note ──────────────────────────────────
story.append(Spacer(1, 0.2*cm))
cmp_data = [
[Paragraph("Possessive ADJECTIVE\n(before a noun)", TABLE_HEADER),
Paragraph("Possessive PRONOUN\n(stands alone)", TABLE_HEADER)],
[Paragraph("This is <b>my</b> book.\nЭто <b>моя</b> книга.", TABLE_CELL),
Paragraph("This book is <b>mine</b>.\nЭта книга — <b>моя</b>.", TABLE_CELL)],
[Paragraph("<b>Your</b> pencil is sharp.\n<b>Твой</b> карандаш острый.", TABLE_CELL),
Paragraph("The sharp pencil is <b>yours</b>.\nОстрый карандаш — <b>твой</b>.", TABLE_CELL)],
]
cmp_tbl = Table(cmp_data, colWidths=[7.75*cm, 7.75*cm])
cmp_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (0,-1), colors.HexColor("#FFF0D0")),
("BACKGROUND", (1,1), (1,-1), colors.HexColor("#DFF5E1")),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
]))
story.append(cmp_tbl)
# ── Page 3 – Table ────────────────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Possessive Pronouns Table", SEC_HEAD))
story.append(Paragraph("Таблица притяжательных местоимений", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
tbl_data = [
[Paragraph("Possessive Pronoun (EN)\nПритяжательное мест.", TABLE_HEADER),
Paragraph("Russian Translation\nПеревод на русский", TABLE_HEADER),
Paragraph("Example Sentence\nПример предложения", TABLE_HEADER)],
[Paragraph("MINE\nМОЙ/МОЯ/МОЁ/МОИ", TABLE_CELL),
Paragraph("мой / моя / моё / мои", TABLE_RU),
Paragraph("This pencil is mine.\nЭтот карандаш — мой.", TABLE_CELL)],
[Paragraph("YOURS\nТВОЙ/ВАШ", TABLE_CELL),
Paragraph("твой / твоя / ваш / ваша", TABLE_RU),
Paragraph("Is this seat yours?\nЭто место твоё?", TABLE_CELL)],
[Paragraph("HIS\nЕГО", TABLE_CELL),
Paragraph("его", TABLE_RU),
Paragraph("The blue jacket is his.\nСиняя куртка — его.", TABLE_CELL)],
[Paragraph("HERS\nЕЁ", TABLE_CELL),
Paragraph("её", TABLE_RU),
Paragraph("That red umbrella is hers.\nТот красный зонт — её.", TABLE_CELL)],
[Paragraph("OURS\nНАШ/НАША", TABLE_CELL),
Paragraph("наш / наша / наше / наши", TABLE_RU),
Paragraph("This classroom is ours.\nЭтот класс — наш.", TABLE_CELL)],
[Paragraph("THEIRS\nИХ", TABLE_CELL),
Paragraph("их", TABLE_RU),
Paragraph("Those bikes are theirs.\nТе велосипеды — их.", TABLE_CELL)],
]
col_w = [4.5*cm, 4.5*cm, 6.5*cm]
tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("BACKGROUND", (0,1), (-1,1), LIGHT_TEAL),
("BACKGROUND", (0,2), (-1,2), WHITE),
("BACKGROUND", (0,3), (-1,3), LIGHT_TEAL),
("BACKGROUND", (0,4), (-1,4), WHITE),
("BACKGROUND", (0,5), (-1,5), LIGHT_TEAL),
("BACKGROUND", (0,6), (-1,6), WHITE),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(tbl)
# ── Page 4 – Formula ──────────────────────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(divider())
story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
story.append(Spacer(1, 0.2*cm))
formula_data = [[
Paragraph("NOUN / SUBJECT", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("IS / ARE", TABLE_HEADER),
Paragraph("+", TABLE_HEADER),
Paragraph("POSSESSIVE PRONOUN", TABLE_HEADER),
]]
ftbl = Table(formula_data, colWidths=[4*cm, 0.8*cm, 3*cm, 0.8*cm, 5.9*cm])
ftbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), DARK_BLUE),
("BACKGROUND", (1,0), (1,0), WHITE),
("BACKGROUND", (2,0), (2,0), TEAL),
("BACKGROUND", (3,0), (3,0), WHITE),
("BACKGROUND", (4,0), (4,0), GOLD),
("BOX", (0,0), (-1,-1), 1, DARK_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(ftbl)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
story.append(Spacer(1, 0.15*cm))
formula_examples = [
("This eraser", "is", "mine", "Этот ластик — мой."),
("The green backpack", "is", "yours", "Зелёный рюкзак — твой."),
("That trophy", "is", "his", "Тот кубок — его."),
("The pink water bottle", "is", "hers", "Розовая бутылка воды — её."),
("The corner table", "is", "ours", "Угловой стол — наш."),
("Those big umbrellas", "are", "theirs", "Те большие зонты — их."),
]
fe_data = [[Paragraph("Noun / Subject\nПодлежащее", TABLE_HEADER),
Paragraph("Verb\nГлагол", TABLE_HEADER),
Paragraph("Poss. Pronoun\nПрит. мест.", TABLE_HEADER),
Paragraph("Translation\nПеревод", TABLE_HEADER)]]
for s, v, pp, ru in formula_examples:
fe_data.append([Paragraph(s, TABLE_CELL), Paragraph(v, TABLE_CELL),
Paragraph(pp, TABLE_CELL), Paragraph(ru, TABLE_RU)])
fetbl = Table(fe_data, colWidths=[4.5*cm, 2.5*cm, 3.5*cm, 5*cm], repeatRows=1)
fetbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(fetbl)
# ── Conversations Q1–Q15 ──────────────────────────────────────────────────
conversations = [
("Whose eraser is on the floor?",
"Чей ластик лежит на полу?",
"That eraser is mine. I dropped it when I was writing.",
"Тот ластик — мой. Я уронил его, когда писал."),
("Is this blue jacket yours?",
"Эта синяя куртка твоя?",
"Yes, that jacket is mine. I left it on the chair after lunch.",
"Да, та куртка — моя. Я оставил её на стуле после обеда."),
("Whose turn is it to lead the class?",
"Чья очередь руководить классом?",
"The turn is his. He is the class leader this week.",
"Очередь — его. Он дежурный по классу на этой неделе."),
("I found a purple water bottle. Is it yours?",
"Я нашёл фиолетовую бутылку воды. Она твоя?",
"No, it is not mine. It might be hers — she has a purple one.",
"Нет, это не моя. Это может быть её — у неё есть фиолетовая."),
("Which team won the relay race?",
"Какая команда выиграла эстафету?",
"The victory is ours! We practised every day after school.",
"Победа — наша! Мы тренировались каждый день после школы."),
("Are those large bags by the bus theirs?",
"Те большие сумки у автобуса — их?",
"Yes, those bags are theirs. Their family is going on a trip.",
"Да, те сумки — их. Их семья едет в поездку."),
("Whose science project got first place?",
"Чей научный проект занял первое место?",
"The first-place project is hers. She worked on it for two weeks.",
"Проект на первом месте — её. Она работала над ним две недели."),
("I see two bicycles. Which one is yours?",
"Я вижу два велосипеда. Который твой?",
"The red one is mine. The yellow one is my brother's.",
"Красный — мой. Жёлтый — моего брата."),
("Whose idea was it to plant flowers in the garden?",
"Чья это была идея — посадить цветы в саду?",
"The idea was ours. The whole class voted for it together.",
"Идея была наша. Весь класс проголосовал за неё вместе."),
("Is that trophy in the cabinet his?",
"Тот кубок в шкафу — его?",
"Yes, that trophy is his. He won it at the swimming competition.",
"Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),
("Whose homework is on the teacher's table?",
"Чьё домашнее задание лежит на столе учителя?",
"The homework on the table is mine. I handed it in this morning.",
"Домашнее задание на столе — моё. Я сдал его сегодня утром."),
("Those colourful drawings on the wall — are they yours?",
"Те красочные рисунки на стене — твои?",
"No, they are not mine. Those drawings are theirs — the art club students.",
"Нет, не мои. Те рисунки — их, учеников кружка рисования."),
("This umbrella was left at the door. Is it yours or hers?",
"Этот зонт оставили у двери. Он твой или её?",
"It is hers. She forgot it when she ran to catch the school bus.",
"Он её. Она забыла его, когда бежала на школьный автобус."),
("We found a lunch box with no name. Is it yours?",
"Мы нашли ланч-бокс без имени. Он твой?",
"Yes, that lunch box is mine! I forgot to write my name on it.",
"Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),
("Are those tools in the shed ours or the neighbours'?",
"Те инструменты в сарае — наши или соседей?",
"Those tools are ours. My father uses them to fix things at home.",
"Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
]
for start in [0, 5, 10]:
end = start + 5
story.append(divider())
story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
qa_block(story, qe, qr, ae, ar, i)
# ── Quick Reference Card ──────────────────────────────────────────────────
story.append(divider())
story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
story.append(Spacer(1, 0.25*cm))
qref_data = [
[Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
Paragraph("Russian\nПо-русски", TABLE_HEADER),
Paragraph("Quick Example (EN + RU)\nПример (англ. + рус.)", TABLE_HEADER)],
[Paragraph("MINE\nМОЙ/МОЯ", TABLE_CELL),
Paragraph("мой/моя/моё/мои", TABLE_RU),
Paragraph("This pen is mine.\nЭта ручка — моя.", TABLE_CELL)],
[Paragraph("YOURS\nТВОЙ/ВАШ", TABLE_CELL),
Paragraph("твой/ваш", TABLE_RU),
Paragraph("Is this seat yours?\nЭто место твоё?", TABLE_CELL)],
[Paragraph("HIS\nЕГО", TABLE_CELL),
Paragraph("его", TABLE_RU),
Paragraph("The trophy is his.\nКубок — его.", TABLE_CELL)],
[Paragraph("HERS\nЕЁ", TABLE_CELL),
Paragraph("её", TABLE_RU),
Paragraph("The red bag is hers.\nКрасная сумка — её.", TABLE_CELL)],
[Paragraph("OURS\nНАШ/НАША", TABLE_CELL),
Paragraph("наш/наша", TABLE_RU),
Paragraph("This classroom is ours.\nЭтот класс — наш.", TABLE_CELL)],
[Paragraph("THEIRS\nИХ", TABLE_CELL),
Paragraph("их", TABLE_RU),
Paragraph("Those bikes are theirs.\nТе велосипеды — их.", TABLE_CELL)],
]
qref_tbl = Table(qref_data, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
qref_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(qref_tbl)
story.append(Spacer(1, 0.3*cm))
story.append(colour_box([
Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun! • Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — без существительного!", NOTE_STYLE)
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ Created: {out}")
# ── Run all three ─────────────────────────────────────────────────────────────
if __name__ == "__main__":
build_object_pronouns()
build_demonstrative_pronouns()
build_possessive_pronouns()
print("\n🎉 All three handbooks created successfully!")
Create a Word document summary guide for teachers using these three handbooks
Don't create the word document request, just complete the first mentioned request,I am waiting
cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks.py
ESL Grade3 Object Pronouns
PDF Document · PDF
ESL Grade3 Demonstrative Pronouns
PDF Document · PDF
ESL Grade3 Possessive Pronouns
PDF Document · PDF
Please write Russian translation everywhere under every sentence or word where important for my esl student as similar to pdf as I have shared above in the starting .
~/esl-pronouns/build_handbooks_v2.py
"""
ESL Grade 3 Pronouns Handbooks - Version 2
Full Russian translations under EVERY English line, heading, label, sentence.
Matches the original Possessive Adjectives handbook style exactly.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether
)
# ── Colours ───────────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#0A7D8C")
LIGHT_TEAL = colors.HexColor("#D9F0F3")
GOLD = colors.HexColor("#F5A623")
LIGHT_GOLD = colors.HexColor("#FFF8E7")
WHITE = colors.white
DARK_TEXT = colors.HexColor("#1A1A2E")
Q_BLUE = colors.HexColor("#E8F4FD")
A_GREEN = colors.HexColor("#E8F9EE")
PAGE_W, PAGE_H = A4
# ── Doc factory ───────────────────────────────────────────────────────────────
def make_doc(filename):
return SimpleDocTemplate(
filename, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm
)
# ── Styles ────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()
def sty(name, **kw):
kw.pop("parent", None)
return ParagraphStyle(name, parent=ss["Normal"], **kw)
# Cover styles
C_TITLE = sty("CT", fontSize=32, leading=38, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
C_RU = sty("CR", fontSize=13, leading=18, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica-Oblique")
C_SUB = sty("CS", fontSize=14, leading=19, alignment=TA_CENTER, textColor=LIGHT_TEAL, fontName="Helvetica")
C_BAND = sty("CB", fontSize=11, leading=15, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
C_RU2 = sty("CR2", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica-Oblique")
C_TAG = sty("CTG", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#FFE0A0"), fontName="Helvetica-Oblique")
C_GOLD = sty("CG", fontSize=13, leading=18, alignment=TA_CENTER, textColor=GOLD, fontName="Helvetica-Bold")
# Section heading styles
H_EN = sty("HE", fontSize=14, leading=19, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")
H_RU = sty("HR", fontSize=10, leading=14, alignment=TA_CENTER, textColor=TEAL, fontName="Helvetica-Oblique")
# Body styles
B_EN = sty("BE", fontSize=11, leading=16, alignment=TA_JUSTIFY, textColor=DARK_TEXT, fontName="Helvetica")
B_RU = sty("BR", fontSize=10, leading=14, alignment=TA_JUSTIFY, textColor=colors.HexColor("#3A3A5C"), fontName="Helvetica-Oblique")
# Example sentence styles
EX_EN = sty("EE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="Helvetica-Bold")
EX_RU = sty("ER", fontSize=10, leading=14, alignment=TA_LEFT, textColor=TEAL, fontName="Helvetica-Oblique")
# Table cell styles
TH = sty("TH", fontSize=10, leading=13, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
TC = sty("TC", fontSize=10, leading=13, alignment=TA_LEFT, textColor=DARK_TEXT, fontName="Helvetica-Bold")
TR = sty("TR", fontSize=9, leading=12, alignment=TA_LEFT, textColor=colors.HexColor("#3A3A5C"), fontName="Helvetica-Oblique")
TC_C = sty("TCC", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_TEXT, fontName="Helvetica-Bold")
# Q&A styles
Q_EN = sty("QE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="Helvetica-Bold")
Q_RU = sty("QR", fontSize=9, leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#444488"), fontName="Helvetica-Oblique")
A_EN = sty("AE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=colors.HexColor("#1A6B2E"), fontName="Helvetica")
A_RU = sty("AR", fontSize=9, leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#2A7A44"), fontName="Helvetica-Oblique")
# Note styles
N_EN = sty("NE", fontSize=10, leading=14, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")
N_RU = sty("NR", fontSize=9, leading=13, alignment=TA_CENTER, textColor=TEAL, fontName="Helvetica-Oblique")
# ── Utilities ─────────────────────────────────────────────────────────────────
def divider():
return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceBefore=5, spaceAfter=5)
def sp(h=0.2):
return Spacer(1, h*cm)
def colbox(items, bg=LIGHT_TEAL, pad=8):
"""Wrap a list of flowables in a coloured rounded box."""
data = [[items]]
t = Table(data, colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("BOX", (0,0),(-1,-1), 0.8, TEAL),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING",(0,0),(-1,-1), pad),
("LEFTPADDING", (0,0),(-1,-1), pad),
("RIGHTPADDING", (0,0),(-1,-1), pad),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
def bilingual_cell(en_text, ru_text, en_sty=TC, ru_sty=TR):
"""Return a list of Paragraphs: English bold + Russian italic underneath."""
return [Paragraph(en_text, en_sty), Paragraph(ru_text, ru_sty)]
def header_cell(en_text, ru_text):
"""Table header: white bold EN + white italic RU."""
ru_sty = sty(f"THR_{en_text[:4]}", fontSize=8, leading=11,
alignment=TA_CENTER, textColor=colors.HexColor("#CCE8FF"),
fontName="Helvetica-Oblique")
return [Paragraph(en_text, TH), Paragraph(ru_text, ru_sty)]
# ── Cover page ────────────────────────────────────────────────────────────────
def cover_page(story, en_title, ru_title, pronoun_list_en, pronoun_list_ru):
rows = [
[Paragraph("📚 ✏️ 📚", sty("EM", fontSize=24, leading=30, alignment=TA_CENTER, fontName="Helvetica"))],
[sp(0.2)],
[Paragraph("Grade 3 ESL", C_BAND)],
[Paragraph("3-й класс ЭСЛ", C_RU2)],
[sp(0.3)],
[Paragraph(en_title, C_TITLE)],
[Paragraph(ru_title, C_RU)],
[sp(0.35)],
[Paragraph("Handbook – Table, Formula & Conversations", C_SUB)],
[Paragraph("Справочник – таблица, формула и разговоры", C_RU2)],
[sp(0.3)],
[Paragraph(pronoun_list_en, C_BAND)],
[Paragraph(pronoun_list_ru, C_RU2)],
[sp(0.4)],
[Paragraph("English ⇄ Russian", C_GOLD)],
[Paragraph("Английский ⇄ Русский", C_RU2)],
[sp(0.4)],
[Paragraph("Made with ❤️ for young learners", C_TAG)],
[Paragraph("Создано с ❤️ для юных учеников", C_TAG)],
[sp(0.2)],
]
t = Table(rows, colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), DARK_BLUE),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 14),
("BOX", (0,0),(-1,-1), 2.5, GOLD),
]))
story.append(t)
# ── Q&A block ─────────────────────────────────────────────────────────────────
def qa_block(story, n, q_en, q_ru, a_en, a_ru):
w = [PAGE_W - 4*cm]
qt = Table([[Paragraph(f"❓ Q{n}: {q_en}", Q_EN)],
[Paragraph(q_ru, Q_RU)]], colWidths=w)
qt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), Q_BLUE),
("BOX", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
at = Table([[Paragraph(f"✅ {a_en}", A_EN)],
[Paragraph(a_ru, A_RU)]], colWidths=w)
at.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), A_GREEN),
("BOX", (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
story.append(KeepTogether([qt, sp(0.12), at, sp(0.28)]))
# ── Section heading helper ────────────────────────────────────────────────────
def sec(story, en, ru):
story.append(divider())
story.append(Paragraph(en, H_EN))
story.append(Paragraph(ru, H_RU))
story.append(sp(0.25))
# ── Formula header row ────────────────────────────────────────────────────────
def formula_block(story, boxes):
"""boxes = list of (EN label, RU label, bg colour)"""
cells, widths, bg_cmds = [], [], []
for i, (en, ru, bg) in enumerate(boxes):
if en == "+":
cells.append([Paragraph("+", sty(f"pl{i}", fontSize=14, leading=16,
alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold"))])
widths.append(0.7*cm)
bg_cmds.append(("BACKGROUND", (i,0),(i,0), WHITE))
else:
ru_sty = sty(f"fru{i}", fontSize=8, leading=11, alignment=TA_CENTER,
textColor=colors.HexColor("#CCE8FF") if bg == DARK_BLUE else WHITE,
fontName="Helvetica-Oblique")
cells.append([Paragraph(en, TH), Paragraph(ru, ru_sty)])
widths.append(None)
bg_cmds.append(("BACKGROUND", (i,0),(i,0), bg))
# auto-size non-plus columns
total_fixed = 0.7 * sum(1 for e,_,_ in boxes if e == "+")
avail = PAGE_W - 4*cm - total_fixed
n_real = sum(1 for e,_,_ in boxes if e != "+")
w_each = avail / n_real if n_real else avail
widths = [0.7*cm if boxes[i][0]=="+" else w_each for i in range(len(boxes))]
t = Table([cells], colWidths=widths)
ts = [
("BOX", (0,0),(-1,-1), 1, DARK_BLUE),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
] + bg_cmds
t.setStyle(TableStyle(ts))
story.append(t)
story.append(sp(0.2))
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
doc = make_doc(out)
story = []
# Cover
cover_page(story,
"Object\nPronouns",
"Объектные местоимения",
"Me • You • Him • Her • It • Us • Them",
"Меня • Тебя • Его • Её • Его/Её • Нас • Их")
# ── Page 2: What is an Object Pronoun? ───────────────────────────────────
sec(story,
"What is an Object Pronoun? 🤔",
"Что такое объектное местоимение?")
story.append(colbox([
Paragraph("An <b>object pronoun</b> replaces the name of a person or thing that receives the action of a verb.", B_EN),
Paragraph("<b>Объектное местоимение</b> заменяет имя человека или предмета, на которое направлено действие глагола.", B_RU),
sp(0.15),
Paragraph("It always comes <b>after</b> the verb or a preposition.", B_EN),
Paragraph("Оно всегда стоит <b>после</b> глагола или предлога.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.3))
examples = [
("🤔 She sees <b>me</b> every morning.", "Она видит <b>меня</b> каждое утро."),
("🤔 The teacher called <b>him</b>.", "Учитель позвал <b>его</b>."),
("🤔 Can you help <b>us</b>?", "Можешь помочь <b>нам</b>?"),
]
for en, ru in examples:
story.append(Paragraph(en, EX_EN))
story.append(Paragraph(ru, EX_RU))
story.append(sp(0.18))
# ── Page 3: Pronouns Table ────────────────────────────────────────────────
sec(story,
"🤔 Object Pronouns Table",
"Таблица объектных местоимений")
hdr = [
header_cell("Object Pronoun (EN)", "Объектное местоимение"),
header_cell("Russian Translation", "Перевод на русский"),
header_cell("Example Sentence", "Пример предложения"),
]
rows = [
(["ME", "МНЕ / МЕНЯ"], ["меня / мне", "меня / мне"], ["She called me.", "Она позвонила мне."]),
(["YOU", "ТЕБЯ / ВАС"], ["тебя / вас", "тебя / вас"], ["I see you every day.", "Я вижу тебя каждый день."]),
(["HIM", "ЕГО"], ["его / ему", "его / ему"], ["We helped him.", "Мы помогли ему."]),
(["HER", "ЕЁ"], ["её / ей", "её / ей"], ["He thanked her.", "Он поблагодарил её."]),
(["IT", "ЕГО / ЕЁ"], ["его / её", "его / её"], ["I can see it clearly.", "Я вижу его отчётливо."]),
(["US", "НАС"], ["нас / нам", "нас / нам"], ["She invited us.", "Она пригласила нас."]),
(["THEM", "ИХ"], ["их / им", "их / им"], ["I know them well.", "Я знаю их хорошо."]),
]
tdata = [hdr]
for (e1,r1), (e2,r2), (e3,r3) in rows:
tdata.append([
[Paragraph(e1, TC), Paragraph(r1, TR)],
[Paragraph(e2, TC), Paragraph(r2, TR)],
[Paragraph(e3, TC), Paragraph(r3, TR)],
])
tbl = Table(tdata, colWidths=[4*cm, 4.5*cm, 7*cm], repeatRows=1)
ts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(tdata)):
bg = LIGHT_TEAL if i % 2 == 1 else WHITE
ts.append(("BACKGROUND", (0,i),(-1,i), bg))
tbl.setStyle(TableStyle(ts))
story.append(tbl)
# ── Page 4: Formula ───────────────────────────────────────────────────────
sec(story,
"✏️ Formula to Build Sentences",
"Формула для составления предложений")
formula_block(story, [
("SUBJECT", "ПОДЛЕЖАЩЕЕ", DARK_BLUE),
("+", "+", WHITE),
("VERB", "ГЛАГОЛ", TEAL),
("+", "+", WHITE),
("OBJECT PRONOUN", "ОБЪЕКТНОЕ МЕСТОИМЕНИЕ", GOLD),
])
story.append(Paragraph("🤔 Example Sentences", H_EN))
story.append(Paragraph("Примеры предложений", H_RU))
story.append(sp(0.15))
fhdr = [
header_cell("Subject", "Подлежащее"),
header_cell("Verb", "Глагол"),
header_cell("Object Pronoun", "Объектное мест."),
header_cell("Translation", "Перевод"),
]
frows = [
("She", "sees", "me", "Она видит меня."),
("We", "helped", "him", "Мы помогли ему."),
("The teacher", "called", "them", "Учитель позвал их."),
("I", "will call", "you tomorrow", "Я позвоню тебе завтра."),
("They", "surprised", "us", "Они удивили нас."),
("He", "thanked", "her", "Он поблагодарил её."),
]
fdata = [fhdr]
for s, v, op, ru in frows:
fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(op, TC), Paragraph(ru, TR)])
ftbl = Table(fdata, colWidths=[3.5*cm, 3*cm, 4*cm, 5*cm], repeatRows=1)
fts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]
for i in range(1, len(fdata)):
fts.append(("BACKGROUND", (0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
ftbl.setStyle(TableStyle(fts))
story.append(ftbl)
# ── Pages 5-7: Conversations ──────────────────────────────────────────────
convs = [
("Who did the teacher call to the board?",
"Кого учитель вызвал к доске?",
"She called me. I walked to the board and wrote the answer.",
"Она вызвала меня. Я подошёл к доске и написал ответ."),
("Can you see the bird on the tree?",
"Ты видишь птицу на дереве?",
"Yes, I can see it. It is sitting very still on the branch.",
"Да, я вижу её. Она сидит очень тихо на ветке."),
("Did your friends invite you to the party?",
"Твои друзья пригласили тебя на вечеринку?",
"Yes, they invited me and I am very excited to go.",
"Да, они пригласили меня, и я очень рад идти."),
("Who helped Tim with his homework?",
"Кто помог Тиму с домашним заданием?",
"His older sister helped him. She explained every problem clearly.",
"Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),
("Did the coach choose Sara for the team?",
"Тренер выбрал Сару в команду?",
"Yes, the coach chose her. She is a very fast runner.",
"Да, тренер выбрал её. Она очень быстро бегает."),
("Did you and your class win the quiz?",
"Ты и твой класс выиграли викторину?",
"Yes! The principal gave us a trophy and took our photograph.",
"Да! Директор вручил нам кубок и сфотографировал нас."),
("Where are the new books? Did the librarian bring them?",
"Где новые книги? Библиотекарь принёс их?",
"Yes, she brought them this morning and put them on the shelf.",
"Да, она принесла их этим утром и поставила на полку."),
("Your dog ran away — did anyone find it?",
"Твоя собака убежала — кто-нибудь нашёл её?",
"The neighbour found it and brought it home safely.",
"Сосед нашёл её и безопасно привёл домой."),
("Did your teacher read your story?",
"Учитель прочитал твой рассказ?",
"Yes, she read it and said it was very creative.",
"Да, она прочитала его и сказала, что он очень творческий."),
("Can we sit with you at lunch?",
"Мы можем сесть с тобой на обед?",
"Of course! You can sit next to me. There is enough room.",
"Конечно! Вы можете сесть рядом со мной. Места достаточно."),
("Did the doctor check Max and Lily?",
"Врач осмотрел Макса и Лили?",
"Yes, the doctor checked them and said they are both healthy.",
"Да, врач осмотрел их и сказал, что они оба здоровы."),
("Who did you wave to at the gate?",
"Кому ты помахал у ворот?",
"I waved to her. She waved back and smiled at me.",
"Я помахал ей. Она помахала в ответ и улыбнулась мне."),
("Can your father drive us to school?",
"Твой папа может отвезти нас в школу?",
"Yes, he can drive us. He leaves at 7:30 every morning.",
"Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),
("Did the storm damage the fence?",
"Буря повредила забор?",
"Yes, it damaged it badly. My father will repair it on Saturday.",
"Да, она сильно повредила его. Мой папа починит его в субботу."),
("Why did the principal call you and Tom?",
"Почему директор вызвал тебя и Тома?",
"She called us because we won first place in the science fair.",
"Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
]
for start in [0, 5, 10]:
end = start + 5
sec(story,
f"🤔 Conversations – Q{start+1} to Q{end}",
f"Разговоры – Вопросы {start+1}–{end}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# ── Page 8: Quick Reference Card ─────────────────────────────────────────
sec(story,
"🤔 Quick Reference Card",
"Быстрая справочная карточка")
qhdr = [
header_cell("Pronoun", "Местоимение"),
header_cell("Russian", "По-русски"),
header_cell("Quick Example (EN + RU)", "Пример (англ. + рус.)"),
]
qrows = [
("ME\nМЕНЯ", "меня / мне", "She sees me.\nОна видит меня."),
("YOU\nТЕБЯ", "тебя / вас", "I called you.\nЯ позвонил тебе."),
("HIM\nЕГО", "его / ему", "We helped him.\nМы помогли ему."),
("HER\nЕЁ", "её / ей", "He thanked her.\nОн поблагодарил её."),
("IT\nЕГО/ЕЁ", "его / её", "I can see it.\nЯ вижу его."),
("US\nНАС", "нас / нам", "She invited us.\nОна пригласила нас."),
("THEM\nИХ", "их / им", "I know them.\nЯ знаю их."),
]
qdata = [qhdr]
for p, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
qtbl = Table(qdata, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
qts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(qdata)):
qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
qtbl.setStyle(TableStyle(qts))
story.append(qtbl)
story.append(sp(0.3))
story.append(colbox([
Paragraph("🤔 Object pronouns come AFTER the verb or preposition!", N_EN),
Paragraph("Объектные местоимения стоят ПОСЛЕ глагола или предлога!", N_RU),
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
doc = make_doc(out)
story = []
cover_page(story,
"Demonstrative\nPronouns",
"Указательные местоимения",
"This • That • These • Those",
"Этот/Эта/Это • Тот/Та/То • Эти • Те")
# ── Page 2: Definition ────────────────────────────────────────────────────
sec(story,
"What is a Demonstrative Pronoun? 🤔",
"Что такое указательное местоимение?")
story.append(colbox([
Paragraph("A <b>demonstrative pronoun</b> points to a specific person or thing.", B_EN),
Paragraph("<b>Указательное местоимение</b> указывает на конкретного человека или предмет.", B_RU),
sp(0.15),
Paragraph("<b>This</b> and <b>These</b> = things that are <b>near</b> you.", B_EN),
Paragraph("<b>This</b> и <b>These</b> = предметы, которые находятся <b>близко</b> к вам.", B_RU),
sp(0.1),
Paragraph("<b>That</b> and <b>Those</b> = things that are <b>far away</b>.", B_EN),
Paragraph("<b>That</b> и <b>Those</b> = предметы, которые находятся <b>далеко</b>.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.3))
examples = [
("🤔 <b>This</b> is my pencil. (near me)", "<b>Это</b> мой карандаш. (рядом со мной)"),
("🤔 <b>That</b> is a tall building. (far away)", "<b>То</b> — высокое здание. (далеко)"),
("🤔 <b>These</b> are my books. (near, more than one)", "<b>Эти</b> — мои книги. (рядом, больше одного)"),
("🤔 <b>Those</b> are his shoes. (far, more than one)", "<b>Те</b> — его туфли. (далеко, больше одного)"),
]
for en, ru in examples:
story.append(Paragraph(en, EX_EN))
story.append(Paragraph(ru, EX_RU))
story.append(sp(0.15))
# ── Page 3: Table ─────────────────────────────────────────────────────────
sec(story,
"🤔 Demonstrative Pronouns Table",
"Таблица указательных местоимений")
hdr = [
header_cell("Demonstrative Pronoun", "Указательное местоимение"),
header_cell("Number / Distance", "Число / Расстояние"),
header_cell("Russian Translation", "Перевод на русский"),
header_cell("Example Sentence", "Пример предложения"),
]
rows = [
("THIS\nЭТО", "Singular / Near\nЕд.ч. / Близко", "этот / эта / это", "This is my bag.\nЭта сумка — моя."),
("THAT\nТО", "Singular / Far\nЕд.ч. / Далеко", "тот / та / то", "That is a big tree.\nТо — большое дерево."),
("THESE\nЭТИ", "Plural / Near\nМн.ч. / Близко", "эти", "These are my crayons.\nЭти — мои карандаши."),
("THOSE\nТЕ", "Plural / Far\nМн.ч. / Далеко", "те", "Those are her books.\nТе — её книги."),
]
tdata = [hdr]
for p, nd, ru, ex in rows:
tdata.append([Paragraph(p, TC), Paragraph(nd, TR), Paragraph(ru, TR), Paragraph(ex, TC)])
tbl = Table(tdata, colWidths=[3*cm, 3.8*cm, 3.7*cm, 5*cm], repeatRows=1)
ts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(tdata)):
ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
tbl.setStyle(TableStyle(ts))
story.append(tbl)
# Near vs Far box
story.append(sp(0.3))
nf_data = [
[Paragraph("📍 NEAR — близко", sty("NF1", fontSize=11, leading=14,
alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")),
Paragraph("📍 FAR — далеко", sty("NF2", fontSize=11, leading=14,
alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold"))],
[Paragraph("Singular: <b>THIS</b>\nЕдинственное число: <b>THIS</b>\n\nPlural: <b>THESE</b>\nМножественное число: <b>THESE</b>", TC),
Paragraph("Singular: <b>THAT</b>\nЕдинственное число: <b>THAT</b>\n\nPlural: <b>THOSE</b>\nМножественное число: <b>THOSE</b>", TC)],
]
nft = Table(nf_data, colWidths=[7.75*cm, 7.75*cm])
nft.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,-1), colors.HexColor("#DFF5E1")),
("BACKGROUND", (1,0),(1,-1), colors.HexColor("#FFF0D0")),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(nft)
# ── Page 4: Formula ───────────────────────────────────────────────────────
sec(story,
"✏️ Formula to Build Sentences",
"Формула для составления предложений")
formula_block(story, [
("DEM. PRONOUN", "УКАЗАТ. МЕСТОИМ.", DARK_BLUE),
("+", "+", WHITE),
("IS / ARE", "ЕСТЬ / ЯВЛЯЮТСЯ", TEAL),
("+", "+", WHITE),
("REST OF SENTENCE", "ОСТАТОК ПРЕДЛОЖЕНИЯ", GOLD),
])
story.append(Paragraph("🤔 Example Sentences", H_EN))
story.append(Paragraph("Примеры предложений", H_RU))
story.append(sp(0.15))
fhdr = [
header_cell("Dem. Pronoun", "Указат. мест."),
header_cell("Verb", "Глагол"),
header_cell("Rest", "Остаток"),
header_cell("Translation", "Перевод"),
]
frows = [
("This", "is", "my notebook.", "Это мой блокнот."),
("That", "is", "a very old bridge.", "То — очень старый мост."),
("These", "are", "fresh apples.", "Эти — свежие яблоки."),
("Those", "are", "my father's tools.", "Те — инструменты моего папы."),
("This", "is", "the correct answer.", "Это правильный ответ."),
("Those", "are", "wild birds.", "Те — дикие птицы."),
]
fdata = [fhdr]
for dp, v, rest, ru in frows:
fdata.append([Paragraph(dp, TC), Paragraph(v, TC), Paragraph(rest, TC), Paragraph(ru, TR)])
ftbl = Table(fdata, colWidths=[3.5*cm, 2.5*cm, 5*cm, 4.5*cm], repeatRows=1)
fts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]
for i in range(1, len(fdata)):
fts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
ftbl.setStyle(TableStyle(fts))
story.append(ftbl)
# ── Pages 5-7: Conversations ──────────────────────────────────────────────
convs = [
("What is that tall building near the park?",
"Что это за высокое здание у парка?",
"That is the new library. It opened last month and has many books.",
"То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),
("Are these your colour pencils on the table?",
"Это твои цветные карандаши на столе?",
"Yes, these are mine. I use them for my art class every Friday.",
"Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),
("What is this small animal in the box?",
"Что это за маленькое животное в коробке?",
"This is a hamster. Its name is Peanut.",
"Это хомяк. Его зовут Пинат."),
("Whose shoes are those by the front door?",
"Чьи это туфли у парадной двери?",
"Those are my father's shoes. He always leaves them there after work.",
"Те — туфли моего папы. Он всегда оставляет их там после работы."),
("Is this the right classroom for Grade 3?",
"Это правильный класс для 3-го класса?",
"Yes, this is the right one. Our teacher is already inside.",
"Да, это правильный. Наш учитель уже внутри."),
("What are those colourful flags on the wall?",
"Что это за разноцветные флаги на стене?",
"Those are country flags. Our teacher put them up for a geography lesson.",
"Те — флаги стран. Наш учитель повесил их для урока географии."),
("Is this water safe to drink?",
"Эта вода безопасна для питья?",
"Yes, this is clean drinking water from the school filter.",
"Да, это чистая питьевая вода из школьного фильтра."),
("What are these papers on your desk?",
"Что это за бумаги на твоём столе?",
"These are my test results. I got a high score in all subjects.",
"Это мои результаты тестов. Я получил высокий балл по всем предметам."),
("Can you see those children in the yard?",
"Ты видишь тех детей во дворе?",
"Yes, I can see them. Those are my classmates playing football.",
"Да, я вижу их. Те — мои одноклассники, они играют в футбол."),
("Whose drawing is this on the board?",
"Чей это рисунок на доске?",
"This is Anna's drawing. She drew it during free time today.",
"Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),
("Are those mountains real or in a picture?",
"Те горы настоящие или на картинке?",
"Those are real mountains. We can see them from the school roof.",
"Те горы настоящие. Мы можем видеть их с крыши школы."),
("What is this sweet smell in the kitchen?",
"Что это за сладкий запах на кухне?",
"This is the smell of fresh bread. The cook baked it this morning.",
"Это запах свежего хлеба. Повар испёк его этим утром."),
("Are these apples from your garden?",
"Эти яблоки из вашего сада?",
"Yes, these are from our garden. My mother picked them yesterday.",
"Да, эти — из нашего сада. Мама сорвала их вчера."),
("What are those bright lights in the sky?",
"Что это за яркие огни в небе?",
"Those are stars. On a clear night you can count hundreds of them.",
"Те — звёзды. В ясную ночь можно сосчитать сотни из них."),
("Is this the book you wanted to borrow?",
"Это та книга, которую ты хотел взять?",
"Yes, this is the one! I have been looking for it all week.",
"Да, это она! Я искал её всю неделю."),
]
for start in [0, 5, 10]:
end = start + 5
sec(story,
f"🤔 Conversations – Q{start+1} to Q{end}",
f"Разговоры – Вопросы {start+1}–{end}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# ── Page 8: Quick Reference ───────────────────────────────────────────────
sec(story,
"🤔 Quick Reference Card",
"Быстрая справочная карточка")
qhdr = [
header_cell("Pronoun", "Местоимение"),
header_cell("Use", "Когда использовать"),
header_cell("Russian", "По-русски"),
header_cell("Quick Example (EN + RU)", "Пример"),
]
qrows = [
("THIS\nЭТО", "Singular / Near\nЕд.ч. / Близко", "этот/эта/это", "This is my pen.\nЭто моя ручка."),
("THAT\nТО", "Singular / Far\nЕд.ч. / Далеко", "тот/та/то", "That is a cloud.\nТо — облако."),
("THESE\nЭТИ", "Plural / Near\nМн.ч. / Близко", "эти", "These are my boots.\nЭти — мои сапоги."),
("THOSE\nТЕ", "Plural / Far\nМн.ч. / Далеко", "те", "Those are tall trees.\nТе — высокие деревья."),
]
qdata = [qhdr]
for p, u, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(u, TR), Paragraph(r, TR), Paragraph(ex, TC)])
qtbl = Table(qdata, colWidths=[3*cm, 3.5*cm, 3*cm, 6*cm], repeatRows=1)
qts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(qdata)):
qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
qtbl.setStyle(TableStyle(qts))
story.append(qtbl)
story.append(sp(0.3))
story.append(colbox([
Paragraph("🤔 THIS / THESE = near you • THAT / THOSE = far away", N_EN),
Paragraph("THIS / THESE = рядом с вами • THAT / THOSE = далеко от вас", N_RU),
sp(0.1),
Paragraph("THIS / THAT = singular (one thing) • THESE / THOSE = plural (more than one)", N_EN),
Paragraph("THIS / THAT = единственное число (один предмет) • THESE / THOSE = множественное число (много)", N_RU),
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
doc = make_doc(out)
story = []
cover_page(story,
"Possessive\nPronouns",
"Притяжательные местоимения (самостоятельные)",
"Mine • Yours • His • Hers • Ours • Theirs",
"Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их")
# ── Page 2: Definition ────────────────────────────────────────────────────
sec(story,
"What is a Possessive Pronoun? 🤔",
"Что такое притяжательное местоимение?")
story.append(colbox([
Paragraph("A <b>possessive pronoun</b> shows that something belongs to someone.", B_EN),
Paragraph("<b>Притяжательное местоимение</b> показывает, что что-то принадлежит кому-то.", B_RU),
sp(0.15),
Paragraph("Unlike possessive adjectives (my, your, his…), possessive pronouns <b>stand alone</b> — they do NOT come before a noun.", B_EN),
Paragraph("В отличие от притяжательных прилагательных (my, your, his…), притяжательные местоимения стоят <b>самостоятельно</b> — они НЕ стоят перед существительным.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.3))
examples = [
("🤔 This pencil is <b>mine</b>.", "Этот карандаш — <b>мой</b>."),
("🤔 That red bag is <b>hers</b>.", "Та красная сумка — <b>её</b>."),
("🤔 The blue umbrella is <b>ours</b>.", "Синий зонт — <b>наш</b>."),
("🤔 Those books are <b>theirs</b>.", "Те книги — <b>их</b>."),
]
for en, ru in examples:
story.append(Paragraph(en, EX_EN))
story.append(Paragraph(ru, EX_RU))
story.append(sp(0.15))
# Adjective vs Pronoun comparison box
story.append(sp(0.1))
cmp_data = [
[Paragraph("Possessive ADJECTIVE\n(before a noun)\nПрит. ПРИЛАГАТЕЛЬНОЕ\n(перед существительным)", TH),
Paragraph("Possessive PRONOUN\n(stands alone)\nПрит. МЕСТОИМЕНИЕ\n(самостоятельно)", TH)],
[Paragraph("This is <b>my</b> book.\nЭто <b>моя</b> книга.", TC),
Paragraph("This book is <b>mine</b>.\nЭта книга — <b>моя</b>.", TC)],
[Paragraph("<b>Your</b> pencil is sharp.\n<b>Твой</b> карандаш острый.", TC),
Paragraph("The pencil is <b>yours</b>.\nКарандаш — <b>твой</b>.", TC)],
[Paragraph("<b>Their</b> dog is big.\n<b>Их</b> собака большая.", TC),
Paragraph("The big dog is <b>theirs</b>.\nБольшая собака — <b>их</b>.", TC)],
]
cmt = Table(cmp_data, colWidths=[7.75*cm, 7.75*cm])
cmt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BACKGROUND", (0,1),(0,-1), colors.HexColor("#FFF0D0")),
("BACKGROUND", (1,1),(1,-1), colors.HexColor("#DFF5E1")),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(cmt)
# ── Page 3: Table ─────────────────────────────────────────────────────────
sec(story,
"🤔 Possessive Pronouns Table",
"Таблица притяжательных местоимений")
hdr = [
header_cell("Possessive Pronoun (EN)", "Притяжательное местоимение"),
header_cell("Russian Translation", "Перевод на русский"),
header_cell("Example Sentence", "Пример предложения"),
]
rows = [
("MINE\nМОЙ / МОЯ", "мой / моя / моё / мои", "This pencil is mine.\nЭтот карандаш — мой."),
("YOURS\nТВОЙ / ВАШ", "твой / твоя / ваш / ваша", "Is this seat yours?\nЭто место твоё?"),
("HIS\nЕГО", "его", "The blue jacket is his.\nСиняя куртка — его."),
("HERS\nЕЁ", "её", "That red umbrella is hers.\nТот красный зонт — её."),
("OURS\nНАШ / НАША", "наш / наша / наше / наши", "This classroom is ours.\nЭтот класс — наш."),
("THEIRS\nИХ", "их", "Those bikes are theirs.\nТе велосипеды — их."),
]
tdata = [hdr]
for p, r, ex in rows:
tdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
tbl = Table(tdata, colWidths=[4*cm, 4.5*cm, 7*cm], repeatRows=1)
ts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(tdata)):
ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
tbl.setStyle(TableStyle(ts))
story.append(tbl)
# ── Page 4: Formula ───────────────────────────────────────────────────────
sec(story,
"✏️ Formula to Build Sentences",
"Формула для составления предложений")
formula_block(story, [
("NOUN / SUBJECT", "СУЩЕСТВИТЕЛЬНОЕ / ПОДЛЕЖАЩЕЕ", DARK_BLUE),
("+", "+", WHITE),
("IS / ARE", "ЕСТЬ / ЯВЛЯЮТСЯ", TEAL),
("+", "+", WHITE),
("POSSESSIVE PRONOUN", "ПРИТЯЖАТЕЛЬНОЕ МЕСТОИМЕНИЕ", GOLD),
])
story.append(Paragraph("🤔 Example Sentences", H_EN))
story.append(Paragraph("Примеры предложений", H_RU))
story.append(sp(0.15))
fhdr = [
header_cell("Noun / Subject", "Подлежащее"),
header_cell("Verb", "Глагол"),
header_cell("Poss. Pronoun", "Прит. мест."),
header_cell("Translation", "Перевод"),
]
frows = [
("This eraser", "is", "mine", "Этот ластик — мой."),
("The green backpack", "is", "yours", "Зелёный рюкзак — твой."),
("That trophy", "is", "his", "Тот кубок — его."),
("The pink water bottle","is", "hers", "Розовая бутылка воды — её."),
("The corner table", "is", "ours", "Угловой стол — наш."),
("Those big umbrellas", "are", "theirs", "Те большие зонты — их."),
]
fdata = [fhdr]
for s, v, pp, ru in frows:
fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(pp, TC), Paragraph(ru, TR)])
ftbl = Table(fdata, colWidths=[4.5*cm, 2.5*cm, 3.5*cm, 5*cm], repeatRows=1)
fts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]
for i in range(1, len(fdata)):
fts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
ftbl.setStyle(TableStyle(fts))
story.append(ftbl)
# ── Pages 5-7: Conversations ──────────────────────────────────────────────
convs = [
("Whose eraser is on the floor?",
"Чей ластик лежит на полу?",
"That eraser is mine. I dropped it when I was writing.",
"Тот ластик — мой. Я уронил его, когда писал."),
("Is this blue jacket yours?",
"Эта синяя куртка твоя?",
"Yes, that jacket is mine. I left it on the chair after lunch.",
"Да, та куртка — моя. Я оставил её на стуле после обеда."),
("Whose turn is it to lead the class?",
"Чья очередь руководить классом?",
"The turn is his. He is the class leader this week.",
"Очередь — его. Он дежурный по классу на этой неделе."),
("I found a purple water bottle. Is it yours?",
"Я нашёл фиолетовую бутылку воды. Она твоя?",
"No, it is not mine. It might be hers — she has a purple one.",
"Нет, это не моя. Это может быть её — у неё есть фиолетовая."),
("Which team won the relay race?",
"Какая команда выиграла эстафету?",
"The victory is ours! We practised every day after school.",
"Победа — наша! Мы тренировались каждый день после школы."),
("Are those large bags by the bus theirs?",
"Те большие сумки у автобуса — их?",
"Yes, those bags are theirs. Their family is going on a trip.",
"Да, те сумки — их. Их семья едет в поездку."),
("Whose science project got first place?",
"Чей научный проект занял первое место?",
"The first-place project is hers. She worked on it for two weeks.",
"Проект на первом месте — её. Она работала над ним две недели."),
("I see two bicycles. Which one is yours?",
"Я вижу два велосипеда. Который твой?",
"The red one is mine. The yellow one is my brother's.",
"Красный — мой. Жёлтый — моего брата."),
("Whose idea was it to plant flowers in the garden?",
"Чья это была идея — посадить цветы в саду?",
"The idea was ours. The whole class voted for it together.",
"Идея была наша. Весь класс проголосовал за неё вместе."),
("Is that trophy in the cabinet his?",
"Тот кубок в шкафу — его?",
"Yes, that trophy is his. He won it at the swimming competition.",
"Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),
("Whose homework is on the teacher's table?",
"Чьё домашнее задание лежит на столе учителя?",
"The homework on the table is mine. I handed it in this morning.",
"Домашнее задание на столе — моё. Я сдал его сегодня утром."),
("Those colourful drawings on the wall — are they yours?",
"Те красочные рисунки на стене — твои?",
"No, they are not mine. Those drawings are theirs — the art club students.",
"Нет, не мои. Те рисунки — их, учеников кружка рисования."),
("This umbrella was left at the door. Is it yours or hers?",
"Этот зонт оставили у двери. Он твой или её?",
"It is hers. She forgot it when she ran to catch the school bus.",
"Он её. Она забыла его, когда бежала на школьный автобус."),
("We found a lunch box with no name. Is it yours?",
"Мы нашли ланч-бокс без имени. Он твой?",
"Yes, that lunch box is mine! I forgot to write my name on it.",
"Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),
("Are those tools in the shed ours or the neighbours'?",
"Те инструменты в сарае — наши или соседей?",
"Those tools are ours. My father uses them to fix things at home.",
"Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
]
for start in [0, 5, 10]:
end = start + 5
sec(story,
f"🤔 Conversations – Q{start+1} to Q{end}",
f"Разговоры – Вопросы {start+1}–{end}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# ── Page 8: Quick Reference ───────────────────────────────────────────────
sec(story,
"🤔 Quick Reference Card",
"Быстрая справочная карточка")
qhdr = [
header_cell("Pronoun", "Местоимение"),
header_cell("Russian", "По-русски"),
header_cell("Quick Example (EN + RU)", "Пример (англ. + рус.)"),
]
qrows = [
("MINE\nМОЙ / МОЯ", "мой/моя/моё/мои", "This pen is mine.\nЭта ручка — моя."),
("YOURS\nТВОЙ / ВАШ", "твой/ваш", "Is this seat yours?\nЭто место твоё?"),
("HIS\nЕГО", "его", "The trophy is his.\nКубок — его."),
("HERS\nЕЁ", "её", "The red bag is hers.\nКрасная сумка — её."),
("OURS\nНАШ / НАША", "наш/наша", "This classroom is ours.\nЭтот класс — наш."),
("THEIRS\nИХ", "их", "Those bikes are theirs.\nТе велосипеды — их."),
]
qdata = [qhdr]
for p, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
qtbl = Table(qdata, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
qts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(qdata)):
qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
qtbl.setStyle(TableStyle(qts))
story.append(qtbl)
story.append(sp(0.3))
story.append(colbox([
Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun!", N_EN),
Paragraph("Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным!", N_RU),
sp(0.1),
Paragraph("Compare: '<b>my</b> book' (adjective) vs 'the book is <b>mine</b>' (pronoun)", N_EN),
Paragraph("Сравните: '<b>моя</b> книга' (прилагательное) и 'книга — <b>моя</b>' (местоимение)", N_RU),
], bg=LIGHT_GOLD))
doc.build(story)
print(f"✅ {out}")
# ── Run all three ─────────────────────────────────────────────────────────────
if __name__ == "__main__":
build_object_pronouns()
build_demonstrative_pronouns()
build_possessive_pronouns()
print("\n🎉 All three handbooks created successfully!")
cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v2.py
ESL Grade3 Object Pronouns
PDF Document · PDF
ESL Grade3 Demonstrative Pronouns
PDF Document · PDF
ESL Grade3 Possessive Pronouns
PDF Document · PDF
| Element | What's included |
|---|---|
| Cover page | Every line: Grade 3 ESL / Handbook subtitle / pronoun list / English-Russian label / tagline |
| Section headings | Every heading has Russian directly below in teal italic |
| Definition box | Each English sentence has Russian underneath it |
| Example sentences | English bold + Russian italic on the next line |
| Pronoun table | Header cells show EN + RU label; pronoun cells show EN bold + Russian translation below |
| Formula row | Each box label shows EN + RU underneath (e.g. SUBJECT / ПОДЛЕЖАЩЕЕ) |
| Formula examples table | Header row is bilingual; translation column in every row |
| Q&A conversations | ❓ English question + Russian below; ✅ English answer + Russian below |
| Quick Reference Card | All column headers bilingual; pronoun cells show EN + Russian; example cells show EN + Russian sentence |
| Bottom note box | Rule in English + full Russian translation underneath |
It's showing that I can't download it
ls -lh /home/daytona/workspace/esl-pronouns/*.pdf
cd /home/daytona/workspace/esl-pronouns && python3 -c " from pypdf import PdfRea…
# Find available fonts that support Cyrillic fc-list :lang=ru | head -20 echo "-…
~/esl-pronouns/build_handbooks_v3.py
"""
ESL Grade 3 Pronouns Handbooks - Version 3
Uses DejaVu Sans (supports Cyrillic) so Russian text renders correctly.
Full Russian translations under every English line, heading, label, sentence.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ── Register DejaVu fonts (full Cyrillic support) ─────────────────────────────
FONT_DIR = "/usr/share/fonts/truetype/dejavu/"
pdfmetrics.registerFont(TTFont("DV", FONT_DIR + "DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DV-B", FONT_DIR + "DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DV-I", FONT_DIR + "DejaVuSans-Oblique.ttf"))
pdfmetrics.registerFont(TTFont("DV-BI", FONT_DIR + "DejaVuSans-BoldOblique.ttf"))
# ── Colours ───────────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#0A7D8C")
LIGHT_TEAL = colors.HexColor("#D9F0F3")
GOLD = colors.HexColor("#F5A623")
LIGHT_GOLD = colors.HexColor("#FFF8E7")
WHITE = colors.white
DARK_TEXT = colors.HexColor("#1A1A2E")
Q_BLUE = colors.HexColor("#E8F4FD")
A_GREEN = colors.HexColor("#E8F9EE")
BLUE_LIGHT = colors.HexColor("#CCE8FF")
PAGE_W, PAGE_H = A4
# ── Doc factory ───────────────────────────────────────────────────────────────
def make_doc(filename):
return SimpleDocTemplate(
filename, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm
)
# ── Styles (all using DejaVu) ─────────────────────────────────────────────────
ss = getSampleStyleSheet()
def sty(name, **kw):
return ParagraphStyle(name, parent=ss["Normal"], **kw)
# Cover
C_TITLE = sty("CT", fontSize=30, leading=36, alignment=TA_CENTER, textColor=WHITE, fontName="DV-B")
C_RU = sty("CR", fontSize=12, leading=17, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="DV-I")
C_SUB = sty("CS", fontSize=13, leading=18, alignment=TA_CENTER, textColor=LIGHT_TEAL, fontName="DV")
C_BAND = sty("CB", fontSize=11, leading=15, alignment=TA_CENTER, textColor=WHITE, fontName="DV-B")
C_RU2 = sty("CR2", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="DV-I")
C_TAG = sty("CTG", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#FFE0A0"), fontName="DV-I")
C_GOLD = sty("CG", fontSize=13, leading=18, alignment=TA_CENTER, textColor=GOLD, fontName="DV-B")
# Headings
H_EN = sty("HE", fontSize=13, leading=18, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B")
H_RU = sty("HR", fontSize=10, leading=14, alignment=TA_CENTER, textColor=TEAL, fontName="DV-I")
# Body
B_EN = sty("BE", fontSize=11, leading=16, alignment=TA_JUSTIFY, textColor=DARK_TEXT, fontName="DV")
B_RU = sty("BR", fontSize=10, leading=14, alignment=TA_JUSTIFY, textColor=colors.HexColor("#3A3A5C"), fontName="DV-I")
# Example sentences
EX_EN = sty("EE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="DV-B")
EX_RU = sty("ER", fontSize=10, leading=14, alignment=TA_LEFT, textColor=TEAL, fontName="DV-I")
# Table
TH = sty("TH", fontSize=9, leading=12, alignment=TA_CENTER, textColor=WHITE, fontName="DV-B")
TH_RU = sty("THR", fontSize=8, leading=11, alignment=TA_CENTER, textColor=BLUE_LIGHT, fontName="DV-I")
TC = sty("TC", fontSize=10, leading=13, alignment=TA_LEFT, textColor=DARK_TEXT, fontName="DV-B")
TR = sty("TR", fontSize=9, leading=12, alignment=TA_LEFT, textColor=colors.HexColor("#3A3A5C"), fontName="DV-I")
# Q&A
Q_EN = sty("QE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="DV-B")
Q_RU = sty("QR", fontSize=9, leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#444488"), fontName="DV-I")
A_EN = sty("AE", fontSize=11, leading=15, alignment=TA_LEFT, textColor=colors.HexColor("#1A6B2E"), fontName="DV")
A_RU = sty("AR", fontSize=9, leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#2A7A44"), fontName="DV-I")
# Notes
N_EN = sty("NE", fontSize=10, leading=14, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B")
N_RU = sty("NR", fontSize=9, leading=13, alignment=TA_CENTER, textColor=TEAL, fontName="DV-I")
# ── Utilities ─────────────────────────────────────────────────────────────────
def divider():
return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceBefore=5, spaceAfter=5)
def sp(h=0.2):
return Spacer(1, h * cm)
def colbox(items, bg=LIGHT_TEAL, pad=8):
data = [[items]]
t = Table(data, colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("BOX", (0,0),(-1,-1), 0.8, TEAL),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING", (0,0),(-1,-1), pad),
("LEFTPADDING", (0,0),(-1,-1), pad),
("RIGHTPADDING", (0,0),(-1,-1), pad),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
def hdr_cell(en, ru):
return [Paragraph(en, TH), Paragraph(ru, TH_RU)]
def sec(story, en, ru):
story.append(divider())
story.append(Paragraph(en, H_EN))
story.append(Paragraph(ru, H_RU))
story.append(sp(0.22))
def qa_block(story, n, qe, qr, ae, ar):
w = [PAGE_W - 4*cm]
qt = Table([[Paragraph(f"❓ Q{n}: {qe}", Q_EN)], [Paragraph(qr, Q_RU)]], colWidths=w)
qt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), Q_BLUE),
("BOX", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
at = Table([[Paragraph(f"✅ {ae}", A_EN)], [Paragraph(ar, A_RU)]], colWidths=w)
at.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), A_GREEN),
("BOX", (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
story.append(KeepTogether([qt, sp(0.1), at, sp(0.25)]))
def formula_row(story, boxes):
"""boxes = list of (EN, RU, bg_color) or ('+', '', WHITE)"""
cells, widths, bg_cmds = [], [], []
for i, (en, ru, bg) in enumerate(boxes):
if en == "+":
cells.append([Paragraph("+", sty(f"pl{i}", fontSize=14, leading=16,
alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B"))])
widths.append(0.65*cm)
else:
cells.append([Paragraph(en, TH), Paragraph(ru, TH_RU)])
widths.append(None)
bg_cmds.append(("BACKGROUND", (i,0),(i,0), bg))
n_real = sum(1 for e,_,_ in boxes if e != "+")
fixed = 0.65 * sum(1 for e,_,_ in boxes if e == "+")
w_each = (PAGE_W - 4*cm - fixed*cm) / n_real
widths = [0.65*cm if boxes[i][0]=="+" else w_each for i in range(len(boxes))]
t = Table([cells], colWidths=widths)
t.setStyle(TableStyle([
("BOX", (0,0),(-1,-1), 1, DARK_BLUE),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
] + bg_cmds))
story.append(t)
story.append(sp(0.2))
def std_table(data, col_widths, story):
tbl = Table(data, colWidths=col_widths, repeatRows=1)
ts = [
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for i in range(1, len(data)):
ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
tbl.setStyle(TableStyle(ts))
story.append(tbl)
def cover_page(story, en_title, ru_title, list_en, list_ru):
rows = [
[Paragraph("📚 ✏️ 📚", sty("EM", fontSize=22, leading=28,
alignment=TA_CENTER, textColor=WHITE, fontName="DV"))],
[sp(0.2)],
[Paragraph("Grade 3 ESL", C_BAND)],
[Paragraph("3-й класс ЭСЛ", C_RU2)],
[sp(0.3)],
[Paragraph(en_title, C_TITLE)],
[Paragraph(ru_title, C_RU)],
[sp(0.3)],
[Paragraph("Handbook – Table, Formula & Conversations", C_SUB)],
[Paragraph("Справочник – таблица, формула и разговоры", C_RU2)],
[sp(0.25)],
[Paragraph(list_en, C_BAND)],
[Paragraph(list_ru, C_RU2)],
[sp(0.35)],
[Paragraph("English ⇄ Russian", C_GOLD)],
[Paragraph("Английский ⇄ Русский", C_RU2)],
[sp(0.35)],
[Paragraph("Made with ❤️ for young learners", C_TAG)],
[Paragraph("Создано с ❤️ для юных учеников", C_TAG)],
[sp(0.2)],
]
t = Table(rows, colWidths=[PAGE_W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), DARK_BLUE),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 14),
("BOX", (0,0),(-1,-1), 2.5, GOLD),
]))
story.append(t)
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
story = []
cover_page(story,
"Object\nPronouns",
"Объектные местоимения",
"Me • You • Him • Her • It • Us • Them",
"Меня • Тебя • Его • Её • Его/Её • Нас • Их")
# Page 2 – What is an Object Pronoun?
sec(story, "What is an Object Pronoun? 🤔", "Что такое объектное местоимение?")
story.append(colbox([
Paragraph("An object pronoun replaces the name of a person or thing that receives the action of a verb.", B_EN),
Paragraph("Объектное местоимение заменяет имя человека или предмета, на которое направлено действие глагола.", B_RU),
sp(0.12),
Paragraph("It always comes AFTER the verb or a preposition.", B_EN),
Paragraph("Оно всегда стоит ПОСЛЕ глагола или предлога.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.28))
for en, ru in [
("🤔 She sees me every morning.", "Она видит меня каждое утро."),
("🤔 The teacher called him.", "Учитель позвал его."),
("🤔 Can you help us?", "Можешь помочь нам?"),
]:
story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.15))
# Page 3 – Table
sec(story, "🤔 Object Pronouns Table", "Таблица объектных местоимений")
hdr = [hdr_cell("Object Pronoun (EN)\nОбъектное местоимение",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
rows = [
("ME / МНЕ / МЕНЯ", "меня / мне", "She called me.\nОна позвонила мне."),
("YOU / ТЕБЯ / ВАС", "тебя / вас", "I see you every day.\nЯ вижу тебя каждый день."),
("HIM / ЕГО", "его / ему", "We helped him.\nМы помогли ему."),
("HER / ЕЁ", "её / ей", "He thanked her.\nОн поблагодарил её."),
("IT / ЕГО / ЕЁ", "его / её", "I can see it clearly.\nЯ вижу его отчётливо."),
("US / НАС", "нас / нам", "She invited us.\nОна пригласила нас."),
("THEM / ИХ", "их / им", "I know them well.\nЯ знаю их хорошо."),
]
tdata = [hdr]
for p, r, ex in rows:
tdata.append([[Paragraph(p, TC)], [Paragraph(r, TR)], [Paragraph(ex, TC)]])
std_table(tdata, [4*cm, 4.2*cm, 7.3*cm], story)
# Page 4 – Formula
sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
formula_row(story, [
("SUBJECT\nПОДЛЕЖАЩЕЕ", "", DARK_BLUE),
("+","",WHITE),
("VERB\nГЛАГОЛ", "", TEAL),
("+","",WHITE),
("OBJECT PRONOUN\nОБЪЕКТНОЕ МЕСТОИМЕНИЕ", "", GOLD),
])
sec(story, "🤔 Example Sentences", "Примеры предложений")
fhdr = [hdr_cell("Subject\nПодлежащее",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Object Pronoun\nОбъектное мест.",""), hdr_cell("Translation\nПеревод","")]
frows = [
("She", "sees", "me", "Она видит меня."),
("We", "helped", "him", "Мы помогли ему."),
("The teacher", "called", "them", "Учитель позвал их."),
("I", "will call", "you tomorrow", "Я позвоню тебе завтра."),
("They", "surprised", "us", "Они удивили нас."),
("He", "thanked", "her", "Он поблагодарил её."),
]
fdata = [fhdr]
for s, v, op, ru in frows:
fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(op, TC), Paragraph(ru, TR)])
std_table(fdata, [3.5*cm, 3*cm, 4*cm, 5*cm], story)
# Pages 5-7 – Conversations
convs = [
("Who did the teacher call to the board?","Кого учитель вызвал к доске?","She called me. I walked to the board and wrote the answer.","Она вызвала меня. Я подошёл к доске и написал ответ."),
("Can you see the bird on the tree?","Ты видишь птицу на дереве?","Yes, I can see it. It is sitting very still on the branch.","Да, я вижу её. Она сидит очень тихо на ветке."),
("Did your friends invite you to the party?","Твои друзья пригласили тебя на вечеринку?","Yes, they invited me and I am very excited to go.","Да, они пригласили меня, и я очень рад идти."),
("Who helped Tim with his homework?","Кто помог Тиму с домашним заданием?","His older sister helped him. She explained every problem clearly.","Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),
("Did the coach choose Sara for the team?","Тренер выбрал Сару в команду?","Yes, the coach chose her. She is a very fast runner.","Да, тренер выбрал её. Она очень быстро бегает."),
("Did you and your class win the quiz?","Ты и твой класс выиграли викторину?","Yes! The principal gave us a trophy and took our photograph.","Да! Директор вручил нам кубок и сфотографировал нас."),
("Where are the new books? Did the librarian bring them?","Где новые книги? Библиотекарь принёс их?","Yes, she brought them this morning and put them on the shelf.","Да, она принесла их этим утром и поставила на полку."),
("Your dog ran away — did anyone find it?","Твоя собака убежала — кто-нибудь нашёл её?","The neighbour found it and brought it home safely.","Сосед нашёл её и безопасно привёл домой."),
("Did your teacher read your story?","Учитель прочитал твой рассказ?","Yes, she read it and said it was very creative.","Да, она прочитала его и сказала, что он очень творческий."),
("Can we sit with you at lunch?","Мы можем сесть с тобой на обед?","Of course! You can sit next to me. There is enough room.","Конечно! Вы можете сесть рядом со мной. Места достаточно."),
("Did the doctor check Max and Lily?","Врач осмотрел Макса и Лили?","Yes, the doctor checked them and said they are both healthy.","Да, врач осмотрел их и сказал, что они оба здоровы."),
("Who did you wave to at the gate?","Кому ты помахал у ворот?","I waved to her. She waved back and smiled at me.","Я помахал ей. Она помахала в ответ и улыбнулась мне."),
("Can your father drive us to school?","Твой папа может отвезти нас в школу?","Yes, he can drive us. He leaves at 7:30 every morning.","Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),
("Did the storm damage the fence?","Буря повредила забор?","Yes, it damaged it badly. My father will repair it on Saturday.","Да, она сильно повредила его. Мой папа починит его в субботу."),
("Why did the principal call you and Tom?","Почему директор вызвал тебя и Тома?","She called us because we won first place in the science fair.","Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
]
for start in [0, 5, 10]:
sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# Page 8 – Quick Reference
sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример (англ. + рус.)","")]
qrows = [
("ME\nМЕНЯ", "меня / мне", "She sees me.\nОна видит меня."),
("YOU\nТЕБЯ", "тебя / вас", "I called you.\nЯ позвонил тебе."),
("HIM\nЕГО", "его / ему", "We helped him.\nМы помогли ему."),
("HER\nЕЁ", "её / ей", "He thanked her.\nОн поблагодарил её."),
("IT\nЕГО/ЕЁ", "его / её", "I can see it.\nЯ вижу его."),
("US\nНАС", "нас / нам", "She invited us.\nОна пригласила нас."),
("THEM\nИХ", "их / им", "I know them.\nЯ знаю их."),
]
qdata = [qhdr]
for p, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
std_table(qdata, [3.5*cm, 4*cm, 8*cm], story)
story.append(sp(0.25))
story.append(colbox([
Paragraph("🤔 Object pronouns come AFTER the verb or preposition!", N_EN),
Paragraph("Объектные местоимения стоят ПОСЛЕ глагола или предлога!", N_RU),
], bg=LIGHT_GOLD))
make_doc(out).build(story)
print(f"✅ {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
story = []
cover_page(story,
"Demonstrative\nPronouns",
"Указательные местоимения",
"This • That • These • Those",
"Этот/Эта/Это • Тот/Та/То • Эти • Те")
# Page 2 – Definition
sec(story, "What is a Demonstrative Pronoun? 🤔", "Что такое указательное местоимение?")
story.append(colbox([
Paragraph("A demonstrative pronoun points to a specific person or thing.", B_EN),
Paragraph("Указательное местоимение указывает на конкретного человека или предмет.", B_RU),
sp(0.12),
Paragraph("THIS and THESE = things that are NEAR you.", B_EN),
Paragraph("THIS и THESE = предметы, которые находятся БЛИЗКО к вам.", B_RU),
sp(0.08),
Paragraph("THAT and THOSE = things that are FAR AWAY.", B_EN),
Paragraph("THAT и THOSE = предметы, которые находятся ДАЛЕКО от вас.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.28))
for en, ru in [
("🤔 This is my pencil. (near me)", "Это мой карандаш. (рядом со мной)"),
("🤔 That is a tall building. (far away)", "То — высокое здание. (далеко)"),
("🤔 These are my books. (near, more than one)", "Эти — мои книги. (рядом, больше одного)"),
("🤔 Those are his shoes. (far, more than one)", "Те — его туфли. (далеко, больше одного)"),
]:
story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.12))
# Page 3 – Table
sec(story, "🤔 Demonstrative Pronouns Table", "Таблица указательных местоимений")
hdr = [hdr_cell("Demonstrative Pronoun\nУказательное местоимение",""), hdr_cell("Number / Distance\nЧисло / Расстояние",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
rows = [
("THIS / ЭТО", "Singular / Near\nЕд.ч. / Близко", "этот / эта / это", "This is my bag.\nЭта сумка — моя."),
("THAT / ТО", "Singular / Far\nЕд.ч. / Далеко", "тот / та / то", "That is a big tree.\nТо — большое дерево."),
("THESE / ЭТИ", "Plural / Near\nМн.ч. / Близко", "эти", "These are my crayons.\nЭти — мои карандаши."),
("THOSE / ТЕ", "Plural / Far\nМн.ч. / Далеко", "те", "Those are her books.\nТе — её книги."),
]
tdata = [hdr]
for p, nd, ru, ex in rows:
tdata.append([Paragraph(p, TC), Paragraph(nd, TR), Paragraph(ru, TR), Paragraph(ex, TC)])
std_table(tdata, [3*cm, 3.7*cm, 3.5*cm, 5.3*cm], story)
# Near vs Far visual box
story.append(sp(0.25))
nf = Table([
[Paragraph("📍 NEAR — близко к вам", sty("NF1", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B")),
Paragraph("📍 FAR — далеко от вас", sty("NF2", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B"))],
[Paragraph("Singular (1): THIS\nЕдинственное число (1): THIS\n\nPlural (2+): THESE\nМножественное число (2+): THESE", TC),
Paragraph("Singular (1): THAT\nЕдинственное число (1): THAT\n\nPlural (2+): THOSE\nМножественное число (2+): THOSE", TC)],
], colWidths=[7.75*cm, 7.75*cm])
nf.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,-1), colors.HexColor("#DFF5E1")),
("BACKGROUND", (1,0),(1,-1), colors.HexColor("#FFF0D0")),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(nf)
# Page 4 – Formula
sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
formula_row(story, [
("DEM. PRONOUN\nУКАЗАТ. МЕСТОИМ.", "", DARK_BLUE),
("+","",WHITE),
("IS / ARE\nЕСТЬ / ЯВЛЯЮТСЯ", "", TEAL),
("+","",WHITE),
("REST OF SENTENCE\nОСТАТОК ПРЕДЛОЖЕНИЯ", "", GOLD),
])
sec(story, "🤔 Example Sentences", "Примеры предложений")
fhdr = [hdr_cell("Dem. Pronoun\nУказат. мест.",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Rest\nОстаток",""), hdr_cell("Translation\nПеревод","")]
frows = [
("This", "is", "my notebook.", "Это мой блокнот."),
("That", "is", "a very old bridge.", "То — очень старый мост."),
("These", "are", "fresh apples.", "Эти — свежие яблоки."),
("Those", "are", "my father's tools.", "Те — инструменты моего папы."),
("This", "is", "the correct answer.", "Это правильный ответ."),
("Those", "are", "wild birds.", "Те — дикие птицы."),
]
fdata = [fhdr]
for dp, v, rest, ru in frows:
fdata.append([Paragraph(dp, TC), Paragraph(v, TC), Paragraph(rest, TC), Paragraph(ru, TR)])
std_table(fdata, [3.5*cm, 2.5*cm, 5*cm, 4.5*cm], story)
# Pages 5-7 – Conversations
convs = [
("What is that tall building near the park?","Что это за высокое здание у парка?","That is the new library. It opened last month and has many books.","То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),
("Are these your colour pencils on the table?","Это твои цветные карандаши на столе?","Yes, these are mine. I use them for my art class every Friday.","Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),
("What is this small animal in the box?","Что это за маленькое животное в коробке?","This is a hamster. Its name is Peanut.","Это хомяк. Его зовут Пинат."),
("Whose shoes are those by the front door?","Чьи это туфли у парадной двери?","Those are my father's shoes. He always leaves them there after work.","Те — туфли моего папы. Он всегда оставляет их там после работы."),
("Is this the right classroom for Grade 3?","Это правильный класс для 3-го класса?","Yes, this is the right one. Our teacher is already inside.","Да, это правильный. Наш учитель уже внутри."),
("What are those colourful flags on the wall?","Что это за разноцветные флаги на стене?","Those are country flags. Our teacher put them up for a geography lesson.","Те — флаги стран. Наш учитель повесил их для урока географии."),
("Is this water safe to drink?","Эта вода безопасна для питья?","Yes, this is clean drinking water from the school filter.","Да, это чистая питьевая вода из школьного фильтра."),
("What are these papers on your desk?","Что это за бумаги на твоём столе?","These are my test results. I got a high score in all subjects.","Это мои результаты тестов. Я получил высокий балл по всем предметам."),
("Can you see those children in the yard?","Ты видишь тех детей во дворе?","Yes, I can see them. Those are my classmates playing football.","Да, я вижу их. Те — мои одноклассники, они играют в футбол."),
("Whose drawing is this on the board?","Чей это рисунок на доске?","This is Anna's drawing. She drew it during free time today.","Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),
("Are those mountains real or in a picture?","Те горы настоящие или на картинке?","Those are real mountains. We can see them from the school roof.","Те горы настоящие. Мы можем видеть их с крыши школы."),
("What is this sweet smell in the kitchen?","Что это за сладкий запах на кухне?","This is the smell of fresh bread. The cook baked it this morning.","Это запах свежего хлеба. Повар испёк его этим утром."),
("Are these apples from your garden?","Эти яблоки из вашего сада?","Yes, these are from our garden. My mother picked them yesterday.","Да, эти — из нашего сада. Мама сорвала их вчера."),
("What are those bright lights in the sky?","Что это за яркие огни в небе?","Those are stars. On a clear night you can count hundreds of them.","Те — звёзды. В ясную ночь можно сосчитать сотни из них."),
("Is this the book you wanted to borrow?","Это та книга, которую ты хотел взять?","Yes, this is the one! I have been looking for it all week.","Да, это она! Я искал её всю неделю."),
]
for start in [0, 5, 10]:
sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# Page 8 – Quick Reference
sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Use\nКогда использовать",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример","")]
qrows = [
("THIS / ЭТО", "Singular / Near\nЕд.ч. / Близко", "этот/эта/это", "This is my pen.\nЭто моя ручка."),
("THAT / ТО", "Singular / Far\nЕд.ч. / Далеко", "тот/та/то", "That is a cloud.\nТо — облако."),
("THESE / ЭТИ", "Plural / Near\nМн.ч. / Близко", "эти", "These are my boots.\nЭти — мои сапоги."),
("THOSE / ТЕ", "Plural / Far\nМн.ч. / Далеко", "те", "Those are tall trees.\nТе — высокие деревья."),
]
qdata = [qhdr]
for p, u, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(u, TR), Paragraph(r, TR), Paragraph(ex, TC)])
std_table(qdata, [3*cm, 3.5*cm, 3*cm, 6*cm], story)
story.append(sp(0.25))
story.append(colbox([
Paragraph("🤔 THIS / THESE = near you • THAT / THOSE = far away", N_EN),
Paragraph("THIS / THESE = рядом с вами • THAT / THOSE = далеко от вас", N_RU),
sp(0.1),
Paragraph("THIS / THAT = singular (one) • THESE / THOSE = plural (more than one)", N_EN),
Paragraph("THIS / THAT = единственное число (один) • THESE / THOSE = множественное число (много)", N_RU),
], bg=LIGHT_GOLD))
make_doc(out).build(story)
print(f"✅ {out}")
# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
story = []
cover_page(story,
"Possessive\nPronouns",
"Притяжательные местоимения (самостоятельные)",
"Mine • Yours • His • Hers • Ours • Theirs",
"Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их")
# Page 2 – Definition
sec(story, "What is a Possessive Pronoun? 🤔", "Что такое притяжательное местоимение?")
story.append(colbox([
Paragraph("A possessive pronoun shows that something belongs to someone.", B_EN),
Paragraph("Притяжательное местоимение показывает, что что-то принадлежит кому-то.", B_RU),
sp(0.12),
Paragraph("Unlike possessive adjectives (my, your, his...), possessive pronouns STAND ALONE — they do NOT come before a noun.", B_EN),
Paragraph("В отличие от притяжательных прилагательных (my, your, his...), притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным.", B_RU),
], bg=LIGHT_TEAL))
story.append(sp(0.25))
for en, ru in [
("🤔 This pencil is mine.", "Этот карандаш — мой."),
("🤔 That red bag is hers.", "Та красная сумка — её."),
("🤔 The blue umbrella is ours.", "Синий зонт — наш."),
("🤔 Those books are theirs.", "Те книги — их."),
]:
story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.12))
# Adjective vs Pronoun comparison
story.append(sp(0.1))
cmp = Table([
[Paragraph("Possessive ADJECTIVE (before a noun)\nПрит. ПРИЛАГАТЕЛЬНОЕ (перед существительным)", TH),
Paragraph("Possessive PRONOUN (stands alone)\nПрит. МЕСТОИМЕНИЕ (самостоятельно)", TH)],
[Paragraph("This is my book.\nЭто моя книга.", TC),
Paragraph("This book is mine.\nЭта книга — моя.", TC)],
[Paragraph("Your pencil is sharp.\nТвой карандаш острый.", TC),
Paragraph("The pencil is yours.\nКарандаш — твой.", TC)],
[Paragraph("Their dog is big.\nИх собака большая.", TC),
Paragraph("The big dog is theirs.\nБольшая собака — их.", TC)],
], colWidths=[7.75*cm, 7.75*cm])
cmp.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), DARK_BLUE),
("BACKGROUND", (0,1),(0,-1), colors.HexColor("#FFF0D0")),
("BACKGROUND", (1,1),(1,-1), colors.HexColor("#DFF5E1")),
("BOX", (0,0),(-1,-1), 1, TEAL),
("INNERGRID", (0,0),(-1,-1), 0.5, TEAL),
("TOPPADDING", (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(cmp)
# Page 3 – Table
sec(story, "🤔 Possessive Pronouns Table", "Таблица притяжательных местоимений")
hdr = [hdr_cell("Possessive Pronoun (EN)\nПритяжательное местоимение",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
rows = [
("MINE\nМОЙ / МОЯ / МОЁ", "мой / моя / моё / мои", "This pencil is mine.\nЭтот карандаш — мой."),
("YOURS\nТВОЙ / ВАШ", "твой / твоя / ваш / ваша", "Is this seat yours?\nЭто место твоё?"),
("HIS\nЕГО", "его", "The blue jacket is his.\nСиняя куртка — его."),
("HERS\nЕЁ", "её", "That red umbrella is hers.\nТот красный зонт — её."),
("OURS\nНАШ / НАША", "наш / наша / наше / наши", "This classroom is ours.\nЭтот класс — наш."),
("THEIRS\nИХ", "их", "Those bikes are theirs.\nТе велосипеды — их."),
]
tdata = [hdr]
for p, r, ex in rows:
tdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
std_table(tdata, [4*cm, 4.5*cm, 7*cm], story)
# Page 4 – Formula
sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
formula_row(story, [
("NOUN / SUBJECT\nСУЩ. / ПОДЛЕЖАЩЕЕ", "", DARK_BLUE),
("+","",WHITE),
("IS / ARE\nЕСТЬ / ЯВЛЯЮТСЯ", "", TEAL),
("+","",WHITE),
("POSSESSIVE PRONOUN\nПРИТЯЖ. МЕСТОИМЕНИЕ", "", GOLD),
])
sec(story, "🤔 Example Sentences", "Примеры предложений")
fhdr = [hdr_cell("Noun / Subject\nПодлежащее",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Poss. Pronoun\nПрит. мест.",""), hdr_cell("Translation\nПеревод","")]
frows = [
("This eraser", "is", "mine", "Этот ластик — мой."),
("The green backpack", "is", "yours", "Зелёный рюкзак — твой."),
("That trophy", "is", "his", "Тот кубок — его."),
("The pink water bottle","is", "hers", "Розовая бутылка воды — её."),
("The corner table", "is", "ours", "Угловой стол — наш."),
("Those big umbrellas", "are", "theirs", "Те большие зонты — их."),
]
fdata = [fhdr]
for s, v, pp, ru in frows:
fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(pp, TC), Paragraph(ru, TR)])
std_table(fdata, [4.5*cm, 2.5*cm, 3.5*cm, 5*cm], story)
# Pages 5-7 – Conversations
convs = [
("Whose eraser is on the floor?","Чей ластик лежит на полу?","That eraser is mine. I dropped it when I was writing.","Тот ластик — мой. Я уронил его, когда писал."),
("Is this blue jacket yours?","Эта синяя куртка твоя?","Yes, that jacket is mine. I left it on the chair after lunch.","Да, та куртка — моя. Я оставил её на стуле после обеда."),
("Whose turn is it to lead the class?","Чья очередь руководить классом?","The turn is his. He is the class leader this week.","Очередь — его. Он дежурный по классу на этой неделе."),
("I found a purple water bottle. Is it yours?","Я нашёл фиолетовую бутылку воды. Она твоя?","No, it is not mine. It might be hers — she has a purple one.","Нет, это не моя. Это может быть её — у неё есть фиолетовая."),
("Which team won the relay race?","Какая команда выиграла эстафету?","The victory is ours! We practised every day after school.","Победа — наша! Мы тренировались каждый день после школы."),
("Are those large bags by the bus theirs?","Те большие сумки у автобуса — их?","Yes, those bags are theirs. Their family is going on a trip.","Да, те сумки — их. Их семья едет в поездку."),
("Whose science project got first place?","Чей научный проект занял первое место?","The first-place project is hers. She worked on it for two weeks.","Проект на первом месте — её. Она работала над ним две недели."),
("I see two bicycles. Which one is yours?","Я вижу два велосипеда. Который твой?","The red one is mine. The yellow one is my brother's.","Красный — мой. Жёлтый — моего брата."),
("Whose idea was it to plant flowers in the garden?","Чья это была идея — посадить цветы в саду?","The idea was ours. The whole class voted for it together.","Идея была наша. Весь класс проголосовал за неё вместе."),
("Is that trophy in the cabinet his?","Тот кубок в шкафу — его?","Yes, that trophy is his. He won it at the swimming competition.","Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),
("Whose homework is on the teacher's table?","Чьё домашнее задание лежит на столе учителя?","The homework on the table is mine. I handed it in this morning.","Домашнее задание на столе — моё. Я сдал его сегодня утром."),
("Those colourful drawings on the wall — are they yours?","Те красочные рисунки на стене — твои?","No, they are not mine. Those drawings are theirs — the art club students.","Нет, не мои. Те рисунки — их, учеников кружка рисования."),
("This umbrella was left at the door. Is it yours or hers?","Этот зонт оставили у двери. Он твой или её?","It is hers. She forgot it when she ran to catch the school bus.","Он её. Она забыла его, когда бежала на школьный автобус."),
("We found a lunch box with no name. Is it yours?","Мы нашли ланч-бокс без имени. Он твой?","Yes, that lunch box is mine! I forgot to write my name on it.","Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),
("Are those tools in the shed ours or the neighbours'?","Те инструменты в сарае — наши или соседей?","Those tools are ours. My father uses them to fix things at home.","Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
]
for start in [0, 5, 10]:
sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
qa_block(story, i, qe, qr, ae, ar)
# Page 8 – Quick Reference
sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример (англ. + рус.)","")]
qrows = [
("MINE\nМОЙ / МОЯ", "мой/моя/моё/мои", "This pen is mine.\nЭта ручка — моя."),
("YOURS\nТВОЙ / ВАШ", "твой/ваш", "Is this seat yours?\nЭто место твоё?"),
("HIS\nЕГО", "его", "The trophy is his.\nКубок — его."),
("HERS\nЕЁ", "её", "The red bag is hers.\nКрасная сумка — её."),
("OURS\nНАШ / НАША", "наш/наша", "This classroom is ours.\nЭтот класс — наш."),
("THEIRS\nИХ", "их", "Those bikes are theirs.\nТе велосипеды — их."),
]
qdata = [qhdr]
for p, r, ex in qrows:
qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
std_table(qdata, [3.5*cm, 4*cm, 8*cm], story)
story.append(sp(0.25))
story.append(colbox([
Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun!", N_EN),
Paragraph("Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным!", N_RU),
sp(0.1),
Paragraph("Compare: 'my book' (adjective) vs. 'the book is mine' (pronoun)", N_EN),
Paragraph("Сравните: 'моя книга' (прилагательное) и 'книга — моя' (местоимение)", N_RU),
], bg=LIGHT_GOLD))
make_doc(out).build(story)
print(f"✅ {out}")
# ── Run ───────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
build_object_pronouns()
build_demonstrative_pronouns()
build_possessive_pronouns()
print("\n🎉 All three handbooks created successfully!")
cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v3.py 2>&1
ls /usr/share/fonts/truetype/dejavu/ echo "---" ls /usr/share/fonts/truetype/lib…
~/esl-pronouns/build_handbooks_v3.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/esl-pronouns/build_handbooks_v3.py'
cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v3.py 2>&1
ls -lh /home/daytona/workspace/esl-pronouns/*.pdf && python3 -c " from pypdf imp…
ESL Grade3 Object Pronouns
PDF Document · PDF
ESL Grade3 Demonstrative Pronouns
PDF Document · PDF
ESL Grade3 Possessive Pronouns
PDF Document · PDF