mcpField
R
rtl-document-translation

rtl-document-translation

github.com/belumumeドキュメント4675 回インストール6 週間前に更新
リポジトリ

rtl-document-translation について

rtl-document-translationは、構造化された業務用DOCXをアラビア語やヘブライ語などのRTL言語に変換するスキルです。分析、翻訳、生成、検証の段階を踏み、ネストした表を含む構造や見た目を保ちます。

主な機能

  1. 01段階的な文書変換フロー
  2. 02表と段落の構造を維持
  3. 03RTLの文字方向と配置を適用
  4. 04色やスタイルを検出・維持
  5. 05ネストした表の内容に対応
  6. 06出力と見た目を検証

活用シーン

  1. 01アラビア語の財務DOCX作成
  2. 02複雑な表を含むフォームの翻訳
  3. 03英語版と配置をそろえたRTL文書の作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/belumume/claude-skills --skill rtl-document-translation

インストール後、Claude Code で/rtl-document-translationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
REFERENCE.md
examples/
translation_dictionary_template.json
utils/
create_translation.py
verify_document.py

詳細

RTL ドキュメント翻訳スキル

ピクセル単位で正確な書式、色、表の構造、プロフェッショナルな外観を維持しながら、構造化されたビジネス文書を右から左(RTL)に記述する言語に翻訳します。

このスキルを使用するタイミング

次の依頼があった場合にこのスキルを使用します。

  • DOCX ファイルをアラビア語、ヘブライ語、ウルドゥー語などの RTL 言語に翻訳する
  • 文書の正確な構造(表、セクション、書式)を維持する
  • 色、背景、視覚的なスタイルを維持する
  • ビジネス文書や財務文書を RTL 形式に変換する
  • 英語の原文に正確に一致する RTL 版を作成する

次の用途には使用しないでください:

  • 単純なテキスト翻訳(翻訳 API を直接使用してください)
  • 新しい文書を一から作成する
  • PDF のみのワークフロー(このスキルは DOCX に対応しています)

基本的な手法

1. 段階的なアプローチ(重要)

フェーズ 1:分析 → フェーズ 2:翻訳辞書 → フェーズ 3:文書生成 → フェーズ 4:検証

生成に直接進むことは避けてください。構造分析を行わないと、次のような重大なエラーが発生するおそれがあります。

  • 複数行のセルが複数の行に分割される
  • 表の寸法が見落とされる
  • セクションの向きが誤る
2. RTL 書式(3 つのレベル)

RTL 文書では、異なる 3 つの書式レベルが必要です。

レベル 1 — テキストの方向:

paragraph.paragraph_format.bidi = True
run.font.rtl = True
run.font.complex_script = True

レベル 2 — テキストの配置:

paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT

レベル 3 — レイアウトの方向: データ表や財務表では、列を左から右の順序に保ちます

  • 時系列の並び(月 1、2、3 など)は左から右に進みます
  • 行ラベルは英語版と同じ位置に保ちます
  • RTL にするのはセル内のテキストのみです

例:月の見出しは次のようにします。

[الشهر] [1] [2] [3] [4]  ← Correct (columns L→R, text RTL)
[4] [3] [2] [1] [الشهر]  ← Wrong (mirrored columns)

実装パターン

パターン 1:背景色の検出

問題: 属性への単純なアクセスでは失敗します
解決策: XML を走査します

from docx.oxml.ns import qn

def get_cell_background(cell):
    """Reliably extract cell background color"""
    tc = cell._element
    tcPr = tc.tcPr if hasattr(tc, 'tcPr') and tc.tcPr is not None else None

    if tcPr is None:
        return None

    # CRITICAL: Use findall(), not direct attribute access
    shd_list = tcPr.findall(qn('w:shd'))
    for shd in shd_list:
        fill = shd.get(qn('w:fill'))
        if fill and fill != 'auto':
            return fill.upper()

    return None

理由: tcPr.shading は一貫して動作しません。XML の走査なら確実です。

パターン 2:セルの背景色を設定する
from docx.oxml import OxmlElement

def set_cell_background(cell, rgb_hex):
    """Set cell background color (e.g., 'CC0029' for red)"""
    tc = cell._element
    tcPr = tc.get_or_add_tcPr()

    # Remove existing shading
    for shd in tcPr.findall(qn('w:shd')):
        tcPr.remove(shd)

    # Add new shading
    shd = OxmlElement('w:shd')
    shd.set(qn('w:fill'), rgb_hex)
    tcPr.append(shd)
