Source code for dsw_document_template_tool._translation_tree.outline

"""Outline rendering for translator-facing translation trees."""

from __future__ import annotations

import os
from pathlib import Path

from .document import parse_sentence_text, parse_translation_document
from .manifest import TREE_MANIFEST_PATH, load_tree_manifest
from .models import OutlineUnit, TranslationTreeError


[docs] def refresh_outline_markdown( *, tree_dir: Path, source_lang: str, target_lang: str, ) -> Path: """Rewrite the tree outline from the current translation documents.""" tree_dir = Path(tree_dir).resolve() output_outline = tree_dir / "outline.md" output_outline.write_text( render_outline_markdown( outline_units=load_outline_units( tree_dir=tree_dir, source_lang=source_lang, target_lang=target_lang, ), output_outline=output_outline, ), encoding="utf-8", ) return output_outline
[docs] def load_outline_units( *, tree_dir: Path, source_lang: str, target_lang: str, ) -> list[OutlineUnit]: """Load outline rows from the tree manifest and current translation blocks.""" tree_dir = Path(tree_dir).resolve() manifest = load_tree_manifest(tree_dir) units = manifest.get("units") if not isinstance(units, list): raise TranslationTreeError( f"Invalid translation-tree manifest at {tree_dir / TREE_MANIFEST_PATH}" ) outline_units: list[OutlineUnit] = [] for unit in units: outline_units.append( _outline_unit_from_manifest_entry( tree_dir=tree_dir, unit=unit, source_lang=source_lang, target_lang=target_lang, ) ) return outline_units
[docs] def render_outline_markdown( *, outline_units: list[OutlineUnit], output_outline: Path, ) -> str: """Render a clickable progress outline for translation units.""" lines = ["### DSW Document Template Translation", ""] for source_file in sorted({unit.source_file for unit in outline_units}): file_units = [unit for unit in outline_units if unit.source_file == source_file] lines.append( _render_outline_checkbox_line( depth=0, is_complete=_all_translated(file_units), layer_label="[file]", label=f"{source_file} ({_progress_label(file_units)})", ) ) lines.append("") lines.append(f" [J2] `{source_file}`") lines.append("") wrapper_orders = sorted({unit.wrapper_order for unit in file_units}) for wrapper_order in wrapper_orders: wrapper_units = [unit for unit in file_units if unit.wrapper_order == wrapper_order] wrapper = wrapper_units[0] lines.append( _render_outline_checkbox_line( depth=1, is_complete=_all_translated(wrapper_units), layer_label="[wrapper]", label=f"{wrapper.wrapper_folder_name} ({_progress_label(wrapper_units)})", ) ) lines.append("") lines.append(f" [W] `{wrapper.wrapper_folder_name}`") lines.append("") for unit in wrapper_units: relative_link = os.path.relpath(unit.document_path, output_outline.parent) formatted_link = _format_link_destination(relative_link) lines.append( _render_outline_checkbox_line( depth=2, is_complete=unit.is_translated, layer_label="[unit]", label=f"{unit.unit_folder_name}: {unit.sentence_text}", ) ) lines.append("") lines.append(f" [T] [translation]({formatted_link})") lines.append("") return "\n".join(lines).rstrip() + "\n"
def _render_outline_checkbox_line( *, depth: int, is_complete: bool, layer_label: str, label: str, ) -> str: indent = " " * depth checkbox = "x" if is_complete else " " return f"{indent}- [{checkbox}] {layer_label} {label}" def _all_translated(units: list[OutlineUnit]) -> bool: return bool(units) and all(unit.is_translated for unit in units) def _progress_label(units: list[OutlineUnit]) -> str: translated = sum(1 for unit in units if unit.is_translated) return f"{translated}/{len(units)}" def _format_link_destination(destination: str) -> str: escaped = destination.replace(">", "\\>") return f"<{escaped}>" def _outline_unit_from_manifest_entry( *, tree_dir: Path, unit: object, source_lang: str, target_lang: str, ) -> OutlineUnit: if not isinstance(unit, dict): raise TranslationTreeError( f"Invalid translation-tree manifest entry at {tree_dir / TREE_MANIFEST_PATH}" ) source_file = unit.get("source_file") wrapper_order = unit.get("wrapper_order") wrapper_folder_name = unit.get("wrapper_folder_name") unit_folder_name = unit.get("unit_folder_name") document_path_raw = unit.get("document_path") if ( not isinstance(source_file, str) or not isinstance(wrapper_order, int) or not isinstance(wrapper_folder_name, str) or not isinstance(unit_folder_name, str) or not isinstance(document_path_raw, str) ): raise TranslationTreeError( f"Invalid translation-tree manifest entry at {tree_dir / TREE_MANIFEST_PATH}" ) document_path = tree_dir / document_path_raw if not document_path.is_file(): raise TranslationTreeError(f"Missing translation document at {document_path}") return OutlineUnit( source_file=source_file, wrapper_order=wrapper_order, wrapper_folder_name=wrapper_folder_name, unit_folder_name=unit_folder_name, document_path=document_path, sentence_text=parse_sentence_text( document_path=document_path, source_lang=source_lang, ), is_translated=bool( parse_translation_document( document_path=document_path, source_lang=source_lang, target_lang=target_lang, ).strip() ), )