=encoding utf-8

=head1 NAME

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

=head1 SYNOPSIS

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

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

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

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

=head1 VERSION

Version 0.9918

=head1 DESCRIPTION

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

Если вы хотите перевести обычные текстовые блоки в документе, написанном в стиле pod Perl, используйте команду 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

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

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

    greple -Mxlate -E normalized -E not-normalized

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

=head1 MASKING

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

    --xlate-setopt maskfile=MASKPATTERN

Каждая строка файла `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>. Четыре столбца зарезервированы для работы run-in, поэтому каждая строка может содержать максимум 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<gpt4>: gpt-4.1

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

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

=item * B<gpt5>: gpt-5

=back

=item B<--xlate-labor>

=item B<--xlabor>

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

=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+>

Оригинальный и преобразованный текст печатаются, разделённые одной пустой строкой.

=item B<xtxt>

Для C<space+> также выводится новая строка после преобразованного текста.

=back

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

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

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

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

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

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

Укажите пользовательский запрос, который будет отправлен в движок перевода. Эта опция доступна только при использовании движков ChatGPT (gpt3, gpt4, gpt4o). Вы можете настроить поведение перевода, предоставив конкретные инструкции языковой модели. Если запрос содержит 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)

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

=item B<--xlate-stripe>

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

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

=item B<--xlate-mask>

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

=item B<--match-all>

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

=item B<--lineify-cm>

=item B<--lineify-colon>

В случае форматов C<cm> и C<colon> вывод разбивается и форматируется построчно.

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

=back

=head1 CACHE OPTIONS

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

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

=over 7

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

=over 4

=item C<auto> (Default)

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

=item C<create>

Поддерживать кэш-файл, если он существует.

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

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

=item C<clear>

Поддерживать кэш в любом случае, если целевой файл является обычным файлом.

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

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

=item C<accumulate>

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

=back

=item B<--xlate-update>

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

=back

=head1 COMMAND LINE INTERFACE

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

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

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

Операции Docker обрабатываются скриптом C<xrun>, который также может использоваться как отдельная команда. Скрипт C<xrun> поддерживает конфигурационный файл C<.xrunrc> для постоянных настроек контейнера.

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

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

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

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

=head1 EMACS

Загрузите файл F<xlate.el>, включенный в репозиторий, чтобы использовать команду C<xlate> из редактора Emacs. 

=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

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

=item OPENAI_API_KEY

Установите ваш ключ аутентификации для сервиса DeepL.

=back

=head1 INSTALL

=head2 CPANMINUS

    $ cpanm App::Greple::xlate

=head2 TOOLS

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

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

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

=head1 SEE ALSO

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

L<App::Greple::xlate>

L<App::Greple::xlate::gpt4>

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

=over 2

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

L<App::Greple::xlate::gpt3>

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

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

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

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

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

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

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

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

=item * L<App::Greple>

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

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

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

=item * L<App::sdif>

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

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

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

=back

=head2 ARTICLES

=over 2

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

Модуль Greple B<stripe> используется с опцией B<--xlate-stripe>.

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

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

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

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

=back

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright © 2023-2025 Kazumasa Utashiro.

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

=cut