パターン 3:引用符の正規化

問題: DOCX ファイルには、辞書の検索を妨げる曲線形の引用符(U+201C、U+201D)が含まれています

解決策: 複数回に分けて正規化します

def normalize_text(text):
    """Normalize quotes and unicode spaces for reliable matching"""
    # Convert curly quotes → straight quotes
    text = text.replace('\u201c', '"').replace('\u201d', '"')
    text = text.replace('\u2018', "'").replace('\u2019', "'")

    # Normalize unicode spaces → regular spaces
    text = re.sub(r'[\u2002\u2003\u2009\u200A\u00A0]+', ' ', text)

    return text.strip()
パターン 4:複数段階の翻訳マッチング

問題: 空白、引用符、書式の違いにより、文字列の完全一致に失敗します

解決策: 段階的なフォールバック戦略を使用します

def translate_text(text, translation_dict):
    """Multi-pass translation with normalization fallbacks"""
    if not text or not text.strip():
        return text

    # Pass 1: Exact match
    if text in translation_dict:
        return translation_dict[text]

    # Pass 2: Stripped
    if text.strip() in translation_dict:
        return translation_dict[text.strip()]

    # Pass 3: Normalized quotes
    normalized_quotes = text.replace('\u201c', '"').replace('\u201d', '"')
    normalized_quotes = normalized_quotes.replace('\u2018', "'").replace('\u2019', "'")
    if normalized_quotes in translation_dict:
        return translation_dict[normalized_quotes]

    # Pass 4: Stripped + normalized
    if normalized_quotes.strip() in translation_dict:
        return translation_dict[normalized_quotes.strip()]

    # Pass 5: Unicode spaces
    cleaned = re.sub(r'[\u2002\u2003\u2009\u200A\u00A0]+', ' ', text).strip()
    if cleaned in translation_dict:
        return translation_dict[cleaned]

    # Pass 6: Combined (quotes + spaces)
    cleaned_quotes = re.sub(r'[\u2002\u2003\u2009\u200A\u00A0]+', ' ', normalized_quotes).strip()
    if cleaned_quotes in translation_dict:
        return translation_dict[cleaned_quotes]

    # Pass 7: Normalized whitespace (collapse multiple spaces)
    normalized_ws = ' '.join(text.split())
    if normalized_ws in translation_dict:
        return translation_dict[normalized_ws]

    # No match found - return as-is
    return text

成功率: 完全一致のみの場合の 60% に対して 95% 以上

パターン 5:RTL セルの書式設定
def apply_rtl_to_cell(cell, arabic_text, font_size=10, bold=False, text_color=None):
    """Apply complete RTL formatting to table cell"""
    # Clear cell
    cell.text = ''

    # Add paragraph with Arabic text
    paragraph = cell.paragraphs[0]
    run = paragraph.add_run(arabic_text)

    # RTL text direction (Level 1)
    paragraph.paragraph_format.bidi = True
    run.font.rtl = True
    run.font.complex_script = True

    # Right alignment (Level 2)
    paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT

    # Font settings
    run.font.name = 'Simplified Arabic'  # or 'Times New Roman' for formal docs
    run._element.rPr.rFonts.set(qn('w:ascii'), 'Simplified Arabic')
    run._element.rPr.rFonts.set(qn('w:hAnsi'), 'Simplified Arabic')
    run._element.rPr.rFonts.set(qn('w:cs'), 'Simplified Arabic')
    run.font.size = Pt(font_size)

    if bold:
        run.font.bold = True

    if text_color:
        run.font.color.rgb = RGBColor(*text_color)

    return cell
パターン 6:暗い背景上の白いテキストを自動修正する

問題: 暗い背景上でテキストが見えなくなります

解決策: 自動検出して修正します

def apply_colors_to_cell(cell, eng_cell, ar_text, font_size=10, bold=False):
    """Apply colors with auto-correction for visibility"""
    # Get background color
    bg_color = get_cell_background(eng_cell)

    # Get text color from English
    text_color = None
    if eng_cell.paragraphs and eng_cell.paragraphs[0].runs:
        for run in eng_cell.paragraphs[0].runs:
            if run.font.color and run.font.color.rgb:
                rgb = run.font.color.rgb
                text_color = (rgb[0], rgb[1], rgb[2])
                break

    # AUTO-CORRECTION: Set white text for dark backgrounds
    if bg_color and bg_color in ['CC0029', 'C00000', '000000']:  # Red/black
        text_color = (255, 255, 255)  # White

    # Apply formatting
    apply_rtl_to_cell(cell, ar_text, font_size, bold, text_color)

    # Set background
    if bg_color:
        set_cell_background(cell, bg_color)
