=encoding utf-8

=head1 NAME

App::Greple::xlate - модуль поддержки перевода для greple

=head1 SYNOPSIS

    greple -Mxlate::deepl --xlate pattern target-file

    greple -Mxlate::gpt5 --xlate pattern target-file

    greple -Mxlate --xlate-engine gpt5 --xlate pattern target-file

=head1 VERSION

Version 1.0202

=head1 DESCRIPTION

B<Greple> B<xlate> модуль находит нужные текстовые блоки и заменяет их переведённым текстом. В настоящее время в качестве бэкэнд-движка реализованы модули DeepL (F<deepl.pm>) и GPT-5.5 (F<gpt5.pm>).

Если вы хотите перевести обычные текстовые блоки в документе, написанном в стиле Perl's pod, используйте команду B<greple> с модулем C<xlate::deepl> и C<perl> следующим образом:

    greple -Mxlate::deepl -Mperl --pod --re '^([\w\pP].*\n)+' --all foo.pm

В этой команде шаблонная строка C<^([\w\pP].*\n)+> означает последовательные строки, начинающиеся с букв алфавитно-цифрового ряда и знаков препинания. Эта команда показывает область, которую нужно перевести, выделенной. Опция B<--all> используется для перевода всего текста.

=for html <p>
<img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/App-Greple-xlate/main/images/select-area.png">
</p>

Затем добавьте опцию C<--xlate> для перевода выделенной области. После этого программа найдет нужные участки и заменит их выводом команды B<--deepl>.

По умолчанию оригинальный и транслированный текст печатается в формате "маркер конфликта", совместимом с L<git(1)>. Используя формат C<ifdef>, можно легко получить нужную часть командой L<unifdef(1)>. Выходной формат может быть задан опцией B<--xlate-format>.

=for html <p>
<img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/App-Greple-xlate/main/images/format-conflict.png">
</p>

Если требуется перевести весь текст, используйте опцию B<--match-all>. Это сокращение для указания шаблона C<(?s).+>, который соответствует всему тексту.

Данные в формате конфликтных маркеров можно просматривать в стиле "бок о бок" с помощью команды L<sdif|App::sdif> с опцией C<-V>. Поскольку сравнивать по каждой строке не имеет смысла, рекомендуется использовать опцию C<--no-cdif>. Если вам не нужно окрашивать текст, укажите C<--no-textcolor> (или C<--no-tc>).

    sdif -V --no-filename --no-tc --no-cdif data_shishin.deepl-EN-US.cm

=for html <p>
<img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/App-Greple-xlate/main/images/sdif-cm-view.png">
</p>

=head1 NORMALIZATION

Обработка выполняется в заданных единицах, но в случае последовательности из нескольких строк непустого текста они преобразуются в одну строку. Эта операция выполняется следующим образом:

=over 2

=item *

Удалите пробелы в начале и конце каждой строки.

=item *

Если строка заканчивается полноразмерным символом препинания, объедините ее со следующей строкой.

=item *

Если строка заканчивается символом полной ширины и следующая строка начинается символом полной ширины, объедините строки.

=item *

Если конец или начало строки не являются символами полной ширины, объедините их, вставив символ пробела.

=back

Кэш-данные управляются на основе нормализованного текста, поэтому даже если будут внесены изменения, не влияющие на результаты нормализации, кэшированные данные перевода будут по-прежнему эффективны.

Этот процесс нормализации выполняется только для первого (0-го) и четного шаблона. Таким образом, если два шаблона указаны следующим образом, то текст, соответствующий первому шаблону, будет обработан после нормализации, а для текста, соответствующего второму шаблону, процесс нормализации не будет выполняться.

    greple -Mxlate -E normalized -E not-normalized

Поэтому используйте первый шаблон для текста, который должен быть обработан путем объединения нескольких строк в одну, а второй - для предварительно отформатированного текста. Если в первом шаблоне нет текста для проверки, используйте шаблон, который ничему не соответствует, например C<(?!)>.

=head1 MASKING

Иногда встречаются части текста, которые не нужно переводить. Например, теги в файлах формата markdown. На сайте DeepL предлагается в таких случаях преобразовывать исключаемые части текста в XML-теги, переводить их, а затем восстанавливать после завершения перевода. Чтобы поддержать эту идею, можно указать части, которые нужно замаскировать от перевода.

    --xlate-setopt maskfile=MASKPATTERN

