"""Output formatters for translations.""" from __future__ import annotations import json from pathlib import Path from typing import TYPE_CHECKING from src.utils.furigana import parse_furigana, format_furigana_html if TYPE_CHECKING: from src.data.storage import Storage from src.models.verse import BookMetadata class OutputFormatter: """Formats translations for various output formats.""" def __init__(self, storage: Storage) -> None: """Initialize the formatter. Args: storage: Storage instance for loading translations. """ self.storage = storage def export_chapter_json( self, book: str, chapter: int, output_path: Path ) -> Path: """Export a chapter as JSON. Args: book: Book name. chapter: Chapter number. output_path: Directory to write output. Returns: Path to the created file. """ translations = self.storage.load_chapter_translations(book, chapter) output_data = { "book": book, "chapter": chapter, "verses": {}, } for verse_num, translation in sorted(translations.items()): output_data["verses"][str(verse_num)] = { "text": translation.text, "model": translation.model, "timestamp": translation.timestamp.isoformat(), } output_path.mkdir(parents=True, exist_ok=True) file_path = output_path / f"{book}_chapter_{chapter:02d}.json" with file_path.open("w", encoding="utf-8") as f: json.dump(output_data, f, ensure_ascii=False, indent=2) return file_path def export_chapter_text( self, book: str, chapter: int, output_path: Path ) -> Path: """Export a chapter as plain text. Args: book: Book name. chapter: Chapter number. output_path: Directory to write output. Returns: Path to the created file. """ translations = self.storage.load_chapter_translations(book, chapter) lines = [f"{book.title()} Chapter {chapter}", "=" * 40, ""] for verse_num, translation in sorted(translations.items()): lines.append(f"{verse_num}. {translation.text}") lines.append("") output_path.mkdir(parents=True, exist_ok=True) file_path = output_path / f"{book}_chapter_{chapter:02d}.txt" with file_path.open("w", encoding="utf-8") as f: f.write("\n".join(lines)) return file_path def export_chapter_html( self, book: str, chapter: int, output_path: Path, metadata: BookMetadata | None = None, ) -> Path: """Export a chapter as HTML. Args: book: Book name. chapter: Chapter number. output_path: Directory to write output. metadata: Optional book metadata for title. Returns: Path to the created file. """ translations = self.storage.load_chapter_translations(book, chapter) book_name = metadata.name_japanese if metadata else book.title() title = f"{book_name} 第{chapter}章" html_parts = [ "", '', "
", '', '', f"{verse_num}' f"{verse_html}
" ) html_parts.extend(["", ""]) output_path.mkdir(parents=True, exist_ok=True) file_path = output_path / f"{book}_chapter_{chapter:02d}.html" with file_path.open("w", encoding="utf-8") as f: f.write("\n".join(html_parts)) return file_path def export_book_json(self, book: str, output_path: Path) -> Path: """Export an entire book as JSON. Args: book: Book name. output_path: Directory to write output. Returns: Path to the created file. """ all_chapters: dict = {} # Find all chapter files book_output_dir = self.storage.output_dir / book if book_output_dir.exists(): for chapter_file in sorted(book_output_dir.glob("chapter_*.json")): # Extract chapter number from filename chapter_num = int(chapter_file.stem.split("_")[1]) translations = self.storage.load_chapter_translations(book, chapter_num) all_chapters[str(chapter_num)] = { str(v): {"text": t.text, "model": t.model} for v, t in sorted(translations.items()) } output_data = {"book": book, "chapters": all_chapters} output_path.mkdir(parents=True, exist_ok=True) file_path = output_path / f"{book}_complete.json" with file_path.open("w", encoding="utf-8") as f: json.dump(output_data, f, ensure_ascii=False, indent=2) return file_path def export_book_text(self, book: str, output_path: Path) -> Path: """Export an entire book as plain text. Args: book: Book name. output_path: Directory to write output. Returns: Path to the created file. """ lines = [f"{book.title()}", "=" * 40, ""] book_output_dir = self.storage.output_dir / book if book_output_dir.exists(): for chapter_file in sorted(book_output_dir.glob("chapter_*.json")): chapter_num = int(chapter_file.stem.split("_")[1]) translations = self.storage.load_chapter_translations(book, chapter_num) lines.append(f"\nChapter {chapter_num}") lines.append("-" * 20) for verse_num, translation in sorted(translations.items()): lines.append(f"{verse_num}. {translation.text}") lines.append("") output_path.mkdir(parents=True, exist_ok=True) file_path = output_path / f"{book}_complete.txt" with file_path.open("w", encoding="utf-8") as f: f.write("\n".join(lines)) return file_path