Please create a handbook pdf on following: Please write list of 20 conversation questions can I practice with my 3rd /4thgrade ESL student along with answers, most important that the sentences in English for questions and answers must have Russian translation under it , student back home from from trip hl during his summer vacation. Topics like travel and journey, food ,tastes ,sight and places seen during trip , activities and people etc. Please ask logical and not funny questions based on only present simple, present continuous, articles, possessive cases etc.
fc-list | grep -i dejavu; python3 -c "import reportlab; print(reportlab.Version)"; find / -iname "DejaVuSans*.ttf" 2>/dev/null
mkdir -p /tmp/workspace/esl-handbook && ls -la /tmp/workspace/
~/esl-handbook/build_pdf.py
# -*- coding: utf-8 -*-
"""
Build an ESL conversation-practice handbook PDF:
"My Summer Trip" - 20 English/Russian Q&A pairs for a 3rd/4th grade student.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ---------- Fonts (DejaVu supports Cyrillic) ----------
FONT_DIR = "/opt/amazon/genesis1p-tools/venv/lib/python3.12/site-packages/matplotlib/mpl-data/fonts/ttf"
pdfmetrics.registerFont(TTFont("DejaVu", f"{FONT_DIR}/DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", f"{FONT_DIR}/DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Oblique", f"{FONT_DIR}/DejaVuSans-Oblique.ttf"))
PAGE_W, PAGE_H = A4
# ---------- Styles ----------
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
"TitleCustom", fontName="DejaVu-Bold", fontSize=22, leading=27,
textColor=colors.HexColor("#14406B"), alignment=1, spaceAfter=6,
)
subtitle_style = ParagraphStyle(
"SubtitleCustom", fontName="DejaVu", fontSize=12.5, leading=17,
textColor=colors.HexColor("#444444"), alignment=1, spaceAfter=4,
)
note_style = ParagraphStyle(
"NoteCustom", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#333333"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#F4F8FB"), borderPadding=8,
)
section_style = ParagraphStyle(
"SectionCustom", fontName="DejaVu-Bold", fontSize=15, leading=19,
textColor=colors.white, alignment=0, spaceBefore=0, spaceAfter=0,
)
qnum_style = ParagraphStyle(
"QNum", fontName="DejaVu-Bold", fontSize=12.5, leading=16,
textColor=colors.HexColor("#14406B"),
)
q_en_style = ParagraphStyle(
"QEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#1B1B1B"), spaceAfter=1,
)
q_ru_style = ParagraphStyle(
"QRu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#7A4B00"), spaceAfter=6,
)
a_en_style = ParagraphStyle(
"AEn", fontName="DejaVu", fontSize=11.5, leading=15,
textColor=colors.HexColor("#0B5D2E"), spaceAfter=1,
)
a_ru_style = ParagraphStyle(
"ARu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#5B6B5B"), spaceAfter=2,
)
grammar_tag_style = ParagraphStyle(
"GTag", fontName="DejaVu-Oblique", fontSize=8.7, leading=11,
textColor=colors.HexColor("#8A8A8A"),
)
footer_style = ParagraphStyle(
"Footer", fontName="DejaVu", fontSize=8.5, leading=11,
textColor=colors.HexColor("#999999"), alignment=1,
)
SECTION_COLORS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#2E6BAD"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#C1622B"),
"Sights & Places / Виды и места": colors.HexColor("#3E8E5A"),
"Activities & People / Занятия и люди": colors.HexColor("#8E3E7B"),
}
# ---------- Content: 20 Q&A pairs grouped by topic ----------
DATA = [
("Travel & Journey / Путешествие и поездка", [
dict(
q_en="How do you usually travel to your grandmother's village?",
q_ru="Как ты обычно добираешься в деревню к бабушке?",
a_en="We usually travel by train.",
a_ru="Мы обычно едем на поезде.",
g="Present Simple, Possessive case",
),
dict(
q_en="What is in your suitcase?",
q_ru="Что находится в твоём чемодане?",
a_en="My clothes and my toys are in my suitcase.",
a_ru="Моя одежда и мои игрушки в моём чемодане.",
g="Present Simple, Possessive adjectives",
),
dict(
q_en="Whose camera is this?",
q_ru="Чей это фотоаппарат?",
a_en="It is my father's camera.",
a_ru="Это фотоаппарат моего папы.",
g="Possessive case ('s)",
),
dict(
q_en="Is your family driving to the sea this summer?",
q_ru="Твоя семья едет на машине к морю этим летом?",
a_en="Yes, we are driving to the sea this summer.",
a_ru="Да, этим летом мы едем к морю на машине.",
g="Present Continuous",
),
dict(
q_en="How long is the journey to the sea?",
q_ru="Сколько длится поездка до моря?",
a_en="The journey is about five hours.",
a_ru="Поездка длится около пяти часов.",
g="Present Simple, Article 'the'",
),
]),
("Food & Tastes / Еда и вкусы", [
dict(
q_en="What do you usually eat for breakfast at the hotel?",
q_ru="Что ты обычно ешь на завтрак в отеле?",
a_en="I usually eat eggs and bread for breakfast.",
a_ru="Я обычно ем яйца и хлеб на завтрак.",
g="Present Simple, Article 'the'",
),
dict(
q_en="How does the ice cream taste?",
q_ru="Какое на вкус мороженое?",
a_en="The ice cream tastes very sweet.",
a_ru="Мороженое очень сладкое на вкус.",
g="Present Simple, Article 'the'",
),
dict(
q_en="Is the soup salty or sweet?",
q_ru="Суп солёный или сладкий?",
a_en="The soup is salty.",
a_ru="Суп солёный.",
g="Present Simple, Article 'the'",
),
dict(
q_en="What is your favorite fruit at the market?",
q_ru="Какой твой любимый фрукт на рынке?",
a_en="My favorite fruit is a watermelon.",
a_ru="Мой любимый фрукт - арбуз.",
g="Possessive adjective, Article 'a'",
),
dict(
q_en="Are you drinking juice or water now?",
q_ru="Ты сейчас пьёшь сок или воду?",
a_en="I am drinking orange juice now.",
a_ru="Я сейчас пью апельсиновый сок.",
g="Present Continuous",
),
]),
("Sights & Places / Виды и места", [
dict(
q_en="What are you looking at in this photo?",
q_ru="На что ты смотришь на этой фотографии?",
a_en="I am looking at a big mountain.",
a_ru="Я смотрю на большую гору.",
g="Present Continuous, Article 'a'",
),
dict(
q_en="Is the sea near your hotel?",
q_ru="Море находится рядом с твоим отелем?",
a_en="Yes, the sea is very near our hotel.",
a_ru="Да, море очень близко к нашему отелю.",
g="Present Simple, Article 'the', Possessive adjective",
),
dict(
q_en="What is the name of the city you are visiting?",
q_ru="Как называется город, который ты посещаешь?",
a_en="The city's name is Sochi.",
a_ru="Название города - Сочи.",
g="Present Continuous, Possessive case ('s)",
),
dict(
q_en="Are there many tourists at the beach?",
q_ru="На пляже много туристов?",
a_en="Yes, there are many tourists at the beach.",
a_ru="Да, на пляже много туристов.",
g="Present Simple, Article 'the'",
),
dict(
q_en="What is on the top of the mountain?",
q_ru="Что находится на вершине горы?",
a_en="There is a small church on the top of the mountain.",
a_ru="На вершине горы есть маленькая церковь.",
g="Present Simple, Articles 'a' / 'the'",
),
]),
("Activities & People / Занятия и люди", [
dict(
q_en="What are you doing in this picture?",
q_ru="Что ты делаешь на этой фотографии?",
a_en="I am swimming in the sea.",
a_ru="Я плаваю в море.",
g="Present Continuous, Article 'the'",
),
dict(
q_en="Who is standing next to you in the photo?",
q_ru="Кто стоит рядом с тобой на фотографии?",
a_en="My sister is standing next to me.",
a_ru="Моя сестра стоит рядом со мной.",
g="Present Continuous, Possessive adjective",
),
dict(
q_en="Do you play with other children on the beach?",
q_ru="Ты играешь с другими детьми на пляже?",
a_en="Yes, I play with other children every day.",
a_ru="Да, я играю с другими детьми каждый день.",
g="Present Simple, Article 'the'",
),
dict(
q_en="Is your brother building a sandcastle now?",
q_ru="Твой брат сейчас строит замок из песка?",
a_en="Yes, he is building a big sandcastle.",
a_ru="Да, он строит большой замок из песка.",
g="Present Continuous, Possessive adjective, Article 'a'",
),
dict(
q_en="Whose sunglasses are these on the table?",
q_ru="Чьи это солнечные очки на столе?",
a_en="They are my mother's sunglasses.",
a_ru="Это солнечные очки моей мамы.",
g="Possessive case ('s), Article 'the'",
),
]),
]
# ---------- Build story ----------
doc = SimpleDocTemplate(
"/tmp/workspace/esl-handbook/My_Summer_Trip_ESL_Handbook.pdf",
pagesize=A4,
topMargin=1.6 * cm, bottomMargin=1.6 * cm,
leftMargin=1.8 * cm, rightMargin=1.8 * cm,
title="My Summer Trip - ESL Conversation Handbook",
author="Orris",
)
story = []
# --- Cover ---
story.append(Spacer(1, 1.2 * cm))
story.append(Paragraph("My Summer Trip", title_style))
story.append(Paragraph("Моё летнее путешествие", subtitle_style))
story.append(Spacer(1, 0.3 * cm))
story.append(Paragraph(
"20 Conversation Questions & Answers for a 3rd/4th Grade ESL Student",
subtitle_style))
story.append(Paragraph(
"20 вопросов и ответов для практики разговорной речи (English / Russian)",
subtitle_style))
story.append(Spacer(1, 0.5 * cm))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.4 * cm))
story.append(Paragraph(
"<b>How to use this handbook / Как использовать этот материал:</b> "
"Look at photos or souvenirs from the trip together and ask each question out loud. "
"The student answers in English first, then checks the meaning with the Russian "
"translation printed under every line. Every question and answer uses only four "
"grammar points: <b>Present Simple</b>, <b>Present Continuous</b>, <b>Articles</b> "
"(a / an / the), and <b>Possessive case</b> (my, your, his, her, our, their, "
"and 's).",
note_style))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Просматривайте вместе фотографии или сувениры с поездки и задавайте каждый вопрос "
"вслух. Ученик сначала отвечает по-английски, затем проверяет смысл по русскому "
"переводу под каждой строкой. Во всех вопросах и ответах используются только "
"четыре грамматические темы: <b>простое настоящее время</b>, <b>настоящее "
"продолженное время</b>, <b>артикли</b> (a / an / the) и <b>притяжательный "
"падеж</b> (my, your, his, her, our, their и 's).",
note_style))
story.append(Spacer(1, 0.6 * cm))
legend_data = [[
Paragraph("<b>Color guide / Цветовые обозначения</b>", ParagraphStyle(
"LegendHead", fontName="DejaVu-Bold", fontSize=10.5,
textColor=colors.HexColor("#14406B"))),
]]
story.append(Table(legend_data, colWidths=[16*cm]))
story.append(Spacer(1, 0.2*cm))
legend_rows = [
[Paragraph("Question (English)", ParagraphStyle("l1", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#1B1B1B"))),
Paragraph("Вопрос по-русски курсивом", ParagraphStyle("l2", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#7A4B00")))],
[Paragraph("Answer (English)", ParagraphStyle("l3", fontName="DejaVu", fontSize=9.5, textColor=colors.HexColor("#0B5D2E"))),
Paragraph("Ответ по-русски курсивом", ParagraphStyle("l4", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#5B6B5B")))],
]
legend_table = Table(legend_rows, colWidths=[8*cm, 8*cm])
legend_table.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#DDDDDD")),
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#EEEEEE")),
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#FBFBFB")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(legend_table)
story.append(PageBreak())
# --- Sections with questions ---
q_number = 1
for section_title, items in DATA:
color = SECTION_COLORS[section_title]
header_table = Table([[Paragraph(section_title, section_style)]], colWidths=[16.4*cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(header_table)
story.append(Spacer(1, 0.35 * cm))
for item in items:
row_cells = [
[Paragraph(f"{q_number}.", qnum_style),
Paragraph(
f"{item['q_en']}<br/>{item['q_ru']}<br/>"
f"<font color='#0B5D2E'>{item['a_en']}</font><br/>"
f"<font color='#5B6B5B'><i>{item['a_ru']}</i></font><br/>"
f"<font color='#8A8A8A' size='8.5'><i>Grammar focus: {item['g']}</i></font>",
ParagraphStyle("combo", fontName="DejaVu", fontSize=11.5, leading=15))
]
]
# Build with individually styled paragraphs instead (cleaner control)
cell_flow = [
Paragraph(item["q_en"], q_en_style),
Paragraph(item["q_ru"], q_ru_style),
Paragraph(item["a_en"], a_en_style),
Paragraph(item["a_ru"], a_ru_style),
Paragraph(f"Grammar focus: {item['g']}", grammar_tag_style),
]
t = Table(
[[Paragraph(f"{q_number}", ParagraphStyle(
"numcircle", fontName="DejaVu-Bold", fontSize=13,
textColor=colors.white, alignment=1)), cell_flow]],
colWidths=[0.9 * cm, 15.3 * cm],
)
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), color),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (0, 0), 6),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
("TOPPADDING", (1, 0), (1, 0), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (1, 0), (1, 0), 10),
("BOX", (0, 0), (-1, -1), 0.5, colors.HexColor("#E3E3E3")),
("BACKGROUND", (1, 0), (1, 0), colors.HexColor("#FCFCFC")),
]))
story.append(t)
story.append(Spacer(1, 0.28 * cm))
q_number += 1
story.append(Spacer(1, 0.15 * cm))
story.append(Spacer(1, 0.4 * cm))
story.append(HRFlowable(width="100%", thickness=0.7, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.2 * cm))
story.append(Paragraph(
"Tip for the tutor / Совет для преподавателя: after the student answers, ask them to "
"point at the picture and repeat the answer once more from memory, without reading. "
"This builds fluency in the target grammar structures.",
footer_style))
story.append(Paragraph(
"После того как ученик ответит, попросите его показать на фотографии и повторить "
"ответ ещё раз по памяти, не читая. Это укрепляет навык использования нужных "
"грамматических конструкций.",
footer_style))
doc.build(story)
print("PDF built successfully.")
~/esl-handbook/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/esl-handbook/build_pdf.py'
row_cells block to keep the script clean:~/esl-handbook/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/esl-handbook/build_pdf.py'
cd /tmp/workspace/esl-handbook && python3 build_pdf.py
cd /tmp/workspace/esl-handbook && python3 -c " import pdfplumber with pdfplumber.open('My_Summer_Trip_ESL_Handbook.pdf') as pdf: print('pages:', len(pdf.pages)) for i, p in enumerate(pdf.pages): t = p.extract_text() or '' print('--- page', i+1, 'chars:', len(t)) print(t[:400]) " ls -la My_Summer_Trip_ESL_Handbook.pdf
My Summer Trip ESL Handbook
PDF Document · PDF
The 20 conversation questions should be based on his experience of trip, rewrite all the questions following similar command mentioned above and don't mention extract text information like grammar focus under questions and answers
~/esl-handbook/build_pdf.py
# -*- coding: utf-8 -*-
"""
Build an ESL conversation-practice handbook PDF:
"My Summer Trip" - 20 English/Russian Q&A pairs for a 3rd/4th grade student,
based on the student's own trip experience.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ---------- Fonts (DejaVu supports Cyrillic) ----------
FONT_DIR = "/opt/amazon/genesis1p-tools/venv/lib/python3.12/site-packages/matplotlib/mpl-data/fonts/ttf"
pdfmetrics.registerFont(TTFont("DejaVu", f"{FONT_DIR}/DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", f"{FONT_DIR}/DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Oblique", f"{FONT_DIR}/DejaVuSans-Oblique.ttf"))
# ---------- Styles ----------
title_style = ParagraphStyle(
"TitleCustom", fontName="DejaVu-Bold", fontSize=22, leading=27,
textColor=colors.HexColor("#14406B"), alignment=1, spaceAfter=6,
)
subtitle_style = ParagraphStyle(
"SubtitleCustom", fontName="DejaVu", fontSize=12.5, leading=17,
textColor=colors.HexColor("#444444"), alignment=1, spaceAfter=4,
)
note_style = ParagraphStyle(
"NoteCustom", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#333333"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#F4F8FB"), borderPadding=8,
)
section_style = ParagraphStyle(
"SectionCustom", fontName="DejaVu-Bold", fontSize=15, leading=19,
textColor=colors.white, alignment=0, spaceBefore=0, spaceAfter=0,
)
q_en_style = ParagraphStyle(
"QEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#1B1B1B"), spaceAfter=1,
)
q_ru_style = ParagraphStyle(
"QRu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#7A4B00"), spaceAfter=6,
)
a_en_style = ParagraphStyle(
"AEn", fontName="DejaVu", fontSize=11.5, leading=15,
textColor=colors.HexColor("#0B5D2E"), spaceAfter=1,
)
a_ru_style = ParagraphStyle(
"ARu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#5B6B5B"), spaceAfter=2,
)
footer_style = ParagraphStyle(
"Footer", fontName="DejaVu", fontSize=8.5, leading=11,
textColor=colors.HexColor("#999999"), alignment=1,
)
SECTION_COLORS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#2E6BAD"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#C1622B"),
"Sights & Places / Виды и места": colors.HexColor("#3E8E5A"),
"Activities & People / Занятия и люди": colors.HexColor("#8E3E7B"),
}
# ---------- Content: 20 Q&A pairs about the student's own trip ----------
DATA = [
("Travel & Journey / Путешествие и поездка", [
dict(
q_en="What is the name of the place you visit on your summer trip?",
q_ru="Как называется место, которое ты посещаешь во время летней поездки?",
a_en="The name of the place is Sochi.",
a_ru="Название этого места - Сочи.",
),
dict(
q_en="How do you and your family travel to the seaside?",
q_ru="Как вы с семьёй едете на море?",
a_en="We travel by car.",
a_ru="Мы едем на машине.",
),
dict(
q_en="Whose house do you stay at during your trip?",
q_ru="В чьём доме вы останавливаетесь во время поездки?",
a_en="We stay at my grandmother's house.",
a_ru="Мы останавливаемся в доме моей бабушки.",
),
dict(
q_en="How long is the journey from your home to the seaside?",
q_ru="Сколько длится поездка от дома до моря?",
a_en="The journey is about five hours.",
a_ru="Поездка длится около пяти часов.",
),
dict(
q_en="What is in your travel bag for the trip?",
q_ru="Что лежит в твоей дорожной сумке для поездки?",
a_en="My swimsuit and my sandals are in my travel bag.",
a_ru="Мои плавки и мои сандалии лежат в моей дорожной сумке.",
),
]),
("Food & Tastes / Еда и вкусы", [
dict(
q_en="What is your favorite food at your grandmother's house?",
q_ru="Какая твоя любимая еда в доме бабушки?",
a_en="My favorite food is her pancakes.",
a_ru="Моя любимая еда - это её блины.",
),
dict(
q_en="How does the sea water taste when you swim?",
q_ru="Какая на вкус морская вода, когда ты купаешься?",
a_en="The sea water tastes salty.",
a_ru="Морская вода солёная на вкус.",
),
dict(
q_en="What is your favorite fruit at the seaside market?",
q_ru="Какой твой любимый фрукт на рынке у моря?",
a_en="My favorite fruit is a peach.",
a_ru="Мой любимый фрукт - персик.",
),
dict(
q_en="Is the ice cream at the seaside sweet or sour?",
q_ru="Мороженое у моря сладкое или кислое?",
a_en="The ice cream is very sweet.",
a_ru="Мороженое очень сладкое.",
),
dict(
q_en="What juice do you usually drink for breakfast at the seaside?",
q_ru="Какой сок ты обычно пьёшь на завтрак у моря?",
a_en="I usually drink apple juice for breakfast.",
a_ru="Я обычно пью яблочный сок на завтрак.",
),
]),
("Sights & Places / Виды и места", [
dict(
q_en="What is the most beautiful place on your trip?",
q_ru="Какое самое красивое место в твоей поездке?",
a_en="The most beautiful place is the mountain near the sea.",
a_ru="Самое красивое место - это гора рядом с морем.",
),
dict(
q_en="Is the beach near your grandmother's house?",
q_ru="Пляж находится рядом с домом твоей бабушки?",
a_en="Yes, the beach is very near her house.",
a_ru="Да, пляж очень близко от её дома.",
),
dict(
q_en="What color is the sea at your holiday place?",
q_ru="Какого цвета море в месте, где ты отдыхаешь?",
a_en="The sea is blue and green.",
a_ru="Море синее и зелёное.",
),
dict(
q_en="Are there many boats at the harbor?",
q_ru="В порту много лодок?",
a_en="Yes, there are many boats at the harbor.",
a_ru="Да, в порту много лодок.",
),
dict(
q_en="What is on top of the hill near the village?",
q_ru="Что находится на вершине холма возле деревни?",
a_en="There is an old lighthouse on top of the hill.",
a_ru="На вершине холма есть старый маяк.",
),
]),
("Activities & People / Занятия и люди", [
dict(
q_en="What is your favorite activity on your trip?",
q_ru="Какое твоё любимое занятие в поездке?",
a_en="My favorite activity is swimming in the sea.",
a_ru="Моё любимое занятие - плавать в море.",
),
dict(
q_en="Who do you play with at the seaside?",
q_ru="С кем ты играешь у моря?",
a_en="I play with my cousin and her friends.",
a_ru="Я играю с моей двоюродной сестрой и её подругами.",
),
dict(
q_en="What are you doing in your favorite photo from the trip?",
q_ru="Что ты делаешь на своей любимой фотографии из поездки?",
a_en="I am building a sandcastle with my brother.",
a_ru="Я строю замок из песка с моим братом.",
),
dict(
q_en="Who is standing next to you in your favorite photo?",
q_ru="Кто стоит рядом с тобой на твоей любимой фотографии?",
a_en="My sister is standing next to me.",
a_ru="Моя сестра стоит рядом со мной.",
),
dict(
q_en="Whose sunglasses are you wearing in the photo?",
q_ru="Чьи солнечные очки ты носишь на фотографии?",
a_en="I am wearing my mother's sunglasses.",
a_ru="Я ношу солнечные очки моей мамы.",
),
]),
]
# ---------- Build story ----------
doc = SimpleDocTemplate(
"/tmp/workspace/esl-handbook/My_Summer_Trip_ESL_Handbook.pdf",
pagesize=A4,
topMargin=1.6 * cm, bottomMargin=1.6 * cm,
leftMargin=1.8 * cm, rightMargin=1.8 * cm,
title="My Summer Trip - ESL Conversation Handbook",
author="Orris",
)
story = []
# --- Cover ---
story.append(Spacer(1, 1.2 * cm))
story.append(Paragraph("My Summer Trip", title_style))
story.append(Paragraph("Моё летнее путешествие", subtitle_style))
story.append(Spacer(1, 0.3 * cm))
story.append(Paragraph(
"20 Conversation Questions & Answers for a 3rd/4th Grade ESL Student",
subtitle_style))
story.append(Paragraph(
"20 вопросов и ответов для практики разговорной речи (English / Russian)",
subtitle_style))
story.append(Spacer(1, 0.5 * cm))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.4 * cm))
story.append(Paragraph(
"<b>How to use this handbook / Как использовать этот материал:</b> "
"Talk with the student about their own trip - their photos, souvenirs and memories - "
"and ask each question out loud. The student answers in English first, then checks the "
"meaning with the Russian translation printed under every line.",
note_style))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Поговорите с учеником о его собственной поездке - фотографиях, сувенирах и "
"впечатлениях - и задавайте каждый вопрос вслух. Ученик сначала отвечает "
"по-английски, затем проверяет смысл по русскому переводу под каждой строкой.",
note_style))
story.append(Spacer(1, 0.6 * cm))
legend_data = [[
Paragraph("<b>Color guide / Цветовые обозначения</b>", ParagraphStyle(
"LegendHead", fontName="DejaVu-Bold", fontSize=10.5,
textColor=colors.HexColor("#14406B"))),
]]
story.append(Table(legend_data, colWidths=[16*cm]))
story.append(Spacer(1, 0.2*cm))
legend_rows = [
[Paragraph("Question (English)", ParagraphStyle("l1", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#1B1B1B"))),
Paragraph("Вопрос по-русски курсивом", ParagraphStyle("l2", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#7A4B00")))],
[Paragraph("Answer (English)", ParagraphStyle("l3", fontName="DejaVu", fontSize=9.5, textColor=colors.HexColor("#0B5D2E"))),
Paragraph("Ответ по-русски курсивом", ParagraphStyle("l4", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#5B6B5B")))],
]
legend_table = Table(legend_rows, colWidths=[8*cm, 8*cm])
legend_table.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#DDDDDD")),
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#EEEEEE")),
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#FBFBFB")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(legend_table)
story.append(PageBreak())
# --- Sections with questions ---
q_number = 1
for section_title, items in DATA:
color = SECTION_COLORS[section_title]
header_table = Table([[Paragraph(section_title, section_style)]], colWidths=[16.4*cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(header_table)
story.append(Spacer(1, 0.35 * cm))
for item in items:
cell_flow = [
Paragraph(item["q_en"], q_en_style),
Paragraph(item["q_ru"], q_ru_style),
Paragraph(item["a_en"], a_en_style),
Paragraph(item["a_ru"], a_ru_style),
]
t = Table(
[[Paragraph(f"{q_number}", ParagraphStyle(
"numcircle", fontName="DejaVu-Bold", fontSize=13,
textColor=colors.white, alignment=1)), cell_flow]],
colWidths=[0.9 * cm, 15.3 * cm],
)
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), color),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (0, 0), 6),
("TOPPADDING", (1, 0), (1, 0), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (1, 0), (1, 0), 10),
("BOX", (0, 0), (-1, -1), 0.5, colors.HexColor("#E3E3E3")),
("BACKGROUND", (1, 0), (1, 0), colors.HexColor("#FCFCFC")),
]))
story.append(t)
story.append(Spacer(1, 0.28 * cm))
q_number += 1
story.append(Spacer(1, 0.15 * cm))
story.append(Spacer(1, 0.4 * cm))
story.append(HRFlowable(width="100%", thickness=0.7, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.2 * cm))
story.append(Paragraph(
"Tip for the tutor / Совет для преподавателя: after the student answers, ask them to "
"repeat the answer once more from memory, without reading. This builds confidence in "
"talking about their own trip.",
footer_style))
story.append(Paragraph(
"После того как ученик ответит, попросите его повторить ответ ещё раз по памяти, "
"не читая. Это помогает увереннее рассказывать о своей поездке.",
footer_style))
doc.build(story)
print("PDF built successfully.")
rm -f /tmp/workspace/esl-handbook/build_pdf.py
# -*- coding: utf-8 -*-
"""
Build an ESL conversation-practice handbook PDF:
"My Summer Trip" - 20 English/Russian Q&A pairs for a 3rd/4th grade student,
based on the student's own trip experience.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ---------- Fonts (DejaVu supports Cyrillic) ----------
FONT_DIR = "/opt/amazon/genesis1p-tools/venv/lib/python3.12/site-packages/matplotlib/mpl-data/fonts/ttf"
pdfmetrics.registerFont(TTFont("DejaVu", f"{FONT_DIR}/DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", f"{FONT_DIR}/DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Oblique", f"{FONT_DIR}/DejaVuSans-Oblique.ttf"))
# ---------- Styles ----------
title_style = ParagraphStyle(
"TitleCustom", fontName="DejaVu-Bold", fontSize=22, leading=27,
textColor=colors.HexColor("#14406B"), alignment=1, spaceAfter=6,
)
subtitle_style = ParagraphStyle(
"SubtitleCustom", fontName="DejaVu", fontSize=12.5, leading=17,
textColor=colors.HexColor("#444444"), alignment=1, spaceAfter=4,
)
note_style = ParagraphStyle(
"NoteCustom", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#333333"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#F4F8FB"), borderPadding=8,
)
section_style = ParagraphStyle(
"SectionCustom", fontName="DejaVu-Bold", fontSize=15, leading=19,
textColor=colors.white, alignment=0, spaceBefore=0, spaceAfter=0,
)
q_en_style = ParagraphStyle(
"QEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#1B1B1B"), spaceAfter=1,
)
q_ru_style = ParagraphStyle(
"QRu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#7A4B00"), spaceAfter=6,
)
a_en_style = ParagraphStyle(
"AEn", fontName="DejaVu", fontSize=11.5, leading=15,
textColor=colors.HexColor("#0B5D2E"), spaceAfter=1,
)
a_ru_style = ParagraphStyle(
"ARu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#5B6B5B"), spaceAfter=2,
)
footer_style = ParagraphStyle(
"Footer", fontName="DejaVu", fontSize=8.5, leading=11,
textColor=colors.HexColor("#999999"), alignment=1,
)
SECTION_COLORS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#2E6BAD"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#C1622B"),
"Sights & Places / Виды и места": colors.HexColor("#3E8E5A"),
"Activities & People / Занятия и люди": colors.HexColor("#8E3E7B"),
}
# ---------- Content: 20 Q&A pairs about the student's own trip ----------
DATA = [
("Travel & Journey / Путешествие и поездка", [
dict(
q_en="What is the name of the place you visit on your summer trip?",
q_ru="Как называется место, которое ты посещаешь во время летней поездки?",
a_en="The name of the place is Sochi.",
a_ru="Название этого места - Сочи.",
),
dict(
q_en="How do you and your family travel to the seaside?",
q_ru="Как вы с семьёй едете на море?",
a_en="We travel by car.",
a_ru="Мы едем на машине.",
),
dict(
q_en="Whose house do you stay at during your trip?",
q_ru="В чьём доме вы останавливаетесь во время поездки?",
a_en="We stay at my grandmother's house.",
a_ru="Мы останавливаемся в доме моей бабушки.",
),
dict(
q_en="How long is the journey from your home to the seaside?",
q_ru="Сколько длится поездка от дома до моря?",
a_en="The journey is about five hours.",
a_ru="Поездка длится около пяти часов.",
),
dict(
q_en="What is in your travel bag for the trip?",
q_ru="Что лежит в твоей дорожной сумке для поездки?",
a_en="My swimsuit and my sandals are in my travel bag.",
a_ru="Мои плавки и мои сандалии лежат в моей дорожной сумке.",
),
]),
("Food & Tastes / Еда и вкусы", [
dict(
q_en="What is your favorite food at your grandmother's house?",
q_ru="Какая твоя любимая еда в доме бабушки?",
a_en="My favorite food is her pancakes.",
a_ru="Моя любимая еда - это её блины.",
),
dict(
q_en="How does the sea water taste when you swim?",
q_ru="Какая на вкус морская вода, когда ты купаешься?",
a_en="The sea water tastes salty.",
a_ru="Морская вода солёная на вкус.",
),
dict(
q_en="What is your favorite fruit at the seaside market?",
q_ru="Какой твой любимый фрукт на рынке у моря?",
a_en="My favorite fruit is a peach.",
a_ru="Мой любимый фрукт - персик.",
),
dict(
q_en="Is the ice cream at the seaside sweet or sour?",
q_ru="Мороженое у моря сладкое или кислое?",
a_en="The ice cream is very sweet.",
a_ru="Мороженое очень сладкое.",
),
dict(
q_en="What juice do you usually drink for breakfast at the seaside?",
q_ru="Какой сок ты обычно пьёшь на завтрак у моря?",
a_en="I usually drink apple juice for breakfast.",
a_ru="Я обычно пью яблочный сок на завтрак.",
),
]),
("Sights & Places / Виды и места", [
dict(
q_en="What is the most beautiful place on your trip?",
q_ru="Какое самое красивое место в твоей поездке?",
a_en="The most beautiful place is the mountain near the sea.",
a_ru="Самое красивое место - это гора рядом с морем.",
),
dict(
q_en="Is the beach near your grandmother's house?",
q_ru="Пляж находится рядом с домом твоей бабушки?",
a_en="Yes, the beach is very near her house.",
a_ru="Да, пляж очень близко от её дома.",
),
dict(
q_en="What color is the sea at your holiday place?",
q_ru="Какого цвета море в месте, где ты отдыхаешь?",
a_en="The sea is blue and green.",
a_ru="Море синее и зелёное.",
),
dict(
q_en="Are there many boats at the harbor?",
q_ru="В порту много лодок?",
a_en="Yes, there are many boats at the harbor.",
a_ru="Да, в порту много лодок.",
),
dict(
q_en="What is on top of the hill near the village?",
q_ru="Что находится на вершине холма возле деревни?",
a_en="There is an old lighthouse on top of the hill.",
a_ru="На вершине холма есть старый маяк.",
),
]),
("Activities & People / Занятия и люди", [
dict(
q_en="What is your favorite activity on your trip?",
q_ru="Какое твоё любимое занятие в поездке?",
a_en="My favorite activity is swimming in the sea.",
a_ru="Моё любимое занятие - плавать в море.",
),
dict(
q_en="Who do you play with at the seaside?",
q_ru="С кем ты играешь у моря?",
a_en="I play with my cousin and her friends.",
a_ru="Я играю с моей двоюродной сестрой и её подругами.",
),
dict(
q_en="What are you doing in your favorite photo from the trip?",
q_ru="Что ты делаешь на своей любимой фотографии из поездки?",
a_en="I am building a sandcastle with my brother.",
a_ru="Я строю замок из песка с моим братом.",
),
dict(
q_en="Who is standing next to you in your favorite photo?",
q_ru="Кто стоит рядом с тобой на твоей любимой фотографии?",
a_en="My sister is standing next to me.",
a_ru="Моя сестра стоит рядом со мной.",
),
dict(
q_en="Whose sunglasses are you wearing in the photo?",
q_ru="Чьи солнечные очки ты носишь на фотографии?",
a_en="I am wearing my mother's sunglasses.",
a_ru="Я ношу солнечные очки моей мамы.",
),
]),
]
# ---------- Build story ----------
doc = SimpleDocTemplate(
"/tmp/workspace/esl-handbook/My_Summer_Trip_ESL_Handbook.pdf",
pagesize=A4,
topMargin=1.6 * cm, bottomMargin=1.6 * cm,
leftMargin=1.8 * cm, rightMargin=1.8 * cm,
title="My Summer Trip - ESL Conversation Handbook",
author="Orris",
)
story = []
# --- Cover ---
story.append(Spacer(1, 1.2 * cm))
story.append(Paragraph("My Summer Trip", title_style))
story.append(Paragraph("Моё летнее путешествие", subtitle_style))
story.append(Spacer(1, 0.3 * cm))
story.append(Paragraph(
"20 Conversation Questions & Answers for a 3rd/4th Grade ESL Student",
subtitle_style))
story.append(Paragraph(
"20 вопросов и ответов для практики разговорной речи (English / Russian)",
subtitle_style))
story.append(Spacer(1, 0.5 * cm))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.4 * cm))
story.append(Paragraph(
"<b>How to use this handbook / Как использовать этот материал:</b> "
"Talk with the student about their own trip - their photos, souvenirs and memories - "
"and ask each question out loud. The student answers in English first, then checks the "
"meaning with the Russian translation printed under every line.",
note_style))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Поговорите с учеником о его собственной поездке - фотографиях, сувенирах и "
"впечатлениях - и задавайте каждый вопрос вслух. Ученик сначала отвечает "
"по-английски, затем проверяет смысл по русскому переводу под каждой строкой.",
note_style))
story.append(Spacer(1, 0.6 * cm))
legend_data = [[
Paragraph("<b>Color guide / Цветовые обозначения</b>", ParagraphStyle(
"LegendHead", fontName="DejaVu-Bold", fontSize=10.5,
textColor=colors.HexColor("#14406B"))),
]]
story.append(Table(legend_data, colWidths=[16*cm]))
story.append(Spacer(1, 0.2*cm))
legend_rows = [
[Paragraph("Question (English)", ParagraphStyle("l1", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#1B1B1B"))),
Paragraph("Вопрос по-русски курсивом", ParagraphStyle("l2", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#7A4B00")))],
[Paragraph("Answer (English)", ParagraphStyle("l3", fontName="DejaVu", fontSize=9.5, textColor=colors.HexColor("#0B5D2E"))),
Paragraph("Ответ по-русски курсивом", ParagraphStyle("l4", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#5B6B5B")))],
]
legend_table = Table(legend_rows, colWidths=[8*cm, 8*cm])
legend_table.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#DDDDDD")),
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#EEEEEE")),
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#FBFBFB")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(legend_table)
story.append(PageBreak())
# --- Sections with questions ---
q_number = 1
for section_title, items in DATA:
color = SECTION_COLORS[section_title]
header_table = Table([[Paragraph(section_title, section_style)]], colWidths=[16.4*cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(header_table)
story.append(Spacer(1, 0.35 * cm))
for item in items:
cell_flow = [
Paragraph(item["q_en"], q_en_style),
Paragraph(item["q_ru"], q_ru_style),
Paragraph(item["a_en"], a_en_style),
Paragraph(item["a_ru"], a_ru_style),
]
t = Table(
[[Paragraph(f"{q_number}", ParagraphStyle(
"numcircle", fontName="DejaVu-Bold", fontSize=13,
textColor=colors.white, alignment=1)), cell_flow]],
colWidths=[0.9 * cm, 15.3 * cm],
)
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), color),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (0, 0), 6),
("TOPPADDING", (1, 0), (1, 0), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (1, 0), (1, 0), 10),
("BOX", (0, 0), (-1, -1), 0.5, colors.HexColor("#E3E3E3")),
("BACKGROUND", (1, 0), (1, 0), colors.HexColor("#FCFCFC")),
]))
story.append(t)
story.append(Spacer(1, 0.28 * cm))
q_number += 1
story.append(Spacer(1, 0.15 * cm))
story.append(Spacer(1, 0.4 * cm))
story.append(HRFlowable(width="100%", thickness=0.7, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.2 * cm))
story.append(Paragraph(
"Tip for the tutor / Совет для преподавателя: after the student answers, ask them to "
"repeat the answer once more from memory, without reading. This builds confidence in "
"talking about their own trip.",
footer_style))
story.append(Paragraph(
"После того как ученик ответит, попросите его повторить ответ ещё раз по памяти, "
"не читая. Это помогает увереннее рассказывать о своей поездке.",
footer_style))
doc.build(story)
print("PDF built successfully.")
~/esl-handbook/build_pdf.py
# -*- coding: utf-8 -*-
"""
Build an ESL conversation-practice handbook PDF:
"My Summer Trip" - 20 English/Russian Q&A pairs for a 3rd/4th grade student,
based on the student's own trip experience.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ---------- Fonts (DejaVu supports Cyrillic) ----------
FONT_DIR = "/opt/amazon/genesis1p-tools/venv/lib/python3.12/site-packages/matplotlib/mpl-data/fonts/ttf"
pdfmetrics.registerFont(TTFont("DejaVu", f"{FONT_DIR}/DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", f"{FONT_DIR}/DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Oblique", f"{FONT_DIR}/DejaVuSans-Oblique.ttf"))
# ---------- Styles ----------
title_style = ParagraphStyle(
"TitleCustom", fontName="DejaVu-Bold", fontSize=22, leading=27,
textColor=colors.HexColor("#14406B"), alignment=1, spaceAfter=6,
)
subtitle_style = ParagraphStyle(
"SubtitleCustom", fontName="DejaVu", fontSize=12.5, leading=17,
textColor=colors.HexColor("#444444"), alignment=1, spaceAfter=4,
)
note_style = ParagraphStyle(
"NoteCustom", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#333333"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#F4F8FB"), borderPadding=8,
)
section_style = ParagraphStyle(
"SectionCustom", fontName="DejaVu-Bold", fontSize=15, leading=19,
textColor=colors.white, alignment=0, spaceBefore=0, spaceAfter=0,
)
q_en_style = ParagraphStyle(
"QEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#1B1B1B"), spaceAfter=1,
)
q_ru_style = ParagraphStyle(
"QRu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#7A4B00"), spaceAfter=6,
)
a_en_style = ParagraphStyle(
"AEn", fontName="DejaVu", fontSize=11.5, leading=15,
textColor=colors.HexColor("#0B5D2E"), spaceAfter=1,
)
a_ru_style = ParagraphStyle(
"ARu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#5B6B5B"), spaceAfter=2,
)
footer_style = ParagraphStyle(
"Footer", fontName="DejaVu", fontSize=8.5, leading=11,
textColor=colors.HexColor("#999999"), alignment=1,
)
SECTION_COLORS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#2E6BAD"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#C1622B"),
"Sights & Places / Виды и места": colors.HexColor("#3E8E5A"),
"Activities & People / Занятия и люди": colors.HexColor("#8E3E7B"),
}
# ---------- Content: 20 Q&A pairs about the student's own trip ----------
DATA = [
("Travel & Journey / Путешествие и поездка", [
dict(
q_en="What is the name of the place you visit on your summer trip?",
q_ru="Как называется место, которое ты посещаешь во время летней поездки?",
a_en="The name of the place is Sochi.",
a_ru="Название этого места - Сочи.",
),
dict(
q_en="How do you and your family travel to the seaside?",
q_ru="Как вы с семьёй едете на море?",
a_en="We travel by car.",
a_ru="Мы едем на машине.",
),
dict(
q_en="Whose house do you stay at during your trip?",
q_ru="В чьём доме вы останавливаетесь во время поездки?",
a_en="We stay at my grandmother's house.",
a_ru="Мы останавливаемся в доме моей бабушки.",
),
dict(
q_en="How long is the journey from your home to the seaside?",
q_ru="Сколько длится поездка от дома до моря?",
a_en="The journey is about five hours.",
a_ru="Поездка длится около пяти часов.",
),
dict(
q_en="What is in your travel bag for the trip?",
q_ru="Что лежит в твоей дорожной сумке для поездки?",
a_en="My swimsuit and my sandals are in my travel bag.",
a_ru="Мои плавки и мои сандалии лежат в моей дорожной сумке.",
),
]),
("Food & Tastes / Еда и вкусы", [
dict(
q_en="What is your favorite food at your grandmother's house?",
q_ru="Какая твоя любимая еда в доме бабушки?",
a_en="My favorite food is her pancakes.",
a_ru="Моя любимая еда - это её блины.",
),
dict(
q_en="How does the sea water taste when you swim?",
q_ru="Какая на вкус морская вода, когда ты купаешься?",
a_en="The sea water tastes salty.",
a_ru="Морская вода солёная на вкус.",
),
dict(
q_en="What is your favorite fruit at the seaside market?",
q_ru="Какой твой любимый фрукт на рынке у моря?",
a_en="My favorite fruit is a peach.",
a_ru="Мой любимый фрукт - персик.",
),
dict(
q_en="Is the ice cream at the seaside sweet or sour?",
q_ru="Мороженое у моря сладкое или кислое?",
a_en="The ice cream is very sweet.",
a_ru="Мороженое очень сладкое.",
),
dict(
q_en="What juice do you usually drink for breakfast at the seaside?",
q_ru="Какой сок ты обычно пьёшь на завтрак у моря?",
a_en="I usually drink apple juice for breakfast.",
a_ru="Я обычно пью яблочный сок на завтрак.",
),
]),
("Sights & Places / Виды и места", [
dict(
q_en="What is the most beautiful place on your trip?",
q_ru="Какое самое красивое место в твоей поездке?",
a_en="The most beautiful place is the mountain near the sea.",
a_ru="Самое красивое место - это гора рядом с морем.",
),
dict(
q_en="Is the beach near your grandmother's house?",
q_ru="Пляж находится рядом с домом твоей бабушки?",
a_en="Yes, the beach is very near her house.",
a_ru="Да, пляж очень близко от её дома.",
),
dict(
q_en="What color is the sea at your holiday place?",
q_ru="Какого цвета море в месте, где ты отдыхаешь?",
a_en="The sea is blue and green.",
a_ru="Море синее и зелёное.",
),
dict(
q_en="Are there many boats at the harbor?",
q_ru="В порту много лодок?",
a_en="Yes, there are many boats at the harbor.",
a_ru="Да, в порту много лодок.",
),
dict(
q_en="What is on top of the hill near the village?",
q_ru="Что находится на вершине холма возле деревни?",
a_en="There is an old lighthouse on top of the hill.",
a_ru="На вершине холма есть старый маяк.",
),
]),
("Activities & People / Занятия и люди", [
dict(
q_en="What is your favorite activity on your trip?",
q_ru="Какое твоё любимое занятие в поездке?",
a_en="My favorite activity is swimming in the sea.",
a_ru="Моё любимое занятие - плавать в море.",
),
dict(
q_en="Who do you play with at the seaside?",
q_ru="С кем ты играешь у моря?",
a_en="I play with my cousin and her friends.",
a_ru="Я играю с моей двоюродной сестрой и её подругами.",
),
dict(
q_en="What are you doing in your favorite photo from the trip?",
q_ru="Что ты делаешь на своей любимой фотографии из поездки?",
a_en="I am building a sandcastle with my brother.",
a_ru="Я строю замок из песка с моим братом.",
),
dict(
q_en="Who is standing next to you in your favorite photo?",
q_ru="Кто стоит рядом с тобой на твоей любимой фотографии?",
a_en="My sister is standing next to me.",
a_ru="Моя сестра стоит рядом со мной.",
),
dict(
q_en="Whose sunglasses are you wearing in the photo?",
q_ru="Чьи солнечные очки ты носишь на фотографии?",
a_en="I am wearing my mother's sunglasses.",
a_ru="Я ношу солнечные очки моей мамы.",
),
]),
]
# ---------- Build story ----------
doc = SimpleDocTemplate(
"/tmp/workspace/esl-handbook/My_Summer_Trip_ESL_Handbook.pdf",
pagesize=A4,
topMargin=1.6 * cm, bottomMargin=1.6 * cm,
leftMargin=1.8 * cm, rightMargin=1.8 * cm,
title="My Summer Trip - ESL Conversation Handbook",
author="Orris",
)
story = []
# --- Cover ---
story.append(Spacer(1, 1.2 * cm))
story.append(Paragraph("My Summer Trip", title_style))
story.append(Paragraph("Моё летнее путешествие", subtitle_style))
story.append(Spacer(1, 0.3 * cm))
story.append(Paragraph(
"20 Conversation Questions & Answers for a 3rd/4th Grade ESL Student",
subtitle_style))
story.append(Paragraph(
"20 вопросов и ответов для практики разговорной речи (English / Russian)",
subtitle_style))
story.append(Spacer(1, 0.5 * cm))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.4 * cm))
story.append(Paragraph(
"<b>How to use this handbook / Как использовать этот материал:</b> "
"Talk with the student about their own trip - their photos, souvenirs and memories - "
"and ask each question out loud. The student answers in English first, then checks the "
"meaning with the Russian translation printed under every line.",
note_style))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Поговорите с учеником о его собственной поездке - фотографиях, сувенирах и "
"впечатлениях - и задавайте каждый вопрос вслух. Ученик сначала отвечает "
"по-английски, затем проверяет смысл по русскому переводу под каждой строкой.",
note_style))
story.append(Spacer(1, 0.6 * cm))
legend_data = [[
Paragraph("<b>Color guide / Цветовые обозначения</b>", ParagraphStyle(
"LegendHead", fontName="DejaVu-Bold", fontSize=10.5,
textColor=colors.HexColor("#14406B"))),
]]
story.append(Table(legend_data, colWidths=[16*cm]))
story.append(Spacer(1, 0.2*cm))
legend_rows = [
[Paragraph("Question (English)", ParagraphStyle("l1", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#1B1B1B"))),
Paragraph("Вопрос по-русски курсивом", ParagraphStyle("l2", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#7A4B00")))],
[Paragraph("Answer (English)", ParagraphStyle("l3", fontName="DejaVu", fontSize=9.5, textColor=colors.HexColor("#0B5D2E"))),
Paragraph("Ответ по-русски курсивом", ParagraphStyle("l4", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#5B6B5B")))],
]
legend_table = Table(legend_rows, colWidths=[8*cm, 8*cm])
legend_table.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#DDDDDD")),
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#EEEEEE")),
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#FBFBFB")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(legend_table)
story.append(PageBreak())
# --- Sections with questions ---
q_number = 1
for section_title, items in DATA:
color = SECTION_COLORS[section_title]
header_table = Table([[Paragraph(section_title, section_style)]], colWidths=[16.4*cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(header_table)
story.append(Spacer(1, 0.35 * cm))
for item in items:
cell_flow = [
Paragraph(item["q_en"], q_en_style),
Paragraph(item["q_ru"], q_ru_style),
Paragraph(item["a_en"], a_en_style),
Paragraph(item["a_ru"], a_ru_style),
]
t = Table(
[[Paragraph(f"{q_number}", ParagraphStyle(
"numcircle", fontName="DejaVu-Bold", fontSize=13,
textColor=colors.white, alignment=1)), cell_flow]],
colWidths=[0.9 * cm, 15.3 * cm],
)
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), color),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (0, 0), 6),
("TOPPADDING", (1, 0), (1, 0), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (1, 0), (1, 0), 10),
("BOX", (0, 0), (-1, -1), 0.5, colors.HexColor("#E3E3E3")),
("BACKGROUND", (1, 0), (1, 0), colors.HexColor("#FCFCFC")),
]))
story.append(t)
story.append(Spacer(1, 0.28 * cm))
q_number += 1
story.append(Spacer(1, 0.15 * cm))
story.append(Spacer(1, 0.4 * cm))
story.append(HRFlowable(width="100%", thickness=0.7, color=colors.HexColor("#CCCCCC")))
story.append(Spacer(1, 0.2 * cm))
story.append(Paragraph(
"Tip for the tutor / Совет для преподавателя: after the student answers, ask them to "
"repeat the answer once more from memory, without reading. This builds confidence in "
"talking about their own trip.",
footer_style))
story.append(Paragraph(
"После того как ученик ответит, попросите его повторить ответ ещё раз по памяти, "
"не читая. Это помогает увереннее рассказывать о своей поездке.",
footer_style))
doc.build(story)
print("PDF built successfully.")
cd /tmp/workspace/esl-handbook && python3 build_pdf.py && python3 -c " import pdfplumber with pdfplumber.open('My_Summer_Trip_ESL_Handbook.pdf') as pdf: print('pages:', len(pdf.pages)) for i, p in enumerate(pdf.pages): t = p.extract_text() or '' print('--- page', i+1) print(t[:600]) "
My Summer Trip ESL Handbook
PDF Document · PDF
Some changes are required , please don't mention about grandmother in question number 6,12 Better mention a question about seaside , For 15 also mention about seaside only, for 19 it's sister sitting and not standing, don't mention any advice for teacher at the end of pdf handbook.Make handbook more colorful.
rm -f /tmp/workspace/esl-handbook/build_pdf.py
~/esl-handbook/build_pdf.py
# -*- coding: utf-8 -*-
"""
Build a colorful ESL conversation-practice handbook PDF:
"My Summer Trip" - 20 English/Russian Q&A pairs for a 3rd/4th grade student,
based on the student's own trip experience.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ---------- Fonts (DejaVu supports Cyrillic) ----------
FONT_DIR = "/opt/amazon/genesis1p-tools/venv/lib/python3.12/site-packages/matplotlib/mpl-data/fonts/ttf"
pdfmetrics.registerFont(TTFont("DejaVu", f"{FONT_DIR}/DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", f"{FONT_DIR}/DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DejaVu-Oblique", f"{FONT_DIR}/DejaVuSans-Oblique.ttf"))
PAGE_W, PAGE_H = A4
# ---------- Rainbow stripe palette (used for decorative bars) ----------
RAINBOW = [
colors.HexColor("#E4572E"), colors.HexColor("#F3A712"),
colors.HexColor("#3E8E5A"), colors.HexColor("#2E6BAD"),
colors.HexColor("#8E3E7B"), colors.HexColor("#17A398"),
]
# ---------- Styles ----------
title_style = ParagraphStyle(
"TitleCustom", fontName="DejaVu-Bold", fontSize=26, leading=31,
textColor=colors.HexColor("#1C4E9C"), alignment=1, spaceAfter=6,
)
subtitle_style = ParagraphStyle(
"SubtitleCustom", fontName="DejaVu", fontSize=12.5, leading=17,
textColor=colors.HexColor("#4B4B4B"), alignment=1, spaceAfter=4,
)
note_style = ParagraphStyle(
"NoteCustom", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#2C3E50"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#FFF6DE"), borderPadding=8,
)
note_style2 = ParagraphStyle(
"NoteCustom2", fontName="DejaVu", fontSize=10, leading=14,
textColor=colors.HexColor("#2C3E50"), alignment=0, spaceAfter=4,
backColor=colors.HexColor("#E4F7EF"), borderPadding=8,
)
section_style = ParagraphStyle(
"SectionCustom", fontName="DejaVu-Bold", fontSize=15, leading=19,
textColor=colors.white, alignment=0, spaceBefore=0, spaceAfter=0,
)
q_en_style = ParagraphStyle(
"QEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#12233D"), spaceAfter=1,
)
q_ru_style = ParagraphStyle(
"QRu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#9A5B00"), spaceAfter=6,
)
a_en_style = ParagraphStyle(
"AEn", fontName="DejaVu-Bold", fontSize=11.5, leading=15,
textColor=colors.HexColor("#0B6B33"), spaceAfter=1,
)
a_ru_style = ParagraphStyle(
"ARu", fontName="DejaVu-Oblique", fontSize=10.5, leading=13.5,
textColor=colors.HexColor("#3F6B52"), spaceAfter=2,
)
SECTION_COLORS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#2E6BAD"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#D9722E"),
"Sights & Places / Виды и места": colors.HexColor("#2E9E5B"),
"Activities & People / Занятия и люди": colors.HexColor("#9C3E8E"),
}
SECTION_TINTS = {
"Travel & Journey / Путешествие и поездка": colors.HexColor("#DDEAF8"),
"Food & Tastes / Еда и вкусы": colors.HexColor("#FBE7D6"),
"Sights & Places / Виды и места": colors.HexColor("#DFF5E6"),
"Activities & People / Занятия и люди": colors.HexColor("#F5E1F1"),
}
# ---------- Content: 20 Q&A pairs about the student's own trip ----------
DATA = [
("Travel & Journey / Путешествие и поездка", [
dict(
q_en="What is the name of the place you visit on your summer trip?",
q_ru="Как называется место, которое ты посещаешь во время летней поездки?",
a_en="The name of the place is Sochi.",
a_ru="Название этого места - Сочи.",
),
dict(
q_en="How do you and your family travel to the seaside?",
q_ru="Как вы с семьёй едете на море?",
a_en="We travel by car.",
a_ru="Мы едем на машине.",
),
dict(
q_en="Whose house do you stay at during your trip?",
q_ru="В чьём доме вы останавливаетесь во время поездки?",
a_en="We stay at my grandmother's house.",
a_ru="Мы останавливаемся в доме моей бабушки.",
),
dict(
q_en="How long is the journey from your home to the seaside?",
q_ru="Сколько длится поездка от дома до моря?",
a_en="The journey is about five hours.",
a_ru="Поездка длится около пяти часов.",
),
dict(
q_en="What is in your travel bag for the trip?",
q_ru="Что лежит в твоей дорожной сумке для поездки?",
a_en="My swimsuit and my sandals are in my travel bag.",
a_ru="Мои плавки и мои сандалии лежат в моей дорожной сумке.",
),
]),
("Food & Tastes / Еда и вкусы", [
dict(
q_en="What is your favorite food at the seaside?",
q_ru="Какая твоя любимая еда у моря?",
a_en="My favorite food is grilled fish.",
a_ru="Моя любимая еда - рыба на гриле.",
),
dict(
q_en="How does the sea water taste when you swim?",
q_ru="Какая на вкус морская вода, когда ты купаешься?",
a_en="The sea water tastes salty.",
a_ru="Морская вода солёная на вкус.",
),
dict(
q_en="What is your favorite fruit at the seaside market?",
q_ru="Какой твой любимый фрукт на рынке у моря?",
a_en="My favorite fruit is a peach.",
a_ru="Мой любимый фрукт - персик.",
),
dict(
q_en="Is the ice cream at the seaside sweet or sour?",
q_ru="Мороженое у моря сладкое или кислое?",
a_en="The ice cream is very sweet.",
a_ru="Мороженое очень сладкое.",
),
dict(
q_en="What juice do you usually drink for breakfast at the seaside?",
q_ru="Какой сок ты обычно пьёшь на завтрак у моря?",
a_en="I usually drink apple juice for breakfast.",
a_ru="Я обычно пью яблочный сок на завтрак.",
),
]),
("Sights & Places / Виды и места", [
dict(
q_en="What is the most beautiful place on your trip?",
q_ru="Какое самое красивое место в твоей поездке?",
a_en="The most beautiful place is the mountain near the sea.",
a_ru="Самое красивое место - это гора рядом с морем.",
),
dict(
q_en="Is the beach near your hotel at the seaside?",
q_ru="Пляж находится рядом с твоим отелем у моря?",
a_en="Yes, the beach is very near our hotel.",
a_ru="Да, пляж очень близко от нашего отеля.",
),
dict(
q_en="What color is the sea at your holiday place?",
q_ru="Какого цвета море в месте, где ты отдыхаешь?",
a_en="The sea is blue and green.",
a_ru="Море синее и зелёное.",
),
dict(
q_en="Are there many boats at the harbor?",
q_ru="В порту много лодок?",
a_en="Yes, there are many boats at the harbor.",
a_ru="Да, в порту много лодок.",
),
dict(
q_en="What is on top of the hill near the seaside?",
q_ru="Что находится на вершине холма возле моря?",
a_en="There is an old lighthouse on top of the hill.",
a_ru="На вершине холма есть старый маяк.",
),
]),
("Activities & People / Занятия и люди", [
dict(
q_en="What is your favorite activity on your trip?",
q_ru="Какое твоё любимое занятие в поездке?",
a_en="My favorite activity is swimming in the sea.",
a_ru="Моё любимое занятие - плавать в море.",
),
dict(
q_en="Who do you play with at the seaside?",
q_ru="С кем ты играешь у моря?",
a_en="I play with my cousin and her friends.",
a_ru="Я играю с моей двоюродной сестрой и её подругами.",
),
dict(
q_en="What are you doing in your favorite photo from the trip?",
q_ru="Что ты делаешь на своей любимой фотографии из поездки?",
a_en="I am building a sandcastle with my brother.",
a_ru="Я строю замок из песка с моим братом.",
),
dict(
q_en="Who is sitting next to you in your favorite photo?",
q_ru="Кто сидит рядом с тобой на твоей любимой фотографии?",
a_en="My sister is sitting next to me.",
a_ru="Моя сестра сидит рядом со мной.",
),
dict(
q_en="Whose sunglasses are you wearing in the photo?",
q_ru="Чьи солнечные очки ты носишь на фотографии?",
a_en="I am wearing my mother's sunglasses.",
a_ru="Я ношу солнечные очки моей мамы.",
),
]),
]
# ---------- Page decoration (rainbow stripes on every page) ----------
def draw_page_decoration(c, doc_):
c.saveState()
# top rainbow stripe
stripe_h = 0.3 * cm
seg_w = PAGE_W / len(RAINBOW)
for i, col in enumerate(RAINBOW):
c.setFillColor(col)
c.rect(i * seg_w, PAGE_H - stripe_h, seg_w, stripe_h, fill=1, stroke=0)
# bottom rainbow stripe
for i, col in enumerate(RAINBOW):
c.setFillColor(col)
c.rect(i * seg_w, 0, seg_w, stripe_h, fill=1, stroke=0)
# page number
c.setFont("DejaVu", 8.5)
c.setFillColor(colors.HexColor("#888888"))
c.drawCentredString(PAGE_W / 2, 0.55 * cm, f"{doc_.page}")
c.restoreState()
# ---------- Build story ----------
doc = SimpleDocTemplate(
"/tmp/workspace/esl-handbook/My_Summer_Trip_ESL_Handbook.pdf",
pagesize=A4,
topMargin=2.0 * cm, bottomMargin=1.6 * cm,
leftMargin=1.8 * cm, rightMargin=1.8 * cm,
title="My Summer Trip - ESL Conversation Handbook",
author="Orris",
)
story = []
# --- Cover ---
story.append(Spacer(1, 0.8 * cm))
story.append(Paragraph("My Summer Trip", title_style))
story.append(Paragraph("Моё летнее путешествие", subtitle_style))
story.append(Spacer(1, 0.25 * cm))
story.append(Paragraph(
"20 Conversation Questions & Answers for a 3rd/4th Grade ESL Student",
subtitle_style))
story.append(Paragraph(
"20 вопросов и ответов для практики разговорной речи (English / Russian)",
subtitle_style))
story.append(Spacer(1, 0.35 * cm))
# decorative rainbow divider
rainbow_row = [[""] for _ in RAINBOW]
rb_table = Table([[""] * len(RAINBOW)], colWidths=[16.4 * cm / len(RAINBOW)] * len(RAINBOW), rowHeights=[0.22 * cm])
rb_style = [("TOPPADDING", (0, 0), (-1, -1), 0), ("BOTTOMPADDING", (0, 0), (-1, -1), 0)]
for i, col in enumerate(RAINBOW):
rb_style.append(("BACKGROUND", (i, 0), (i, 0), col))
rb_table.setStyle(TableStyle(rb_style))
story.append(rb_table)
story.append(Spacer(1, 0.5 * cm))
story.append(Paragraph(
"<b>How to use this handbook / Как использовать этот материал:</b> "
"Talk with the student about their own trip - their photos, souvenirs and memories - "
"and ask each question out loud. The student answers in English first, then checks the "
"meaning with the Russian translation printed under every line.",
note_style))
story.append(Spacer(1, 0.15 * cm))
story.append(Paragraph(
"Поговорите с учеником о его собственной поездке - фотографиях, сувенирах и "
"впечатлениях - и задавайте каждый вопрос вслух. Ученик сначала отвечает "
"по-английски, затем проверяет смысл по русскому переводу под каждой строкой.",
note_style2))
story.append(Spacer(1, 0.6 * cm))
legend_data = [[
Paragraph("<b>Color guide / Цветовые обозначения</b>", ParagraphStyle(
"LegendHead", fontName="DejaVu-Bold", fontSize=10.5,
textColor=colors.HexColor("#1C4E9C"))),
]]
story.append(Table(legend_data, colWidths=[16 * cm]))
story.append(Spacer(1, 0.2 * cm))
legend_rows = [
[Paragraph("Question (English)", ParagraphStyle("l1", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#12233D"))),
Paragraph("Вопрос по-русски курсивом", ParagraphStyle("l2", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#9A5B00")))],
[Paragraph("Answer (English)", ParagraphStyle("l3", fontName="DejaVu-Bold", fontSize=9.5, textColor=colors.HexColor("#0B6B33"))),
Paragraph("Ответ по-русски курсивом", ParagraphStyle("l4", fontName="DejaVu-Oblique", fontSize=9.5, textColor=colors.HexColor("#3F6B52")))],
]
legend_table = Table(legend_rows, colWidths=[8 * cm, 8 * cm])
legend_table.setStyle(TableStyle([
("BOX", (0, 0), (-1, -1), 0.8, colors.HexColor("#2E6BAD")),
("INNERGRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#CFE0F2")),
("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#F4F9FF")),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(legend_table)
# section key with colors
story.append(Spacer(1, 0.4 * cm))
sec_key_rows = []
sec_key_style_cmds = [
("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#DDDDDD")),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
]
for idx, (sec_title, _) in enumerate(DATA):
col = SECTION_COLORS[sec_title]
tint = SECTION_TINTS[sec_title]
sec_key_rows.append([Paragraph(sec_title, ParagraphStyle(
f"seckey{idx}", fontName="DejaVu-Bold", fontSize=9.5, textColor=col))])
sec_key_style_cmds.append(("BACKGROUND", (0, idx), (0, idx), tint))
sec_key_table = Table(sec_key_rows, colWidths=[16 * cm])
sec_key_table.setStyle(TableStyle(sec_key_style_cmds))
story.append(sec_key_table)
story.append(PageBreak())
# --- Sections with questions ---
q_number = 1
for section_title, items in DATA:
color = SECTION_COLORS[section_title]
tint = SECTION_TINTS[section_title]
header_table = Table([[Paragraph(section_title, section_style)]], colWidths=[16.4 * cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(header_table)
story.append(Spacer(1, 0.35 * cm))
for item in items:
cell_flow = [
Paragraph(item["q_en"], q_en_style),
Paragraph(item["q_ru"], q_ru_style),
Paragraph(item["a_en"], a_en_style),
Paragraph(item["a_ru"], a_ru_style),
]
t = Table(
[[Paragraph(f"{q_number}", ParagraphStyle(
"numcircle", fontName="DejaVu-Bold", fontSize=13,
textColor=colors.white, alignment=1)), cell_flow]],
colWidths=[0.9 * cm, 15.3 * cm],
)
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), color),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (0, 0), 6),
("TOPPADDING", (1, 0), (1, 0), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (1, 0), (1, 0), 10),
("BOX", (0, 0), (-1, -1), 0.9, color),
("BACKGROUND", (1, 0), (1, 0), tint),
]))
story.append(t)
story.append(Spacer(1, 0.28 * cm))
q_number += 1
story.append(Spacer(1, 0.15 * cm))
doc.build(story, onFirstPage=draw_page_decoration, onLaterPages=draw_page_decoration)
print("PDF built successfully.")
cd /tmp/workspace/esl-handbook && python3 build_pdf.py && python3 -c " import pdfplumber with pdfplumber.open('My_Summer_Trip_ESL_Handbook.pdf') as pdf: print('pages:', len(pdf.pages)) for i, p in enumerate(pdf.pages): t = p.extract_text() or '' print('--- page', i+1) print(t[:700]) "
cd /tmp/workspace/esl-handbook && python3 -c " import pdfplumber with pdfplumber.open('My_Summer_Trip_ESL_Handbook.pdf') as pdf: t = pdf.pages[3].extract_text() print(t) "
My Summer Trip ESL Handbook
PDF Document · PDF