Это будет интерпретировать каждую строку файла C<MASKPATTERN> как регулярное выражение, переводить строку, соответствующую ему, и возвращать после обработки. Строки, начинающиеся с C<#>, игнорируются.

Сложный шаблон может быть записан в нескольких строках с обратным слешем, сопровождаемым новой строкой.

Как текст преобразуется при маскировании, можно увидеть с помощью опции B<--xlate-mask>.

Этот интерфейс является экспериментальным и может быть изменен в будущем.

=head1 OPTIONS

=over 7

=item B<--xlate>

=item B<--xlate-color>

=item B<--xlate-fold>

=item B<--xlate-fold-width>=I<n> (Default: 70)

Запустите процесс перевода для каждой совпавшей области.

Без этой опции B<greple> ведет себя как обычная команда поиска. Таким образом, вы можете проверить, какая часть файла будет подвергнута переводу, прежде чем вызывать фактическую работу.

Результат команды выводится в стандартный аут, поэтому при необходимости перенаправьте его в файл или воспользуйтесь модулем L<App::Greple::update>.

Опция B<--xlate> вызывает опцию B<--xlate-color> с опцией B<--color=never>.

С опцией B<--xlate-fold> преобразованный текст сворачивается на указанную ширину. Ширина по умолчанию равна 70 и может быть задана опцией B<--xlate-fold-width>. Для обкатки зарезервировано четыре колонки, поэтому в каждой строке может содержаться не более 74 символов.

=item B<--xlate-engine>=I<engine>

Определяет используемый движок перевода. Если вы указываете модуль движка напрямую, например C<-Mxlate::deepl>, то этот параметр использовать не нужно.

На данный момент доступны следующие движки

=over 2

=item * B<deepl>: DeepL API

=item * B<gpt3>: gpt-3.5-turbo

=item * B<gpt4o>: gpt-4o-mini

Интерфейс B<gpt-4o> нестабилен и в настоящее время не может быть гарантированно корректной работы.

=item * B<gpt5>: gpt-5.5

=back

=item B<--xlate-labor>

=item B<--xlabor>

Вместо того чтобы вызывать механизм перевода, вы должны работать на него. После подготовки текста для перевода он копируется в буфер обмена. Вы должны вставить их в форму, скопировать результат в буфер обмена и нажать кнопку return.

=item B<--xlate-to> (Default: C<EN-US>)

Укажите целевой язык. Вы можете получить доступные языки с помощью команды C<deepl languages> при использовании движка B<DeepL>.

=item B<--xlate-format>=I<format> (Default: C<conflict>)

Укажите формат вывода оригинального и переведенного текста.

Следующие форматы, кроме C<xtxt>, предполагают, что переводимая часть представляет собой набор строк. На самом деле можно перевести только часть строки, но указание формата, отличного от C<xtxt>, не даст значимых результатов.

=over 4

=item B<conflict>, B<cm>

Оригинальный и преобразованный текст печатаются в формате L<git(1)> маркеров конфликтов.

    <<<<<<< ORIGINAL
    original text
    =======
    translated Japanese text
    >>>>>>> JA

Вы можете восстановить исходный файл следующей командой L<sed(1)>.

    sed -e '/^<<<<<<< /d' -e '/^=======$/,/^>>>>>>> /d'

=item B<colon>, I<:::::::>

Оригинальный и переведенный текст выводятся в пользовательском стиле контейнера markdown.

    ::::::: ORIGINAL
    original text
    :::::::
    ::::::: JA
    translated Japanese text
    :::::::

Приведенный выше текст будет переведен в HTML следующим образом.

    <div class="ORIGINAL">
    original text
    </div>
    <div class="JA">
    translated Japanese text
    </div>

Количество двоеточий по умолчанию равно 7. Если вы укажете последовательность двоеточий, например C<:::::>, то она будет использоваться вместо 7 двоеточий.

=item B<ifdef>

Оригинальный и преобразованный текст печатаются в формате L<cpp(1)> C<#ifdef>.

    #ifdef ORIGINAL
    original text
    #endif
    #ifdef JA
    translated Japanese text
    #endif

Вы можете восстановить только японский текст командой B<unifdef>:

    unifdef -UORIGINAL -DJA foo.ja.pm

=item B<space>

=item B<space+>

