diff --git a/README.md b/README.md index f38f689..a520303 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@

- 简体中文 / English / 日本語 + 简体中文 / English / 日本語 / Tiếng Việt

@@ -526,4 +526,4 @@ Welcome to support the author. Please specify the reason for the donation in the

Donation Code -

\ No newline at end of file +

diff --git a/README_JP.md b/README_JP.md index 7f3132b..e2525af 100644 --- a/README_JP.md +++ b/README_JP.md @@ -13,7 +13,7 @@

- 简体中文 / English / 日本語 + 简体中文 / English / 日本語 / Tiếng Việt

@@ -526,4 +526,4 @@ A: TranslatorConfig で `system_proxy_enable=True` を設定。

寄付コード -

\ No newline at end of file +

diff --git a/README_VI.md b/README_VI.md new file mode 100644 index 0000000..9a492ab --- /dev/null +++ b/README_VI.md @@ -0,0 +1,549 @@ +

+Project Logo +

+ +

DocuTranslate

+ +

+ GitHub stars + GitHub Downloads + PyPI version + Python Version + License +

+ +

+ 简体中文 / English / 日本語 / Tiếng Việt +

+ +

+Một công cụ dịch thuật tệp tin cục bộ gọn nhẹ dựa trên các Mô hình Ngôn ngữ Lớn (LLM). +

