Please prepare a colorful handbook pdf from below mentioned text and instructions ,you can can add or subtract some part of information if you find it's not appropriate for 3rd grade ESL student.Also write formula and format at the top ,also write Russian translation of each and every word UN and sentences under their English.My School Life – 15 Simple Questions & Answers (British English) 1. What do you put in your bag for school? A: My pencil case is in my bag. My lunch is in my bag. These are mine. --- 2. What subject does your best friend like the most? A: Her favourite subject is art. That is her favourite. --- 3. Where do you and your friends eat your lunch? A: We eat our lunch in the dinner hall. This is our table. --- 4. How does your teacher help you when you do not understand? A: My teacher helps. Her voice is kind. That is her help. --- 5. What is your favourite room in the school? A: My favourite room is the library. Its books are nice. Those are my books. --- 6. Who sits beside you in class? A: Oliver sits beside me. His bag is blue. Mine is red. --- 7. What are your friends doing at break time? A: Their game is football. That is their game. Mine is skipping. This is mine. --- 8. What do you see on the walls of your classroom? A: Our paintings are on the wall. These are ours. --- 9. What is your head teacher doing now? A: Our head teacher is at the door. Her smile is big. That is her smile. --- 10. What is an important school rule? A: "Be kind" is our rule. That is our rule. --- 11. How do you keep your classroom tidy? A: My job is books. Your job is pencils. Those are our jobs. --- 12. A new pupil is in your class. Whose seat is next to you? A: His seat is next to mine. Her seat is next to yours. This seat is his. --- 13. What books do you borrow from the library? A: My books are storybooks. These are mine for one week. --- 14. How do your parents get school news? A: Their news is a letter. That letter is theirs. Its news is good. --- 15. What makes you feel proud at school? A: My drawing is on the wall. That drawing is mine. --- Simple Pronoun Guide Type Pronouns Possessive Adjectives my, your, his, her, its, our, their Possessive Pronouns mine, yours, his, hers, ours, theirs Demonstrative Pronouns this, that, these, those
Retry
mkdir -p /tmp/workspace/esl-handbook && ls /tmp/workspace/
~/esl-handbook/build_handbook.py
#!/usr/bin/env python3
"""
My School Life – ESL Handbook for Grade 3
Colourful PDF with English text + Russian translations
Uses ReportLab
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os
# ── Register a Unicode font so Cyrillic renders properly ──────────────────────
# DejaVu ships with most Linux / ReportLab installs
FONT_PATHS = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf",
]
def find_font(name_fragment):
for p in FONT_PATHS:
if name_fragment in p and os.path.exists(p):
return p
# fallback: search common dirs
for base in ["/usr/share/fonts", "/usr/local/share/fonts", os.path.expanduser("~/.fonts")]:
for root, dirs, files in os.walk(base):
for f in files:
if name_fragment in f and f.endswith(".ttf"):
return os.path.join(root, f)
return None
reg_path = find_font("DejaVuSans.ttf")
bold_path = find_font("DejaVuSans-Bold.ttf")
if reg_path:
pdfmetrics.registerFont(TTFont("DejaVu", reg_path))
BASE_FONT = "DejaVu"
else:
BASE_FONT = "Helvetica"
if bold_path:
pdfmetrics.registerFont(TTFont("DejaVu-Bold", bold_path))
BOLD_FONT = "DejaVu-Bold"
else:
BOLD_FONT = "Helvetica-Bold"
print(f"Using fonts: {BASE_FONT} / {BOLD_FONT}")
# ── Colour palette ─────────────────────────────────────────────────────────────
C_PURPLE = colors.HexColor("#6A0DAD")
C_ORANGE = colors.HexColor("#FF6B00")
C_TEAL = colors.HexColor("#008080")
C_PINK = colors.HexColor("#E91E8C")
C_BLUE = colors.HexColor("#1565C0")
C_GREEN = colors.HexColor("#2E7D32")
C_YELLOW = colors.HexColor("#FFF176")
C_LAVENDER = colors.HexColor("#EDE7F6")
C_MINT = colors.HexColor("#E8F5E9")
C_PEACH = colors.HexColor("#FFF3E0")
C_SKYBLUE = colors.HexColor("#E3F2FD")
C_ROSEBLUSH= colors.HexColor("#FCE4EC")
C_WHITE = colors.white
C_DARKGREY = colors.HexColor("#37474F")
C_LTGREY = colors.HexColor("#ECEFF1")
C_RUS_BG = colors.HexColor("#F3E5F5") # soft lilac for Russian lines
# Cycling background colours for Q&A cards
CARD_BG = [C_SKYBLUE, C_MINT, C_PEACH, C_ROSEBLUSH, C_LAVENDER]
# ── Paragraph styles ──────────────────────────────────────────────────────────
def make_style(name, font, size, color, leading=None, align=TA_LEFT,
space_before=0, space_after=2, bg=None):
kwargs = dict(
name=name, fontName=font, fontSize=size, textColor=color,
leading=leading or size * 1.35, alignment=align,
spaceBefore=space_before, spaceAfter=space_after,
)
if bg:
kwargs["backColor"] = bg
return ParagraphStyle(**kwargs)
STYLE_COVER_TITLE = make_style("CoverTitle", BOLD_FONT, 28, C_WHITE, leading=34, align=TA_CENTER)
STYLE_COVER_SUB = make_style("CoverSub", BASE_FONT, 14, C_YELLOW, leading=18, align=TA_CENTER)
STYLE_SECTION_HEAD = make_style("SectionHead", BOLD_FONT, 16, C_WHITE, leading=20, align=TA_CENTER, space_before=6)
STYLE_FORMULA_HEAD = make_style("FormulaHead", BOLD_FONT, 13, C_PURPLE, leading=17, space_before=4)
STYLE_FORMULA_EN = make_style("FormulaEn", BOLD_FONT, 11, C_BLUE, leading=15)
STYLE_FORMULA_RU = make_style("FormulaRu", BASE_FONT, 10, C_PURPLE, leading=14, bg=C_RUS_BG)
STYLE_Q_LABEL = make_style("QLabel", BOLD_FONT, 12, C_WHITE, leading=15, align=TA_LEFT)
STYLE_Q_EN = make_style("QEn", BOLD_FONT, 11, C_DARKGREY, leading=15)
STYLE_Q_RU = make_style("QRu", BASE_FONT, 10, C_PURPLE, leading=14, bg=C_RUS_BG)
STYLE_A_EN = make_style("AEn", BASE_FONT, 11, C_DARKGREY, leading=15)
STYLE_A_RU = make_style("ARu", BASE_FONT, 10, C_TEAL, leading=14, bg=C_RUS_BG)
STYLE_WORD_EN = make_style("WordEn", BOLD_FONT, 10, C_BLUE, leading=13)
STYLE_WORD_RU = make_style("WordRu", BASE_FONT, 9, C_PURPLE, leading=12, bg=C_RUS_BG)
STYLE_TABLE_HEAD = make_style("TableHead", BOLD_FONT, 11, C_WHITE, leading=14, align=TA_CENTER)
STYLE_TABLE_CELL = make_style("TableCell", BASE_FONT, 10, C_DARKGREY, leading=13)
STYLE_TABLE_RU = make_style("TableRu", BASE_FONT, 9, C_PURPLE, leading=12)
STYLE_TIPS_HEAD = make_style("TipsHead", BOLD_FONT, 13, C_ORANGE, leading=17, space_before=4)
STYLE_TIPS_EN = make_style("TipsEn", BASE_FONT, 11, C_DARKGREY, leading=15)
STYLE_TIPS_RU = make_style("TipsRu", BASE_FONT, 10, C_PURPLE, leading=14, bg=C_RUS_BG)
# ── Data ──────────────────────────────────────────────────────────────────────
# Pronoun formula / format section at top
FORMULA = {
"title_en": "📘 Pronoun Formula & Format",
"title_ru": "📘 Формула и формат местоимений",
"rows": [
# (Type EN, Type RU, pronouns EN, pronouns RU, example EN, example RU)
(
"Possessive Adjectives",
"Притяжательные прилагательные",
"my, your, his, her, its, our, their",
"мой/моя/моё, твой, его, её, его (неод.), наш, их",
"My bag is red. / Her book is nice.",
"Моя сумка красная. / Её книга красивая.",
),
(
"Possessive Pronouns",
"Притяжательные местоимения",
"mine, yours, his, hers, ours, theirs",
"мой/моя, твой/твоя, его, её, наш/наша, их",
"This bag is mine. / That book is hers.",
"Эта сумка моя. / Та книга её.",
),
(
"Demonstrative Pronouns",
"Указательные местоимения",
"this, that, these, those",
"этот/эта/это, тот/та/то, эти, те",
"This is my pencil. / Those are our books.",
"Это мой карандаш. / Те книги наши.",
),
],
"format_en": (
"✏️ FORMAT: \n"
"• Possessive Adjective + Noun → my pencil, her book, our class\n"
"• Subject + is/are + Possessive Pronoun → This is mine. Those are ours.\n"
"• Demonstrative + Noun → This pencil, Those books"
),
"format_ru": (
"✏️ ФОРМАТ: \n"
"• Притяжательное прилагательное + Существительное → мой карандаш, её книга, наш класс\n"
"• Подлежащее + is/are + Притяжательное местоимение → Это моё. Те — наши.\n"
"• Указательное местоимение + Существительное → Этот карандаш, Те книги"
),
}
# Key vocabulary with Russian translations
VOCAB = [
("bag", "сумка"), ("pencil case", "пенал"), ("lunch", "обед"),
("subject", "предмет"), ("art", "рисование/искусство"), ("favourite", "любимый"),
("dinner hall", "столовая"), ("table", "стол"), ("teacher", "учитель/учительница"),
("voice", "голос"), ("kind", "добрый"), ("library", "библиотека"),
("books", "книги"), ("class", "класс"), ("bag", "сумка"),
("break time", "перемена"), ("football", "футбол"), ("skipping", "прыжки со скакалкой"),
("paintings", "картины/рисунки"), ("wall", "стена"), ("head teacher", "директор школы"),
("smile", "улыбка"), ("rule", "правило"), ("tidy", "аккуратный/в порядке"),
("job", "обязанность/дело"), ("seat", "место"), ("storybooks", "книги со сказками"),
("letter", "письмо"), ("news", "новости"), ("proud", "гордый"),
("drawing", "рисунок"), ("pupil", "ученик/ученица"),
]
# Remove duplicate "bag"
seen = set()
VOCAB_CLEAN = []
for pair in VOCAB:
if pair[0] not in seen:
seen.add(pair[0])
VOCAB_CLEAN.append(pair)
# Q&A data: (question EN, question RU, answer EN, answer RU)
QA = [
(
"1. What do you put in your bag for school?",
"1. Что ты кладёшь в сумку для школы?",
"My pencil case is in my bag. My lunch is in my bag. These are mine.",
"Мой пенал в моей сумке. Мой обед в моей сумке. Всё это — моё.",
),
(
"2. What subject does your best friend like the most?",
"2. Какой предмет больше всего нравится твоему лучшему другу?",
"Her favourite subject is art. That is her favourite.",
"Её любимый предмет — рисование. Это её любимое.",
),
(
"3. Where do you and your friends eat your lunch?",
"3. Где вы с друзьями едите обед?",
"We eat our lunch in the dinner hall. This is our table.",
"Мы едим обед в столовой. Это наш стол.",
),
(
"4. How does your teacher help you when you do not understand?",
"4. Как учитель помогает тебе, когда ты не понимаешь?",
"My teacher helps me. Her voice is kind. That is her help.",
"Моя учительница помогает мне. Её голос добрый. Это её помощь.",
),
(
"5. What is your favourite room in the school?",
"5. Какая комната в школе твоя любимая?",
"My favourite room is the library. Its books are nice.",
"Моя любимая комната — библиотека. Её книги замечательные.",
),
(
"6. Who sits beside you in class?",
"6. Кто сидит рядом с тобой в классе?",
"Oliver sits beside me. His bag is blue. Mine is red.",
"Оливер сидит рядом со мной. Его сумка синяя. Моя — красная.",
),
(
"7. What are your friends doing at break time?",
"7. Чем занимаются твои друзья на перемене?",
"Their game is football. That is their game. Mine is skipping.",
"Их игра — футбол. Это их игра. Моя — прыжки со скакалкой.",
),
(
"8. What do you see on the walls of your classroom?",
"8. Что ты видишь на стенах своего класса?",
"Our paintings are on the wall. These are ours.",
"Наши картины висят на стене. Они наши.",
),
(
"9. What is your head teacher doing now?",
"9. Что сейчас делает директор школы?",
"Our head teacher is at the door. Her smile is big.",
"Наш директор стоит у двери. Её улыбка широкая.",
),
(
"10. What is an important school rule?",
"10. Какое важное школьное правило ты знаешь?",
'"Be kind" is our rule. That is our rule.',
'«Будь добрым» — наше правило. Это наше правило.',
),
(
"11. How do you keep your classroom tidy?",
"11. Как вы поддерживаете порядок в классе?",
"My job is books. Your job is pencils. Those are our jobs.",
"Моя обязанность — книги. Твоя обязанность — карандаши. Всё это — наши дела.",
),
(
"12. A new pupil is in your class. Whose seat is next to you?",
"12. В твоём классе новый ученик. Чьё место рядом с тобой?",
"His seat is next to mine. Her seat is next to yours. This seat is his.",
"Его место рядом с моим. Её место рядом с твоим. Это место — его.",
),
(
"13. What books do you borrow from the library?",
"13. Какие книги ты берёшь в библиотеке?",
"My books are storybooks. These are mine for one week.",
"Мои книги — это книги со сказками. Они мои на одну неделю.",
),
(
"14. How do your parents get school news?",
"14. Как твои родители узнают школьные новости?",
"Their news is a letter. That letter is theirs. Its news is good.",
"Их новости — это письмо. То письмо — их. Новости в нём хорошие.",
),
(
"15. What makes you feel proud at school?",
"15. Что заставляет тебя гордиться в школе?",
"My drawing is on the wall. That drawing is mine.",
"Мой рисунок висит на стене. Тот рисунок — мой.",
),
]
# Study tips
TIPS = [
(
"🌟 Tip 1: Possessive Adjectives go BEFORE a noun.",
"🌟 Совет 1: Притяжательные прилагательные ставятся ПЕРЕД существительным.",
'Example: "my bag", "her book", "our class"',
'Пример: «моя сумка», «её книга», «наш класс»',
),
(
"🌟 Tip 2: Possessive Pronouns stand ALONE – no noun after them.",
"🌟 Совет 2: Притяжательные местоимения стоят ОТДЕЛЬНО – после них нет существительного.",
'Example: "This bag is mine." / "Those books are ours."',
'Пример: «Эта сумка моя.» / «Те книги наши.»',
),
(
"🌟 Tip 3: This / These = near you. That / Those = far from you.",
"🌟 Совет 3: This / These = рядом с тобой. That / Those = далеко от тебя.",
'"This is my pencil." (near) / "That is her bag." (far)',
'«Это мой карандаш.» (рядом) / «Та сумка — её.» (далеко)',
),
]
# ── Helper: coloured banner paragraph ────────────────────────────────────────
def banner(text, bg_color, style, padding=4):
"""Return a single-cell Table acting as a coloured banner."""
t = Table([[Paragraph(text, style)]], colWidths=[17*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg_color),
("TOPPADDING", (0,0), (-1,-1), padding),
("BOTTOMPADDING", (0,0), (-1,-1), padding),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4]),
]))
return t
# ── Build story ───────────────────────────────────────────────────────────────
story = []
# ── Cover / Title ─────────────────────────────────────────────────────────────
cover_data = [[
Paragraph("🏫 My School Life", STYLE_COVER_TITLE),
]]
cover_table = Table(cover_data, colWidths=[17*cm])
cover_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_PURPLE),
("TOPPADDING", (0,0), (-1,-1), 18),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
]))
story.append(cover_table)
sub_data = [[
Paragraph("15 Simple Questions & Answers • British English • Grade 3 ESL", STYLE_COVER_SUB),
]]
sub_table = Table(sub_data, colWidths=[17*cm])
sub_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_PINK),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
]))
story.append(sub_table)
ru_sub_data = [[
Paragraph("15 простых вопросов и ответов • Британский английский • 3-й класс ESL", STYLE_Q_RU),
]]
ru_sub_table = Table(ru_sub_data, colWidths=[17*cm])
ru_sub_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_RUS_BG),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 12),
]))
story.append(ru_sub_table)
story.append(Spacer(1, 0.4*cm))
# ── FORMULA & FORMAT SECTION ──────────────────────────────────────────────────
story.append(banner("📘 PRONOUN FORMULA & FORMAT / ФОРМУЛА И ФОРМАТ МЕСТОИМЕНИЙ",
C_TEAL, STYLE_SECTION_HEAD))
story.append(Spacer(1, 0.25*cm))
# Formula table header
formula_header = [
Paragraph("Type / Тип", STYLE_TABLE_HEAD),
Paragraph("Pronouns / Местоимения", STYLE_TABLE_HEAD),
Paragraph("Example / Пример", STYLE_TABLE_HEAD),
]
formula_rows = [formula_header]
for row in FORMULA["rows"]:
type_en, type_ru, pron_en, pron_ru, ex_en, ex_ru = row
formula_rows.append([
Paragraph(f"{type_en}\n{type_ru}", ParagraphStyle(
"fc", fontName=BASE_FONT, fontSize=9, leading=13,
textColor=C_DARKGREY)),
Paragraph(f"<b>{pron_en}</b>\n{pron_ru}", ParagraphStyle(
"fp", fontName=BASE_FONT, fontSize=9, leading=13,
textColor=C_BLUE)),
Paragraph(f"{ex_en}\n{ex_ru}", ParagraphStyle(
"fe", fontName=BASE_FONT, fontSize=9, leading=13,
textColor=C_DARKGREY)),
])
ftable = Table(formula_rows, colWidths=[5*cm, 5.5*cm, 6.5*cm])
ftable.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_PURPLE),
("BACKGROUND", (0,1), (-1,1), C_SKYBLUE),
("BACKGROUND", (0,2), (-1,2), C_MINT),
("BACKGROUND", (0,3), (-1,3), C_PEACH),
("GRID", (0,0), (-1,-1), 0.5, colors.white),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(ftable)
story.append(Spacer(1, 0.25*cm))
# Format box
fmt_data = [[
Paragraph(FORMULA["format_en"], ParagraphStyle(
"fmten", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_BLUE)),
]]
fmt_table = Table(fmt_data, colWidths=[17*cm])
fmt_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_SKYBLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1.5, C_BLUE),
]))
story.append(fmt_table)
story.append(Spacer(1, 0.1*cm))
fmt_ru_data = [[
Paragraph(FORMULA["format_ru"], ParagraphStyle(
"fmtru", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_PURPLE)),
]]
fmt_ru_table = Table(fmt_ru_data, colWidths=[17*cm])
fmt_ru_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_RUS_BG),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1.5, C_PURPLE),
]))
story.append(fmt_ru_table)
story.append(Spacer(1, 0.4*cm))
# ── Q&A SECTION ───────────────────────────────────────────────────────────────
story.append(banner("❓ QUESTIONS & ANSWERS / ВОПРОСЫ И ОТВЕТЫ",
C_ORANGE, STYLE_SECTION_HEAD))
story.append(Spacer(1, 0.3*cm))
for i, (q_en, q_ru, a_en, a_ru) in enumerate(QA):
bg = CARD_BG[i % len(CARD_BG)]
q_style = ParagraphStyle(
f"qs{i}", fontName=BOLD_FONT, fontSize=11, leading=15,
textColor=C_DARKGREY, spaceAfter=2)
q_ru_style = ParagraphStyle(
f"qrs{i}", fontName=BASE_FONT, fontSize=10, leading=14,
textColor=C_PURPLE, spaceAfter=3)
a_style = ParagraphStyle(
f"as{i}", fontName=BASE_FONT, fontSize=11, leading=15,
textColor=C_GREEN, spaceAfter=2)
a_ru_style = ParagraphStyle(
f"ars{i}", fontName=BASE_FONT, fontSize=10, leading=14,
textColor=C_TEAL)
inner = [
Paragraph(q_en, q_style),
Paragraph(q_ru, q_ru_style),
Paragraph(f"✅ {a_en}", a_style),
Paragraph(f"✅ {a_ru}", a_ru_style),
]
card_data = [[inner]]
card = Table(card_data, colWidths=[17*cm])
card.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1, C_LTGREY),
]))
story.append(KeepTogether([card, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── VOCABULARY SECTION ────────────────────────────────────────────────────────
story.append(banner("📚 KEY VOCABULARY / КЛЮЧЕВЫЕ СЛОВА",
C_GREEN, STYLE_SECTION_HEAD))
story.append(Spacer(1, 0.25*cm))
# Build vocab in 3-column layout
voc_rows = []
for i in range(0, len(VOCAB_CLEAN), 3):
chunk = VOCAB_CLEAN[i:i+3]
row = []
for en, ru in chunk:
cell_content = [
Paragraph(f"<b>{en}</b>", ParagraphStyle(
"ven", fontName=BOLD_FONT, fontSize=10, leading=13, textColor=C_BLUE)),
Paragraph(ru, ParagraphStyle(
"vru", fontName=BASE_FONT, fontSize=9, leading=12, textColor=C_PURPLE)),
]
row.append(cell_content)
while len(row) < 3:
row.append("")
voc_rows.append(row)
vtable = Table(voc_rows, colWidths=[5.5*cm, 5.5*cm, 5.5*cm])
vtable_style = [
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
("GRID", (0,0), (-1,-1), 0.5, C_LTGREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
# Alternating row colours
for r in range(len(voc_rows)):
bg_v = C_MINT if r % 2 == 0 else C_PEACH
vtable_style.append(("BACKGROUND", (0,r), (-1,r), bg_v))
vtable.setStyle(TableStyle(vtable_style))
story.append(vtable)
story.append(Spacer(1, 0.4*cm))
# ── PRONOUN TABLE (summary) ───────────────────────────────────────────────────
story.append(banner("📋 PRONOUN QUICK GUIDE / КРАТКИЙ СПРАВОЧНИК ПО МЕСТОИМЕНИЯМ",
C_PINK, STYLE_SECTION_HEAD))
story.append(Spacer(1, 0.25*cm))
pron_data = [
[
Paragraph("Type / Тип", STYLE_TABLE_HEAD),
Paragraph("Pronouns / Местоимения", STYLE_TABLE_HEAD),
Paragraph("Russian / Русский", STYLE_TABLE_HEAD),
],
[
Paragraph("Possessive Adjectives\nПритяжательные прилагательные",
ParagraphStyle("pt1", fontName=BOLD_FONT, fontSize=10, leading=14, textColor=C_BLUE)),
Paragraph("my, your, his, her, its, our, their",
ParagraphStyle("pp1", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_DARKGREY)),
Paragraph("мой, твой, его, её, его (неод.), наш, их",
ParagraphStyle("pr1", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_PURPLE)),
],
[
Paragraph("Possessive Pronouns\nПритяжательные местоимения",
ParagraphStyle("pt2", fontName=BOLD_FONT, fontSize=10, leading=14, textColor=C_BLUE)),
Paragraph("mine, yours, his, hers, ours, theirs",
ParagraphStyle("pp2", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_DARKGREY)),
Paragraph("мой/моя, твой/твоя, его, её, наш/наша, их",
ParagraphStyle("pr2", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_PURPLE)),
],
[
Paragraph("Demonstrative Pronouns\nУказательные местоимения",
ParagraphStyle("pt3", fontName=BOLD_FONT, fontSize=10, leading=14, textColor=C_BLUE)),
Paragraph("this, that, these, those",
ParagraphStyle("pp3", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_DARKGREY)),
Paragraph("этот/эта/это, тот/та/то, эти, те",
ParagraphStyle("pr3", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_PURPLE)),
],
]
ptable = Table(pron_data, colWidths=[5.5*cm, 5.5*cm, 6*cm])
ptable.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_PINK),
("BACKGROUND", (0,1), (-1,1), C_SKYBLUE),
("BACKGROUND", (0,2), (-1,2), C_MINT),
("BACKGROUND", (0,3), (-1,3), C_PEACH),
("GRID", (0,0), (-1,-1), 0.5, colors.white),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(ptable)
story.append(Spacer(1, 0.4*cm))
# ── STUDY TIPS ────────────────────────────────────────────────────────────────
story.append(banner("💡 STUDY TIPS / СОВЕТЫ ДЛЯ УЧЁБЫ",
C_BLUE, STYLE_SECTION_HEAD))
story.append(Spacer(1, 0.25*cm))
for tip_en, tip_ru, ex_en, ex_ru in TIPS:
tip_data = [[
[
Paragraph(tip_en, ParagraphStyle(
"tpen", fontName=BOLD_FONT, fontSize=11, leading=15, textColor=C_ORANGE)),
Paragraph(tip_ru, ParagraphStyle(
"tpru", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_PURPLE, spaceAfter=3)),
Paragraph(ex_en, ParagraphStyle(
"exen", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_DARKGREY)),
Paragraph(ex_ru, ParagraphStyle(
"exru", fontName=BASE_FONT, fontSize=10, leading=14, textColor=C_TEAL)),
]
]]
tip_table = Table(tip_data, colWidths=[17*cm])
tip_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_LAVENDER),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1, C_PURPLE),
]))
story.append(KeepTogether([tip_table, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── FOOTER ────────────────────────────────────────────────────────────────────
footer_data = [[
Paragraph(
"Well done! You are a School Star! ⭐ • Отлично! Ты — звезда школы! ⭐",
ParagraphStyle("ft", fontName=BOLD_FONT, fontSize=12, leading=16,
textColor=C_WHITE, alignment=TA_CENTER)),
]]
footer_table = Table(footer_data, colWidths=[17*cm])
footer_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_ORANGE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
]))
story.append(footer_table)
# ── Generate PDF ──────────────────────────────────────────────────────────────
out_path = "/tmp/workspace/esl-handbook/My_School_Life_Handbook.pdf"
doc = SimpleDocTemplate(
out_path,
pagesize=A4,
rightMargin=1*cm, leftMargin=1*cm,
topMargin=1.2*cm, bottomMargin=1*cm,
title="My School Life – ESL Handbook Grade 3",
author="ESL Teacher",
)
doc.build(story)
print(f"\n✅ PDF saved to: {out_path}")
import os
size = os.path.getsize(out_path)
print(f" File size: {size:,} bytes")
python3 /tmp/workspace/esl-handbook/build_handbook.py 2>&1
python3 -c " import os, glob # search for any TTF with dejavu or noto or liberation results = [] for base in ['/usr/share/fonts', '/usr/local/share/fonts', os.path.expanduser('~/.fonts'), '/usr/share/truetype']: if os.path.exists(base): for root, dirs, files in os.walk(base): for f in files: if f.endswith('.ttf') or f.endswith('.TTF'): results.append(os.path.join(root, f)) print('\n'.join(results[:40])) print('Total:', len(results)) "
python3 -c " from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont # Test DroidSans for Cyrillic try: pdfmetrics.registerFont(TTFont('DroidSans', '/usr/share/fonts/google-droid-sans-fonts/DroidSans.ttf')) pdfmetrics.registerFont(TTFont('DroidSans-Bold', '/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf')) print('DroidSans registered OK') except Exception as e: print('DroidSans error:', e) # Test NotoSans VF try: pdfmetrics.registerFont(TTFont('NotoSans', '/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf')) print('NotoSans VF registered OK') except Exception as e: print('NotoSans VF error:', e) # Quick Cyrillic codepoint test test = 'Привет мир' print('Cyrillic test string bytes:', test.encode('utf-8')) "
~/esl-handbook/build_handbook.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/esl-handbook/build_handbook.py'
python3 /tmp/workspace/esl-handbook/build_handbook.py 2>&1
python3 -c " import pdfplumber with pdfplumber.open('/tmp/workspace/esl-handbook/My_School_Life_Handbook.pdf') as pdf: print('Pages:', len(pdf.pages)) # Check first page for some content p1 = pdf.pages[0].extract_text() print('--- Page 1 sample (first 500 chars) ---') print(p1[:500] if p1 else 'No text extracted') p2 = pdf.pages[1].extract_text() if len(pdf.pages) > 1 else '' print('--- Page 2 sample (first 400 chars) ---') print(p2[:400] if p2 else 'No text / single page') "
My School Life Handbook
PDF Document · PDF
| Section | Details |
|---|---|
| Cover Banner | Purple + pink title banner with English & Russian subtitle |
| Pronoun Formula & Format | Colour-coded table at the top showing all 3 pronoun types with Russian, plus a FORMAT box showing exactly how to use each type |
| 15 Q&A Cards | Each card has: English question → Russian question → English answer → Russian answer, on alternating coloured backgrounds (blue, green, peach, rose, lavender) |
| Key Vocabulary | 30 school words in a 3-column table, each word in English (bold blue) with Russian below (purple), alternating mint/peach rows |
| Pronoun Quick Guide | Summary reference table with all pronouns and Russian equivalents |
| Study Tips | 3 tip boxes explaining Possessive Adjectives, Possessive Pronouns, and This/That/These/Those - each with English + Russian |
| Footer | "Well done! You are a School Star! ⭐" in orange banner (bilingual) |
Please create a similar style handbook with logical 15 questions and answers with Russian translation under English but all 15 questions should be different from this above prepared pdf
~/esl-handbook/build_handbook2.py
#!/usr/bin/env python3
"""
My School Life – ESL Handbook 2 for Grade 3
15 NEW questions (different from Handbook 1)
Colourful PDF with English + Russian translations under every line
Uses ReportLab + DroidSans (Cyrillic-capable)
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ── Fonts ──────────────────────────────────────────────────────────────────────
pdfmetrics.registerFont(TTFont(
"DroidSans", "/usr/share/fonts/google-droid-sans-fonts/DroidSans.ttf"))
pdfmetrics.registerFont(TTFont(
"DroidSans-Bold", "/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf"))
BASE_FONT = "DroidSans"
BOLD_FONT = "DroidSans-Bold"
# ── Colours ────────────────────────────────────────────────────────────────────
C_PURPLE = colors.HexColor("#6A0DAD")
C_ORANGE = colors.HexColor("#FF6B00")
C_TEAL = colors.HexColor("#008080")
C_PINK = colors.HexColor("#E91E8C")
C_BLUE = colors.HexColor("#1565C0")
C_GREEN = colors.HexColor("#2E7D32")
C_YELLOW = colors.HexColor("#FFF176")
C_LAVENDER = colors.HexColor("#EDE7F6")
C_MINT = colors.HexColor("#E8F5E9")
C_PEACH = colors.HexColor("#FFF3E0")
C_SKYBLUE = colors.HexColor("#E3F2FD")
C_ROSEBLUSH= colors.HexColor("#FCE4EC")
C_WHITE = colors.white
C_DARKGREY = colors.HexColor("#37474F")
C_LTGREY = colors.HexColor("#ECEFF1")
C_RUS_BG = colors.HexColor("#F3E5F5")
C_AMBER = colors.HexColor("#FF8F00")
C_INDIGO = colors.HexColor("#283593")
CARD_BG = [C_SKYBLUE, C_MINT, C_PEACH, C_ROSEBLUSH, C_LAVENDER]
# ── Style helper ───────────────────────────────────────────────────────────────
def S(name, font, size, color, leading=None, align=TA_LEFT,
sb=0, sa=2, bg=None):
kw = dict(name=name, fontName=font, fontSize=size, textColor=color,
leading=leading or size*1.35, alignment=align,
spaceBefore=sb, spaceAfter=sa)
if bg: kw["backColor"] = bg
return ParagraphStyle(**kw)
# ── Banner helper ──────────────────────────────────────────────────────────────
def banner(text, bg_color, style, pad=4):
t = Table([[Paragraph(text, style)]], colWidths=[17*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg_color),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING", (0,0),(-1,-1), pad),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
return t
# ── Styles ─────────────────────────────────────────────────────────────────────
ST_COVER_TITLE = S("CT", BOLD_FONT, 28, C_WHITE, leading=34, align=TA_CENTER)
ST_COVER_SUB = S("CS", BASE_FONT, 14, C_YELLOW, leading=18, align=TA_CENTER)
ST_COVER_RU = S("CR", BASE_FONT, 12, C_PURPLE, leading=16, align=TA_CENTER, bg=C_RUS_BG)
ST_SEC_HEAD = S("SH", BOLD_FONT, 15, C_WHITE, leading=19, align=TA_CENTER, sb=6)
ST_TABLE_HEAD = S("TH", BOLD_FONT, 11, C_WHITE, leading=14, align=TA_CENTER)
ST_FORMULA_HEAD = S("FH", BOLD_FONT, 13, C_PURPLE, leading=17, sb=4)
# ── NEW 15 Q&A (all different from Handbook 1 topics) ────────────────────────
# Topics: school trip, PE/sports day, uniform, music lesson, school garden,
# computer room, school assembly, school lunch menu, science experiment,
# timetable, school play, classroom helper, birthday in school,
# reading corner, school notice board
QA = [
# 1
(
"1. Where did your class go on the school trip?",
"1. Куда ездил твой класс на школьную экскурсию?",
"Our class went to the museum. Its rooms were big. That trip was ours.",
"Наш класс ездил в музей. Его залы были большими. Та экскурсия была наша.",
),
# 2
(
"2. What do you wear for PE at your school?",
"2. Что ты надеваешь на урок физкультуры в твоей школе?",
"My PE kit is white and blue. That kit is mine. Hers is red.",
"Мой спортивный костюм белый и синий. Этот костюм — мой. Её — красный.",
),
# 3
(
"3. What instrument does your music teacher play?",
"3. На каком инструменте играет твой учитель музыки?",
"Our music teacher plays the piano. That piano is hers. Its sound is lovely.",
"Наш учитель музыки играет на пианино. То пианино — её. Его звук прекрасен.",
),
# 4
(
"4. What does your class grow in the school garden?",
"4. Что ваш класс выращивает в школьном саду?",
"Our plants are tomatoes. These plants are ours. Their colour is green.",
"Наши растения — это помидоры. Эти растения — наши. Их цвет зелёный.",
),
# 5
(
"5. What do you do in the computer room?",
"5. Что ты делаешь в компьютерном классе?",
"My computer is on. Its screen is bright. That seat is mine.",
"Мой компьютер включён. Его экран яркий. То место — моё.",
),
# 6
(
"6. What happens at school assembly every morning?",
"6. Что происходит на школьной линейке каждое утро?",
"Our head teacher speaks to us. Her words are kind. That speech is hers.",
"Наш директор говорит с нами. Её слова добрые. Та речь — её.",
),
# 7
(
"7. What is your favourite thing on the school lunch menu?",
"7. Что тебе больше всего нравится в школьном меню на обед?",
"My favourite meal is pasta. That dish is mine. Its taste is great.",
"Моё любимое блюдо — паста. Это блюдо — моё. Его вкус отличный.",
),
# 8
(
"8. What did you use in your science experiment today?",
"8. Что ты использовал на сегодняшнем уроке науки?",
"Our group used a magnet. This magnet is ours. Its power is strong.",
"Наша группа использовала магнит. Этот магнит — наш. Его сила большая.",
),
# 9
(
"9. Which lesson is first on your timetable on Monday?",
"9. Какой урок первый в твоём расписании в понедельник?",
"My first lesson is maths. That timetable is mine. His first lesson is English.",
"Мой первый урок — математика. То расписание — моё. Его первый урок — английский.",
),
# 10
(
"10. What part did you play in the school play?",
"10. Какую роль ты играл в школьном спектакле?",
"My role was a lion. That costume is mine. His role was a tree.",
"Моя роль была лев. Тот костюм — мой. Его роль — дерево.",
),
# 11
(
"11. What is the classroom helper's job this week?",
"11. В чём обязанность дежурного по классу на этой неделе?",
"Her job is to give out the books. Those books are hers to hand out. Mine is to water the plants.",
"Её обязанность — раздавать книги. Те книги она раздаёт. Моя обязанность — поливать растения.",
),
# 12
(
"12. What does your friend bring to school on his birthday?",
"12. Что твой друг приносит в школу в день своего рождения?",
"His birthday cake is chocolate. That cake is his. These sweets are his too.",
"Его праздничный торт шоколадный. Тот торт — его. Эти сладости тоже его.",
),
# 13
(
"13. What do you find in the reading corner of your classroom?",
"13. Что ты находишь в читальном уголке своего класса?",
"Our reading corner has soft cushions. These cushions are ours. That shelf is ours too.",
"В нашем читальном уголке есть мягкие подушки. Эти подушки — наши. Та полка тоже наша.",
),
# 14
(
"14. What is on the school notice board today?",
"14. Что сегодня висит на школьной доске объявлений?",
"Our notice board shows the sports day list. That list is ours. Its date is Friday.",
"На нашей доске объявлений висит список спортивного дня. Тот список — наш. Его дата — пятница.",
),
# 15
(
"15. Who won the spelling competition in your class?",
"15. Кто выиграл конкурс по правописанию в твоём классе?",
"Sofia won the spelling competition. Her certificate is on the wall. That certificate is hers.",
"София выиграла конкурс по правописанию. Её грамота висит на стене. Та грамота — её.",
),
]
# ── Vocabulary (new words from the 15 questions above) ────────────────────────
VOCAB = [
("museum", "музей"),
("school trip", "школьная экскурсия"),
("PE kit", "спортивная форма"),
("instrument", "музыкальный инструмент"),
("piano", "пианино"),
("garden", "сад"),
("tomatoes", "помидоры"),
("computer room", "компьютерный класс"),
("screen", "экран"),
("assembly", "школьная линейка"),
("speech", "речь"),
("menu", "меню"),
("pasta", "паста"),
("magnet", "магнит"),
("experiment", "эксперимент"),
("timetable", "расписание"),
("maths", "математика"),
("costume", "костюм"),
("school play", "школьный спектакль"),
("role", "роль"),
("helper", "дежурный/помощник"),
("birthday cake", "праздничный торт"),
("cushions", "подушки"),
("notice board", "доска объявлений"),
("sports day", "день спорта"),
("spelling", "правописание"),
("certificate", "грамота/сертификат"),
("plants", "растения"),
("shelf", "полка"),
("sweets", "сладости"),
]
# ── Pronoun formula / format (same reference table, new examples) ──────────────
FORMULA_ROWS = [
(
"Possessive Adjectives",
"Притяжательные прилагательные",
"my, your, his, her, its, our, their",
"мой/моя/моё, твой, его, её, его (неод.), наш, их",
"My trip was great. / Her piano is new.",
"Моя экскурсия была отличной. / Её пианино новое.",
),
(
"Possessive Pronouns",
"Притяжательные местоимения",
"mine, yours, his, hers, ours, theirs",
"мой/моя, твой/твоя, его, её, наш/наша, их",
"That costume is mine. / This magnet is ours.",
"Тот костюм — мой. / Этот магнит — наш.",
),
(
"Demonstrative Pronouns",
"Указательные местоимения",
"this, that, these, those",
"этот/эта/это, тот/та/то, эти, те",
"This cake is his. / Those cushions are ours.",
"Этот торт — его. / Те подушки — наши.",
),
]
FORMAT_EN = (
"FORMULA:\n"
" Possessive Adjective + Noun => my timetable, her role, our garden\n"
" Subject + is/are + Possessive Pronoun => That cake is his. These are ours.\n"
" Demonstrative + Noun => This magnet, Those cushions"
)
FORMAT_RU = (
"ФОРМУЛА:\n"
" Притяжательное прилагательное + Существительное => моё расписание, её роль, наш сад\n"
" Подлежащее + is/are + Притяжательное местоимение => Тот торт — его. Эти — наши.\n"
" Указательное местоимение + Существительное => Этот магнит, Те подушки"
)
# ── Study tips (new examples) ─────────────────────────────────────────────────
TIPS = [
(
"Tip 1: Use a Possessive Adjective BEFORE a noun to show who owns it.",
"Совет 1: Ставь притяжательное прилагательное ПЕРЕД существительным, чтобы показать владельца.",
'Examples: "my costume", "his birthday cake", "our garden"',
'Примеры: «мой костюм», «его праздничный торт», «наш сад»',
),
(
"Tip 2: Use a Possessive Pronoun ALONE – never add a noun after it.",
"Совет 2: Притяжательное местоимение стоит ОТДЕЛЬНО – никогда не добавляй существительное после него.",
'"That certificate is hers." NOT: "That certificate is hers certificate."',
'«Та грамота — её.» НЕ: «Та грамота — её грамота.»',
),
(
"Tip 3: This & These = close to you. That & Those = far from you.",
"Совет 3: This и These = близко к тебе. That и Those = далеко от тебя.",
'"This cushion is soft." (near you) / "That shelf is tall." (far away)',
'«Эта подушка мягкая.» (рядом) / «Та полка высокая.» (далеко)',
),
]
# ══════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── Cover ─────────────────────────────────────────────────────────────────────
cover_tbl = Table(
[[Paragraph("My School Life - Book 2", ST_COVER_TITLE)]],
colWidths=[17*cm])
cover_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_INDIGO),
("TOPPADDING", (0,0),(-1,-1), 18),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
]))
story.append(cover_tbl)
sub_tbl = Table(
[[Paragraph(
"15 New Questions & Answers | British English | Grade 3 ESL",
ST_COVER_SUB)]],
colWidths=[17*cm])
sub_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_AMBER),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
]))
story.append(sub_tbl)
ru_sub_tbl = Table(
[[Paragraph(
"15 новых вопросов и ответов | Британский английский | 3-й класс ESL",
ST_COVER_RU)]],
colWidths=[17*cm])
ru_sub_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RUS_BG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 12),
]))
story.append(ru_sub_tbl)
story.append(Spacer(1, 0.4*cm))
# ── Pronoun Formula & Format ───────────────────────────────────────────────────
story.append(banner(
"PRONOUN FORMULA & FORMAT / ФОРМУЛА И ФОРМАТ МЕСТОИМЕНИЙ",
C_TEAL, S("bsh", BOLD_FONT, 14, C_WHITE, leading=18, align=TA_CENTER)))
story.append(Spacer(1, 0.25*cm))
# Formula table
fhdr = [
Paragraph("Type / Тип", ST_TABLE_HEAD),
Paragraph("Pronouns / Местоимения", ST_TABLE_HEAD),
Paragraph("Example / Пример", ST_TABLE_HEAD),
]
frows = [fhdr]
row_bgs = [C_SKYBLUE, C_MINT, C_PEACH]
for ri, (ten, tru, pen, pru, een, eru) in enumerate(FORMULA_ROWS):
frows.append([
Paragraph(f"{ten}\n{tru}",
S(f"fc{ri}", BASE_FONT, 9, C_DARKGREY, leading=13)),
Paragraph(pen + "\n" + pru,
S(f"fp{ri}", BOLD_FONT, 9, C_BLUE, leading=13)),
Paragraph(f"{een}\n{eru}",
S(f"fe{ri}", BASE_FONT, 9, C_DARKGREY, leading=13)),
])
ftbl = Table(frows, colWidths=[5*cm, 5.5*cm, 6.5*cm])
fstyle = [
("BACKGROUND", (0,0),(-1,0), C_INDIGO),
("GRID", (0,0),(-1,-1), 0.5, C_WHITE),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1), 5),
("RIGHTPADDING",(0,0),(-1,-1),5),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for ri, bg in enumerate(row_bgs, start=1):
fstyle.append(("BACKGROUND", (0,ri),(-1,ri), bg))
ftbl.setStyle(TableStyle(fstyle))
story.append(ftbl)
story.append(Spacer(1, 0.2*cm))
# Format box EN
fmt_tbl = Table(
[[Paragraph(FORMAT_EN, S("fmten", BASE_FONT, 10, C_BLUE, leading=14))]],
colWidths=[17*cm])
fmt_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_SKYBLUE),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1.5, C_BLUE),
]))
story.append(fmt_tbl)
story.append(Spacer(1, 0.1*cm))
fmt_ru_tbl = Table(
[[Paragraph(FORMAT_RU, S("fmtru", BASE_FONT, 10, C_PURPLE, leading=14))]],
colWidths=[17*cm])
fmt_ru_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RUS_BG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1.5, C_PURPLE),
]))
story.append(fmt_ru_tbl)
story.append(Spacer(1, 0.4*cm))
# ── Q&A Cards ─────────────────────────────────────────────────────────────────
story.append(banner(
"QUESTIONS & ANSWERS / ВОПРОСЫ И ОТВЕТЫ",
C_AMBER, S("qah", BOLD_FONT, 14, C_WHITE, leading=18, align=TA_CENTER)))
story.append(Spacer(1, 0.3*cm))
for i, (q_en, q_ru, a_en, a_ru) in enumerate(QA):
bg = CARD_BG[i % len(CARD_BG)]
inner = [
Paragraph(q_en, S(f"qe{i}", BOLD_FONT, 11, C_DARKGREY, leading=15, sa=2)),
Paragraph(q_ru, S(f"qr{i}", BASE_FONT, 10, C_PURPLE, leading=14, sa=3, bg=C_RUS_BG)),
Paragraph(f" {a_en}", S(f"ae{i}", BASE_FONT, 11, C_GREEN, leading=15, sa=2)),
Paragraph(f" {a_ru}", S(f"ar{i}", BASE_FONT, 10, C_TEAL, leading=14, bg=C_RUS_BG)),
]
card = Table([[inner]], colWidths=[17*cm])
card.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, C_LTGREY),
]))
story.append(KeepTogether([card, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Vocabulary ────────────────────────────────────────────────────────────────
story.append(banner(
"KEY VOCABULARY / КЛЮЧЕВЫЕ СЛОВА",
C_GREEN, S("vsh", BOLD_FONT, 14, C_WHITE, leading=18, align=TA_CENTER)))
story.append(Spacer(1, 0.25*cm))
vrows = []
for i in range(0, len(VOCAB), 3):
chunk = VOCAB[i:i+3]
row = []
for en, ru in chunk:
row.append([
Paragraph(en, S(f"ven{i}", BOLD_FONT, 10, C_BLUE, leading=13)),
Paragraph(ru, S(f"vru{i}", BASE_FONT, 9, C_PURPLE, leading=12)),
])
while len(row) < 3:
row.append("")
vrows.append(row)
vstyle = [
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.5, C_LTGREY),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for r in range(len(vrows)):
vstyle.append(("BACKGROUND", (0,r),(-1,r),
C_MINT if r % 2 == 0 else C_PEACH))
vtbl = Table(vrows, colWidths=[5.5*cm, 5.5*cm, 5.5*cm])
vtbl.setStyle(TableStyle(vstyle))
story.append(vtbl)
story.append(Spacer(1, 0.4*cm))
# ── Pronoun Quick Guide ───────────────────────────────────────────────────────
story.append(banner(
"PRONOUN QUICK GUIDE / КРАТКИЙ СПРАВОЧНИК",
C_PINK, S("psh", BOLD_FONT, 14, C_WHITE, leading=18, align=TA_CENTER)))
story.append(Spacer(1, 0.25*cm))
pg_rows = [
[
Paragraph("Type / Тип", ST_TABLE_HEAD),
Paragraph("Pronouns / Местоимения", ST_TABLE_HEAD),
Paragraph("Russian / Русский", ST_TABLE_HEAD),
],
[
Paragraph("Possessive Adjectives\nПритяжательные прилагательные",
S("pg1t", BOLD_FONT, 10, C_BLUE, leading=14)),
Paragraph("my, your, his, her, its, our, their",
S("pg1p", BASE_FONT, 10, C_DARKGREY, leading=14)),
Paragraph("мой, твой, его, её, его (неод.), наш, их",
S("pg1r", BASE_FONT, 10, C_PURPLE, leading=14)),
],
[
Paragraph("Possessive Pronouns\nПритяжательные местоимения",
S("pg2t", BOLD_FONT, 10, C_BLUE, leading=14)),
Paragraph("mine, yours, his, hers, ours, theirs",
S("pg2p", BASE_FONT, 10, C_DARKGREY, leading=14)),
Paragraph("мой/моя, твой/твоя, его, её, наш/наша, их",
S("pg2r", BASE_FONT, 10, C_PURPLE, leading=14)),
],
[
Paragraph("Demonstrative Pronouns\nУказательные местоимения",
S("pg3t", BOLD_FONT, 10, C_BLUE, leading=14)),
Paragraph("this, that, these, those",
S("pg3p", BASE_FONT, 10, C_DARKGREY, leading=14)),
Paragraph("этот/эта/это, тот/та/то, эти, те",
S("pg3r", BASE_FONT, 10, C_PURPLE, leading=14)),
],
]
pgtbl = Table(pg_rows, colWidths=[5.5*cm, 5.5*cm, 6*cm])
pgtbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_PINK),
("BACKGROUND", (0,1),(-1,1), C_SKYBLUE),
("BACKGROUND", (0,2),(-1,2), C_MINT),
("BACKGROUND", (0,3),(-1,3), C_PEACH),
("GRID", (0,0),(-1,-1), 0.5, C_WHITE),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
story.append(pgtbl)
story.append(Spacer(1, 0.4*cm))
# ── Study Tips ────────────────────────────────────────────────────────────────
story.append(banner(
"STUDY TIPS / СОВЕТЫ ДЛЯ УЧЁБЫ",
C_BLUE, S("tsh", BOLD_FONT, 14, C_WHITE, leading=18, align=TA_CENTER)))
story.append(Spacer(1, 0.25*cm))
for ti, (ten, tru, een, eru) in enumerate(TIPS):
tip_inner = [
Paragraph(ten, S(f"tte{ti}", BOLD_FONT, 11, C_ORANGE, leading=15)),
Paragraph(tru, S(f"ttr{ti}", BASE_FONT, 10, C_PURPLE, leading=14, sa=3)),
Paragraph(een, S(f"tex{ti}", BASE_FONT, 10, C_DARKGREY, leading=14)),
Paragraph(eru, S(f"ter{ti}", BASE_FONT, 10, C_TEAL, leading=14)),
]
tip_card = Table([[tip_inner]], colWidths=[17*cm])
tip_card.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_LAVENDER),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, C_PURPLE),
]))
story.append(KeepTogether([tip_card, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Footer ────────────────────────────────────────────────────────────────────
foot = Table(
[[Paragraph(
"Fantastic work! Keep learning and growing! - "
"Отличная работа! Продолжай учиться и расти!",
S("ft", BOLD_FONT, 12, C_WHITE, leading=16, align=TA_CENTER))]],
colWidths=[17*cm])
foot.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_AMBER),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
]))
story.append(foot)
# ── Render ────────────────────────────────────────────────────────────────────
OUT = "/tmp/workspace/esl-handbook/My_School_Life_Handbook2.pdf"
doc = SimpleDocTemplate(
OUT, pagesize=A4,
rightMargin=1*cm, leftMargin=1*cm,
topMargin=1.2*cm, bottomMargin=1*cm,
title="My School Life Book 2 - ESL Handbook Grade 3",
author="ESL Teacher",
)
doc.build(story)
import os
sz = os.path.getsize(OUT)
print(f"PDF saved: {OUT} ({sz:,} bytes)")
python3 /tmp/workspace/esl-handbook/build_handbook2.py 2>&1
python3 -c " import pdfplumber with pdfplumber.open('/tmp/workspace/esl-handbook/My_School_Life_Handbook2.pdf') as pdf: print('Pages:', len(pdf.pages)) t = pdf.pages[0].extract_text() print(t[:600] if t else 'no text') " 2>&1
My School Life Handbook2
PDF Document · PDF
| Section | Details |
|---|---|
| Cover | Indigo + amber banner - "My School Life - Book 2" with English & Russian subtitle |
| Pronoun Formula & Format | Same reference table at the top, but with new examples from the new topics |
| 15 Brand-New Q&A Cards | Every question is a completely new school-life topic |
| Key Vocabulary | 30 new words in 3-column table, each with Russian below |
| Pronoun Quick Guide | Same handy reference table with all types and Russian translations |
| Study Tips | 3 bilingual tips with new examples from the new questions |
| Footer | "Fantastic work! Keep learning and growing!" in amber banner |
Please prepare for 3rd grade ESL student and only use present simple tense and present continuous tense only, don't use past tense and use easy vocabulary.
~/esl-handbook/build_handbook3.py
#!/usr/bin/env python3
"""
My School Life – ESL Handbook 3 for Grade 3
15 NEW questions using ONLY Present Simple & Present Continuous
Easy vocabulary | No past tense
Colourful PDF with English + Russian translations under every line
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ── Fonts ──────────────────────────────────────────────────────────────────────
pdfmetrics.registerFont(TTFont(
"DroidSans", "/usr/share/fonts/google-droid-sans-fonts/DroidSans.ttf"))
pdfmetrics.registerFont(TTFont(
"DroidSans-Bold", "/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf"))
BASE = "DroidSans"
BOLD = "DroidSans-Bold"
# ── Colours ────────────────────────────────────────────────────────────────────
C_DARK_GREEN = colors.HexColor("#1B5E20")
C_MED_GREEN = colors.HexColor("#388E3C")
C_LIME = colors.HexColor("#DCEDC8")
C_TEAL = colors.HexColor("#00695C")
C_TEAL_LIGHT = colors.HexColor("#E0F2F1")
C_ORANGE = colors.HexColor("#E65100")
C_ORANGE_SOFT = colors.HexColor("#FFF3E0")
C_PURPLE = colors.HexColor("#6A0DAD")
C_PURPLE_SOFT = colors.HexColor("#F3E5F5")
C_BLUE = colors.HexColor("#0D47A1")
C_BLUE_SOFT = colors.HexColor("#E3F2FD")
C_PINK = colors.HexColor("#AD1457")
C_PINK_SOFT = colors.HexColor("#FCE4EC")
C_AMBER = colors.HexColor("#FF8F00")
C_YELLOW_SOFT = colors.HexColor("#FFF9C4")
C_WHITE = colors.white
C_GREY = colors.HexColor("#37474F")
C_LTGREY = colors.HexColor("#ECEFF1")
C_RUS_BG = colors.HexColor("#F3E5F5") # lilac for Russian lines
CARD_BG = [C_BLUE_SOFT, C_LIME, C_ORANGE_SOFT, C_PINK_SOFT, C_TEAL_LIGHT]
# ── Style helper ───────────────────────────────────────────────────────────────
def S(name, font, size, color, leading=None, align=TA_LEFT, sb=0, sa=2, bg=None):
kw = dict(name=name, fontName=font, fontSize=size, textColor=color,
leading=leading or size*1.4, alignment=align,
spaceBefore=sb, spaceAfter=sa)
if bg: kw["backColor"] = bg
return ParagraphStyle(**kw)
# ── Banner helper ──────────────────────────────────────────────────────────────
def banner(text, bg, fg=C_WHITE, fs=14, pad=7):
st = S("bn", BOLD, fs, fg, leading=fs*1.3, align=TA_CENTER)
t = Table([[Paragraph(text, st)]], colWidths=[17*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING", (0,0),(-1,-1), pad),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
return t
# ════════════════════════════════════════════════════════════════════════════════
# CONTENT
# All 15 questions use ONLY Present Simple or Present Continuous
# All topics are different from Books 1 & 2
# Easy words for Grade 3 ESL
# ════════════════════════════════════════════════════════════════════════════════
# Format: (question EN, question RU, answer EN, answer RU,
# tense label EN, tense label RU)
QA = [
(
"1. What colour is your school bag?",
"1. Какого цвета твоя школьная сумка?",
"My school bag is red. It is big. This bag is mine.",
"Моя школьная сумка красная. Она большая. Эта сумка — моя.",
"Present Simple",
"Настоящее простое время",
),
(
"2. What are you doing right now in class?",
"2. Что ты сейчас делаешь на уроке?",
"I am writing in my notebook. My teacher is talking. She is helping us.",
"Я пишу в своей тетради. Моя учительница говорит. Она помогает нам.",
"Present Continuous",
"Настоящее длительное время",
),
(
"3. How many children are in your class?",
"3. Сколько детей в твоём классе?",
"There are twenty children in my class. Our class is big and fun.",
"В моём классе двадцать детей. Наш класс большой и весёлый.",
"Present Simple",
"Настоящее простое время",
),
(
"4. What does your teacher write on the board?",
"4. Что пишет твой учитель на доске?",
"My teacher writes words on the board. She uses a white chalk. Those words are new.",
"Моя учительница пишет слова на доске. Она использует белый мел. Те слова новые.",
"Present Simple",
"Настоящее простое время",
),
(
"5. What are your classmates doing at break time right now?",
"5. Что твои одноклассники делают на перемене прямо сейчас?",
"Some of them are running. Others are eating. My friend is drinking water. These are his biscuits.",
"Некоторые из них бегут. Другие едят. Мой друг пьёт воду. Это его печенье.",
"Present Continuous",
"Настоящее длительное время",
),
(
"6. What subjects do you study every day?",
"6. Какие предметы ты изучаешь каждый день?",
"I study English, maths and reading every day. These are my favourite subjects.",
"Я изучаю английский, математику и чтение каждый день. Это мои любимые предметы.",
"Present Simple",
"Настоящее простое время",
),
(
"7. What is the teacher doing now?",
"7. Что учитель делает сейчас?",
"She is reading a story to us. Her book is big. That story is funny.",
"Она читает нам рассказ. Её книга большая. Тот рассказ смешной.",
"Present Continuous",
"Настоящее длительное время",
),
(
"8. Where do you sit in the classroom?",
"8. Где ты сидишь в классе?",
"I sit near the window. My desk is clean. That window is mine to look after.",
"Я сижу у окна. Моя парта чистая. Это окно я должен беречь.",
"Present Simple",
"Настоящее простое время",
),
(
"9. What does the school bell do every day?",
"9. Что школьный звонок делает каждый день?",
"The bell rings at nine o'clock. Its sound is loud. That bell is ours.",
"Звонок звенит в девять часов. Его звук громкий. Тот звонок — наш.",
"Present Simple",
"Настоящее простое время",
),
(
"10. What are you wearing to school today?",
"10. Что ты сегодня надел в школу?",
"I am wearing my school uniform today. My shoes are black. These socks are mine.",
"Сегодня я надел школьную форму. Мои туфли чёрные. Эти носки — мои.",
"Present Continuous",
"Настоящее длительное время",
),
(
"11. What do you eat for lunch at school?",
"11. Что ты ешь на обед в школе?",
"I eat a sandwich and an apple. My lunch box is yellow. That apple is mine.",
"Я ем бутерброд и яблоко. Мой ланч-бокс жёлтый. То яблоко — моё.",
"Present Simple",
"Настоящее простое время",
),
(
"12. What is your friend drawing in art class?",
"12. Что твой друг рисует на уроке рисования?",
"My friend is drawing a rainbow. Her colours are bright. Those pencils are hers.",
"Моя подруга рисует радугу. Её цвета яркие. Те карандаши — её.",
"Present Continuous",
"Настоящее длительное время",
),
(
"13. How do you go to school every morning?",
"13. Как ты добираешься до школы каждое утро?",
"I walk to school with my mum. Our road is safe. This is our path.",
"Я иду в школу с мамой. Наша дорога безопасная. Это наш путь.",
"Present Simple",
"Настоящее простое время",
),
(
"14. What is happening in the school hall right now?",
"14. Что сейчас происходит в школьном зале?",
"The children are singing a song. Their voices are loud. That song is ours.",
"Дети поют песню. Их голоса громкие. Та песня — наша.",
"Present Continuous",
"Настоящее длительное время",
),
(
"15. What does your class do after the last lesson?",
"15. Что твой класс делает после последнего урока?",
"We pack our bags and say goodbye. My bag is heavy. That is our goodbye wave.",
"Мы собираем наши сумки и прощаемся. Моя сумка тяжёлая. Это наше прощальное приветствие.",
"Present Simple",
"Настоящее простое время",
),
]
# ── Tense Formula tables ───────────────────────────────────────────────────────
PS_ROWS = [
# (Subject EN, Subject RU, verb EN, verb RU, example EN, example RU)
("I / You", "Я / Ты", "verb", "глагол", "I walk. / You eat.", "Я иду. / Ты ешь."),
("He / She / It", "Он / Она / Оно", "verb + s", "глагол + s", "She reads. / It rings.", "Она читает. / Оно звенит."),
("We / They / You", "Мы / Они / Вы", "verb", "глагол", "We study. / They sing.", "Мы учимся. / Они поют."),
]
PC_ROWS = [
("I", "Я", "am + verb-ing", "am + глагол-ing", "I am writing.", "Я пишу."),
("He / She / It", "Он / Она / Оно", "is + verb-ing", "is + глагол-ing", "She is reading.", "Она читает."),
("We / You / They", "Мы / Вы / Они", "are + verb-ing", "are + глагол-ing", "We are singing.", "Мы поём."),
]
# ── Vocabulary ─────────────────────────────────────────────────────────────────
VOCAB = [
("school bag", "школьная сумка"),
("notebook", "тетрадь"),
("chalk", "мел"),
("board", "доска"),
("biscuit", "печенье"),
("maths", "математика"),
("reading", "чтение"),
("story", "рассказ/история"),
("desk", "парта"),
("window", "окно"),
("bell", "звонок"),
("uniform", "школьная форма"),
("shoes", "туфли/ботинки"),
("socks", "носки"),
("sandwich", "бутерброд"),
("lunch box", "ланч-бокс"),
("rainbow", "радуга"),
("colours", "цвета"),
("path", "путь/дорожка"),
("hall", "зал"),
("voices", "голоса"),
("goodbye", "до свидания"),
("heavy", "тяжёлый"),
("safe", "безопасный"),
("loud", "громкий"),
("bright", "яркий"),
("clean", "чистый"),
("funny", "смешной"),
("twenty", "двадцать"),
("wave", "приветственный жест"),
]
# ── Study Tips ─────────────────────────────────────────────────────────────────
TIPS = [
(
"Present Simple = things that happen every day or are always true.",
"Настоящее простое = действия, которые происходят каждый день или всегда верны.",
'Signal words: every day, always, usually, never\n'
'Example: "I walk to school every day."',
'Сигнальные слова: каждый день, всегда, обычно, никогда\n'
'Пример: «Я хожу в школу каждый день.»',
),
(
"Present Continuous = things happening RIGHT NOW.",
"Настоящее длительное = действия, происходящие ПРЯМО СЕЙЧАС.",
'Signal words: now, right now, at the moment, look!, listen!\n'
'Example: "She is reading a story now."',
'Сигнальные слова: сейчас, прямо сейчас, в данный момент, смотри!, слушай!\n'
'Пример: «Она читает рассказ сейчас.»',
),
(
"Possessive: use my/his/her/our BEFORE a noun. Use mine/his/hers/ours ALONE.",
"Притяжательные: my/his/her/our ставятся ПЕРЕД существительным. mine/his/hers/ours стоят ОТДЕЛЬНО.",
'"My bag is red." (before noun) / "That bag is mine." (alone)',
'«Моя сумка красная.» (перед существительным) / «Та сумка — моя.» (отдельно)',
),
]
# ════════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ════════════════════════════════════════════════════════════════════════════════
story = []
# ── Cover ─────────────────────────────────────────────────────────────────────
cv = Table(
[[Paragraph("My School Life - Book 3",
S("ct", BOLD, 26, C_WHITE, leading=32, align=TA_CENTER))]],
colWidths=[17*cm])
cv.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_DARK_GREEN),
("TOPPADDING", (0,0),(-1,-1), 20),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
]))
story.append(cv)
sub_en = Table(
[[Paragraph(
"15 Questions & Answers | Present Simple & Present Continuous | Grade 3 ESL",
S("cs", BASE, 12, C_WHITE, leading=16, align=TA_CENTER))]],
colWidths=[17*cm])
sub_en.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_MED_GREEN),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
]))
story.append(sub_en)
sub_ru = Table(
[[Paragraph(
"15 вопросов и ответов | Настоящее простое и длительное время | 3-й класс ESL",
S("cr", BASE, 11, C_PURPLE, leading=15, align=TA_CENTER))]],
colWidths=[17*cm])
sub_ru.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RUS_BG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
]))
story.append(sub_ru)
story.append(Spacer(1, 0.4*cm))
# ── Tense Formula Section ─────────────────────────────────────────────────────
story.append(banner(
"TENSE FORMULA & FORMAT / ФОРМУЛА И ФОРМАТ ВРЕМЁН",
C_TEAL, fs=14))
story.append(Spacer(1, 0.2*cm))
# -- Present Simple table --
story.append(Table(
[[Paragraph("Present Simple (Every day / Каждый день)",
S("psh", BOLD, 11, C_WHITE, leading=14, align=TA_CENTER))]],
colWidths=[17*cm],
style=[("BACKGROUND",(0,0),(-1,-1),C_BLUE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),8),("RIGHTPADDING",(0,0),(-1,-1),8)]))
ps_hdr = [
Paragraph("Subject / Подлежащее",
S("ph0", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
Paragraph("Verb Form / Форма глагола",
S("ph1", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
Paragraph("Example / Пример",
S("ph2", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
]
ps_rows = [ps_hdr]
ps_bgs = [C_BLUE_SOFT, C_LIME, C_ORANGE_SOFT]
for ri, (sen, sru, ven, vru, een, eru) in enumerate(PS_ROWS):
ps_rows.append([
Paragraph(f"{sen}\n{sru}",
S(f"ps0{ri}", BASE, 9, C_GREY, leading=13)),
Paragraph(f"{ven}\n{vru}",
S(f"ps1{ri}", BOLD, 9, C_BLUE, leading=13)),
Paragraph(f"{een}\n{eru}",
S(f"ps2{ri}", BASE, 9, C_GREY, leading=13)),
])
pstbl = Table(ps_rows, colWidths=[5*cm, 5.5*cm, 6.5*cm])
ps_style = [
("BACKGROUND", (0,0),(-1,0), C_BLUE),
("GRID", (0,0),(-1,-1), 0.5, C_WHITE),
("TOPPADDING", (0,0),(-1,-1), 5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1), 5),("RIGHTPADDING",(0,0),(-1,-1),5),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for ri, bg in enumerate(ps_bgs, 1):
ps_style.append(("BACKGROUND",(0,ri),(-1,ri), bg))
pstbl.setStyle(TableStyle(ps_style))
story.append(pstbl)
story.append(Spacer(1, 0.2*cm))
# Format box PS
ps_fmt_en = (
"FORMAT: Subject + verb (+ s/es for he/she/it)\n"
" I walk. She walks. They eat. He eats."
)
ps_fmt_ru = (
"ФОРМАТ: Подлежащее + глагол (+ s/es для he/she/it)\n"
" Я иду. Она идёт. Они едят. Он ест."
)
for txt, bgc, txc in [(ps_fmt_en, C_BLUE_SOFT, C_BLUE),
(ps_fmt_ru, C_RUS_BG, C_PURPLE)]:
bt = Table([[Paragraph(txt, S("fmt", BASE, 10, txc, leading=14))]],
colWidths=[17*cm])
bt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),bgc),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10),
("BOX",(0,0),(-1,-1),1.2,txc),
]))
story.append(bt)
story.append(Spacer(1, 0.05*cm))
story.append(Spacer(1, 0.2*cm))
# -- Present Continuous table --
story.append(Table(
[[Paragraph("Present Continuous (Right now / Прямо сейчас)",
S("pch", BOLD, 11, C_WHITE, leading=14, align=TA_CENTER))]],
colWidths=[17*cm],
style=[("BACKGROUND",(0,0),(-1,-1),C_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)]))
pc_hdr = [
Paragraph("Subject / Подлежащее",
S("pch0", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
Paragraph("Verb Form / Форма глагола",
S("pch1", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
Paragraph("Example / Пример",
S("pch2", BOLD, 10, C_WHITE, leading=13, align=TA_CENTER)),
]
pc_rows = [pc_hdr]
pc_bgs = [C_TEAL_LIGHT, C_LIME, C_ORANGE_SOFT]
for ri, (sen, sru, ven, vru, een, eru) in enumerate(PC_ROWS):
pc_rows.append([
Paragraph(f"{sen}\n{sru}",
S(f"pc0{ri}", BASE, 9, C_GREY, leading=13)),
Paragraph(f"{ven}\n{vru}",
S(f"pc1{ri}", BOLD, 9, C_TEAL, leading=13)),
Paragraph(f"{een}\n{eru}",
S(f"pc2{ri}", BASE, 9, C_GREY, leading=13)),
])
pctbl = Table(pc_rows, colWidths=[5*cm, 5.5*cm, 6.5*cm])
pc_style = [
("BACKGROUND",(0,0),(-1,0), C_TEAL),
("GRID", (0,0),(-1,-1), 0.5, C_WHITE),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
("VALIGN", (0,0),(-1,-1),"TOP"),
]
for ri, bg in enumerate(pc_bgs, 1):
pc_style.append(("BACKGROUND",(0,ri),(-1,ri), bg))
pctbl.setStyle(TableStyle(pc_style))
story.append(pctbl)
story.append(Spacer(1, 0.2*cm))
pc_fmt_en = (
"FORMAT: Subject + am/is/are + verb-ing\n"
" I am walking. She is reading. They are singing."
)
pc_fmt_ru = (
"ФОРМАТ: Подлежащее + am/is/are + глагол-ing\n"
" Я иду. Она читает. Они поют."
)
for txt, bgc, txc in [(pc_fmt_en, C_TEAL_LIGHT, C_TEAL),
(pc_fmt_ru, C_RUS_BG, C_PURPLE)]:
bt = Table([[Paragraph(txt, S("pcf", BASE, 10, txc, leading=14))]],
colWidths=[17*cm])
bt.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),bgc),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10),
("BOX",(0,0),(-1,-1),1.2,txc),
]))
story.append(bt)
story.append(Spacer(1, 0.05*cm))
story.append(Spacer(1, 0.35*cm))
# ── Q&A Cards ─────────────────────────────────────────────────────────────────
story.append(banner(
"QUESTIONS & ANSWERS / ВОПРОСЫ И ОТВЕТЫ",
C_ORANGE, fs=14))
story.append(Spacer(1, 0.3*cm))
for i, (q_en, q_ru, a_en, a_ru, tense_en, tense_ru) in enumerate(QA):
bg = CARD_BG[i % len(CARD_BG)]
# tense badge colour
tb_bg = C_BLUE if "Simple" in tense_en else C_TEAL
tb_txt = C_WHITE
tense_badge = Table(
[[Paragraph(f"{tense_en} | {tense_ru}",
S(f"tb{i}", BOLD, 9, tb_txt, leading=12, align=TA_CENTER))]],
colWidths=[17*cm])
tense_badge.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), tb_bg),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
]))
inner = [
Paragraph(q_en,
S(f"qe{i}", BOLD, 11, C_GREY, leading=15, sa=2)),
Paragraph(q_ru,
S(f"qr{i}", BASE, 10, C_PURPLE, leading=14, sa=3, bg=C_RUS_BG)),
Paragraph(f" {a_en}",
S(f"ae{i}", BASE, 11, C_DARK_GREEN, leading=15, sa=2)),
Paragraph(f" {a_ru}",
S(f"ar{i}", BASE, 10, C_TEAL, leading=14, bg=C_RUS_BG)),
]
card = Table([[inner]], colWidths=[17*cm])
card.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, C_LTGREY),
]))
story.append(KeepTogether([tense_badge, card, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Vocabulary ────────────────────────────────────────────────────────────────
story.append(banner(
"KEY VOCABULARY / КЛЮЧЕВЫЕ СЛОВА",
C_MED_GREEN, fs=14))
story.append(Spacer(1, 0.25*cm))
vrows = []
for i in range(0, len(VOCAB), 3):
chunk = VOCAB[i:i+3]
row = []
for en, ru in chunk:
row.append([
Paragraph(en, S(f"ven{i}", BOLD, 10, C_BLUE, leading=13)),
Paragraph(ru, S(f"vru{i}", BASE, 9, C_PURPLE, leading=12)),
])
while len(row) < 3:
row.append("")
vrows.append(row)
vstyle = [
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.5, C_LTGREY),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for r in range(len(vrows)):
vstyle.append(("BACKGROUND",(0,r),(-1,r),
C_LIME if r % 2 == 0 else C_ORANGE_SOFT))
vtbl = Table(vrows, colWidths=[5.5*cm, 5.5*cm, 5.5*cm])
vtbl.setStyle(TableStyle(vstyle))
story.append(vtbl)
story.append(Spacer(1, 0.35*cm))
# ── Signal Words Box ──────────────────────────────────────────────────────────
story.append(banner(
"SIGNAL WORDS / СИГНАЛЬНЫЕ СЛОВА",
C_PINK, fs=14))
story.append(Spacer(1, 0.2*cm))
sw_rows = [
[
Paragraph("Present Simple\nНастоящее простое",
S("sw1t", BOLD, 10, C_BLUE, leading=14)),
Paragraph(
"every day, always, usually, often, sometimes, never\n"
"каждый день, всегда, обычно, часто, иногда, никогда",
S("sw1w", BASE, 10, C_GREY, leading=14)),
],
[
Paragraph("Present Continuous\nНастоящее длительное",
S("sw2t", BOLD, 10, C_TEAL, leading=14)),
Paragraph(
"now, right now, at the moment, today, look!, listen!\n"
"сейчас, прямо сейчас, в данный момент, сегодня, смотри!, слушай!",
S("sw2w", BASE, 10, C_GREY, leading=14)),
],
]
swtbl = Table(sw_rows, colWidths=[5*cm, 12*cm])
swtbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_BLUE_SOFT),
("BACKGROUND", (0,1),(-1,1), C_TEAL_LIGHT),
("GRID", (0,0),(-1,-1), 0.5, C_LTGREY),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING",(0,0),(-1,-1),7),
("LEFTPADDING",(0,0),(-1,-1), 8),
("RIGHTPADDING",(0,0),(-1,-1),8),
("VALIGN", (0,0),(-1,-1),"TOP"),
]))
story.append(swtbl)
story.append(Spacer(1, 0.35*cm))
# ── Study Tips ────────────────────────────────────────────────────────────────
story.append(banner(
"STUDY TIPS / СОВЕТЫ ДЛЯ УЧЁБЫ",
C_BLUE, fs=14))
story.append(Spacer(1, 0.25*cm))
tip_icons = ["1", "2", "3"]
for ti, (ten, tru, een, eru) in enumerate(TIPS):
tc = Table([[
[
Paragraph(ten, S(f"te{ti}", BOLD, 11, C_ORANGE, leading=15)),
Paragraph(tru, S(f"tr{ti}", BASE, 10, C_PURPLE, leading=14, sa=3, bg=C_RUS_BG)),
Paragraph(een, S(f"ee{ti}", BASE, 10, C_GREY, leading=14)),
Paragraph(eru, S(f"er{ti}", BASE, 10, C_TEAL, leading=14)),
]
]], colWidths=[17*cm])
tc.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_YELLOW_SOFT),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, C_AMBER),
]))
story.append(KeepTogether([tc, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Footer ────────────────────────────────────────────────────────────────────
ft = Table([[Paragraph(
"Great job! You are learning every day! - "
"Молодец! Ты учишься каждый день!",
S("ft", BOLD, 12, C_WHITE, leading=16, align=TA_CENTER))]],
colWidths=[17*cm])
ft.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_DARK_GREEN),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
]))
story.append(ft)
# ── Render ────────────────────────────────────────────────────────────────────
OUT = "/tmp/workspace/esl-handbook/My_School_Life_Handbook3.pdf"
doc = SimpleDocTemplate(
OUT, pagesize=A4,
rightMargin=1*cm, leftMargin=1*cm,
topMargin=1.2*cm, bottomMargin=1*cm,
title="My School Life Book 3 - ESL Grade 3 - Present Simple & Continuous",
author="ESL Teacher",
)
doc.build(story)
import os
print(f"PDF saved: {OUT} ({os.path.getsize(OUT):,} bytes)")
python3 /tmp/workspace/esl-handbook/build_handbook3.py 2>&1
python3 -c " import pdfplumber with pdfplumber.open('/tmp/workspace/esl-handbook/My_School_Life_Handbook3.pdf') as pdf: print('Pages:', len(pdf.pages)) t = pdf.pages[0].extract_text() print(t[:700] if t else 'no text') " 2>&1
My School Life Handbook3
PDF Document · PDF
| Section | What's inside |
|---|---|
| Cover | Dark green + mid-green banner, Book 3 title, both English & Russian |
| Tense Formula & Format | Two separate tables - one for Present Simple, one for Present Continuous - each with subject, verb form, example (EN + RU), plus a FORMAT box in both languages |
| 15 Q&A Cards | Each card shows the tense name in EN + RU, then question EN → Russian → answer EN → Russian |
| Key Vocabulary | 30 new easy words with Russian, alternating green/peach rows |
| Signal Words Box | Quick reference: "every day / always" for PS, "now / right now / look!" for PC - both bilingual |
| Study Tips | 3 yellow tip boxes - PS vs PC difference, signal words, possessive pronouns |
| Footer | "Great job! You are learning every day!" - dark green, bilingual |
Please don't include questions with "right now " and don't add pronouns in end rather give a direct answer to question using pronouns at starting of sentences only., only use present tenses ( simple ) don't use past tense, you can replace some questions and add other interesting logical questions along with answers in short direct.Alsobadf Russian translation under their English sentences and also remove the format and formulas from above prepared pdf and create a fresh new handbook for 3rd grade ESL student.
~/esl-handbook/build_handbook4.py
#!/usr/bin/env python3
"""
My School Life – ESL Handbook 4 for Grade 3
15 questions & answers – Present Simple ONLY
No 'right now', no formulas/format section
Answers start with a pronoun. Short and direct.
Russian translation under EVERY English line.
Colourful PDF using ReportLab + DroidSans (Cyrillic)
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ── Fonts ──────────────────────────────────────────────────────────────────────
pdfmetrics.registerFont(TTFont(
"DroidSans", "/usr/share/fonts/google-droid-sans-fonts/DroidSans.ttf"))
pdfmetrics.registerFont(TTFont(
"DroidSans-Bold", "/usr/share/fonts/google-droid-sans-fonts/DroidSans-Bold.ttf"))
B = "DroidSans-Bold"
R = "DroidSans"
# ── Colours ────────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0D2B6E")
C_ROYAL = colors.HexColor("#1565C0")
C_SKY = colors.HexColor("#E3F2FD")
C_TEAL = colors.HexColor("#00695C")
C_TEAL_SOFT = colors.HexColor("#E0F2F1")
C_ORANGE = colors.HexColor("#E65100")
C_PEACH = colors.HexColor("#FFF3E0")
C_PURPLE = colors.HexColor("#6A0DAD")
C_LILAC = colors.HexColor("#F3E5F5")
C_GREEN = colors.HexColor("#1B5E20")
C_LIME = colors.HexColor("#F1F8E9")
C_PINK = colors.HexColor("#AD1457")
C_ROSE = colors.HexColor("#FCE4EC")
C_AMBER = colors.HexColor("#FF8F00")
C_YELLOW = colors.HexColor("#FFFDE7")
C_WHITE = colors.white
C_DARK = colors.HexColor("#212121")
C_GREY = colors.HexColor("#37474F")
C_LTGREY = colors.HexColor("#ECEFF1")
C_RU = colors.HexColor("#F3E5F5") # Russian line background
CARD_COLOURS = [C_SKY, C_LIME, C_PEACH, C_ROSE, C_TEAL_SOFT, C_YELLOW]
# ── Style helper ───────────────────────────────────────────────────────────────
def S(name, font, size, color, leading=None, align=TA_LEFT,
sb=0, sa=0, bg=None):
kw = dict(name=name, fontName=font, fontSize=size,
textColor=color, leading=leading or size * 1.45,
alignment=align, spaceBefore=sb, spaceAfter=sa)
if bg:
kw["backColor"] = bg
return ParagraphStyle(**kw)
# ── Banner helper ──────────────────────────────────────────────────────────────
def banner(text_en, text_ru, bg_col, fg_col=C_WHITE, fs=13):
st_en = S("ben", B, fs, fg_col, leading=fs*1.3, align=TA_CENTER)
st_ru = S("bru", R, fs-2, C_PURPLE, leading=(fs-2)*1.35, align=TA_CENTER)
tbl = Table(
[[Paragraph(text_en, st_en)],
[Paragraph(text_ru, st_ru)]],
colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg_col),
("BACKGROUND", (0,1), (0,1), C_RU),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
# ══════════════════════════════════════════════════════════════════════════════
# 15 QUESTIONS & ANSWERS
# Rules:
# - Present Simple ONLY (no "right now", no past tense)
# - Answer starts with a pronoun
# - Short, direct, easy words
# - Russian under every English line
# Format per entry:
# (Q line 1 EN, Q line 1 RU,
# A line 1 EN, A line 1 RU,
# A line 2 EN, A line 2 RU) ← answers are 1-2 short sentences
# ══════════════════════════════════════════════════════════════════════════════
QA = [
(
"1. What do you carry in your school bag?",
"1. Что ты носишь в школьной сумке?",
"I carry my books, my pencil case, and my water bottle.",
"Я ношу свои книги, пенал и бутылку воды.",
"They are heavy but I like them.",
"Они тяжёлые, но мне они нравятся.",
),
(
"2. What time does school start every day?",
"2. В какое время начинается школа каждый день?",
"It starts at nine o'clock in the morning.",
"Она начинается в девять часов утра.",
"We always arrive five minutes early.",
"Мы всегда приходим на пять минут раньше.",
),
(
"3. What do you do first when you arrive at school?",
"3. Что ты делаешь сначала, когда приходишь в школу?",
"I put my bag on my chair and sit at my desk.",
"Я кладу сумку на стул и сажусь за свою парту.",
"She does the same thing every morning.",
"Она делает то же самое каждое утро.",
),
(
"4. How does your teacher check your homework?",
"4. Как твой учитель проверяет твою домашнюю работу?",
"She looks at our notebooks and puts a tick or a star.",
"Она смотрит в наши тетради и ставит галочку или звёздочку.",
"We love a gold star on our work.",
"Мы любим золотую звёздочку в нашей работе.",
),
(
"5. What do children do in the school playground?",
"5. Что дети делают на школьной площадке?",
"They run, jump, and play with their friends.",
"Они бегают, прыгают и играют с друзьями.",
"We all have a great time outside.",
"Нам всем очень весело на улице.",
),
(
"6. What does the school librarian do every week?",
"6. Что библиотекарь школы делает каждую неделю?",
"She puts new books on the shelf for us to read.",
"Она ставит новые книги на полку для нас.",
"We borrow one book each week.",
"Мы берём по одной книге каждую неделю.",
),
(
"7. What do you do when you do not understand a word?",
"7. Что ты делаешь, когда не понимаешь слово?",
"I put my hand up and ask my teacher.",
"Я поднимаю руку и спрашиваю учителя.",
"She always explains it in a simple way.",
"Она всегда объясняет это простым способом.",
),
(
"8. How do students say good morning to the teacher?",
"8. Как ученики говорят доброе утро учителю?",
"We stand up and say \"Good morning\" together.",
"Мы встаём и вместе говорим «Доброе утро».",
"She smiles and says \"Good morning\" back to us.",
"Она улыбается и говорит нам «Доброе утро» в ответ.",
),
(
"9. What does the school cook make for lunch?",
"9. Что школьный повар готовит на обед?",
"He makes soup, rice, and vegetables for all the children.",
"Он готовит суп, рис и овощи для всех детей.",
"It smells very good in the dinner hall.",
"В столовой очень вкусно пахнет.",
),
(
"10. What do you do when you finish your classwork early?",
"10. Что ты делаешь, когда заканчиваешь классную работу раньше?",
"I read a book quietly at my desk.",
"Я тихо читаю книгу за своей партой.",
"My teacher also gives me an extra activity to try.",
"Моя учительница также даёт мне дополнительное задание.",
),
(
"11. How do you keep your desk clean and tidy?",
"11. Как ты поддерживаешь свою парту чистой и аккуратной?",
"I put my pencils in my pencil case after every lesson.",
"Я кладу карандаши в пенал после каждого урока.",
"We also clean our desks before we go home.",
"Мы также убираем парты перед тем, как идти домой.",
),
(
"12. What sport do children play in PE lessons?",
"12. Каким спортом дети занимаются на уроках физкультуры?",
"We play football, do running, and practice jumping.",
"Мы играем в футбол, бегаем и практикуем прыжки.",
"Our PE teacher shows us how to do each exercise.",
"Наш учитель физкультуры показывает нам, как делать каждое упражнение.",
),
(
"13. What do you say to a classmate who feels sad?",
"13. Что ты говоришь однокласснику, который чувствует себя грустно?",
"I say \"Are you OK?\" and sit next to them.",
"Я говорю «Ты в порядке?» и сажусь рядом с ними.",
"We always try to be kind to each other.",
"Мы всегда стараемся быть добрыми друг к другу.",
),
(
"14. What do you see on the classroom door?",
"14. Что ты видишь на двери класса?",
"I see our class name and a colourful sign.",
"Я вижу название нашего класса и красочную табличку.",
"It shows the rules of our classroom.",
"На ней написаны правила нашего класса.",
),
(
"15. Why do you like going to school?",
"15. Почему тебе нравится ходить в школу?",
"I learn new things and meet my friends every day.",
"Я узнаю новое и встречаю своих друзей каждый день.",
"School makes me feel happy and clever.",
"Школа делает меня счастливым и умным.",
),
]
# ── Vocabulary (30 new easy words from the questions above) ───────────────────
VOCAB = [
("carry", "носить"),
("water bottle", "бутылка воды"),
("arrive", "приходить/приезжать"),
("desk", "парта"),
("homework", "домашняя работа"),
("tick", "галочка"),
("gold star", "золотая звёздочка"),
("playground", "школьная площадка"),
("jump", "прыгать"),
("librarian", "библиотекарь"),
("shelf", "полка"),
("borrow", "брать/одалживать"),
("hand up", "поднять руку"),
("explain", "объяснять"),
("simple", "простой"),
("together", "вместе"),
("cook", "повар"),
("soup", "суп"),
("vegetables", "овощи"),
("quietly", "тихо"),
("extra", "дополнительный"),
("tidy", "аккуратный"),
("exercise", "упражнение"),
("kind", "добрый"),
("colourful", "красочный/яркий"),
("sign", "табличка/знак"),
("rules", "правила"),
("clever", "умный"),
("early", "рано/заранее"),
("smell", "пахнуть"),
]
# ── Study Tips (3 tips about Present Simple, no formulas) ─────────────────────
TIPS = [
(
"Tip 1: Use Present Simple for things you do every day.",
"Совет 1: Используй настоящее простое время для действий, которые ты делаешь каждый день.",
'"I walk to school every day." / "She reads a book every night."',
'«Я хожу в школу каждый день.» / «Она читает книгу каждый вечер.»',
),
(
"Tip 2: Add -s or -es to the verb when the subject is He, She, or It.",
"Совет 2: Добавляй -s или -es к глаголу, если подлежащее — He, She или It.",
'"He runs fast." / "She teaches us English." / "It smells good."',
'«Он бегает быстро.» / «Она учит нас английскому.» / «Это вкусно пахнет.»',
),
(
"Tip 3: Start your answer with a pronoun: I, We, He, She, They, It.",
"Совет 3: Начинай ответ с местоимения: I (я), We (мы), He (он), She (она), They (они), It (это).",
'"What do you eat? — I eat a sandwich."',
'«Что ты ешь? — Я ем бутерброд.»',
),
]
# ════════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ════════════════════════════════════════════════════════════════════════════════
story = []
# ── Cover ─────────────────────────────────────────────────────────────────────
cv = Table(
[[Paragraph("My School Life – Book 4",
S("ct", B, 26, C_WHITE, leading=32, align=TA_CENTER))]],
colWidths=[17*cm])
cv.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_NAVY),
("TOPPADDING", (0,0),(-1,-1), 18),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
]))
story.append(cv)
sub_en = Table(
[[Paragraph(
"15 Questions & Answers | Present Simple | Grade 3 ESL",
S("se", R, 12, C_WHITE, leading=16, align=TA_CENTER))]],
colWidths=[17*cm])
sub_en.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_ROYAL),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
]))
story.append(sub_en)
sub_ru = Table(
[[Paragraph(
"15 вопросов и ответов | Настоящее простое время | 3-й класс ESL",
S("sr", R, 11, C_PURPLE, leading=15, align=TA_CENTER))]],
colWidths=[17*cm])
sub_ru.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RU),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
]))
story.append(sub_ru)
story.append(Spacer(1, 0.45*cm))
# ── Q&A Section header ────────────────────────────────────────────────────────
story.append(banner(
"QUESTIONS & ANSWERS",
"ВОПРОСЫ И ОТВЕТЫ",
C_ORANGE))
story.append(Spacer(1, 0.3*cm))
for i, (q_en, q_ru, a1_en, a1_ru, a2_en, a2_ru) in enumerate(QA):
bg = CARD_COLOURS[i % len(CARD_COLOURS)]
# Q label badge
badge_bg = C_ROYAL if i % 2 == 0 else C_TEAL
badge = Table(
[[Paragraph(f"Q {i+1} / Вопрос {i+1}",
S(f"qb{i}", B, 9, C_WHITE,
leading=12, align=TA_CENTER))]],
colWidths=[17*cm])
badge.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), badge_bg),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
]))
# Question rows
q_rows = [
Paragraph(q_en, S(f"qe{i}", B, 11, C_DARK, leading=15, sa=1)),
Paragraph(q_ru, S(f"qr{i}", R, 10, C_PURPLE, leading=14, sa=4, bg=C_RU)),
Paragraph(a1_en, S(f"a1e{i}", R, 11, C_GREEN, leading=15, sa=1)),
Paragraph(a1_ru, S(f"a1r{i}", R, 10, C_TEAL, leading=14, sa=3, bg=C_RU)),
Paragraph(a2_en, S(f"a2e{i}", R, 11, C_GREY, leading=15, sa=1)),
Paragraph(a2_ru, S(f"a2r{i}", R, 10, C_PURPLE, leading=14, bg=C_RU)),
]
card = Table([[q_rows]], colWidths=[17*cm])
card.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 0.8, C_LTGREY),
]))
story.append(KeepTogether([badge, card, Spacer(1, 0.22*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Vocabulary ────────────────────────────────────────────────────────────────
story.append(banner(
"KEY VOCABULARY",
"КЛЮЧЕВЫЕ СЛОВА",
C_GREEN))
story.append(Spacer(1, 0.25*cm))
vrows = []
for i in range(0, len(VOCAB), 3):
chunk = VOCAB[i:i+3]
row = []
for en, ru in chunk:
row.append([
Paragraph(en, S(f"ve{i}", B, 10, C_ROYAL, leading=13)),
Paragraph(ru, S(f"vr{i}", R, 9, C_PURPLE, leading=12)),
])
while len(row) < 3:
row.append("")
vrows.append(row)
vstyle = [
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("RIGHTPADDING", (0,0),(-1,-1), 7),
("GRID", (0,0),(-1,-1), 0.4, C_LTGREY),
("VALIGN", (0,0),(-1,-1), "TOP"),
]
for r in range(len(vrows)):
vstyle.append(("BACKGROUND",(0,r),(-1,r),
C_LIME if r % 2 == 0 else C_PEACH))
vtbl = Table(vrows, colWidths=[5.5*cm, 5.5*cm, 5.5*cm])
vtbl.setStyle(TableStyle(vstyle))
story.append(vtbl)
story.append(Spacer(1, 0.4*cm))
# ── Study Tips ────────────────────────────────────────────────────────────────
story.append(banner(
"REMEMBER THESE!",
"ЗАПОМНИ ЭТО!",
C_PINK))
story.append(Spacer(1, 0.25*cm))
for ti, (ten, tru, een, eru) in enumerate(TIPS):
tip_bg = [C_SKY, C_TEAL_SOFT, C_YELLOW][ti]
border_c = [C_ROYAL, C_TEAL, C_AMBER][ti]
tc = Table([[
[
Paragraph(ten, S(f"te{ti}", B, 11, C_DARK, leading=15, sa=1)),
Paragraph(tru, S(f"tr{ti}", R, 10, C_PURPLE, leading=14, sa=4, bg=C_RU)),
Paragraph(een, S(f"ee{ti}", R, 10, C_GREY, leading=14, sa=1)),
Paragraph(eru, S(f"er{ti}", R, 10, C_TEAL, leading=14, bg=C_RU)),
]
]], colWidths=[17*cm])
tc.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), tip_bg),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.2, border_c),
]))
story.append(KeepTogether([tc, Spacer(1, 0.2*cm)]))
story.append(Spacer(1, 0.3*cm))
# ── Footer ────────────────────────────────────────────────────────────────────
ft = Table([[Paragraph(
"You are a wonderful student! – Ты замечательный ученик!",
S("ft", B, 13, C_WHITE, leading=17, align=TA_CENTER))]],
colWidths=[17*cm])
ft.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_NAVY),
("TOPPADDING", (0,0),(-1,-1), 11),
("BOTTOMPADDING", (0,0),(-1,-1), 11),
]))
story.append(ft)
# ── Render ────────────────────────────────────────────────────────────────────
import os
OUT = "/tmp/workspace/esl-handbook/My_School_Life_Handbook4.pdf"
doc = SimpleDocTemplate(
OUT, pagesize=A4,
rightMargin=1*cm, leftMargin=1*cm,
topMargin=1.2*cm, bottomMargin=1*cm,
title="My School Life Book 4 – ESL Grade 3 – Present Simple",
author="ESL Teacher",
)
doc.build(story)
print(f"PDF saved: {OUT} ({os.path.getsize(OUT):,} bytes)")
python3 /tmp/workspace/esl-handbook/build_handbook4.py 2>&1
python3 -c " import pdfplumber with pdfplumber.open('/tmp/workspace/esl-handbook/My_School_Life_Handbook4.pdf') as pdf: print('Pages:', len(pdf.pages)) t = pdf.pages[0].extract_text() print(t[:700] if t else 'no text') " 2>&1
My School Life Handbook4
PDF Document · PDF
| Feature | Book 4 |
|---|---|
| Tense | Present Simple ONLY - no "right now", no continuous tense |
| Answers | Every answer starts with a pronoun (I, We, She, He, It, They) |
| Format | No grammar formulas or format boxes - clean and simple |
| Russian | Under EVERY English line throughout the whole PDF |
| Structure | Each card has a numbered badge (Q1/Вопрос 1), then question → Russian, answer line 1 → Russian, answer line 2 → Russian |
| # | Question topic |
|---|---|
| 1 | What do you carry in your bag? |
| 2 | What time does school start? |
| 3 | What do you do first when you arrive? |
| 4 | How does the teacher check homework? |
| 5 | What do children do in the playground? |
| 6 | What does the school librarian do? |
| 7 | What do you do when you don't understand a word? |
| 8 | How do students say good morning? |
| 9 | What does the school cook make for lunch? |
| 10 | What do you do when you finish work early? |
| 11 | How do you keep your desk tidy? |
| 12 | What sport do you do in PE? |
| 13 | What do you say to a sad classmate? |
| 14 | What do you see on the classroom door? |
| 15 | Why do you like going to school? |