diff --git a/book/metadata-ru.yaml b/book/metadata-ru.yaml new file mode 100644 index 0000000..1b7c068 --- /dev/null +++ b/book/metadata-ru.yaml @@ -0,0 +1,23 @@ +--- +title: "Руководство по Asterisk" +subtitle: "Создаем IP-АТС на Asterisk 22 LTS" +author: "Флавио Е. Гонсалвес" +date: "Второе издание" +lang: ru +documentclass: book +classoption: + - oneside +toc: true +toc-title: "Содержание" +toc-depth: 1 +numbersections: true +geometry: "paperwidth=7.5in,paperheight=9.25in,inner=0.75in,outer=0.5in,top=0.6in,bottom=0.6in" +fontsize: 11pt +colorlinks: true +linkcolor: black +urlcolor: blue +# Front cover (EPUB uses this directly; the PDF embeds it as a full first page via interior.tex) +cover-image: "src/images/cover.png" +# Monospace-friendly code blocks +listings: false +... diff --git a/book/translate/PLAN-ru.md b/book/translate/PLAN-ru.md new file mode 100644 index 0000000..3037fbb --- /dev/null +++ b/book/translate/PLAN-ru.md @@ -0,0 +1,43 @@ +# План перевода — Portuguese (pt) & Spanish (es) + +Статус: **реализовано.** `book/translate/translate.py` переводит главы с помощью Gemini (модель по умолчанию +`gemini-flash-lite-latest` — самый дешёвый вариант; можно изменить через `GEMINI_TRANSLATE_MODEL`), +кэшируя по хешу содержимого. `book/build.sh` собирает язык с `BOOK_LANG=pt|es`. CI переводит и собирает PT/ES на main/tags, +когда установлен секрет репозитория **`GEMINI_API_KEY`**, и прикрепляет их к релизам. + +```bash +python3 book/translate/translate.py --lang ru # -> i18n/ru/chapters/ (cached by hash) +BOOK_LANG=ru bash book/build.sh clean # -> build/asterisk-guide-ru.{pdf,epub,tex} +``` + +Реализует согласованные спецификации: + +## Решения (от автора) + +- **Движок:** перевод выполняет Google **Gemini**, используя **тот же API-ключ**, что уже есть в `.env` (тот, что использует иллюстратор) — +считываем его так же, как `book/illustrate/nanobanana.py`. Никогда не коммить ключ. +- **Модель:** **самая дешевая текстовая модель Gemini** (например, `gemini-2.0-flash-lite` / текущий уровень flash-lite). +Сделайте её настраиваемой константой с умолчанием на самую дешевую доступную. +- **Изображения остаются на английском** — **не** переводите и не пересоздавайте изображения. Ссылки `![alt](../images/NAME)` оставляем как есть, +указывая на те же английские картинки. (Перевод alt-текста по желанию; файлы изображений не трогаем.) +- **Целевые языки:** португальский (pt-BR) и испанский (es). + +## Подход + +1. `book/translate/translate.py` — для каждого `src/chapters/*.md` отправляй Markdown в Gemini со строгим указанием: +переводи только прозаический текст; **не изменяй** блоки кода, встроенный `код`, конфиги, имена опций CLI, +ссылки `![](../images/...)` и структуру Markdown; не переводи технические термины Asterisk (PJSIP, dialplan, `pjsip.conf` и т.д.). +Делай обработку по главам (или по заголовкам), чтобы не превышать лимиты токенов; +кэшируй по хэшу содержимого, чтобы не платить повторно за неизменённые главы. +2. Вывод в `i18n/pt/chapters/` и `i18n/es/chapters/` (одинаковые имена файлов). Иллюстрации берутся из +`src/images/` через `--resource-path`, так что копии изображений для каждого языка не нужны. +3. `book/build.sh` получает параметр `LANG` (по умолчанию `en`); сборка PT/ES делается так же → +`asterisk-guide-pt.{pdf,epub,tex}` и `-es`. Строки передней части/метаданных локализованы. +4. **CI:** расширить `.github/workflows/build-book.yml` с матрицей языков (`[en, pt, es]`); +шаг перевода выполняется только при изменении глав, использует `GEMINI_API_KEY` из **секрета** GitHub Actions, +а перевод на самой дешёвой модели достаточно дешевый, чтобы запускать его для каждого PR. Релизы прикрепляют все три языка. + +## Открытые вопросы по времени реализации +- pt-BR против pt-PT (предположим **pt-BR**). +- Нужно ли также локализовать альтернативный текст для изображений (дешево; сами изображения остаются на английском). +- Глоссарий терминов, которые нужно оставлять на английском (PJSIP, dialplan, channel, trunk, …). \ No newline at end of file diff --git a/book/translate/translate.py b/book/translate/translate.py index cfc09fc..7569c74 100644 --- a/book/translate/translate.py +++ b/book/translate/translate.py @@ -51,7 +51,7 @@ def unmask_code(md, blocks): LLM_API_KEY = os.environ.get("LLM_API_KEY") or os.environ.get("SIPPULSE_API_KEY") # Bearer, optional LLM_REASONING = os.environ.get("LLM_REASONING") # e.g. "low" for gpt-oss; unset for others LANG_NAMES = {"pt": "Brazilian Portuguese (pt-BR)", "es": "Latin American Spanish (es)", - "fr": "French", "de": "German", "it": "Italian", "hi": "Hindi", + "fr": "French", "de": "German", "it": "Italian", "hi": "Hindi", "ru": "Russian", "zh": "Simplified Chinese (Mandarin)", "ja": "Japanese", "ar": "Modern Standard Arabic"} HERE = os.path.dirname(os.path.abspath(__file__))