Оригинальный и преобразованный текст выводятся на печать, разделенные одной пустой строкой. Для C<пробел+> после преобразованного текста также выводится новая строка.

=item B<xtxt>

Если формат C<xtxt> (переведенный текст) или неизвестен, печатается только переведенный текст.

=back

=item B<--xlate-maxlen>=I<chars> (Default: 0)

Укажите максимальную длину текста, передаваемого в API за один раз. По умолчанию установлено значение, как для бесплатного сервиса DeepL: 128К для API (B<--xlate>) и 5000 для интерфейса буфера обмена (B<--xlate-labor>). Вы можете изменить эти значения, если используете услугу Pro.

=item B<--xlate-maxline>=I<n> (Default: 0)

Укажите максимальное количество строк текста, которое будет отправлено в API за один раз.

Установите значение 1, если вы хотите переводить по одной строке за раз. Этот параметр имеет приоритет перед параметром C<--xlate-maxlen>.

=item B<--xlate-prompt>=I<text>

Укажите пользовательский запрос, который будет отправлен в механизм перевода. Эта опция доступна только при использовании механизмов ChatGPT (gpt3, gpt4o, gpt5). Вы можете настроить поведение перевода, предоставив конкретные инструкции модели ИИ. Если запрос содержит C<%s>, он будет заменен на название целевого языка.

=item B<--xlate-context>=I<text>

Укажите дополнительную контекстную информацию, которая будет отправлена механизму перевода. Этот параметр можно использовать несколько раз, чтобы указать несколько контекстных строк. Контекстная информация помогает механизму перевода понять фон и создать более точный перевод.

=item B<--xlate-glossary>=I<glossary>

Укажите идентификатор глоссария, который будет использоваться при переводе. Этот параметр доступен только при использовании механизма DeepL. Идентификатор глоссария должен быть получен из учетной записи DeepL и обеспечивает последовательный перевод специфических терминов.

=item B<-->[B<no->]B<xlate-progress> (Default: True)

Результат перевода можно увидеть в реальном времени в выводе STDERR.

=item B<--xlate-stripe>

Используйте модуль L<App::Greple::stripe>, чтобы показать совпадающие части в виде полосок зебры. Это удобно, когда совпадающие части соединены встык.

Цветовая палитра переключается в соответствии с цветом фона терминала. Если вы хотите указать его явно, можно использовать B<--xlate-stripe-light> или B<--xlate-stripe-dark>.

=item B<--xlate-mask>

Выполните функцию маскирования и отобразите преобразованный текст как есть, без восстановления.

=item B<--match-all>

Установите весь текст файла в качестве целевой области.

=item B<--lineify-cm>

=item B<--lineify-colon>

В случае форматов C<cm> и C<colon> вывод разбивается и форматируется построчно. Поэтому, если перевести только часть строки, ожидаемый результат не будет получен. Эти фильтры исправляют вывод, испорченный переводом части строки в обычный построчный вывод.

В текущей реализации, если переводится несколько частей строки, они выводятся как независимые строки.

=back

=head1 CACHE OPTIONS

Модуль B<xlate> может хранить кэшированный текст перевода для каждого файла и считывать его перед выполнением, чтобы исключить накладные расходы на запрос к серверу. При стратегии кэширования по умолчанию C<auto>, он сохраняет данные кэша только тогда, когда файл кэша существует для целевого файла.

Используйте B<--xlate-cache=clear>, чтобы запустить управление кэшем или очистить все существующие данные кэша. После выполнения этой опции будет создан новый файл кэша, если он не существует, а затем он будет автоматически поддерживаться.

=over 7

=item --xlate-cache=I<strategy>

=over 4

=item C<auto> (Default)

Сохранять файл кэша, если он существует.

=item C<create>

Создать пустой файл кэша и выйти.

=item C<always>, C<yes>, C<1>

Сохранять кэш в любом случае, пока целевой файл является обычным файлом.

=item C<clear>

Сначала очистите данные кэша.

=item C<never>, C<no>, C<0>

Никогда не использовать файл кэша, даже если он существует.

=item C<accumulate>

По умолчанию неиспользуемые данные удаляются из файла кэша. Если вы не хотите удалять их и сохранять в файле, используйте C<accumulate>.

=back

=item B<--xlate-update>

Эта опция заставляет обновлять файл кэша, даже если в этом нет необходимости.

=back

=head1 COMMAND LINE INTERFACE

