feat: add two new buttons to retranslate

This commit is contained in:
hanyixuanten
2026-07-26 23:59:57 +08:00
parent 076aea0c9f
commit e221a87dd5
3 changed files with 58 additions and 28 deletions
+2 -2
View File
@@ -73,9 +73,9 @@ Before production use, test the plugin in a WordPress staging environment. Cover
## Retranslation
The Posts and Pages lists show a status column for every target language, including the latest successful translation time and a translation action. The Settings page also provides **重新翻译所有内容**. It shows a confirmation warning before scheduling a forced refresh of published posts, pages, categories, and tags; this bypasses persisted translations and consumes Baidu API quota.
The Posts and Pages lists show a status column for every target language, including the latest successful translation time and a translation action. The Settings page provides **重新翻译所有内容**, **翻译所有文章**, and **翻译所有分类标签**. Each action shows a confirmation before scheduling a forced refresh of all supported content, only published posts and pages, or only categories and tags; this bypasses persisted translations and consumes Baidu API quota.
The Settings page also shows a live progress panel. It refreshes every five seconds and counts completed post/page and category/tag items for every configured target language. When **重新翻译所有内容** starts a batch, progress resets and counts only translations completed after that batch began, so historical translations do not make a new batch appear complete. Progress reads only local WordPress and translation-table data; it does not send additional requests to Baidu.
The Settings page also shows a live progress panel. It refreshes every five seconds and counts completed post/page and category/tag items for every configured target language. When **重新翻译所有内容** starts a batch, progress resets and counts only translations completed after that batch began, so historical translations do not make a new batch appear complete. Forced retranslation jobs are scheduled one minute apart, so a single WP-Cron request processes at most one batch item instead of timing out while processing every post. Progress reads only local WordPress and translation-table data; it does not send additional requests to Baidu.
## Known Limitations
+2 -2
View File
@@ -72,9 +72,9 @@ find . -path './.git' -prune -o -type f -name '*.php' -print0 | xargs -0 -n1 php
## 重新翻译
文章和页面列表会显示每种目标语言的状态列,包括最近成功翻译时间和翻译操作。设置页提供 **重新翻译所有内容**。它会在为已发布文章、页面、分类标签安排强制刷新前显示确认警告;此操作会绕过已持久化的翻译并消耗百度 API 配额。
文章和页面列表会显示每种目标语言的状态列,包括最近成功翻译时间和翻译操作。设置页提供 **重新翻译所有内容**、**翻译所有文章** 和 **翻译所有分类标签**。它们会在为相应内容安排强制刷新前显示确认警告;此操作会绕过已持久化的翻译并消耗百度 API 配额。
设置页还显示实时进度面板。面板每五秒刷新一次,统计每种已配置目标语言中完成的文章/页面和分类/标签项目。当 **重新翻译所有内容** 启动批处理时,进度会重置,仅统计该批处理开始后完成的翻译,因此历史翻译不会让新的批处理看似已完成。进度只读取本地 WordPress 和翻译表数据,不会发送额外请求。
设置页还显示实时进度面板。面板每五秒刷新一次,统计每种已配置目标语言中完成的文章/页面和分类/标签项目。当 **重新翻译所有内容** 启动批处理时,进度会重置,仅统计该批处理开始后完成的翻译,因此历史翻译不会让新的批处理看似已完成。强制重翻任务会按一分钟间隔排队,单次 WP-Cron 请求最多处理一个内容项,避免一次处理全部文章而超时。进度只读取本地 WordPress 和翻译表数据,不会发送额外请求。
## 已知限制
+54 -24
View File
@@ -77,6 +77,19 @@ class WPT_Admin {
<?php wp_nonce_field( 'wpt_queue_existing_translations' ); ?>
<?php submit_button( '重新翻译所有内容', '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" onsubmit="return window.confirm('这将重新翻译所有文章和页面,请注意 API 消耗。确认继续吗?');">
<input type="hidden" name="action" value="wpt_queue_existing_translations" />
<input type="hidden" name="scope" value="posts" />
<?php wp_nonce_field( 'wpt_queue_existing_translations' ); ?>
<?php submit_button( '翻译所有文章', 'secondary', 'submit', false ); ?>
</form>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" style="display:inline-block" onsubmit="return window.confirm('这将重新翻译所有分类和标签,请注意 API 消耗。确认继续吗?');">
<input type="hidden" name="action" value="wpt_queue_existing_translations" />
<input type="hidden" name="scope" value="terms" />
<?php wp_nonce_field( 'wpt_queue_existing_translations' ); ?>
<?php submit_button( '翻译所有分类标签', 'secondary', 'submit', false ); ?>
</form>
<hr />
<h2>翻译进度</h2>
<div id="wpt-translation-progress" aria-live="polite">
@@ -119,6 +132,11 @@ class WPT_Admin {
}
check_admin_referer( 'wpt_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( '无效的翻译范围。' );
}
$batch_started_at = current_time( 'mysql', true );
update_option(
'wpt_retranslation_batch',
@@ -128,37 +146,43 @@ class WPT_Admin {
false
);
$post_ids = get_posts(
array(
'post_type' => array( 'post', 'page' ),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
)
);
$scheduled = 0;
$next_run = time() + MINUTE_IN_SECONDS;
foreach ( $post_ids as $post_id ) {
foreach ( WPT_Settings::target_languages() as $target_language ) {
if ( ! wp_next_scheduled( 'wpt_process_translation', array( $post_id, $target_language, true ) ) ) {
wp_schedule_single_event( time() + 30, 'wpt_process_translation', array( $post_id, $target_language, true ) );
if ( 'all' === $scope || 'posts' === $scope ) {
$post_ids = get_posts(
array(
'post_type' => array( 'post', 'page' ),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
)
);
foreach ( $post_ids as $post_id ) {
foreach ( WPT_Settings::target_languages() as $target_language ) {
$this->clear_scheduled_event( 'wpt_process_translation', array( $post_id, $target_language, true ) );
wp_schedule_single_event( $next_run, 'wpt_process_translation', array( $post_id, $target_language, true ) );
$next_run += MINUTE_IN_SECONDS;
++$scheduled;
}
}
}
$terms = get_terms(
array(
'taxonomy' => array( 'category', 'post_tag' ),
'hide_empty' => false,
'fields' => 'ids',
)
);
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term_id ) {
foreach ( WPT_Settings::target_languages() as $target_language ) {
if ( ! wp_next_scheduled( 'wpt_process_term_translation', array( $term_id, $target_language, true ) ) ) {
wp_schedule_single_event( time() + 30, 'wpt_process_term_translation', array( $term_id, $target_language, true ) );
if ( 'all' === $scope || 'terms' === $scope ) {
$terms = get_terms(
array(
'taxonomy' => array( 'category', 'post_tag' ),
'hide_empty' => false,
'fields' => 'ids',
)
);
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term_id ) {
foreach ( WPT_Settings::target_languages() as $target_language ) {
$this->clear_scheduled_event( 'wpt_process_term_translation', array( $term_id, $target_language, true ) );
wp_schedule_single_event( $next_run, 'wpt_process_term_translation', array( $term_id, $target_language, true ) );
$next_run += MINUTE_IN_SECONDS;
++$scheduled;
}
}
@@ -169,6 +193,12 @@ class WPT_Admin {
exit;
}
private function clear_scheduled_event( $hook, $args ) {
while ( false !== ( $timestamp = wp_next_scheduled( $hook, $args ) ) ) {
wp_unschedule_event( $timestamp, $hook, $args );
}
}
public function add_plugin_settings_link( $links ) {
array_unshift( $links, '<a href="' . esc_url( admin_url( 'options-general.php?page=wp-btranslate' ) ) . '">设置</a>' );