69 lines
8.4 KiB
Python
69 lines
8.4 KiB
Python
"""Original miniature book used for Luna full-book forward testing. Pass an output directory."""
|
||
from ebooklib import epub
|
||
from pathlib import Path
|
||
|
||
import sys
|
||
OUT = Path(sys.argv[1]) if len(sys.argv) > 1 else Path('.work/luna-fixture')
|
||
OUT.mkdir(parents=True, exist_ok=True)
|
||
book = epub.EpubBook()
|
||
book.set_identifier('urn:uuid:6a7c4302-c2ab-4e0d-b385-luna-test-2026')
|
||
book.set_title('The Lantern Ledger: A Small Book About Big Decisions')
|
||
book.set_language('en')
|
||
book.add_author('Mira Vale')
|
||
book.add_metadata('DC', 'description', 'An original miniature nonfiction-style book created for a complete EPUB translation workflow test.')
|
||
book.add_metadata('DC', 'publisher', 'Fieldglass Press')
|
||
book.add_metadata('DC', 'date', '2026')
|
||
book.add_metadata('DC', 'rights', 'Copyright © 2026 Mira Vale. All rights reserved.')
|
||
|
||
style = '''body { font-family: serif; line-height: 1.45; } h1 { margin-top: 1.8em; } .opening { font-size: 1.08em; } .caption { font-size: .9em; font-style: italic; } .small { font-size: .85em; }'''
|
||
css = epub.EpubItem(uid='style', file_name='style/book.css', media_type='text/css', content=style)
|
||
book.add_item(css)
|
||
|
||
svg = '''<svg xmlns="http://www.w3.org/2000/svg" width="720" height="360" viewBox="0 0 720 360"><rect width="720" height="360" fill="#e8edf0"/><path d="M0 270 Q180 220 360 270 T720 250 V360 H0Z" fill="#778b84"/><path d="M95 255 L180 150 L265 255Z" fill="#34464b"/><rect x="168" y="205" width="25" height="50" fill="#f6c96a"/><circle cx="180" cy="176" r="23" fill="#f6c96a" opacity=".85"/><path d="M440 265 L525 120 L610 265Z" fill="#43565b"/><path d="M460 230 H590" stroke="#d9e0dc" stroke-width="8"/><text x="360" y="325" text-anchor="middle" font-family="serif" font-size="20" fill="#24363a">A light kept for the next decision</text></svg>'''
|
||
img = epub.EpubItem(uid='lantern-art', file_name='images/lantern.svg', media_type='image/svg+xml', content=svg)
|
||
book.add_item(img)
|
||
|
||
def page(uid, title, body, file_name=None):
|
||
item = epub.EpubHtml(title=title, file_name=file_name or f'{uid}.xhtml', lang='en', uid=uid)
|
||
item.content = f'''<html xmlns="http://www.w3.org/1999/xhtml"><head><title>{title}</title><link rel="stylesheet" type="text/css" href="style/book.css"/></head><body>{body}</body></html>'''
|
||
book.add_item(item)
|
||
return item
|
||
|
||
cover = page('cover', 'The Lantern Ledger', '''<h1>The Lantern Ledger</h1><p class="opening">A Small Book About Big Decisions</p><p>by Mira Vale</p><p class="small">An original translation-workflow test edition</p>''')
|
||
intro = page('opening-note', 'Opening Note', '''<h1>Opening Note</h1><p class="opening">At dusk, a room can make a plan look smaller than it is. The table holds one lamp, three cups, and a map whose edges curl upward. Outside, rain edits the street into reflections.</p><p>This little book follows the work of deciding: how people gather evidence, choose a direction, and explain what they have chosen. Its scenes are deliberately compact, but every section belongs to the complete book.</p><p>Names and examples appear here to exercise translation details. The imagined scenes are not reports of actual meetings.</p>''')
|
||
|
||
p1c1 = page('ch1', 'Part I · The Signal', '''<h1>Part I</h1><p>The Signal</p><h2>Chapter 1: A Question in the Margin</h2><p class="opening">The first clue was not a number. It was a question pencilled beside a number: “What would make this true?”</p><p>At the fictional company Northstar Works, analyst Lena Park kept a ledger of claims and their sources. She did not distrust confident people; she simply wanted confidence to leave a trail.</p><p>When the team discussed a distant market, one slide showed a steep line climbing into the future. Lena wrote down the assumptions beneath it: customers would arrive, costs would fall, and the calendar would behave.</p><p>That last assumption made everyone laugh. Then they checked it.</p><p>A useful forecast, she said, is not a promise. It is a map of what must happen for a promise to become plausible.</p><p>Her margin question traveled from the meeting room to the workshop wall, where it stayed long after the slide was replaced.</p>''')
|
||
|
||
p1c2 = page('ch2', 'Part I · The Signal', '''<h2>Chapter 2: The Name on the Door</h2><p>In a translation exercise, a short name can carry a long shadow. A profile may introduce Masayoshi Son and later call him Masa. Those references point to one person; the shorter form is a familiar name, not a second executive.</p><p>Our fictional narrator imagines a conference hallway where an investor pauses at a hand-drawn chart. The point of the scene is not to claim that the encounter happened. It is to test whether a translator can preserve the distinction between a real public name and an invented setting.</p><p>“Keep the subject clear,” Lena tells a junior editor. “A pronoun should not make the reader guess which person is speaking.”</p><p>The editor adds a note to the style sheet: introduce the full name first, then use the established short form consistently.</p>''')
|
||
|
||
p2c1 = page('ch3', 'Part II · The Choice', '''<h1>Part II</h1><p>The Choice</p><h2>Chapter 3: What the Photograph Leaves Out</h2><p class="opening">A photograph can show a lamp, but it cannot show who paid the electricity bill.</p><figure><img src="images/lantern.svg" alt="A small glowing lantern stands between two dark hills."/><figcaption class="caption">Figure 1. The lantern marks a pause between what is known and what remains to be checked.</figcaption></figure><p>When a picture enters a book, its caption becomes part of the argument. It identifies what the reader sees and, just as carefully, avoids claiming what the image cannot prove.</p><p>The team labels the illustration as a conceptual drawing. No real person or office is pictured. That short sentence protects the reader from mistaking atmosphere for evidence.</p><p>Lena places the image beside a paragraph about uncertainty. The lamp does not answer the question; it makes the question easier to see.</p>''')
|
||
|
||
p2c2 = page('ch4', 'Part II · The Choice', '''<h2>Chapter 4: The Small Print</h2><p>A decision memo had one footnote: “The sample covers three districts, not the whole country.”<a id="callout-1" href="notes.xhtml#note-1" epub:type="noteref">1</a> Without that sentence, the chart looked broader than its evidence.</p><p>In review, Lena asked the writer to keep the note close to the claim. Readers should not have to search several pages to learn the boundary of a number.</p><p>The note did not weaken the recommendation. It made the recommendation precise enough to use.</p><p>At the bottom of the page, the editor added a return link so a reader could move from note to sentence and back again.</p>''')
|
||
|
||
notes = page('notes', 'Notes', '''<h1>Notes</h1><ol><li id="note-1" epub:type="footnote">The district count is invented for this original test book. <a href="ch4.xhtml#callout-1" epub:type="backlink">Return to the text.</a></li></ol>''')
|
||
index = page('index', 'Index', '''<h1>Index</h1><p><a href="ch2.xhtml">Masayoshi Son, 8</a></p><p><a href="ch2.xhtml">Masa, 8</a></p><p><a href="ch1.xhtml">Northstar Works, 6</a></p><p><a href="ch3.xhtml">Photographs and captions, 10–11</a></p><p><a href="ch4.xhtml">Uncertainty, 12–13</a></p>''')
|
||
rights = page('rights', 'Copyright', '''<h1>Copyright</h1><p>Copyright © 2026 Mira Vale.</p><p>All rights reserved. This original miniature book was written for software workflow evaluation. No portion is derived from an existing published book.</p><p>Illustration: “A light kept for the next decision,” created for this edition.</p><p>Published by Fieldglass Press, 2026.</p>''')
|
||
|
||
book.toc = [
|
||
epub.Link('opening-note.xhtml', 'Opening Note', 'opening-note'),
|
||
(epub.Section('Part I · The Signal'), [
|
||
epub.Link('ch1.xhtml', 'Chapter 1: A Question in the Margin', 'ch1'),
|
||
epub.Link('ch2.xhtml', 'Chapter 2: The Name on the Door', 'ch2'),
|
||
]),
|
||
(epub.Section('Part II · The Choice'), [
|
||
epub.Link('ch3.xhtml', 'Chapter 3: What the Photograph Leaves Out', 'ch3'),
|
||
epub.Link('ch4.xhtml', 'Chapter 4: The Small Print', 'ch4'),
|
||
]),
|
||
epub.Link('notes.xhtml', 'Notes', 'notes'),
|
||
epub.Link('index.xhtml', 'Index', 'index'),
|
||
epub.Link('rights.xhtml', 'Copyright', 'rights'),
|
||
]
|
||
book.spine = [cover, intro, p1c1, p1c2, p2c1, p2c2, notes, index, rights]
|
||
book.add_item(epub.EpubNcx())
|
||
|
||
# The title page is the opening spine item; the illustration appears in Chapter 3.
|
||
|
||
outfile = OUT / 'source.epub'
|
||
epub.write_epub(str(outfile), book)
|
||
print(outfile)
|