Вы можете легко использовать этот модуль из командной строки с помощью команды C<xlate>, входящей в дистрибутив. Информацию об использовании см. на странице руководства C<xlate>.

Команда C<xlate> поддерживает длинные опции в стиле GNU, такие как C<--to-lang>, C<--from-lang>, C<--engine> и C<--file>. Используйте C<xlate -h>, чтобы увидеть все доступные опции.

Команда C<xlate> работает совместно со средой Docker, поэтому даже если у вас ничего не установлено, вы можете использовать ее, пока доступен Docker. Используйте опцию C<-D> или C<-C>.

Операции Docker выполняются командой L<App::dozo>, которая также может использоваться как отдельная команда. Команда C<dozo> поддерживает конфигурационный файл C<.dozorc> для постоянных настроек контейнера.

Кроме того, поскольку в комплекте поставляются make-файлы для различных стилей документов, перевод на другие языки возможен без специальных уточнений. Используйте опцию C<-M>.

Вы также можете комбинировать опции Docker и C<make>, чтобы запустить C<make> в среде Docker.

Выполнение C<xlate -C> запустит оболочку с подключенным текущим рабочим git-репозиторием.

Подробности читайте в японской статье в разделе L</SEE ALSO>.

=head1 EMACS

Загрузите файл F<xlate.el>, включенный в репозиторий, чтобы использовать команду C<xlate> из редактора Emacs. Функция C<xlate-region> переводит заданный регион. Язык по умолчанию - C<EN-US>, и вы можете указать язык, вызывая ее с помощью аргумента prefix.

=for html <p>
<img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/App-Greple-xlate/main/images/emacs.png">
</p>

=head1 ENVIRONMENT

=over 7

=item DEEPL_AUTH_KEY

Задайте ключ аутентификации для сервиса DeepL.

=item OPENAI_API_KEY

Ключ аутентификации OpenAI.

=back

=head1 INSTALL

=head2 CPANMINUS

    $ cpanm App::Greple::xlate

=head2 TOOLS

Необходимо установить инструменты командной строки для DeepL и ChatGPT.

L<https://github.com/DeepLcom/deepl-python>

L<https://github.com/tecolicom/App-gpty>

=head1 SEE ALSO

=head2 MODULES

L<App::Greple::xlate::deepl>, L<App::Greple::xlate::gpt5>

L<App::dozo> - общий Docker runner, используемый xlate для операций с контейнерами.

=head2 RELATED MODULES

=over 2

=item * L<App::Greple>

Подробную информацию о шаблоне целевого текста см. в руководстве B<greple>. Используйте опции B<--inside>, B<--outside>, B<--include>, B<--exclude> для ограничения области совпадения.

=item * L<App::Greple::update>

Вы можете использовать модуль C<-Mupdate> для модификации файлов по результатам команды B<greple>.

=item * L<App::sdif>

Используйте B<sdif>, чтобы показать формат маркера конфликта бок о бок с опцией B<-V>.

=item * L<App::Greple::stripe>

Использование модуля Greple B<stripe> с помощью опции B<--xlate-stripe>.

=back

=head2 RESOURCES

=over 2

=item * L<https://hub.docker.com/r/tecolicom/xlate>

Образ контейнера Docker.

=item * L<https://github.com/tecolicom/getoptlong>

Библиотека C<getoptlong.sh> используется для разбора опций в скрипте C<xlate> и L<App::dozo>.

=item * L<https://github.com/DeepLcom/deepl-python>

DeepL Библиотека Python и команда CLI.

=item * L<https://github.com/openai/openai-python>

Библиотека OpenAI Python

=item * L<https://github.com/tecolicom/App-gpty>

Интерфейс командной строки OpenAI

=back

=head2 ARTICLES

=over 2

=item * L<https://qiita.com/kaz-utashiro/items/1c1a51a4591922e18250>

Модуль Greple для перевода и замены только необходимых частей с помощью DeepL API (на японском языке)

=item * L<https://qiita.com/kaz-utashiro/items/a5e19736416ca183ecf6>

Генерация документов на 15 языках с помощью модуля DeepL API (на японском языке)

=item * L<https://qiita.com/kaz-utashiro/items/1b9e155d6ae0620ab4dd>

Автоматический перевод Docker-окружения с помощью DeepL API (на японском языке)

=back

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright © 2023-2026 Kazumasa Utashiro.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