+ +* ✅ **Hỗ trợ Đa định dạng**: Dịch các file `pdf`, `docx`, `xlsx`, `md`, `txt`, `json`, `epub`, `srt`, `ass`, và nhiều hơn nữa. +* ✅ **Tự động Tạo Thuật ngữ (Glossary)**: Hỗ trợ tự động tạo bảng thuật ngữ để đảm bảo sự đồng nhất về thuật ngữ. +* ✅ **Nhận dạng Bảng, Công thức, Mã trong PDF**: Tận dụng các công cụ phân tích PDF như `docling` và `mineru` để nhận dạng và dịch các bảng, công thức và mã code thường thấy trong các bài báo học thuật. +* ✅ **Dịch thuật JSON**: Hỗ trợ chỉ định các giá trị cần dịch trong JSON bằng đường dẫn (sử dụng cú pháp `jsonpath-ng`). +* ✅ **Bảo toàn Định dạng Word/Excel**: Hỗ trợ file `docx` và `xlsx` (hiện chưa hỗ trợ `doc` hoặc `xls`) trong khi vẫn giữ nguyên định dạng gốc. +* ✅ **Hỗ trợ Đa Nền tảng AI**: Hỗ trợ hầu hết các nền tảng AI, cho phép dịch thuật AI đồng thời hiệu suất cao với các prompt tùy chỉnh. +* ✅ **Hỗ trợ Bất đồng bộ (Async)**: Được thiết kế cho các kịch bản hiệu suất cao, cung cấp hỗ trợ bất đồng bộ đầy đủ và các giao diện cho đa nhiệm song song. +* ✅ **Hỗ trợ Mạng LAN & Đa người dùng**: Hỗ trợ sử dụng đồng thời bởi nhiều người dùng trong cùng một mạng cục bộ (LAN). +* ✅ **Giao diện Web Tương tác**: Cung cấp sẵn Giao diện Web (Web UI) và RESTful API để dễ dàng tích hợp và sử dụng. +* ✅ **Các gói Portable Gọn nhẹ**: Các gói portable cho Windows và Mac dưới 40MB (các phiên bản không sử dụng `docling` để phân tích PDF cục bộ). + +> Khi dịch `pdf`, tệp sẽ được chuyển đổi sang markdown trước. Điều này sẽ làm **mất** bố cục gốc. Người dùng có yêu cầu khắt khe về bố cục nên lưu ý điều này. + +> Nhóm Cộng đồng QQ: 1047781902 + +**Giao diện UI**: +![UI Interface](/images/UI界面.png) + +**Dịch thuật Bài báo/Giấy tờ**: +![Paper Translation](/images/论文翻译.png) + +**Dịch thuật Tiểu thuyết**: +![Novel Translation](/images/小说翻译.png) + +## Các Gói Tích hợp + +Dành cho những người dùng muốn bắt đầu nhanh chóng, chúng tôi cung cấp các gói tích hợp trên [GitHub Releases](https://github.com/xunbu/docutranslate/releases). Chỉ cần tải xuống, giải nén và nhập API-Key nền tảng AI của bạn để bắt đầu sử dụng. + +* **DocuTranslate**: Phiên bản tiêu chuẩn. Sử dụng `minerU` (online hoặc triển khai cục bộ) để phân tích PDF. Hỗ trợ gọi API minerU cục bộ. (Được khuyến nghị) +* **DocuTranslate_full**: Phiên bản đầy đủ. Bao gồm công cụ phân tích PDF cục bộ tích hợp sẵn là `docling`. Chọn phiên bản này nếu bạn cần phân tích PDF offline mà không cần minerU. + +## Cài đặt + +### Sử dụng pip + +```bash +# Cài đặt cơ bản +pip install docutranslate + +# Nếu bạn cần sử dụng docling để phân tích PDF cục bộ +pip install docutranslate[docling] + +``` + +### Sử dụng uv + +```bash +# Khởi tạo môi trường +uv init + +# Cài đặt cơ bản +uv add docutranslate + +# Cài đặt phần mở rộng docling +uv add docutranslate[docling] + +``` + +### Sử dụng git + +```bash +# Khởi tạo môi trường +git clone https://github.com/xunbu/docutranslate.git + +cd docutranslate + +uv sync + + +``` + +### Sử dụng docker + +```bash +docker run -d -p 8010:8010 xunbu/docutranslate:latest +# docker run -it -p 8010:8010 xunbu/docutranslate:latest +# docker run -it -p 8010:8010 xunbu/docutranslate:v1.5.4 + +``` + +## Khái niệm Cốt lõi: Workflow (Quy trình làm việc) + +DocuTranslate sử dụng hệ thống **Workflow** - mỗi workflow là một đường ống dịch thuật hoàn chỉnh cho một loại tệp cụ thể. + +**Luồng cơ bản:** + +1. Chọn workflow dựa trên loại tệp +2. Cấu hình workflow (LLM, công cụ phân tích, định dạng đầu ra) +3. Thực thi dịch thuật +4. Lưu kết quả + +## Khởi chạy Web UI và Dịch vụ API + +Để thuận tiện cho việc sử dụng, DocuTranslate cung cấp Giao diện Web đầy đủ chức năng và RESTful API. + +**Khởi chạy Dịch vụ:** + +```bash +# Khởi chạy dịch vụ, mặc định lắng nghe trên cổng 8010 +docutranslate -i + +# Khởi chạy trên một cổng cụ thể +docutranslate -i -p 8011 + +# Cho phép các yêu cầu CORS +docutranslate -i --cors + + +# Bạn cũng có thể chỉ định cổng thông qua biến môi trường +export DOCUTRANSLATE_PORT=8011 +docutranslate -i + +``` + +* **Giao diện Tương tác**: Sau khi khởi chạy dịch vụ, vui lòng truy cập `http://127.0.0.1:8010` (hoặc cổng bạn đã chỉ định) trên trình duyệt. +* **Tài liệu API**: Tài liệu API đầy đủ (Swagger UI) nằm tại `http://127.0.0.1:8010/docs`. + +## Ví dụ Sử dụng + +### Sử dụng Client SDK Đơn giản (Được khuyến nghị) + +Cách dễ nhất để bắt đầu là sử dụng lớp `Client`, cung cấp một API đơn giản và trực quan cho việc dịch thuật: + +```python +from docutranslate.sdk import Client + +# Khởi tạo client với cài đặt nền tảng AI của bạn +client = Client( + api_key="YOUR_OPENAI_API_KEY", # hoặc bất kỳ API key nền tảng AI nào khác + base_url="https://api.openai.com/v1/", + model_id="gpt-4o", + to_lang="Chinese", # Ngôn ngữ đích + concurrent=10, # Số lượng yêu cầu đồng thời +) + +# Ví dụ 1: Dịch các tệp văn bản thuần túy (không cần công cụ phân tích PDF) +result = client.translate("path/to/your/document.txt") +print(f"Dịch hoàn tất! Đã lưu tại: {result.save()}") + +# Ví dụ 2: Dịch tệp PDF (yêu cầu mineru_token hoặc triển khai cục bộ) +# Tùy chọn A: Sử dụng MinerU online (yêu cầu token: https://mineru.net/apiManage/token) +result = client.translate( + "path/to/your/document.pdf", + convert_engine="mineru", + mineru_token="YOUR_MINERU_TOKEN", # Thay thế bằng MinerU Token của bạn + formula_ocr=True, # Bật nhận dạng công thức +) +result.save(fmt="html") + +# Tùy chọn B: Sử dụng MinerU triển khai cục bộ (khuyên dùng cho mạng nội bộ/offline) +# Đầu tiên khởi chạy dịch vụ MinerU cục bộ, tham khảo: https://github.com/opendatalab/MinerU +result = client.translate( + "path/to/your/document.pdf", + convert_engine="mineru_deploy", + mineru_deploy_base_url="http://127.0.0.1:8000", # Địa chỉ MinerU cục bộ của bạn + mineru_deploy_backend="hybrid-auto-engine", # Loại backend +) +result.save(fmt="markdown") + +# Ví dụ 3: Dịch tệp Docx (giữ nguyên định dạng) +result = client.translate( + "path/to/your/document.docx", + insert_mode="replace", # replace (thay thế)/append (thêm vào sau)/prepend (thêm vào trước) +) +result.save(fmt="docx") # Lưu dưới định dạng docx + +# Ví dụ 4: Xuất dưới dạng chuỗi mã hóa base64 (để truyền qua API) +base64_content = result.export(fmt="html") +print(f"Độ dài nội dung đã xuất: {len(base64_content)}") + +# Bạn cũng có thể truy cập workflow bên dưới để thực hiện các thao tác nâng cao +# workflow = result.workflow + +``` + +**Các tính năng của Client:** + +* **Tự động phát hiện**: Tự động phát hiện loại tệp và chọn workflow phù hợp +* **Cấu hình linh hoạt**: Ghi đè bất kỳ cài đặt mặc định nào cho mỗi lần gọi dịch +* **Nhiều tùy chọn đầu ra**: Lưu vào đĩa hoặc xuất dưới dạng chuỗi Base64 +* **Hỗ trợ Bất đồng bộ**: Sử dụng `translate_async()` cho các tác vụ dịch đồng thời + +#### Tham số Client SDK + +| Tham số | Loại | Mặc định | Mô tả | +| --- | --- | --- | --- | +| **api_key** | `str` | - | API key nền tảng AI | +| **base_url** | `str` | - | Base URL nền tảng AI (ví dụ: `https://api.openai.com/v1/`) | +| **model_id** | `str` | - | ID Model sử dụng để dịch | +| **to_lang** | `str` | - | Ngôn ngữ đích (ví dụ: `"Chinese"`, `"English"`, `"Japanese"`) | +| **concurrent** | `int` | 10 | Số lượng yêu cầu LLM đồng thời | +| **convert_engine** | `str` | `"mineru"` | Công cụ phân tích PDF: `"mineru"`, `"docling"`, `"mineru_deploy"` | +| **mineru_deploy_base_url** | `str` | - | Địa chỉ API minerU cục bộ (khi dùng `convert_engine="mineru_deploy"`) | +| **mineru_deploy_parse_method** | `str` | `"auto"` | Phương pháp phân tích minerU cục bộ: `"auto"`, `"txt"`, `"ocr"` | +| **mineru_deploy_table_enable** | `bool` | `True` | Bật nhận dạng bảng cho minerU cục bộ | +| **mineru_token** | `str` | - | Token API minerU (khi sử dụng minerU online) | +| **skip_translate** | `bool` | `False` | Bỏ qua dịch thuật, chỉ phân tích tài liệu | +| **output_dir** | `str` | `"./output"` | Thư mục đầu ra mặc định cho `save()` | +| **chunk_size** | `int` | 3000 | Kích thước đoạn văn bản (chunk) để LLM xử lý | +| **temperature** | `float` | 0.3 | Tham số temperature của LLM | +| **timeout** | `int` | 60 | Thời gian chờ yêu cầu tính bằng giây | +| **retry** | `int` | 3 | Số lần thử lại khi thất bại | +| **provider** | `str` | `"auto"` | Loại nhà cung cấp AI (auto, openai, azure, v.v.) | +| **force_json** | `bool` | `False` | Bắt buộc chế độ đầu ra JSON | +| **rpm** | `int` | - | Giới hạn số yêu cầu mỗi phút | +| **tpm** | `int` | - | Giới hạn số token mỗi phút | + +#### Các phương thức Kết quả (Result Methods) + +| Phương thức | Tham số | Mô tả | +| --- | --- | --- | +| **save()** | `output_dir`, `name`, `fmt` | Lưu kết quả dịch vào đĩa | +| **export()** | `fmt` | Xuất dưới dạng chuỗi mã hóa Base64 | +| **supported_formats** | - | Lấy danh sách các định dạng đầu ra được hỗ trợ | +| **workflow** | - | Truy cập đối tượng workflow bên dưới | + +```python +import asyncio +from docutranslate.sdk import Client + +async def translate_multiple(): + client = Client( + api_key="YOUR_API_KEY", + base_url="https://api.openai.com/v1/", + model_id="gpt-4o", + to_lang="Chinese", + ) + + # Dịch nhiều file đồng thời + files = ["doc1.pdf", "doc2.docx", "notes.txt"] + results = await asyncio.gather( + *[client.translate_async(f) for f in files] + ) + + for r in results: + print(f"Đã lưu: {r.save()}") + +asyncio.run(translate_multiple()) + +``` + +### Sử dụng Workflow API (Để Kiểm soát Nâng cao) + +Để kiểm soát nhiều hơn, hãy sử dụng trực tiếp Workflow API. Mỗi workflow tuân theo cùng một mẫu: + +```python +# Mẫu: +# 1. Tạo TranslatorConfig (cài đặt LLM) +# 2. Tạo WorkflowConfig (cài đặt workflow) +# 3. Tạo instance Workflow +# 4. workflow.read_path(file) +# 5. await workflow.translate_async() +# 6. workflow.save_as_*(name=...) hoặc export_to_*(...) + +``` + +#### Các Workflow và Phương thức Đầu ra có sẵn + +| Workflow | Đầu vào | save_as_* | export_to_* | Các tùy chọn Config chính | +| --- | --- | --- | --- | --- | +| **MarkdownBasedWorkflow** | `.pdf`, `.docx`, `.md`, `.png`, `.jpg` | `html`, `markdown`, `markdown_zip` | `html`, `markdown`, `markdown_zip` | `convert_engine`, `translator_config` | +| **TXTWorkflow** | `.txt` | `txt`, `html` | `txt`, `html` | `translator_config` | +| **JsonWorkflow** | `.json` | `json`, `html` | `json`, `html` | `translator_config`, `json_paths` | +| **DocxWorkflow** | `.docx` | `docx`, `html` | `docx`, `html` | `translator_config`, `insert_mode` | +| **XlsxWorkflow** | `.xlsx`, `.csv` | `xlsx`, `html` | `xlsx`, `html` | `translator_config`, `insert_mode` | +| **SrtWorkflow** | `.srt` | `srt`, `html` | `srt`, `html` | `translator_config` | +| **EpubWorkflow** | `.epub` | `epub`, `html` | `epub`, `html` | `translator_config`, `insert_mode` | +| **HtmlWorkflow** | `.html`, `.htm` | `html` | `html` | `translator_config`, `insert_mode` | +| **AssWorkflow** | `.ass` | `ass`, `html` | `ass`, `html` | `translator_config` | + +#### Các Tùy chọn Cấu hình Chính + +**Các tùy chọn TranslatorConfig chung:** + +| Tùy chọn | Loại | Mặc định | Mô tả | +| --- | --- | --- | --- | +| `base_url` | `str` | - | Base URL của nền tảng AI | +| `api_key` | `str` | - | API key của nền tảng AI | +| `model_id` | `str` | - | ID Model | +| `to_lang` | `str` | - | Ngôn ngữ đích | +| `chunk_size` | `int` | 3000 | Kích thước đoạn văn bản (chunk) | +| `concurrent` | `int` | 10 | Số lượng yêu cầu đồng thời | +| `temperature` | `float` | 0.3 | Nhiệt độ LLM | +| `timeout` | `int` | 60 | Thời gian chờ yêu cầu (giây) | +| `retry` | `int` | 3 | Số lần thử lại | + +**Các tùy chọn Dành riêng cho Định dạng:** + +| Tùy chọn | Các Workflow áp dụng | Mô tả | +| --- | --- | --- | +| `insert_mode` | Docx, Xlsx, Html, Epub | `"replace"` (mặc định), `"append"`, `"prepend"` | +| `json_paths` | Json | Biểu thức JSONPath (ví dụ: `["$.*", "$.name"]`) | +| `separator` | Docx, Xlsx, Html, Epub | Dấu phân cách văn bản cho các chế độ `"append"` / `"prepend"` | +| `convert_engine` | MarkdownBased | `"mineru"` (mặc định), `"docling"`, `"mineru_deploy"` | + +#### Ví dụ 1: Dịch một tệp PDF (Sử dụng `MarkdownBasedWorkflow`) + +Đây là trường hợp sử dụng phổ biến nhất. Chúng tôi sẽ sử dụng engine `mineru` để chuyển đổi PDF sang Markdown, và sau đó dịch nó bằng LLM. Ví dụ này sử dụng thực thi bất đồng bộ. + +```python +import asyncio +from docutranslate.workflow.md_based_workflow import MarkdownBasedWorkflow, MarkdownBasedWorkflowConfig +from docutranslate.converter.x2md.converter_mineru import ConverterMineruConfig +from docutranslate.translator.ai_translator.md_translator import MDTranslatorConfig +from docutranslate.exporter.md.md2html_exporter import MD2HTMLExporterConfig + + +async def main(): + # 1. Xây dựng Cấu hình Translator + translator_config = MDTranslatorConfig( + base_url="https://open.bigmodel.cn/api/paas/v4", # Base URL Nền tảng AI + api_key="YOUR_ZHIPU_API_KEY", # API Key Nền tảng AI + model_id="glm-4-air", # ID Model + to_lang="English", # Ngôn ngữ đích + chunk_size=3000, # Kích thước đoạn văn bản + concurrent=10, # Mức độ đồng thời + # glossary_generate_enable=True, # Bật tự động tạo thuật ngữ + # glossary_dict={"Jobs":"Steve Jobs"}, # Truyền vào từ điển thuật ngữ + # system_proxy_enable=True, # Bật proxy hệ thống + ) + + # 2. Xây dựng Cấu hình Converter (Sử dụng minerU) + converter_config = ConverterMineruConfig( + mineru_token="YOUR_MINERU_TOKEN", # MinerU Token của bạn + formula_ocr=True # Bật nhận dạng công thức + ) + + # 3. Xây dựng Cấu hình Workflow Chính + workflow_config = MarkdownBasedWorkflowConfig( + convert_engine="mineru", # Chỉ định engine phân tích + converter_config=converter_config, # Truyền cấu hình converter + translator_config=translator_config, # Truyền cấu hình translator + html_exporter_config=MD2HTMLExporterConfig(cdn=True) # Cấu hình xuất HTML + ) + + # 4. Khởi tạo Workflow + workflow = MarkdownBasedWorkflow(config=workflow_config) + + # 5. Đọc file và thực thi dịch thuật + print("Đang bắt đầu đọc và dịch file...") + workflow.read_path("path/to/your/document.pdf") + await workflow.translate_async() + # Hoặc sử dụng phương thức đồng bộ + # workflow.translate() + print("Dịch hoàn tất!") + + # 6. Lưu kết quả + workflow.save_as_html(name="translated_document.html") + workflow.save_as_markdown_zip(name="translated_document.zip") + workflow.save_as_markdown(name="translated_document.md") # Markdown với hình ảnh được nhúng + print("Các file đã được lưu vào thư mục ./output.") + + # Hoặc lấy trực tiếp chuỗi nội dung + html_content = workflow.export_to_html() + html_content = workflow.export_to_markdown() + # print(html_content) + + +if __name__ == "__main__": + asyncio.run(main()) + +``` + +### Các Workflow khác + +Tất cả các workflow đều tuân theo cùng một mẫu. Import config và workflow tương ứng, sau đó cấu hình: + +```python +# TXT: from docutranslate.workflow.txt_workflow import TXTWorkflow, TXTWorkflowConfig +# JSON: from docutranslate.workflow.json_workflow import JsonWorkflow, JsonWorkflowConfig +# DOCX: from docutranslate.workflow.docx_workflow import DocxWorkflow, DocxWorkflowConfig +# XLSX: from docutranslate.workflow.xlsx_workflow import XlsxWorkflow, XlsxWorkflowConfig +# EPUB: from docutranslate.workflow.epub_workflow import EpubWorkflow, EpubWorkflowConfig +# HTML: from docutranslate.workflow.html_workflow import HtmlWorkflow, HtmlWorkflowConfig +# SRT: from docutranslate.workflow.srt_workflow import SrtWorkflow, SrtWorkflowConfig +# ASS: from docutranslate.workflow.ass_workflow import AssWorkflow, AssWorkflowConfig + +``` + +Các tùy chọn config chính: + +* **insert_mode**: `"replace"`, `"append"`, hoặc `"prepend"` (cho docx/xlsx/html/epub) +* **json_paths**: Biểu thức JSONPath cho dịch thuật JSON (ví dụ: `["$.*", "$.name"]`) +* **separator**: Dấu phân cách văn bản cho các chế độ `"append"` / `"prepend"` + +## Điều kiện tiên quyết và Cấu hình chi tiết + +### 1. Lấy API Key Mô hình Lớn + +Chức năng dịch thuật dựa vào các Mô hình Ngôn ngữ Lớn (LLM). Bạn cần lấy `base_url`, `api_key`, và `model_id` từ nền tảng AI tương ứng. + +> Các model được khuyến nghị: `doubao-seed-1-6-flash` của Volcengine, dòng `doubao-seed-1-6`, `glm-4-flash` của Zhipu, `qwen-plus`, `qwen-flash` của Alibaba Cloud, `deepseek-chat` của Deepseek, v.v. + +> [302.AI](https://share.302.ai/BgRLAe) 👈 Đăng ký qua link này để nhận $1 tín dụng miễn phí. + +| Tên Nền tảng | Lấy API Key | Base URL | +| --- | --- | --- | +| ollama | | http://127.0.0.1:11434/v1 | +| lm studio | | http://127.0.0.1:1234/v1 | +| 302.AI | [Nhấn để lấy](https://share.302.ai/BgRLAe) | https://api.302.ai/v1 | +| openrouter | [Nhấn để lấy](https://openrouter.ai/settings/keys) | [https://openrouter.ai/api/v1](https://openrouter.ai/api/v1) | +| openai | [Nhấn để lấy](https://platform.openai.com/api-keys) | https://api.openai.com/v1/ | +| gemini | [Nhấn để lấy](https://aistudio.google.com/u/0/apikey) | [https://generativelanguage.googleapis.com/v1beta/openai/](https://generativelanguage.googleapis.com/v1beta/openai/) | +| deepseek | [Nhấn để lấy](https://platform.deepseek.com/api_keys) | [https://api.deepseek.com/v1](https://api.deepseek.com/v1) | +| Zhipu AI | [Nhấn để lấy](https://open.bigmodel.cn/usercenter/apikeys) | [https://open.bigmodel.cn/api/paas/v4](https://open.bigmodel.cn/api/paas/v4) | +| Tencent Hunyuan | [Nhấn để lấy](https://console.cloud.tencent.com/hunyuan/api-key) | https://api.hunyuan.cloud.tencent.com/v1 | +| Alibaba Bailian | [Nhấn để lấy](https://bailian.console.aliyun.com/?tab=model#/api-key) | [https://dashscope.aliyuncs.com/compatible-mode/v1](https://dashscope.aliyuncs.com/compatible-mode/v1) | +| Volcengine | [Nhấn để lấy](https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey?apikey=%7B%7D) | https://ark.cn-beijing.volces.com/api/v3 | +| SiliconFlow | [Nhấn để lấy](https://cloud.siliconflow.cn/account/ak) | https://api.siliconflow.cn/v1 | +| DMXAPI | [Nhấn để lấy](https://www.dmxapi.cn/token) | [https://www.dmxapi.cn/v1](https://www.dmxapi.cn/v1) | +| Juguang AI | [Nhấn để lấy](https://ai.juguang.chat/console/token) | [https://ai.juguang.chat/v1](https://ai.juguang.chat/v1) | + +### 2. Công cụ Phân tích PDF (Bỏ qua nếu bạn không cần dịch PDF) + +### 2.1 Lấy Token minerU (Phân tích PDF Online, Miễn phí, Được khuyến nghị) + +Nếu bạn chọn `mineru` làm engine phân tích tài liệu (`convert_engine="mineru"`), bạn cần đăng ký nhận Token miễn phí. + +1. Truy cập [Trang web minerU](https://mineru.net/apiManage/docs) để đăng ký và nộp đơn xin API. +2. Tạo API Token mới trong [Giao diện Quản lý API Token](https://mineru.net/apiManage/token). + +> **Lưu ý**: Token minerU có giá trị trong 14 ngày. Vui lòng tạo lại sau khi hết hạn. + +### 2.2. Cấu hình Engine docling (Phân tích PDF Cục bộ) + +Nếu bạn chọn `docling` làm engine phân tích tài liệu (`convert_engine="docling"`), nó sẽ tải xuống các model cần thiết từ Hugging Face trong lần sử dụng đầu tiên. + +> Một lựa chọn tốt hơn là tải xuống `docling_artifact.zip` từ [GitHub Releases](https://github.com/xunbu/docutranslate/releases) và giải nén nó vào thư mục làm việc của bạn. + +**Giải pháp cho Vấn đề Mạng khi Tải Model `docling`:** + +1. **Thiết lập Hugging Face Mirror (Được khuyến nghị)**: + +* **Phương pháp A (Biến môi trường)**: Đặt biến môi trường hệ thống `HF_ENDPOINT` và khởi động lại IDE hoặc terminal của bạn. +``` +HF_ENDPOINT=https://hf-mirror.com + +``` + + +* **Phương pháp B (Trong Code)**: Thêm đoạn mã sau vào đầu tập lệnh Python của bạn. + +```python +import os + +os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com' + +``` + +2. **Sử dụng Offline (Tải trước Gói Model)**: + +* Tải xuống `docling_artifact.zip` từ [GitHub Releases](https://github.com/xunbu/docutranslate/releases). +* Giải nén nó vào thư mục dự án của bạn. +* Chỉ định đường dẫn model trong cấu hình (nếu model không nằm trong cùng thư mục với tập lệnh): + +```python +from docutranslate.converter.x2md.converter_docling import ConverterDoclingConfig + +converter_config = ConverterDoclingConfig( + artifact="./docling_artifact", # Trỏ đến thư mục đã giải nén + code_ocr=True, + formula_ocr=True +) + +``` + +### 2.3. Dịch vụ MinerU Triển khai Cục bộ + +Đối với môi trường offline/mạng nội bộ, hãy triển khai `minerU` cục bộ với API được kích hoạt. Đặt `mineru_deploy_base_url` thành endpoint API minerU của bạn. + +**Client SDK:** + +```python +from docutranslate.sdk import Client + +client = Client( + api_key="YOUR_LLM_API_KEY", + model_id="llama3", + to_lang="Chinese", + convert_engine="mineru_deploy", + mineru_deploy_base_url="http://127.0.0.1:8000", # Địa chỉ API minerU của bạn +) +result = client.translate("document.pdf") +result.save(fmt="markdown") + +``` + +## Câu hỏi thường gặp (FAQ) + +**H: Đầu ra vẫn là ngôn ngữ gốc?** +Đ: Kiểm tra nhật ký (logs) để tìm lỗi. Thường là do hết tín dụng API hoặc vấn đề mạng. + +**H: Cổng 8010 bị chiếm dụng?** +Đ: Sử dụng `docutranslate -i -p 8011` hoặc thiết lập `DOCUTRANSLATE_PORT=8011`. + +**H: PDF scan có được hỗ trợ không?** +Đ: Có, sử dụng engine `mineru` với khả năng OCR. + +**H: Dịch PDF lần đầu tiên rất chậm?** +Đ: `docling` cần tải xuống các model trong lần chạy đầu tiên. Hãy sử dụng Hugging Face mirror hoặc tải trước gói artifact. + +**H: Sử dụng trong mạng nội bộ/offline được không?** +Đ: Có. Sử dụng LLM cục bộ (Ollama/LM Studio) và minerU hoặc docling cục bộ. + +**H: Cơ chế cache PDF?** +Đ: `MarkdownBasedWorkflow` lưu trữ kết quả phân tích trong bộ nhớ (10 lần phân tích gần nhất). Cấu hình qua `DOCUTRANSLATE_CACHE_NUM`. + +**H: Bật proxy?** +Đ: Thiết lập `system_proxy_enable=True` trong TranslatorConfig. + +## Lịch sử Sao + + + + + + Star History Chart + + + +## Hỗ trợ Quyên góp + +Hoan nghênh ủng hộ tác giả. Vui lòng ghi rõ lý do quyên góp trong phần bình luận! + +