パターン 7:入れ子の表からコンテンツを抽出する ⭐

問題: cell.text プロパティには、セル内の入れ子の表に含まれるテキストが含まれません。そのため、フォーム、チェックリスト、複雑なレイアウトを含むセルが空に見えることがあります。

検出:

if cell.tables:
    print(f"Cell contains {len(cell.tables)} nested table(s)")

解決策: cell.tables プロパティを使用して、入れ子の表からコンテンツを抽出します

def extract_cell_content_with_nested_tables(cell):
    """
    Extract all text from a cell, including text from nested tables.

    Handles Word documents that use nested tables for:
    - Checklists with options
    - Forms with checkboxes
    - Complex multi-row cell layouts
    """
    text_parts = []

    # Get direct paragraph text (not inside nested tables)
    for para in cell.paragraphs:
        para_text = para.text.strip()
        if para_text:
            text_parts.append(para_text)

    # Get content from nested tables
    if cell.tables:
        for nested_table in cell.tables:
            for nested_row in nested_table.rows:
                # Extract text from first column only (skip checkbox/form columns)
                if nested_row.cells:
                    first_col_text = nested_row.cells[0].text.strip()
                    # Filter out checkbox characters
                    if first_col_text and first_col_text not in ['', '☐', '☑', '☒']:
                        text_parts.append(first_col_text)

    return '\n'.join(text_parts) if text_parts else ''

翻訳ワークフローでの使用方法:

# Instead of:
eng_text = eng_cell.text  # ❌ Misses nested table content

# Use:
eng_text = extract_cell_content_with_nested_tables(eng_cell)  # ✓ Gets all content
ar_text = translate_text(eng_text)

重要な理由:

  • 政府のフォームでは、チェックボックスのグリッドに入れ子の表がよく使用されます
  • 評価フォームでは、評価尺度に入れ子の表が使用されます
  • ビジネス用チェックリストでは、選択肢が入れ子の表に埋め込まれています
  • これを行わないと、翻訳後の文書でセルが空になります

文書の種類別フォントの推奨

文書の種類推奨フォント理由
財務/ビジネスSimplified Arabic数字や表をより適切に表示できます
学術/フォーマルTimes New Roman伝統的で、段落に適しています
技術Arial Unicode MS幅広い文字に対応しています
避けるArialアラビア語の表示品質が低い

完全なワークフロー

ステップ 1:構造分析
def analyze_document(docx_path):
    doc = Document(docx_path)

    structure = {
        'sections': [],
        'tables': [],
        'paragraphs': len(doc.paragraphs),
        'colors': {'text': {}, 'backgrounds': {}},
        'fonts': {}
    }

    # Analyze sections
    for idx, section in enumerate(doc.sections):
        structure['sections'].append({
            'index': idx,
            'orientation': 'portrait' if section.page_width < section.page_height else 'landscape',
            'width': section.page_width.inches,
            'height': section.page_height.inches
        })

    # Analyze tables
    for idx, table in enumerate(doc.tables):
        table_info = {
            'index': idx,
            'rows': len(table.rows),
            'cols': len(table.columns),
            'multiline_cells': []
        }

        # Detect multi-line cells
        for r_idx, row in enumerate(table.rows):
            for c_idx, cell in enumerate(row.cells):
                if '\n' in cell.text:
                    table_info['multiline_cells'].append({
                        'row': r_idx,
                        'col': c_idx,
                        'content': cell.text
                    })

        structure['tables'].append(table_info)

    return structure
ステップ 2:翻訳辞書の作成
def create_translation_dictionary(docx_files, target_language='arabic'):
    """Extract unique texts and create translation map"""
    unique_texts = set()

    for docx_path in docx_files:
        doc = Document(docx_path)

        # Extract from paragraphs
        for para in doc.paragraphs:
            if para.text.strip():
                unique_texts.add(para.text.strip())

        # Extract from tables
        for table in doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    if cell.text.strip():
                        unique_texts.add(cell.text.strip())

    # Create translation map
    translations = {}
    for text in unique_texts:
        # Call translation API or load from file
        arabic_text = translate_via_api(text, target_language)
        translations[text] = arabic_text

        # Also add normalized versions
        normalized = normalize_text(text)
        if normalized != text:
            translations[normalized] = arabic_text

    return translations
