add multilanguage support

This commit is contained in:
hanyixuanten
2026-07-28 14:51:36 +08:00
parent 37abe27ebd
commit 085d7d1ffb
12 changed files with 480 additions and 40 deletions
+2
View File
@@ -36,6 +36,7 @@ jobs:
cp btranslate.php uninstall.php readme.txt readme-zh_CN.txt LICENSE "build/${plugin_slug}/"
cp -R includes "build/${plugin_slug}/"
cp -R assets "build/${plugin_slug}/"
cp -R languages "build/${plugin_slug}/"
(
cd build
zip -qr "../${archive_name}" "${plugin_slug}"
@@ -44,6 +45,7 @@ jobs:
unzip -p "${archive_name}" "${plugin_slug}/btranslate.php" | grep -q '^ \* Plugin Name: Btranslate$'
unzip -p "${archive_name}" "${plugin_slug}/readme.txt" | grep -q "^Stable tag: ${version}$"
unzip -p "${archive_name}" "${plugin_slug}/readme-zh_CN.txt" | grep -q "^Stable tag: ${version}$"
unzip -Z1 "${archive_name}" | grep -q "^${plugin_slug}/languages/btranslate-zh_CN.mo$"
! unzip -Z1 "${archive_name}" | grep -Eq '/README(\.zh-CN)?\.md$'
printf 'archive=%s\n' "${archive_name}" >> "$GITHUB_OUTPUT"
+1
View File
@@ -44,6 +44,7 @@ Unless a user explicitly requests a refresh, each translatable value must be tra
- Add focused tests for language selection, routing, translation cache reuse and invalidation, persistence, provider signing/error handling, and content/meta filtering.
- Mock Baidu API calls in every test. Tests must not require live credentials or outbound network access.
- Keep changes narrow and avoid unrelated refactors or formatting churn.
- After every file change, review `.github/workflows/package-plugin.yml` and ensure the automated packaging Action includes all runtime files required by the change. Validate the packaging commands locally when practical.
- Plugin slug and PHP prefix: `btranslate` and `btranslate_`/`BTRANSLATE_`. The current minimum supported PHP version is 8.1 and the current minimum WordPress version is 6.4.
- The repository has no Composer-managed development dependencies or bundled automated test suite. Validate PHP syntax with `find . -path './.git' -prune -o -type f -name '*.php' -print0 | xargs -0 -n1 php -l`. Any future automated tests must mock WordPress API calls and must not require live credentials, external network access, or a WordPress database.
- Document supported languages, routing modes, data retention, translation lifecycle, and known limitations in the README whenever the implementation changes.
+2
View File
@@ -4,6 +4,8 @@
Btranslate is a WordPress plugin skeleton for persistent multilingual content using the Baidu Translate API.
The WordPress admin interface follows the current WordPress locale. English is the default, and a bundled Simplified Chinese translation is used when WordPress is set to `zh_CN`.
## Requirements
- WordPress 6.4 or later.
+2
View File
@@ -4,6 +4,8 @@
Btranslate 是一个 WordPress 插件骨架,使用百度翻译 API 持久化管理多语言内容。
WordPress 后台界面会跟随当前 WordPress 语言:默认显示英文,WordPress 设为 `zh_CN` 时使用插件内置的简体中文翻译。
## 要求
- WordPress 6.4 或更高版本。
+9 -3
View File
@@ -27,12 +27,18 @@
parent.appendChild(document.createTextNode(text));
}
function format(template, values) {
return template.replace(/%([1-9]\d*)\$s/g, function (match, position) {
return values[Number(position) - 1];
});
}
function renderProgress(progress) {
var summary = document.createElement('p');
var percent = document.createElement('strong');
percent.textContent = progress.percent + '%';
summary.appendChild(percent);
appendText(summary, '' + progress.completed + ' / ' + progress.total + ' 个内容项)');
appendText(summary, ' ' + format(btranslateAdmin.i18n.contentItems, [progress.completed, progress.total]));
var progressBar = document.createElement('div');
progressBar.style.cssText = 'max-width:480px;height:12px;background:#dcdcde';
@@ -43,14 +49,14 @@
var description = document.createElement('p');
description.className = 'description';
description.textContent = '最近任务:' + progress.task_label + '。文章和页面:' + progress.posts_completed + ' / ' + progress.posts_total + ';分类和标签:' + progress.terms_completed + ' / ' + progress.terms_total + '。每 5 秒自动更新。';
description.textContent = format(btranslateAdmin.i18n.latestTask, [progress.task_label, progress.posts_completed, progress.posts_total, progress.terms_completed, progress.terms_total]);
container.replaceChildren(summary, progressBar, description);
}
function renderProgressError() {
var message = document.createElement('p');
message.textContent = '暂时无法读取翻译进度。';
message.textContent = btranslateAdmin.i18n.progressError;
container.replaceChildren(message);
}
+6
View File
@@ -9,6 +9,7 @@
* License: GPL-3.0-only
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
* Text Domain: btranslate
* Domain Path: /languages
*/
defined( 'ABSPATH' ) || exit;
@@ -35,4 +36,9 @@ require_once BTRANSLATE_PATH . 'includes/class-btranslate-uninstaller.php';
register_activation_hook( BTRANSLATE_FILE, array( 'BTRANSLATE_Plugin', 'activate' ) );
register_deactivation_hook( BTRANSLATE_FILE, array( 'BTRANSLATE_Plugin', 'deactivate' ) );
function btranslate_load_textdomain() {
load_plugin_textdomain( 'btranslate', false, dirname( plugin_basename( BTRANSLATE_FILE ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'btranslate_load_textdomain', 5 );
add_action( 'plugins_loaded', array( 'BTRANSLATE_Plugin', 'instance' ) );
+42 -37
View File
@@ -44,6 +44,11 @@ class BTRANSLATE_Admin {
array(
'progressUrl' => admin_url( 'admin-ajax.php' ),
'progressNonce' => wp_create_nonce( 'btranslate_translation_progress' ),
'i18n' => array(
'contentItems' => __( '(%1$s / %2$s content items)', 'btranslate' ),
'latestTask' => __( 'Latest task: %1$s. Posts and pages: %2$s / %3$s; categories and tags: %4$s / %5$s. Updates automatically every 5 seconds.', 'btranslate' ),
'progressError' => __( 'Unable to load translation progress at this time.', 'btranslate' ),
),
)
);
}
@@ -87,49 +92,49 @@ class BTRANSLATE_Admin {
<form action="options.php" method="post">
<?php settings_fields( 'btranslate_settings' ); ?>
<table class="form-table" role="presentation">
<tr><th scope="row"><label for="btranslate-source-language">源语言</label></th><td><input id="btranslate-source-language" name="btranslate_settings[source_language]" type="text" value="<?php echo esc_attr( $settings['source_language'] ); ?>" /><p class="description">使用百度翻译语言代码,例如 <code>zh</code>。</p></td></tr>
<tr><th scope="row"><label for="btranslate-target-languages">目标语言</label></th><td><input id="btranslate-target-languages" name="btranslate_settings[target_languages]" type="text" value="<?php echo esc_attr( implode( ',', $settings['target_languages'] ) ); ?>" class="regular-text" /><p class="description">多个语言代码用英文逗号分隔,例如 <code>en,ja</code>。</p></td></tr>
<tr><th scope="row">网址模式</th><td><fieldset id="btranslate-routing-mode"><label><input type="checkbox" name="btranslate_settings[routing_mode][]" value="subdirectory" <?php checked( in_array( 'subdirectory', $settings['routing_mode'], true ) ); ?> /> 子目录</label><br /><label><input type="checkbox" name="btranslate_settings[routing_mode][]" value="domain" <?php checked( in_array( 'domain', $settings['routing_mode'], true ) ); ?> /> 子域名</label></fieldset></td></tr>
<tr id="btranslate-domain-bindings-row"<?php echo in_array( 'domain', $settings['routing_mode'], true ) ? '' : ' style="display:none"'; ?>><th scope="row"><label for="btranslate-domain-bindings">域名绑定</label></th><td><textarea id="btranslate-domain-bindings" name="btranslate_settings[domain_bindings]" rows="4" class="large-text" placeholder="en.example.com=en"><?php echo esc_textarea( implode( "\n", $bindings ) ); ?></textarea><p class="description">每行一个 <code>域名=语言代码</code>,例如 <code>en.example.com=en</code>。请勿填写 <code>https://</code>、路径或端口。</p></td></tr>
<tr><th scope="row"><label for="btranslate-baidu-app-id">百度应用 ID</label></th><td><input id="btranslate-baidu-app-id" name="btranslate_settings[baidu_app_id]" type="text" value="<?php echo esc_attr( $settings['baidu_app_id'] ); ?>" class="regular-text" /></td></tr>
<tr><th scope="row"><label for="btranslate-baidu-secret-key">百度密钥</label></th><td><input id="btranslate-baidu-secret-key" name="btranslate_settings[baidu_secret_key]" type="password" value="<?php echo esc_attr( $settings['baidu_secret_key'] ); ?>" class="regular-text" autocomplete="new-password" /></td></tr>
<tr><th scope="row">请求日志</th><td><label for="btranslate-log-requests"><input id="btranslate-log-requests" name="btranslate_settings[log_requests]" type="checkbox" value="1" <?php checked( $settings['log_requests'] ); ?> /> 记录每次百度翻译请求</label><p class="description">启用后触发 <code>btranslate_translation_request_logged</code> 操作,提供语言、字段、文本指纹、长度和结果状态;不会提供密钥、原文、译文或完整 API 响应。</p></td></tr>
<tr><th scope="row"><label for="btranslate-source-language"><?php esc_html_e( 'Source language', 'btranslate' ); ?></label></th><td><input id="btranslate-source-language" name="btranslate_settings[source_language]" type="text" value="<?php echo esc_attr( $settings['source_language'] ); ?>" /><p class="description"><?php esc_html_e( 'Use a Baidu Translate language code, for example zh.', 'btranslate' ); ?></p></td></tr>
<tr><th scope="row"><label for="btranslate-target-languages"><?php esc_html_e( 'Target languages', 'btranslate' ); ?></label></th><td><input id="btranslate-target-languages" name="btranslate_settings[target_languages]" type="text" value="<?php echo esc_attr( implode( ',', $settings['target_languages'] ) ); ?>" class="regular-text" /><p class="description"><?php esc_html_e( 'Separate multiple language codes with commas, for example en,ja.', 'btranslate' ); ?></p></td></tr>
<tr><th scope="row"><?php esc_html_e( 'URL mode', 'btranslate' ); ?></th><td><fieldset id="btranslate-routing-mode"><label><input type="checkbox" name="btranslate_settings[routing_mode][]" value="subdirectory" <?php checked( in_array( 'subdirectory', $settings['routing_mode'], true ) ); ?> /> <?php esc_html_e( 'Subdirectory', 'btranslate' ); ?></label><br /><label><input type="checkbox" name="btranslate_settings[routing_mode][]" value="domain" <?php checked( in_array( 'domain', $settings['routing_mode'], true ) ); ?> /> <?php esc_html_e( 'Domain', 'btranslate' ); ?></label></fieldset></td></tr>
<tr id="btranslate-domain-bindings-row"<?php echo in_array( 'domain', $settings['routing_mode'], true ) ? '' : ' style="display:none"'; ?>><th scope="row"><label for="btranslate-domain-bindings"><?php esc_html_e( 'Domain bindings', 'btranslate' ); ?></label></th><td><textarea id="btranslate-domain-bindings" name="btranslate_settings[domain_bindings]" rows="4" class="large-text" placeholder="en.example.com=en"><?php echo esc_textarea( implode( "\n", $bindings ) ); ?></textarea><p class="description"><?php esc_html_e( 'Enter one domain=language code pair per line, for example en.example.com=en. Do not include https://, a path, or a port.', 'btranslate' ); ?></p></td></tr>
<tr><th scope="row"><label for="btranslate-baidu-app-id"><?php esc_html_e( 'Baidu application ID', 'btranslate' ); ?></label></th><td><input id="btranslate-baidu-app-id" name="btranslate_settings[baidu_app_id]" type="text" value="<?php echo esc_attr( $settings['baidu_app_id'] ); ?>" class="regular-text" /></td></tr>
<tr><th scope="row"><label for="btranslate-baidu-secret-key"><?php esc_html_e( 'Baidu secret key', 'btranslate' ); ?></label></th><td><input id="btranslate-baidu-secret-key" name="btranslate_settings[baidu_secret_key]" type="password" value="<?php echo esc_attr( $settings['baidu_secret_key'] ); ?>" class="regular-text" autocomplete="new-password" /></td></tr>
<tr><th scope="row"><?php esc_html_e( 'Request logging', 'btranslate' ); ?></th><td><label for="btranslate-log-requests"><input id="btranslate-log-requests" name="btranslate_settings[log_requests]" type="checkbox" value="1" <?php checked( $settings['log_requests'] ); ?> /> <?php esc_html_e( 'Log each Baidu Translate request', 'btranslate' ); ?></label><p class="description"><?php esc_html_e( 'When enabled, fires the btranslate_translation_request_logged action with the language, field, text fingerprint, length, and result status. Credentials, source text, translated text, and full API responses are never included.', 'btranslate' ); ?></p></td></tr>
</table>
<?php submit_button(); ?>
</form>
<hr />
<h2>重新翻译所有内容</h2>
<p>此操作会将所有已发布文章、页面、分类和标签重新加入翻译队列。</p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" data-btranslate-confirm="这将重新翻译所有内容,请注意 API 消耗。确认继续吗?">
<h2><?php esc_html_e( 'Retranslate content', 'btranslate' ); ?></h2>
<p><?php esc_html_e( 'Queue all published posts, pages, categories, and tags for translation again.', 'btranslate' ); ?></p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" data-btranslate-confirm="<?php echo esc_attr__( 'This will retranslate all content and use your API quota. Continue?', 'btranslate' ); ?>">
<input type="hidden" name="action" value="btranslate_queue_existing_translations" />
<?php wp_nonce_field( 'btranslate_queue_existing_translations' ); ?>
<?php submit_button( '重新翻译所有内容', 'secondary', 'submit', false ); ?>
<?php submit_button( __( 'Retranslate all content', 'btranslate' ), 'secondary', 'submit', false ); ?>
</form>
<p>也可以只重新翻译一种内容类型。</p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" style="display:inline-block;margin-right:8px" data-btranslate-confirm="这将重新翻译所有文章和页面,请注意 API 消耗。确认继续吗?">
<p><?php esc_html_e( 'You can also retranslate a single content type.', 'btranslate' ); ?></p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" style="display:inline-block;margin-right:8px" data-btranslate-confirm="<?php echo esc_attr__( 'This will retranslate all posts and pages and use your API quota. Continue?', 'btranslate' ); ?>">
<input type="hidden" name="action" value="btranslate_queue_existing_translations" />
<input type="hidden" name="scope" value="posts" />
<?php wp_nonce_field( 'btranslate_queue_existing_translations' ); ?>
<?php submit_button( '翻译所有文章', 'secondary', 'submit', false ); ?>
<?php submit_button( __( 'Translate all posts', 'btranslate' ), 'secondary', 'submit', false ); ?>
</form>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" style="display:inline-block" data-btranslate-confirm="这将重新翻译所有分类和标签,请注意 API 消耗。确认继续吗?">
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" style="display:inline-block" data-btranslate-confirm="<?php echo esc_attr__( 'This will retranslate all categories and tags and use your API quota. Continue?', 'btranslate' ); ?>">
<input type="hidden" name="action" value="btranslate_queue_existing_translations" />
<input type="hidden" name="scope" value="terms" />
<?php wp_nonce_field( 'btranslate_queue_existing_translations' ); ?>
<?php submit_button( '翻译所有分类标签', 'secondary', 'submit', false ); ?>
<?php submit_button( __( 'Translate all categories and tags', 'btranslate' ), 'secondary', 'submit', false ); ?>
</form>
<hr />
<h2>翻译缓存</h2>
<p>清除后,前台会暂时显示源文;重新翻译时将再次调用百度翻译 API。</p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" data-btranslate-confirm="这将删除所有已保存的翻译、取消待执行翻译任务并重置进度。确认继续吗?">
<h2><?php esc_html_e( 'Translation cache', 'btranslate' ); ?></h2>
<p><?php esc_html_e( 'After clearing the cache, the front end temporarily displays source content. Baidu Translate API calls resume when content is translated again.', 'btranslate' ); ?></p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" data-btranslate-confirm="<?php echo esc_attr__( 'This will delete all saved translations, cancel pending translation tasks, and reset progress. Continue?', 'btranslate' ); ?>">
<input type="hidden" name="action" value="btranslate_clear_translation_cache" />
<?php wp_nonce_field( 'btranslate_clear_translation_cache' ); ?>
<?php submit_button( '清除已翻译的缓存', 'delete', 'submit', false ); ?>
<?php submit_button( __( 'Clear translation cache', 'btranslate' ), 'delete', 'submit', false ); ?>
</form>
<hr />
<h2>翻译进度</h2>
<h2><?php esc_html_e( 'Translation progress', 'btranslate' ); ?></h2>
<div id="btranslate-translation-progress" aria-live="polite">
<p>正在读取翻译进度...</p>
<p><?php esc_html_e( 'Loading translation progress...', 'btranslate' ); ?></p>
</div>
</div>
<?php
@@ -137,13 +142,13 @@ class BTRANSLATE_Admin {
public function queue_existing_translations() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( '您没有执行此操作的权限。' );
wp_die( esc_html__( 'You do not have permission to perform this action.', 'btranslate' ) );
}
check_admin_referer( 'btranslate_queue_existing_translations' );
$scope = isset( $_POST['scope'] ) ? sanitize_key( wp_unslash( $_POST['scope'] ) ) : 'all';
if ( ! in_array( $scope, array( 'all', 'posts', 'terms' ), true ) ) {
wp_die( '无效的翻译范围。' );
wp_die( esc_html__( 'Invalid translation scope.', 'btranslate' ) );
}
$scheduled = 0;
@@ -203,14 +208,14 @@ class BTRANSLATE_Admin {
public function clear_translation_cache() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( '您没有执行此操作的权限。' );
wp_die( esc_html__( 'You do not have permission to perform this action.', 'btranslate' ) );
}
check_admin_referer( 'btranslate_clear_translation_cache' );
$deleted = ( new BTRANSLATE_Translation_Store() )->clear();
if ( false === $deleted ) {
wp_die( '翻译缓存清除失败。' );
wp_die( esc_html__( 'Failed to clear the translation cache.', 'btranslate' ) );
}
wp_clear_scheduled_hook( 'btranslate_process_translation' );
@@ -230,7 +235,7 @@ class BTRANSLATE_Admin {
}
public function add_plugin_settings_link( $links ) {
array_unshift( $links, '<a href="' . esc_url( admin_url( 'options-general.php?page=btranslate' ) ) . '">设置</a>' );
array_unshift( $links, '<a href="' . esc_url( admin_url( 'options-general.php?page=btranslate' ) ) . '">' . esc_html__( 'Settings', 'btranslate' ) . '</a>' );
return $links;
}
@@ -273,7 +278,7 @@ class BTRANSLATE_Admin {
}
public function add_translation_column( $columns ) {
$columns['btranslate_translation'] = '翻译状态';
$columns['btranslate_translation'] = __( 'Translation status', 'btranslate' );
return $columns;
}
@@ -288,7 +293,7 @@ class BTRANSLATE_Admin {
foreach ( BTRANSLATE_Settings::target_languages() as $target_language ) {
$status = $store->get_post_language_status( $post_id, $target_language );
$translated = ! empty( $status['translated_fields'] );
$button_text = $translated ? '重新翻译' : '翻译';
$button_text = $translated ? __( 'Retranslate', 'btranslate' ) : __( 'Translate', 'btranslate' );
$action_url = wp_nonce_url(
add_query_arg(
array(
@@ -303,9 +308,9 @@ class BTRANSLATE_Admin {
);
echo '<p><strong>' . esc_html( strtoupper( $target_language ) ) . '</strong>: ';
echo $translated ? '<span style="color:#008a20">已翻译</span>' : '<span>未翻译</span>';
echo $translated ? '<span style="color:#008a20">' . esc_html__( 'Translated', 'btranslate' ) . '</span>' : '<span>' . esc_html__( 'Not translated', 'btranslate' ) . '</span>';
if ( $translated && ! empty( $status['last_translated_at'] ) ) {
echo '<br><small>上次翻译:' . esc_html( get_date_from_gmt( $status['last_translated_at'], 'Y-m-d H:i' ) ) . '</small>';
echo '<br><small>' . esc_html__( 'Last translated:', 'btranslate' ) . ' ' . esc_html( get_date_from_gmt( $status['last_translated_at'], 'Y-m-d H:i' ) ) . '</small>';
}
echo '<br><a class="button button-small" href="' . esc_url( $action_url ) . '">' . esc_html( $button_text ) . '</a></p>';
}
@@ -317,7 +322,7 @@ class BTRANSLATE_Admin {
$force_refresh = ! empty( $_GET['force'] );
if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) || ! BTRANSLATE_Settings::is_supported_language( $target_language ) || $target_language === BTRANSLATE_Settings::get()['source_language'] ) {
wp_die( '无效的翻译请求。' );
wp_die( esc_html__( 'Invalid translation request.', 'btranslate' ) );
}
check_admin_referer( 'btranslate_translate_post_' . $post_id . '_' . $target_language );
@@ -343,21 +348,21 @@ class BTRANSLATE_Admin {
private function translation_task_label( $post_ids, $term_ids ) {
if ( ! empty( $post_ids ) && ! empty( $term_ids ) ) {
return '全量翻译';
return __( 'Full translation', 'btranslate' );
}
if ( 1 === count( $post_ids ) ) {
return '单篇文章翻译';
return __( 'Single post translation', 'btranslate' );
}
if ( ! empty( $post_ids ) ) {
return '文章和页面翻译';
return __( 'Posts and pages translation', 'btranslate' );
}
if ( ! empty( $term_ids ) ) {
return '分类和标签翻译';
return __( 'Categories and tags translation', 'btranslate' );
}
return '暂无翻译任务';
return __( 'No translation task', 'btranslate' );
}
}
Binary file not shown.
+171
View File
@@ -0,0 +1,171 @@
# Simplified Chinese translations for Btranslate.
# Copyright (C) 2026 Btranslate contributors
# This file is distributed under the same license as the Btranslate package.
msgid ""
msgstr ""
"Project-Id-Version: Btranslate 0.2.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-28 14:41+0800\n"
"PO-Revision-Date: 2026-07-28 14:45+0800\n"
"Last-Translator: Btranslate contributors\n"
"Language-Team: Chinese (Simplified)\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
msgid "Btranslate"
msgstr "Btranslate"
#, php-format
msgid "(%1$s / %2$s content items)"
msgstr "%1$s / %2$s 个内容项)"
#, php-format
msgid "Latest task: %1$s. Posts and pages: %2$s / %3$s; categories and tags: %4$s / %5$s. Updates automatically every 5 seconds."
msgstr "最近任务:%1$s。文章和页面:%2$s / %3$s;分类和标签:%4$s / %5$s。每 5 秒自动更新。"
msgid "Unable to load translation progress at this time."
msgstr "暂时无法读取翻译进度。"
msgid "Source language"
msgstr "源语言"
msgid "Use a Baidu Translate language code, for example zh."
msgstr "使用百度翻译语言代码,例如 zh。"
msgid "Target languages"
msgstr "目标语言"
msgid "Separate multiple language codes with commas, for example en,ja."
msgstr "多个语言代码用英文逗号分隔,例如 en,ja。"
msgid "URL mode"
msgstr "网址模式"
msgid "Subdirectory"
msgstr "子目录"
msgid "Domain"
msgstr "域名"
msgid "Domain bindings"
msgstr "域名绑定"
msgid "Enter one domain=language code pair per line, for example en.example.com=en. Do not include https://, a path, or a port."
msgstr "每行一个域名=语言代码,例如 en.example.com=en。请勿填写 https://、路径或端口。"
msgid "Baidu application ID"
msgstr "百度应用 ID"
msgid "Baidu secret key"
msgstr "百度密钥"
msgid "Request logging"
msgstr "请求日志"
msgid "Log each Baidu Translate request"
msgstr "记录每次百度翻译请求"
msgid "When enabled, fires the btranslate_translation_request_logged action with the language, field, text fingerprint, length, and result status. Credentials, source text, translated text, and full API responses are never included."
msgstr "启用后触发 btranslate_translation_request_logged 操作,提供语言、字段、文本指纹、长度和结果状态;不会提供密钥、原文、译文或完整 API 响应。"
msgid "Retranslate content"
msgstr "重新翻译内容"
msgid "Queue all published posts, pages, categories, and tags for translation again."
msgstr "将所有已发布文章、页面、分类和标签重新加入翻译队列。"
msgid "This will retranslate all content and use your API quota. Continue?"
msgstr "这将重新翻译所有内容,请注意 API 消耗。确认继续吗?"
msgid "Retranslate all content"
msgstr "重新翻译所有内容"
msgid "You can also retranslate a single content type."
msgstr "也可以只重新翻译一种内容类型。"
msgid "This will retranslate all posts and pages and use your API quota. Continue?"
msgstr "这将重新翻译所有文章和页面,请注意 API 消耗。确认继续吗?"
msgid "Translate all posts"
msgstr "翻译所有文章"
msgid "This will retranslate all categories and tags and use your API quota. Continue?"
msgstr "这将重新翻译所有分类和标签,请注意 API 消耗。确认继续吗?"
msgid "Translate all categories and tags"
msgstr "翻译所有分类和标签"
msgid "Translation cache"
msgstr "翻译缓存"
msgid "After clearing the cache, the front end temporarily displays source content. Baidu Translate API calls resume when content is translated again."
msgstr "清除后,前台会暂时显示源文;重新翻译时将再次调用百度翻译 API。"
msgid "This will delete all saved translations, cancel pending translation tasks, and reset progress. Continue?"
msgstr "这将删除所有已保存的翻译、取消待执行翻译任务并重置进度。确认继续吗?"
msgid "Clear translation cache"
msgstr "清除已翻译的缓存"
msgid "Translation progress"
msgstr "翻译进度"
msgid "Loading translation progress..."
msgstr "正在读取翻译进度..."
msgid "You do not have permission to perform this action."
msgstr "您没有执行此操作的权限。"
msgid "Invalid translation scope."
msgstr "无效的翻译范围。"
msgid "Failed to clear the translation cache."
msgstr "翻译缓存清除失败。"
msgid "Settings"
msgstr "设置"
msgid "Translation status"
msgstr "翻译状态"
msgid "Retranslate"
msgstr "重新翻译"
msgid "Translate"
msgstr "翻译"
msgid "Translated"
msgstr "已翻译"
msgid "Not translated"
msgstr "未翻译"
msgid "Last translated:"
msgstr "上次翻译:"
msgid "Invalid translation request."
msgstr "无效的翻译请求。"
msgid "Full translation"
msgstr "全量翻译"
msgid "Single post translation"
msgstr "单篇文章翻译"
msgid "Posts and pages translation"
msgstr "文章和页面翻译"
msgid "Categories and tags translation"
msgstr "分类和标签翻译"
msgid "No translation task"
msgstr "暂无翻译任务"
msgid "Baidu Translate credentials are not configured."
msgstr "尚未配置百度翻译凭据。"
msgid "Baidu Translate returned an invalid response."
msgstr "百度翻译返回了无效响应。"
+241
View File
@@ -0,0 +1,241 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Btranslate contributors
# This file is distributed under the same license as the Btranslate package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Btranslate 0.2.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-28 14:41+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: includes/class-btranslate-admin.php:22
msgid "Btranslate"
msgstr ""
#: includes/class-btranslate-admin.php:48
#, php-format
msgid "(%1$s / %2$s content items)"
msgstr ""
#: includes/class-btranslate-admin.php:49
#, php-format
msgid ""
"Latest task: %1$s. Posts and pages: %2$s / %3$s; categories and tags: %4$s / "
"%5$s. Updates automatically every 5 seconds."
msgstr ""
#: includes/class-btranslate-admin.php:50
msgid "Unable to load translation progress at this time."
msgstr ""
#: includes/class-btranslate-admin.php:95
msgid "Source language"
msgstr ""
#: includes/class-btranslate-admin.php:95
msgid "Use a Baidu Translate language code, for example zh."
msgstr ""
#: includes/class-btranslate-admin.php:96
msgid "Target languages"
msgstr ""
#: includes/class-btranslate-admin.php:96
msgid "Separate multiple language codes with commas, for example en,ja."
msgstr ""
#: includes/class-btranslate-admin.php:97
msgid "URL mode"
msgstr ""
#: includes/class-btranslate-admin.php:97
msgid "Subdirectory"
msgstr ""
#: includes/class-btranslate-admin.php:97
msgid "Domain"
msgstr ""
#: includes/class-btranslate-admin.php:98
msgid "Domain bindings"
msgstr ""
#: includes/class-btranslate-admin.php:98
msgid ""
"Enter one domain=language code pair per line, for example en.example.com=en. "
"Do not include https://, a path, or a port."
msgstr ""
#: includes/class-btranslate-admin.php:99
msgid "Baidu application ID"
msgstr ""
#: includes/class-btranslate-admin.php:100
msgid "Baidu secret key"
msgstr ""
#: includes/class-btranslate-admin.php:101
msgid "Request logging"
msgstr ""
#: includes/class-btranslate-admin.php:101
msgid "Log each Baidu Translate request"
msgstr ""
#: includes/class-btranslate-admin.php:101
msgid ""
"When enabled, fires the btranslate_translation_request_logged action with "
"the language, field, text fingerprint, length, and result status. "
"Credentials, source text, translated text, and full API responses are never "
"included."
msgstr ""
#: includes/class-btranslate-admin.php:106
msgid "Retranslate content"
msgstr ""
#: includes/class-btranslate-admin.php:107
msgid ""
"Queue all published posts, pages, categories, and tags for translation again."
msgstr ""
#: includes/class-btranslate-admin.php:108
msgid "This will retranslate all content and use your API quota. Continue?"
msgstr ""
#: includes/class-btranslate-admin.php:111
msgid "Retranslate all content"
msgstr ""
#: includes/class-btranslate-admin.php:113
msgid "You can also retranslate a single content type."
msgstr ""
#: includes/class-btranslate-admin.php:114
msgid ""
"This will retranslate all posts and pages and use your API quota. Continue?"
msgstr ""
#: includes/class-btranslate-admin.php:118
msgid "Translate all posts"
msgstr ""
#: includes/class-btranslate-admin.php:120
msgid ""
"This will retranslate all categories and tags and use your API quota. "
"Continue?"
msgstr ""
#: includes/class-btranslate-admin.php:124
msgid "Translate all categories and tags"
msgstr ""
#: includes/class-btranslate-admin.php:127
msgid "Translation cache"
msgstr ""
#: includes/class-btranslate-admin.php:128
msgid ""
"After clearing the cache, the front end temporarily displays source content. "
"Baidu Translate API calls resume when content is translated again."
msgstr ""
#: includes/class-btranslate-admin.php:129
msgid ""
"This will delete all saved translations, cancel pending translation tasks, "
"and reset progress. Continue?"
msgstr ""
#: includes/class-btranslate-admin.php:132
msgid "Clear translation cache"
msgstr ""
#: includes/class-btranslate-admin.php:135
msgid "Translation progress"
msgstr ""
#: includes/class-btranslate-admin.php:137
msgid "Loading translation progress..."
msgstr ""
#: includes/class-btranslate-admin.php:145
#: includes/class-btranslate-admin.php:211
msgid "You do not have permission to perform this action."
msgstr ""
#: includes/class-btranslate-admin.php:151
msgid "Invalid translation scope."
msgstr ""
#: includes/class-btranslate-admin.php:218
msgid "Failed to clear the translation cache."
msgstr ""
#: includes/class-btranslate-admin.php:238
msgid "Settings"
msgstr ""
#: includes/class-btranslate-admin.php:281
msgid "Translation status"
msgstr ""
#: includes/class-btranslate-admin.php:296
msgid "Retranslate"
msgstr ""
#: includes/class-btranslate-admin.php:296
msgid "Translate"
msgstr ""
#: includes/class-btranslate-admin.php:311
msgid "Translated"
msgstr ""
#: includes/class-btranslate-admin.php:311
msgid "Not translated"
msgstr ""
#: includes/class-btranslate-admin.php:313
msgid "Last translated:"
msgstr ""
#: includes/class-btranslate-admin.php:325
msgid "Invalid translation request."
msgstr ""
#: includes/class-btranslate-admin.php:351
msgid "Full translation"
msgstr ""
#: includes/class-btranslate-admin.php:355
msgid "Single post translation"
msgstr ""
#: includes/class-btranslate-admin.php:359
msgid "Posts and pages translation"
msgstr ""
#: includes/class-btranslate-admin.php:363
msgid "Categories and tags translation"
msgstr ""
#: includes/class-btranslate-admin.php:366
msgid "No translation task"
msgstr ""
#: includes/class-btranslate-baidu-provider.php:22
msgid "Baidu Translate credentials are not configured."
msgstr ""
#: includes/class-btranslate-baidu-provider.php:52
msgid "Baidu Translate returned an invalid response."
msgstr ""
+2
View File
@@ -13,6 +13,8 @@ License URI: https://www.gnu.org/licenses/gpl-3.0.html
Btranslate 使用百度翻译 API 翻译 WordPress 内容,并将每个翻译结果持久化保存以供重复使用。插件支持语言子目录 URL 和语言域名绑定。
WordPress 后台界面会跟随当前 WordPress 语言:默认显示英文,WordPress 设为 `zh_CN` 时使用插件内置的简体中文翻译。
支持的内容包括已发布文章和页面的标题、正文、摘要、图片替代文本、分类、标签及部分 SEO 字段。插件只为 `publish` 状态的文章和页面自动安排翻译。完成的翻译保存在插件自建数据表中;前端渲染只读取已保存的翻译,不会动态请求翻译服务。
子目录路由支持 `/en/example-post/` 等路径。域名路由可将配置的主机名映射到目标语言。翻译失败不会中断页面请求;没有有效译文时会回退显示源语言内容。
+2
View File
@@ -13,6 +13,8 @@ Persistent multilingual WordPress translations powered by the Baidu Translate AP
Btranslate translates supported WordPress content with the Baidu Translate API and persists each translation for reuse. It supports language-specific subdirectory URLs and domain bindings.
The WordPress admin interface follows the current WordPress locale. English is the default, and a bundled Simplified Chinese translation is used when WordPress is set to `zh_CN`.
Supported values include published post and page titles, content, excerpts, image alternative text, categories, tags, and selected SEO fields. Automatic translation is only scheduled for posts and pages with the `publish` status. Completed translations are stored in the plugin's custom database table. Front-end rendering reuses stored values and never calls the translation provider dynamically.
Subdirectory routing supports paths such as `/en/example-post/`. Domain routing maps configured hostnames to target languages. Translation failures are non-fatal and fall back to source-language content.