This commit is contained in:
hanyixuanten
2026-07-26 00:06:16 +08:00
parent 9a124c7791
commit b8b5ee6287
5 changed files with 87 additions and 20 deletions
+2 -18
View File
@@ -15,30 +15,14 @@ permissions:
contents: write
jobs:
test-and-package:
name: Test and package plugin
package:
name: Package plugin
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
tools: composer:v2
coverage: none
- name: Install Composer dependencies
run: composer install --no-interaction --prefer-dist --no-progress
- name: Run tests
run: composer test
- name: Lint PHP
run: composer lint
- name: Build installable plugin archive
id: package
run: |
+2 -2
View File
@@ -19,9 +19,9 @@ WP Translate is a WordPress plugin skeleton for persistent multilingual content
## Translation Lifecycle
Translations are generated by the `wpt_process_translation` cron task after a post or page is saved. A translation has a deterministic identity based on the source fingerprint, source language, target language, field context, and provider version. The plugin first looks up a completed result in the `{$wpdb->prefix}wpt_translations` table. Only a cache miss causes a request to Baidu.
Translations are generated by the `wpt_process_translation` cron task after a post or page is saved. For content published before the plugin was activated, open **Settings > WP Translate** and use **Translate existing posts and pages** to schedule all published posts and pages. A translation has a deterministic identity based on the source fingerprint, source language, target language, field context, and provider version. The plugin first looks up a completed result in the `{$wpdb->prefix}wpt_translations` table. Only a cache miss causes a request to Baidu.
Changing source text produces a new fingerprint and therefore schedules a new translation without deleting a valid prior translation. Front-end rendering never contacts Baidu; it reads a completed value from the table and otherwise falls back to the source value.
Changing source text produces a new fingerprint and therefore schedules a new translation without deleting a valid prior translation. Front-end rendering never contacts Baidu; it reads a completed value from the table and otherwise falls back to the source value. WordPress cron must run after queuing content; production sites should configure a real server cron to call WordPress cron regularly.
## Supported Content
+39
View File
@@ -6,6 +6,7 @@ class WPT_Admin {
public function register() {
add_action( 'admin_menu', array( $this, 'add_settings_page' ) );
add_action( 'admin_init', array( $this, 'register_settings' ) );
add_action( 'admin_post_wpt_queue_existing_translations', array( $this, 'queue_existing_translations' ) );
}
public function add_settings_page() {
@@ -61,7 +62,45 @@ class WPT_Admin {
</table>
<?php submit_button(); ?>
</form>
<hr />
<h2>翻译已有内容</h2>
<p>保存语言或百度凭据后,使用此操作将所有已发布的文章和页面加入翻译队列。</p>
<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
<input type="hidden" name="action" value="wpt_queue_existing_translations" />
<?php wp_nonce_field( 'wpt_queue_existing_translations' ); ?>
<?php submit_button( '翻译已有文章和页面', 'secondary', 'submit', false ); ?>
</form>
</div>
<?php
}
public function queue_existing_translations() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( '您没有执行此操作的权限。' );
}
check_admin_referer( 'wpt_queue_existing_translations' );
$post_ids = get_posts(
array(
'post_type' => array( 'post', 'page' ),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
)
);
$scheduled = 0;
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 ) ) ) {
wp_schedule_single_event( time() + 30, 'wpt_process_translation', array( $post_id, $target_language ) );
++$scheduled;
}
}
}
wp_safe_redirect( add_query_arg( 'wpt_queued', $scheduled, admin_url( 'options-general.php?page=wp-translate' ) ) );
exit;
}
}
@@ -24,6 +24,10 @@ class WPT_Content_Controller {
add_filter( 'wpseo_metadesc', array( $this, 'translate_seo_value' ), 20 );
add_filter( 'rank_math/frontend/title', array( $this, 'translate_seo_value' ), 20 );
add_filter( 'rank_math/frontend/description', array( $this, 'translate_seo_value' ), 20 );
add_filter( 'post_link', array( $this, 'localize_permalink' ), 20 );
add_filter( 'page_link', array( $this, 'localize_permalink' ), 20 );
add_filter( 'post_type_link', array( $this, 'localize_permalink' ), 20 );
add_filter( 'term_link', array( $this, 'localize_permalink' ), 20 );
}
public function schedule_post_translation( $post_id, $post, $update ) {
@@ -133,6 +137,10 @@ class WPT_Content_Controller {
return $value;
}
public function localize_permalink( $url ) {
return $this->router->localized_url( $url );
}
private function translated_value( $source_value, $context ) {
$settings = WPT_Settings::get();
$target_language = $this->router->current_language();
+36
View File
@@ -51,4 +51,40 @@ class WPT_Language_Router {
return sanitize_key( $settings['source_language'] );
}
public function localized_url( $url ) {
$settings = WPT_Settings::get();
$language = $this->current_language();
if ( $language === $settings['source_language'] || ! WPT_Settings::is_supported_language( $language ) ) {
return $url;
}
if ( 'domain' === $settings['routing_mode'] ) {
$domain = array_search( $language, (array) $settings['domain_bindings'], true );
$parts = wp_parse_url( $url );
if ( false === $domain || ! is_array( $parts ) || empty( $parts['host'] ) ) {
return $url;
}
$scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : 'https';
$path = isset( $parts['path'] ) ? $parts['path'] : '/';
$query = isset( $parts['query'] ) ? '?' . $parts['query'] : '';
$fragment = isset( $parts['fragment'] ) ? '#' . $parts['fragment'] : '';
return $scheme . '://' . $domain . $path . $query . $fragment;
}
$parts = wp_parse_url( $url );
if ( ! is_array( $parts ) || empty( $parts['path'] ) ) {
return $url;
}
$path = '/' . $language . '/' . ltrim( $parts['path'], '/' );
$query = isset( $parts['query'] ) ? '?' . $parts['query'] : '';
$fragment = isset( $parts['fragment'] ) ? '#' . $parts['fragment'] : '';
return home_url( $path ) . $query . $fragment;
}
}