ステップ 3:文書の生成

実装例の全文については、REFERENCE.md を参照してください。

ステップ 4:検証
def verify_arabic_document(ar_docx_path, eng_docx_path, translation_dict):
    """Comprehensive verification checks"""
    ar_doc = Document(ar_docx_path)
    eng_doc = Document(eng_docx_path)

    results = {
        'structure': 'PASS',
        'alignment': 'PASS',
        'english_scan': 'PASS',
        'colors': 'PASS',
        'issues': []
    }

    # 1. Structure match
    if len(ar_doc.sections) != len(eng_doc.sections):
        results['structure'] = 'FAIL'
        results['issues'].append(f"Section count mismatch")

    if len(ar_doc.tables) != len(eng_doc.tables):
        results['structure'] = 'FAIL'
        results['issues'].append(f"Table count mismatch")

    # 2. Alignment check
    total_cells = 0
    right_aligned = 0
    for table in ar_doc.tables:
        for row in table.rows:
            for cell in row.cells:
                total_cells += 1
                if cell.paragraphs[0].alignment == WD_ALIGN_PARAGRAPH.RIGHT:
                    right_aligned += 1

    if right_aligned != total_cells:
        results['alignment'] = 'FAIL'
        results['issues'].append(f"Only {right_aligned}/{total_cells} cells right-aligned")

    # 3. English word scan
    allowed_english = get_allowed_english(translation_dict)
    unauthorized = scan_for_english(ar_doc, allowed_english)

    if unauthorized:
        results['english_scan'] = 'FAIL'
        results['issues'].extend([f"English found: {w}" for w in unauthorized])

    return results

よくある問題と解決策

問題 1:複数行のセルを分割してしまう

誤り:

# Treats "A\n\nEstimated costs" as multiple rows
lines = cell.text.split('\n')
for line in lines:
    new_row = table.add_row()  # ❌ Creates extra rows

正しい方法:

# Preserves multi-line content in single cell
ar_cell.text = translate_text(eng_cell.text)  # ✓ Keeps \n intact
落とし穴 2:部分的な翻訳

誤り:「التدفق النقدي forecast」(アラビア語と英語の混在)

正しい例:「توقعات التدفق النقدي」(完全に翻訳)

**原因:**辞書に複合語句が登録されていない **解決策:**単語ごとではなく、語句全体を抽出する

落とし穴 3:新しいセルの RTL 設定を忘れる

誤り:

new_para = doc.add_paragraph(arabic_text)  # ❌ Missing RTL

正しい例:

new_para = doc.add_paragraph()
run = new_para.add_run(arabic_text)
new_para.paragraph_format.bidi = True
run.font.rtl = True
new_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT  # ✓ Complete RTL
落とし穴 4:見た目の確認をしない

**問題:**自動チェックには合格しても、見た目が正しくない

**解決策:**必ず比較画像を生成してください:

# Convert to PDF then images
subprocess.run(['soffice', '--headless', '--convert-to', 'pdf', ar_docx])
subprocess.run(['pdftoppm', '-png', 'output.pdf', 'comparison'])

クイックリファレンス:必須関数

# 1. Get cell background
bg = get_cell_background(cell)

# 2. Set cell background
set_cell_background(cell, 'CC0029')

# 3. Normalize text
normalized = normalize_text(text)

# 4. Multi-pass translation
arabic = translate_text(english, translation_dict)

# 5. Apply RTL to cell
apply_rtl_to_cell(cell, arabic_text, font_size=10, bold=False)

# 6. Apply colors with auto-correction
apply_colors_to_cell(cell, eng_cell, ar_text)

# 7. Verify document
results = verify_arabic_document(ar_doc, eng_doc, trans_dict)

完了基準

翻訳の完了と判断する前に、次の項目を確認してください:

  • 構造が完全に一致している(セクション、表、寸法)
  • すべてのテキストが右揃えで、RTL 形式になっている
  • 許可されていない英単語が含まれていない
  • すべての色と背景が保持されている
  • 見た目の比較でレイアウトが一致している
  • 複数行のセルが保持されている(分割されていない)
  • PDF が正常に生成されている

追加リソース

以下については REFERENCE.md を参照してください:

  • コード例の全体
  • 実際のドキュメント用テンプレート
  • トラブルシューティングガイド
  • 高度なパターン

コメント