add multilanguage support
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
Btranslate 是一个 WordPress 插件骨架,使用百度翻译 API 持久化管理多语言内容。
|
||||
|
||||
WordPress 后台界面会跟随当前 WordPress 语言:默认显示英文,WordPress 设为 `zh_CN` 时使用插件内置的简体中文翻译。
|
||||
|
||||
## 要求
|
||||
|
||||
- WordPress 6.4 或更高版本。
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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' ) );
|
||||
|
||||
@@ -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.
@@ -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 "百度翻译返回了无效响应。"
|
||||
@@ -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 ""
|
||||
@@ -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/` 等路径。域名路由可将配置的主机名映射到目标语言。翻译失败不会中断页面请求;没有有效译文时会回退显示源语言内容。
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user