=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.0201

=head1 DESCRIPTION

B<Greple> B<xlate> 模块会查找目标文本块，并将其替换为翻译后的文本。目前已实现 DeepL (F<deepl.pm>) 和 GPT-5.5 (F<gpt5.pm>) 模块作为后端引擎。

如果要翻译以 Perl 的 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>

您需要做的不是调用翻译引擎，而是为其工作。准备好要翻译的文本后，它们会被复制到剪贴板。您需要将它们粘贴到表单中，将结果复制到剪贴板，然后点击回车键。

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

指定目标语言。当使用B<DeepL>引擎时，你可以通过C<deepl languages>命令获得可用语言。

=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<space+>，它还会在转换后的文本后输出一个换行符。

=item B<xtxt>

如果格式是C<xtxt>（翻译文本）或不知道，则只打印翻译文本。

=back

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

指定一次发送到 API 的最大文本长度。默认值与 DeepL 免费账户服务一样：API (B<--xlate>) 为 128K，剪贴板界面 (B<--xlate-labor>) 为 5000。如果使用专业版服务，您可以更改这些值。

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

指定一次发送到 API 的最大文本行数。

如果想一次翻译一行，则将该值设为 1。该选项优先于 C<--xlate-maxlen> 选项。

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

指定要发送给翻译引擎的自定义提示词。此选项仅在使用 ChatGPT 引擎（gpt3、gpt4o、gpt5）时可用。 您可以通过向AI模型提供具体指令来定制翻译行为。如果提示词中包含C<%s>，它将被替换为目标语言名称。

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

指定要发送给翻译引擎的其他上下文信息。此选项可多次使用，以提供多个上下文字符串。上下文信息有助于翻译引擎理解背景并生成更准确的翻译。

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

指定用于翻译的词汇表 ID。该选项仅在使用 DeepL 引擎时可用。词汇表 ID 应从您的 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> man 页。

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> 配置文件。

此外，由于提供了各种文档样式的 makefile，因此无需特别说明即可翻译成其他语言。使用 C<-M> 选项。

你还可以把 Docker 和 C<make> 选项结合起来，这样就能在 Docker 环境中运行 C<make>。

像 C<xlate -C> 这样运行，会启动一个挂载了当前工作 git 仓库的 shell。

详情请阅读 L</SEE ALSO> 部分的日文文章。

=head1 EMACS

加载存储库中的F<xlate.el>文件，从Emacs编辑器中使用C<xlate>命令。C<xlate-region>函数翻译给定的区域。默认的语言是C<EN-US>，你可以用前缀参数指定调用语言。

=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> - xlate 用于容器操作的通用 Docker 运行程序

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

通过 B<--xlate-stripe> 选项查看 B<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>

使用 DeepL API（日语）翻译并仅替换必要部分的 Greple 模块

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

利用 DeepL API 模块生成 15 种语言的文档（日语）

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

利用 DeepL API 自动翻译 Docker 环境（日语）

=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