+Donation Code +

diff --git a/README_ZH.md b/README_ZH.md index eed721f..34d574d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -13,7 +13,7 @@

- 简体中文 / English / 日本語 + 简体中文 / English / 日本語 / Tiếng Việt

@@ -528,4 +528,4 @@ A: 在 TranslatorConfig 中设置 `system_proxy_enable=True`。

赞赏码 -

\ No newline at end of file +

diff --git a/docutranslate/static/i18nData.json b/docutranslate/static/i18nData.json index d0f6714..30521b3 100644 --- a/docutranslate/static/i18nData.json +++ b/docutranslate/static/i18nData.json @@ -344,5 +344,178 @@ "configImportSuccess": "Configuration imported successfully!", "configImportError": "Failed to parse config file, please check the file format.", "providerLabel": "Provider" + }, + "vi": { + "pageTitle": "DocuTranslate - Dịch tài liệu tương tác", + "tutorialBtn": "Hướng dẫn", + "projectContributeBtn": "Hợp tác dự án", + "workflowTitle": "Chọn quy trình làm việc", + "workflowOptionMarkdown": "Chuyển sang Markdown rồi dịch (.pdf/.md/.png, v.v.)", + "workflowOptionTxt": "Dịch văn bản thuần (.txt)", + "workflowOptionEpub": "Dịch EPUB (.epub)", + "workflowOptionDocx": "Dịch DOCX (.docx)", + "workflowOptionXlsx": "Dịch XLSX (.xlsx/.csv)", + "workflowOptionSrt": "Dịch phụ đề SRT (.srt)", + "workflowOptionAss": "Dịch phụ đề ASS (.ass)", + "workflowOptionJson": "Dịch JSON (.json)", + "workflowOptionHtml": "Dịch HTML (.html)", + "workflowOptionPptx": "Thuyết trình PPTX (.pptx)", + "autoWorkflowLabel": "Tự động chọn quy trình", + "txtSettingsTitleText": "Tùy chọn dịch TXT", + "insertModeLabel": "Chế độ chèn", + "insertModeReplace": "Thay thế bản gốc (Replace)", + "insertModeAppend": "Thêm vào sau bản gốc (Append)", + "insertModePrepend": "Thêm vào trước bản gốc (Prepend)", + "insertModeHelpTxt": "Chọn cách chèn văn bản đã dịch.", + "separatorLabel": "Dấu phân cách", + "separatorPlaceholderSimple": "Ví dụ: \\n---\\n", + "separatorHelp": "Ký tự dùng để phân cách văn bản gốc và văn bản dịch trong chế độ Append hoặc Prepend. \\n đại diện cho xuống dòng.", + "segmentModeLabel": "Chế độ phân đoạn", + "segmentModeLine": "Theo dòng (Mỗi dòng là một đoạn)", + "segmentModeParagraph": "Theo đoạn văn (Gộp các dòng không trống liên tiếp)", + "segmentModeNone": "Không phân đoạn (Toàn bộ văn bản là một đoạn)", + "segmentModeHelp": "Chọn cách phân chia văn bản để dịch.", + "docxSettingsTitleText": "Tùy chọn dịch DOCX", + "insertModeHelpDocx": "Chọn cách chèn văn bản đã dịch.", + "xlsxSettingsTitleText": "Tùy chọn dịch XLSX", + "insertModeHelpXlsx": "Chọn cách chèn văn bản đã dịch vào các ô.", + "xlsxTranslateRegionsLabel": "Vùng dịch (Tùy chọn)", + "xlsxTranslateRegionsPlaceholder": "Mỗi dòng một vùng, ví dụ: Sheet1!A1:B10 (áp dụng cho tất cả các sheet nếu bỏ qua tên sheet).", + "srtSettingsTitleText": "Tùy chọn dịch SRT", + "insertModeHelpSrt": "Chọn cách chèn văn bản đã dịch.", + "epubSettingsTitleText": "Tùy chọn dịch EPUB", + "insertModeHelpEpub": "Chọn cách chèn văn bản đã dịch.", + "htmlSettingsTitleText": "Tùy chọn dịch HTML", + "insertModeHelpHtml": "Chọn cách chèn văn bản đã dịch.", + "assSettingsTitleText": "Tùy chọn dịch ASS", + "insertModeHelpAss": "Chọn cách chèn văn bản đã dịch.", + "separatorPlaceholderAss": "Ví dụ: \\N (ký tự xuống dòng)", + "separatorHelpAss": "Ký tự dùng để phân cách văn bản gốc và văn bản dịch trong chế độ Append hoặc Prepend. \\N là ký tự xuống dòng cho định dạng ASS.", + "pptxSettingsTitleText": "Tùy chọn dịch PPTX", + "insertModeHelpPptx": "Chọn cách chèn văn bản đã dịch vào hộp văn bản.", + "jsonSettingsTitleText": "Cấu hình đường dẫn JSON", + "jsonPathLabel": "Đường dẫn JSON cần dịch", + "jsonPathPlaceholder": "Mỗi dòng một đường dẫn, ví dụ:\n$.name\n$.*", + "jsonPathHelp": "Sử dụng cú pháp jsonpath-ng. Mỗi dòng đại diện cho một đường dẫn JSON. Tất cả các chuỗi trong các đối tượng khớp sẽ được dịch.", + "parsingSettingsTitleText": "Cấu hình phân tích", + "parsingEngineLabel": "Công cụ phân tích", + "parsingEngineHelp": "Nếu tệp tải lên đã ở định dạng .md, mục này có thể bỏ qua.", + "mineruTokenPlaceholder": "Bắt buộc khi sử dụng công cụ Mineru", + "modelVersionLabel": "Phiên bản mô hình Mineru", + "modelVersionVlm": "VLM", + "modelVersionPipline": "Pipeline", + "modelVersionHelp": "Mineru VLM là mô hình thử nghiệm nội bộ mới hơn.", + "mineruDeployBaseUrlLabel": "URL dịch vụ (Base URL)", + "mineruDeployBaseUrlPlaceholder": "Ví dụ: http://127.0.0.1:8000", + "mineruDeployBackendLabel": "Loại Backend", + "mineruDeployLangListLabel": "Danh sách ngôn ngữ (Chế độ Pipeline)", + "mineruDeployServerUrlLabel": "URL máy chủ", + "mineruDeployServerUrlPlaceholder": "Ví dụ: http://127.0.0.1:30000", + "mineruDeployParseMethodLabel": "Phương pháp phân tích", + "mineruDeployTableEnableLabel": "Nhận dạng bảng", + "mineruDeployStartPageLabel": "Trang bắt đầu", + "mineruDeployEndPageLabel": "Trang kết thúc", + "mineruDeployFormulaEnableLabel": "Bật phân tích công thức", + "formulaOcrLabel": "Nhận dạng công thức", + "codeOcrLabel": "Nhận dạng mã (Code)", + "aiSettingsTitleText": "Mô hình dịch", + "skipTranslationLabel": "Bỏ qua dịch thuật", + "platformLabel": "Chọn nền tảng", + "platformCustom": "API tùy chỉnh", + "baseUrlLabel": "Địa chỉ API (Base URL)", + "baseUrlPlaceholder": "Địa chỉ tương thích OpenAI", + "apiKeyPlaceholder": "Vui lòng nhập API Key của bạn", + "modelIdLabel": "Model ID", + "modelIdPlaceholder": "Ví dụ: gpt-4o, glm-4", + "systemProxyLabel": "Bật proxy hệ thống", + "forceJson": "Bắt buộc xuất JSON", + "forceJsonTooltip": "Bắt buộc mô hình xuất định dạng JSON khi được yêu cầu. Có thể làm giảm chất lượng dịch; khuyên dùng nên tắt đối với các mô hình tuân thủ hướng dẫn tốt.", + "translationSettingsTitleText": "Cấu hình dịch thuật", + "targetLanguageLabel": "Ngôn ngữ đích", + "targetLanguageCustom": "Khác (Tùy chỉnh)", + "customLangPlaceholder": "Vui lòng nhập ngôn ngữ đích, ví dụ: Vietnamese", + "thinkingModeLabel": "Chế độ tư duy (Thinking Mode)", + "thinkingModeTooltip": "Thiết lập xem mô hình suy luận hỗn hợp có thực hiện tư duy hay không. Hiện được hỗ trợ bởi dòng glm4.5 của Zhipu, dòng seed1.6 của Volcengine, SiliconFlow, dòng Gemini của Google và 302AI (một phần). Khuyên dùng tùy chọn 'Tắt'.", + "thinkingModeEnable": "Bật", + "thinkingModeDisable": "Tắt (Khuyên dùng)", + "thinkingModeDefault": "Mặc định", + "customPromptLabel": "Prompt tùy chỉnh", + "customPromptPlaceholder": "Tùy chọn, ví dụ: \"Không dịch tên người, giữ nguyên ngôn ngữ gốc\"", + "chunkSizeLabel": "Kích thước phân khối (Chunk Size)", + "resetBtn": "Đặt lại", + "concurrentLabel": "Số lượng đồng thời", + "retryLabel": "Thử lại", + "rpmLabel": "Số yêu cầu mỗi phút (RPM)", + "tpmLabel": "Số token mỗi phút (TPM - Ước tính)", + "unlimitedPlaceholder": "Để trống nếu không giới hạn", + "glossaryGenTitle": "Thuật ngữ", + "glossaryLabel": "Bảng thuật ngữ (Tùy chọn)", + "glossaryHelp": "Chọn một hoặc nhiều tệp CSV. Các tệp phải chứa tiêu đề 'src' và 'dst', đại diện cho thuật ngữ nguồn và đích.", + "viewGlossaryBtn": "Xem bảng thuật ngữ", + "clearGlossaryBtn": "Xóa", + "glossaryGenEnableLabel": "Tự động tạo bảng thuật ngữ", + "glossaryCustomPromptLabel": "Prompt tùy chỉnh", + "glossaryCustomPromptPlaceholder": "Gợi ý tạo bảng thuật ngữ", + "glossaryGenConfigLabel": "Cấu hình tạo thuật ngữ", + "glossaryGenConfigSame": "Giống cấu hình dịch", + "glossaryGenConfigCustom": "Tùy chỉnh", + "importConfigBtn": "Nhập cấu hình", + "exportConfigBtn": "Xuất cấu hình", + "taskListTitle": "Danh sách tác vụ", + "newTaskBtn": "Tác vụ mới", + "noTaskPlaceholder": "Chưa có tác vụ nào. Nhấn \"Tác vụ mới\" để bắt đầu!", + "taskCardIdLabel": "ID Tác vụ", + "taskCardIdPlaceholder": "Đang chờ gửi...", + "taskCardFileDrop": "Nhấp hoặc kéo tệp vào đây", + "taskCardFileSelected": "Đã chọn tệp", + "taskCardFilenameLabel": "Tên tệp: ", + "taskCardLogLabel": "Nhật ký (Logs)", + "copyLogsTooltip": "Sao chép nhật ký", + "taskCardStatusWaiting": "Đang chờ tải tệp lên...", + "taskCardPreviewBtn": "Xem trước", + "taskCardDownloadBtn": "Tải xuống", + "taskCardAttachmentBtn": "Tệp đính kèm", + "taskCardStartBtn": "Bắt đầu dịch", + "downloadMdEmbedded": "Markdown (Nhúng ảnh)", + "downloadMdZip": "Markdown nén (Zip)", + "previewBilingualBtn": "Song ngữ", + "previewTranslatedOnlyBtn": "Chỉ bản dịch", + "syncScrollTooltip": "Cuộn đồng bộ", + "previewOriginal": "Bản gốc", + "previewTranslated": "Bản dịch", + "closeBtn": "Đóng", + "tutorialModalTitle": "Hướng dẫn sử dụng", + "tutorialModalBody": "

Video hướng dẫn có sẵn trên Bilibili bằng cách tìm kiếm docutranslate.

Chào mừng bạn đến với DocuTranslate! Vui lòng làm theo các bước sau để dịch tài liệu của bạn:

  1. Bước 1: Chọn quy trình làm việc

    Ở đầu bảng cấu hình bên trái, trước tiên hãy chọn quy trình xử lý phù hợp nhất với loại tệp của bạn.

    Mẹo: \"Tự động chọn quy trình\" được bật theo mặc định. Chỉ cần tải tệp lên, hệ thống sẽ tự động khớp với quy trình phù hợp để đơn giản hóa thao tác.
  2. Bước 2: Cấu hình tham số

    Sau khi chọn quy trình, các tùy chọn cấu hình liên quan sẽ xuất hiện bên dưới. Vui lòng hoàn tất cài đặt theo thứ tự (tất cả cấu hình được tự động lưu trong trình duyệt của bạn):

    A. Tùy chọn riêng theo quy trình (Xuất hiện dựa trên lựa chọn ở Bước 1):

    B. Tùy chọn chung (Áp dụng cho mọi quy trình):

  3. Bước 3: Tải tệp lên

    Trong danh sách tác vụ bên phải, nhấp hoặc kéo tài liệu của bạn vào khu vực tải lên.

  4. Bước 4: Bắt đầu dịch

    Sau khi chọn tệp thành công, nhấp nút Bắt đầu dịch ở góc dưới bên phải thẻ tác vụ. Hệ thống sẽ bắt đầu xử lý và bạn có thể xem tiến độ thời gian thực trong khu vực nhật ký.

  5. Bước 5: Xem và Tải xuống

    Sau khi dịch xong, các nút thao tác sẽ xuất hiện trên thẻ tác vụ:

Lưu ý quan trọng: Tất cả cấu hình được tự động lưu cục bộ trong trình duyệt để sử dụng lần sau. Bạn cũng có thể dùng nút \"Xuất cấu hình\" và \"Nhập cấu hình\" mới để sao lưu và khôi phục cài đặt.
", + "tutorialUnderstandBtn": "Tôi đã hiểu", + "contributorsModalTitle": "Cảm ơn vì đã đóng góp", + "contributorsPara1": "DocuTranslate là một dự án mã nguồn mở! Nhu cầu và việc sử dụng của cộng đồng là động lực thúc đẩy sự tiến bộ của dự án.", + "contributorsPara2": "Cảm ơn tất cả những người đã tài trợ, gửi mã, đóng góp ý kiến quý báu và gắn sao (star) cho dự án!", + "contributorsWelcome": "Hoan nghênh bạn đóng góp qua các cách sau:", + "contributorsGithub": "Trang GitHub", + "contributorsPR": "Gửi Pull Request", + "contributorsIssue": "Báo cáo vấn đề (Issue)", + "contributorsQQ": "Hoặc liên hệ tác giả qua nhóm QQ: 1047781902", + "glossaryModalTitle": "Bảng thuật ngữ hiện tại", + "glossaryTableSource": "Nguồn (src)", + "glossaryTableDestination": "Đích (dst)", + "engineOptionIdentity": "Đã là định dạng Markdown", + "engineOptionMineru": "Mineru (Khuyên dùng)", + "engineOptionDocling": "Docling", + "engineOptionMineru_deploy": "Dịch vụ Mineru Deploy", + "apiHrefInfo302ai": "👈 Đăng ký qua liên kết này để nhận $1 tín dụng miễn phí", + "glossaryEmpty": "Bảng thuật ngữ trống", + "status_fillRequired": "Vui lòng điền tất cả các trường bắt buộc!", + "btn_initializing": "Đang khởi tạo...", + "btn_cancelTranslation": "Hủy dịch", + "status_cancelling": "Đang hủy...", + "btn_reTranslate": "Dịch lại", + "preview_cantPreviewType": "Không thể xem trước loại tệp này", + "preview_noOriginalCache": "Không có tệp gốc được lưu trong bộ nhớ đệm để xem trước.", + "pdf_preparing": "Đang chuẩn bị PDF...", + "preview_bilingual": "Xem trước song ngữ", + "preview_translatedOnly": "Xem trước chỉ bản dịch", + "configImportSuccess": "Nhập cấu hình thành công!", + "configImportError": "Không thể phân tích tệp cấu hình, vui lòng kiểm tra định dạng tệp.", + "providerLabel": "Nhà cung cấp" } -} \ No newline at end of file +} diff --git a/docutranslate/static/index.html b/docutranslate/static/index.html index 65e45b4..679d747 100644 --- a/docutranslate/static/index.html +++ b/docutranslate/static/index.html @@ -1 +1,2437 @@ - DocuTranslate - 交互式文档翻译

DocuTranslate

{{ t(currentWorkflowConfig.insertHelpKey || 'insertModeHelpTxt') }}
{{ t('segmentModeHelp') }}

{{ t('parsingEngineHelp') }}
{{ t('modelVersionHelp') }}

{{ t('glossaryHelp') }}

GitHub主页(欢迎star❤):
https://github.com/xunbu/docutranslate

交流QQ群: 1047781902

version:{{ version ? 'v' + version : '' }}

{{ t('taskListTitle') }}

LOGO

{{ t('noTaskPlaceholder') }}

{{ t('taskCardIdLabel') }}: {{ task.backendId || t('taskCardIdPlaceholder') }}

{{ t('taskCardFileDrop') }}

{{ t('taskCardFileSelected') }}

{{ t('taskCardFilenameLabel') }} {{ task.fileName || task.file.name }}
{{ t('taskCardLogLabel') }}
{{ task.statusMessage || t('taskCardStatusWaiting') }}
{{ previewMode === 'bilingual' ? t('preview_bilingual') : t('preview_translatedOnly') }}
{{ t('previewOriginal') }}
{{ t('previewTranslated') }}
\ No newline at end of file + + + + + + DocuTranslate - 交互式文档翻译 + + + + + + + + + + +
+
+
+ +
+
+
+
+

DocuTranslate

+
+ + +
+
+
+ +
+
+ + +
+

+ +

+
+
+ +
+ + +
+
+
+
+ + +
+

+ +

+
+
+ +
+ + +
+ {{ t(currentWorkflowConfig.insertHelpKey || 'insertModeHelpTxt') }} +
+
+ +
+ + +
+
+ + +
+ + +
{{ t('segmentModeHelp') }}
+
+ +
+ + +
+ +
+ + +
+
+
+
+
+ + +
+

+ +

+
+
+
+ + +
{{ t('parsingEngineHelp') }}
+
+ + +
+
+ +
+ + +
+
+
+ + +
{{ t('modelVersionHelp') }}
+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ + +
+ +
+
+ + +
+
+
+ + +
+ + +
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+
+
+
+ + +
+

+ +

+
+
+
+ + +
+ +
+ + +
+ + +
+
+
+ + +
+ +
+
+
+
+
+ + +
+

+ +

+
+
+
+ + +
+ +
+
+
+ + +
+ + + + + + +
+
+
+ + +
+ + + + + + + +
+ + +
+
+ + +
+ +
+
+
+ + +
+

+ +

+
+
+
+ + +
{{ t('glossaryHelp') }}
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ +
+ + + + +
+
+ +
+ + +
+ + +
+ +
+
+ + + + + + + +
+ + +
+
+ + +
+ +
+ +
+ + + + + + +
+
+
+ + +
+
+ + +
+
+
+
+
+
+
+
+ + +
+ + +
+ + + +
+

GitHub主页(欢迎star❤):
https://github.com/xunbu/docutranslate +

+

交流QQ群: 1047781902

+

version:{{ version ? 'v' + version : '' }}

+
+
+
+ + +
+
+
+

{{ t('taskListTitle') }}

+ +
+
+
+ LOGO +

{{ t('noTaskPlaceholder') }}

+
+
+
+ {{ t('taskCardIdLabel') + }}: {{ task.backendId || t('taskCardIdPlaceholder') }} + +
+
+
+
+ +
+
+ +

{{ t('taskCardFileDrop') }}

+
+
+ +

{{ t('taskCardFileSelected') + }}

+
+
+
+ {{ t('taskCardFilenameLabel') }} {{ task.fileName || task.file.name }} +
+
+
+
{{ t('taskCardLogLabel') }} +
+
+
+ +
+
+ {{ task.statusMessage || t('taskCardStatusWaiting') + }} +
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + +
+
+
+ {{ previewMode === 'bilingual' ? t('preview_bilingual') : t('preview_translatedOnly') }}
+
+ + +
+ + + + + + +
+
+
+
+
{{ t('previewOriginal') }}
+
+
+
+
{{ t('previewTranslated') }}
+
+ +
+
+
+
+
+ + + +
+ + +
+
+ + + + + + + + +