OPEN SOURCE
software/src/output/formatters.py
Read on this site and download the files you need.
Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.
← Back to the open-source guide
1"""Output formatters for translations."""23from __future__ import annotations45import json6from pathlib import Path7from typing import TYPE_CHECKING89from src.utils.furigana import parse_furigana, format_furigana_html1011if TYPE_CHECKING:12from src.data.storage import Storage13from src.models.verse import BookMetadata141516class OutputFormatter:17"""Formats translations for various output formats."""1819def __init__(self, storage: Storage) -> None:20"""Initialize the formatter.2122Args:23storage: Storage instance for loading translations.24"""25self.storage = storage2627def export_chapter_json(28self, book: str, chapter: int, output_path: Path29) -> Path:30"""Export a chapter as JSON.3132Args:33book: Book name.34chapter: Chapter number.35output_path: Directory to write output.3637Returns:38Path to the created file.39"""40translations = self.storage.load_chapter_translations(book, chapter)4142output_data = {43"book": book,44"chapter": chapter,45"verses": {},46}4748for verse_num, translation in sorted(translations.items()):49output_data["verses"][str(verse_num)] = {50"text": translation.text,51"model": translation.model,52"timestamp": translation.timestamp.isoformat(),53}5455output_path.mkdir(parents=True, exist_ok=True)56file_path = output_path / f"{book}_chapter_{chapter:02d}.json"5758with file_path.open("w", encoding="utf-8") as f:59json.dump(output_data, f, ensure_ascii=False, indent=2)6061return file_path6263def export_chapter_text(64self, book: str, chapter: int, output_path: Path65) -> Path:66"""Export a chapter as plain text.6768Args:69book: Book name.70chapter: Chapter number.71output_path: Directory to write output.7273Returns:74Path to the created file.75"""76translations = self.storage.load_chapter_translations(book, chapter)7778lines = [f"{book.title()} Chapter {chapter}", "=" * 40, ""]7980for verse_num, translation in sorted(translations.items()):81lines.append(f"{verse_num}. {translation.text}")82lines.append("")8384output_path.mkdir(parents=True, exist_ok=True)85file_path = output_path / f"{book}_chapter_{chapter:02d}.txt"8687with file_path.open("w", encoding="utf-8") as f:88f.write("\n".join(lines))8990return file_path9192def export_chapter_html(93self,94book: str,95chapter: int,96output_path: Path,97metadata: BookMetadata | None = None,98) -> Path:99"""Export a chapter as HTML.100101Args:102book: Book name.103chapter: Chapter number.104output_path: Directory to write output.105metadata: Optional book metadata for title.106107Returns:108Path to the created file.109"""110translations = self.storage.load_chapter_translations(book, chapter)111112book_name = metadata.name_japanese if metadata else book.title()113title = f"{book_name} 第{chapter}章"114115html_parts = [116"<!DOCTYPE html>",117'<html lang="ja">',118"<head>",119'<meta charset="UTF-8">',120'<meta name="viewport" content="width=device-width, initial-scale=1.0">',121f"<title>{title}</title>",122"<style>",123"body { font-family: 'Noto Sans JP', sans-serif; max-width: 800px; "124"margin: 0 auto; padding: 20px; line-height: 1.8; }",125"h1 { border-bottom: 2px solid #333; padding-bottom: 10px; }",126".verse { margin: 1em 0; }",127".verse-num { color: #666; font-size: 0.8em; vertical-align: super; "128"margin-right: 0.3em; }",129"ruby { ruby-position: over; }",130"rt { font-size: 0.6em; color: #666; }",131"</style>",132"</head>",133"<body>",134f"<h1>{title}</h1>",135]136137for verse_num, translation in sorted(translations.items()):138# Use furigana HTML if available139if translation.text_with_furigana:140plain, annotations = parse_furigana(translation.text_with_furigana)141verse_html = format_furigana_html(plain, annotations)142else:143verse_html = translation.text144145html_parts.append(146f'<p class="verse"><span class="verse-num">{verse_num}</span>'147f"{verse_html}</p>"148)149150html_parts.extend(["</body>", "</html>"])151152output_path.mkdir(parents=True, exist_ok=True)153file_path = output_path / f"{book}_chapter_{chapter:02d}.html"154155with file_path.open("w", encoding="utf-8") as f:156f.write("\n".join(html_parts))157158return file_path159160def export_book_json(self, book: str, output_path: Path) -> Path:161"""Export an entire book as JSON.162163Args:164book: Book name.165output_path: Directory to write output.166167Returns:168Path to the created file.169"""170all_chapters: dict = {}171172# Find all chapter files173book_output_dir = self.storage.output_dir / book174if book_output_dir.exists():175for chapter_file in sorted(book_output_dir.glob("chapter_*.json")):176# Extract chapter number from filename177chapter_num = int(chapter_file.stem.split("_")[1])178translations = self.storage.load_chapter_translations(book, chapter_num)179180all_chapters[str(chapter_num)] = {181str(v): {"text": t.text, "model": t.model}182for v, t in sorted(translations.items())183}184185output_data = {"book": book, "chapters": all_chapters}186187output_path.mkdir(parents=True, exist_ok=True)188file_path = output_path / f"{book}_complete.json"189190with file_path.open("w", encoding="utf-8") as f:191json.dump(output_data, f, ensure_ascii=False, indent=2)192193return file_path194195def export_book_text(self, book: str, output_path: Path) -> Path:196"""Export an entire book as plain text.197198Args:199book: Book name.200output_path: Directory to write output.201202Returns:203Path to the created file.204"""205lines = [f"{book.title()}", "=" * 40, ""]206207book_output_dir = self.storage.output_dir / book208if book_output_dir.exists():209for chapter_file in sorted(book_output_dir.glob("chapter_*.json")):210chapter_num = int(chapter_file.stem.split("_")[1])211translations = self.storage.load_chapter_translations(book, chapter_num)212213lines.append(f"\nChapter {chapter_num}")214lines.append("-" * 20)215216for verse_num, translation in sorted(translations.items()):217lines.append(f"{verse_num}. {translation.text}")218219lines.append("")220221output_path.mkdir(parents=True, exist_ok=True)222file_path = output_path / f"{book}_complete.txt"223224with file_path.open("w", encoding="utf-8") as f:225f.write("\n".join(lines))226227return file_path228