
區塊主題對 WordPress 的翻譯方式與傳統方法不同。傳統的帶有翻譯功能的 PHP 模板檔案無法與 HTML 模板、JavaScript 驅動的區塊和站點編輯器相容。這種轉變需要您以不同的方式理解 WordPress 區塊國際化系統。
本指南提供了使您的區塊主題支援多語言的策略。您將學習如何應對區塊主題翻譯的挑戰、實施解決方案以及如何與翻譯外掛整合。
區塊主題為何打破傳統的翻譯方法(以及如何解決這些問題)
區塊主題用包含區塊標記的 HTML 模板替換了 WordPress 的許多 PHP 檔案。然而,這種轉換帶來了挑戰,因為 HTML 模板無法執行 PHP 翻譯函式,例如 _() 或 _e()。因此,您已有的翻譯字串會毫無用處地堆積在靜態檔案中。
WordPress 6.8 帶來了一些改進,簡化了區塊主題的國際化。首先,具有正確文字域和域路徑標頭的主題不再需要手動呼叫 load_theme_textdomain()。
相反,WordPress 會自動載入翻譯檔案,並優先載入 wp-content/languages/themes/,而不是主題目錄,以提高效能。
首先,使用經典方法設定您的主題,即向 style.css 檔案新增後設資料。
/* Theme Name: My Block Theme Text Domain: my-block-theme Domain Path: /languages */
請注意,Text Domain 標頭必須與主題的資料夾名稱(通常採用短橫線命名)匹配,以確保在較新的 WordPress 版本中翻譯檔案能夠正確自動載入。
與 style.css 類似,您的 functions.php 檔案需要進行最少的設定:
<?php
// Optional in WordPress 6.8+ but included for backward compatibility
function my_block_theme_setup() {
load_theme_textdomain( 'my-block-theme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'my_block_theme_setup' );
// Register block scripts with translation support
function my_block_theme_scripts() {
wp_enqueue_script(
'my-block-theme-scripts',
get_template_directory_uri() . '/assets/js/theme.js',
array( 'wp-i18n' ),
'1.0.0',
true
);
wp_set_script_translations(
'my-block-theme-scripts',
'my-block-theme',
get_template_directory() . '/languages'
);
}
add_action( 'wp_enqueue_scripts', 'my_block_theme_scripts' );
經典主題和 Block 主題之間的主要區別在於,後者將翻譯任務拆分為伺服器端 PHP 和客戶端 JavaScript。相比之下,經典主題必須依賴 PHP 來處理大多數翻譯任務。
如何構建block.json翻譯
block.json 檔案是您要翻譯的區塊的“配置中心”。設定正確的國際化設定可確保您的區塊在編輯器和前端都能正確翻譯。
註冊 Block 的規範方法是透過 block.json。從 textdomain 配置開始,這意味著 WordPress 可以在設定 textdomain 後翻譯標題、描述和關鍵字欄位:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "my-theme/testimonial",
"title": "Testimonial",
"category": "text",
"description": "Display customer testimonials",
"keywords": ["quote", "review", "testimonial"],
"textdomain": "my-block-theme",
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "blockquote"
}
}
}
然而,需要“上下文”的場景需要在伺服器端註冊。在這種情況下,上下文很重要,因為同一個詞可能會根據其用法而有不同的翻譯。例如,“post”作為名詞和動詞,在許多語言中需要不同的翻譯:
function my_theme_register_testimonial_block() {
register_block_type_from_metadata(
get_template_directory() . '/blocks/testimonial',
array(
'title' => _x( 'Testimonial', 'block title', 'my-block-theme' ),
'description' => _x(
'Display customer testimonials',
'block description',
'my-block-theme'
),
'keywords' => array(
_x( 'quote', 'block keyword', 'my-block-theme' ),
_x( 'review', 'block keyword', 'my-block-theme' )
)
)
);
}
add_action( 'init', 'my_theme_register_testimonial_block' );
您新增的任何區塊變體也需要結構化命名,因為 WordPress 在載入翻譯時會查詢特定的模式。每個變體名稱都成為翻譯鍵的一部分:
{
"name": "my-theme/button",
"title": "Button",
"textdomain": "my-block-theme",
"variations": [{
"name": "primary",
"title": "Primary Button",
"attributes": {
"className": "is-style-primary"
}
},
{
"name": "secondary",
"title": "Secondary Button",
"attributes": {
"className": "is-style-secondary"
}
}
]
}
JavaScript 國際化需要您匯入 WordPress i18n 函式並配置指令碼翻譯。這是因為站點編輯器在瀏覽器中執行,而不是在伺服器上執行。由於 JavaScript 中不存在 PHP 翻譯函式,因此 WordPress 透過 @wordpress/i18n 包提供了等效函式:
import {
registerBlockType
} from '@wordpress/blocks';
import {
__
} from '@wordpress/i18n';
import {
useBlockProps,
RichText
} from '@wordpress/block-editor';
registerBlockType('my-theme/testimonial', {
edit: ({
attributes,
setAttributes
}) => {
const blockProps = useBlockProps();
return ( < div { ...blockProps } >
< RichText tagName = "blockquote" value = { attributes.content } onChange = { (content) => setAttributes({
content
})
}
placeholder = {
__('Add testimonial text...', 'my-block-theme')
}
/> < cite >
< RichText tagName = "span" value = { attributes.author } onChange = { (author) => setAttributes({
author
})
}
placeholder = {
__('Author name', 'my-block-theme')
}
/> < /cite> < /div>
);
}
});
此外,為 JavaScript 生成 JSON 翻譯檔案是個好主意,因為 WordPress 使用不同的格式進行客戶端翻譯。PHP 使用 .mo 檔案,但 JavaScript 需要具有特定命名約定的 .json 檔案。您可以使用 WP-CLI 命令自動執行此操作:
# Extract strings from JavaScript files into POT wp i18n make-pot . languages/my-block-theme.pot # Convert PO files to JSON for JavaScript wp i18n make-json languages/ --no-purge --pretty-print
生成的 JSON 檔案遵循一致的格式: {textdomain}-{locale}-{handle}.json。當您呼叫 wp_set_script_translations() 時,WordPress 可以載入這些檔案。
將靜態HTML模板轉換為可翻譯的PHP元件
由於 HTML 模板是靜態的,因此使用它們進行 Block 主題國際化是一項挑戰,因為您現有的翻譯函式和技術將無法正常工作。
PHP 驅動的模板部分可以解決這個問題,因為儘管它們在 HTML 模板中被引用,WordPress 仍會將它們作為 PHP 檔案處理。這種混合方法在支援動態內容的同時,保留了 Block 主題的結構:
<!-- templates/page.html -->
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content /-->
<!-- wp:template-part {"slug":"post-meta"} /-->
</main>
<!-- /wp:group →
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
請注意,模板部分可以包含 PHP:
<!-- parts/post-meta.html -->
<!-- wp:group {"className":"post-meta"} -->
<div class="wp-block-group post-meta">
<?php
echo sprintf(
/* translators: 1: Post date, 2: Post author */
__( 'Published on %1$s by %2$s', 'my-block-theme' ),
get_the_date(),
get_the_author()
);
?>
</div>
<!-- /wp:group -->
複雜的區塊需要 render.php 檔案,因為某些內容需要伺服器端處理,而僅靠區塊屬性無法處理。資料庫查詢、條件邏輯和動態內容生成都需要 PHP 執行:
// blocks/recent-posts/render.php <?php $recent_posts = get_posts( array( 'numberposts' => $attributes['count'] ?? 5 ) ); ?> <div <?php echo get_block_wrapper_attributes(); ?>> <h3><?php echo esc_html__( 'Recent Posts', 'my-block-theme' ); ?></h3> <?php if ( $recent_posts ) : ?> <ul> <?php foreach ( $recent_posts as $post ) : ?> <li> <a href="<?php echo get_permalink( $post ); ?>"> <?php echo get_the_title( $post ); ?> </a> <span class="post-date"> <?php echo get_the_date( '', $post ); ?> </span> </li> <?php endforeach; ?> </ul> <?php else : ?> <p><?php esc_html_e( 'No posts found.', 'my-block-theme' ); ?></p> <?php endif; ?> </div>
這意味著配置您的區塊以使用 block.json 中的渲染檔案:
{
"name": "my-theme/recent-posts",
"render": "file:./render.php",
"attributes": {
"count": {
"type": "number",
"default": 5
}
}
}
如何為自定義欄位和使用者輸入實現動態內容翻譯
儘管動態內容在 WordPress 網站上非常普遍,但它仍可能導致翻譯問題,因為它存在於資料庫中,而不是主題檔案中。因此,您使用的任何第三方翻譯外掛都需要識別和管理此類內容,並將其與靜態主題字串區分開來。
註冊自定義欄位並使用正確的元配置非常重要,因為翻譯外掛會連線到 WordPress 的元系統來檢測任何可翻譯的內容。show_in_rest 引數可以與網站編輯器相容:
function my_theme_register_meta_fields() {
register_post_meta( 'page', 'custom_subtitle', array(
'type' => 'string',
'description' => __( 'Page subtitle', 'my-block-theme' ),
'single' => true,
'show_in_rest' => true,
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
}
));
}
add_action( 'init', 'my_theme_register_meta_fields' );
// Display with plugin compatibility
function my_theme_display_subtitle( $post_id ) {
$subtitle = get_post_meta( $post_id, 'custom_subtitle', true );
if ( ! $subtitle ) {
return;
}
// WPML compatibility
// (documented at wpml.org/documentation/support/wpml-coding-api/wpml-hooks-reference/)
if ( function_exists( 'icl_t' ) ) {
$subtitle = icl_t(
'my-block-theme',
'subtitle_' . $post_id,
$subtitle
);
}
// Polylang compatibility
// (documented at polylang.pro/doc/function-reference/)
if ( function_exists( 'pll_translate_string' ) ) {
$subtitle = pll_translate_string( $subtitle, 'my-block-theme' );
}
echo '<h2 class="page-subtitle">' . esc_html( $subtitle ) . '</h2>';
}
資料庫查詢也需要語言過濾,因為 WordPress 不會自動按語言過濾內容。翻譯外掛會新增查詢修改,您必須適應以下情況:
function my_theme_get_localized_posts( $args = array() ) {
$defaults = array(
'post_type' => 'post',
'posts_per_page' => 10
);
$args = wp_parse_args( $args, $defaults );
// Polylang adds language taxonomy
// (documented at polylang.pro/doc/developpers-how-to/)
if ( function_exists( 'pll_current_language' ) ) {
$args['lang'] = pll_current_language();
}
// WPML filters queries automatically when suppress_filters is false
// (wpml.org/documentation/getting-started-guide/translating-custom-posts/)
if ( defined( 'ICL_LANGUAGE_CODE' ) ) {
$args['suppress_filters'] = false;
}
return get_posts( $args );
}
您的表單處理混合了動態和靜態內容,但表單標籤、錯誤訊息和管理通知都需要語言感知的翻譯。電子郵件收件人也可能因語言而異:
function my_theme_process_contact_form() {
if ( ! isset( $_POST['contact_nonce'] ) ||
! wp_verify_nonce( $_POST['contact_nonce'], 'contact_form' ) ) {
return;
}
$name = sanitize_text_field( $_POST['name'] );
$email = sanitize_email( $_POST['email'] );
$message = sanitize_textarea_field( $_POST['message'] );
// Get admin email in current language
$admin_email = get_option( 'admin_email' );
// For language-specific admin emails, use WPML's string translation
// (documented at wpml.org/documentation/support/wpml-coding-api/wpml-hooks-reference/)
if ( function_exists( 'icl_t' ) ) {
// First register the string if not already registered
if ( function_exists( 'icl_register_string' ) ) {
icl_register_string( 'my-block-theme', 'contact_email', $admin_email );
}
$admin_email = icl_t(
'my-block-theme',
'contact_email',
$admin_email
);
}
$subject = sprintf(
/* translators: %s: Sender name */
__( 'Contact form submission from %s', 'my-block-theme' ),
$name
);
wp_mail( $admin_email, $subject, $message );
}
add_action( 'init', 'my_theme_process_contact_form' );
評估導航語言的認知度也很重要,因為不同語言的選單項、URL 和結構可能有所不同。你的翻譯外掛可能包含用於構建語言切換器的 API:
function my_theme_language_switcher_block() {
if ( ! function_exists( 'pll_the_languages' ) &&
! function_exists( 'icl_get_languages' ) ) {
return;
}
$output = '<div class="language-switcher">';
// Polylang language switcher
// (documented at polylang.pro/doc/function-reference/)
if ( function_exists( 'pll_the_languages' ) ) {
$languages = pll_the_languages( array( 'raw' => 1 ) );
foreach ( $languages as $lang ) {
$output .= sprintf(
'<a href="%s" class="%s">%s</a>',
esc_url( $lang['url'] ),
$lang['current_lang'] ? 'current-lang' : '',
esc_html( $lang['name'] )
);
}
}
// WPML language switcher
// (documented at wpml.org/documentation/support/wpml-coding-api/multi-language-api/)
elseif ( function_exists( 'icl_get_languages' ) ) {
$languages = icl_get_languages();
foreach ( $languages as $lang ) {
$output .= sprintf(
'<a href="%s" class="%s">%s</a>',
esc_url( $lang['url'] ),
$lang['active'] ? 'current-lang' : '',
esc_html( $lang['native_name'] )
);
}
}
$output .= '</div>';
return $output;
}
使用翻譯外掛很可能是你工作中的很大一部分,所以接下來讓我們來看一下這方面。
使用翻譯外掛:相容性和最佳化
每個 WordPress 翻譯外掛處理區塊主題的方式都不同。瞭解不同解決方案所採用的方法有助於你從一開始就構建相容性和靈活性。
WPML 的整站編輯文件概述瞭如何為區塊主題進行特定配置:
// WPML FSE compatibility based on official documentation
add_action( 'init', function() {
if ( ! defined( 'WPML_VERSION' ) ) {
return;
}
// FSE themes are automatically detected in WPML 4.5.3+ // Enable FSE support
add_filter( 'wpml_is_fse_theme', '__return_true' );
// Register custom strings per WPML String Translation documentation
// (documented at wpml.org/documentation/support/wpml-coding-api/wpml-hooks-reference/)
if ( function_exists( 'icl_register_string' ) ) {
icl_register_string(
'my-block-theme',
'footer-copyright',
'© My Company.'
);
}
});
Polylang Pro 自 3.2 版本起支援站點編輯器。該外掛透過其標準字串翻譯介面處理區塊主題:
// Polylang string registration per official documentation
if ( function_exists( 'pll_register_string' ) ) {
pll_register_string(
'Footer Copyright',
'© My Company.',
'my-block-theme',
true // Multiline support
);
}
TranslatePress 的文件顯示,為了獲得最佳效能,需要排除某些動態元素:
// TranslatePress optimization based on official recommendations
// (documented at translatepress.com/docs/developers/)
add_filter( 'trp_stop_translating_page', function( $stop, $url ) {
// Skip admin and API requests per TranslatePress documentation
if ( is_admin() || wp_is_json_request() ) {
return true;
}
// Skip pattern preview URLs that can cause rendering issues
if ( strpos( $url, 'pattern-preview' ) !== false ) {
return true;
}
return $stop;
}, 10, 2 );
最後,在使用第三方程式碼庫(例如外掛)時,有一些通用的技巧可以傳授。首先,確保使用系統的方法來除錯翻譯問題。
// Debug helper for translation issues
function my_theme_debug_translations() {
if ( ! WP_DEBUG || ! current_user_can( 'manage_options' ) ) {
return;
}
error_log( 'Text domain loaded: ' . is_textdomain_loaded(
'my-block-theme' ) );
error_log( 'Current locale: ' . get_locale() );
error_log( 'Translation test: ' . __(
'Hello World',
'my-block-theme'
)
);
// Check JSON translations for blocks
$json_file = WP_LANG_DIR . '/themes/my-block-theme-' . get_locale() . '-script-handle.json';
error_log( 'JSON translation exists: ' . file_exists( $json_file ) );
}
add_action( 'init', 'my_theme_debug_translations' );
網站快取可能會干擾翻譯更新,因此您可能需要在翻譯檔案發生變化時清除快取:
# Clear WordPress transients wp transient delete --all # Generate fresh translation files wp i18n make-pot . languages/my-block-theme.pot wp i18n make-json languages/ --no-purge
對於翻譯外掛來說,效能最佳化至關重要。每個外掛都會增加資料庫查詢和處理開銷,而快取常用的翻譯則能帶來好處:
function my_theme_cached_translation( $text, $domain = 'my-block-theme' ) {
$cache_key = 'translation_' . md5( $text . get_locale() );
$cached = wp_cache_get( $cache_key, 'my_theme_translations' );
if ( false === $cached ) {
$cached = __( $text, $domain );
wp_cache_set( $cache_key, $cached, 'my_theme_translations', HOUR_IN_SECONDS );
}
return $cached;
}
或者,最好在部署前先跳過快取。使用預釋出環境是理想的選擇,而且通常不需要快取帶來的效能提升。
小結
區塊主題的國際化需要您同時使用 WordPress 的翻譯方法,並在站點編輯器中使用新的方法。
透過配置主題後設資料、實施模板策略以及瞭解翻譯外掛的要求,您可以建立效能良好且提供高質量使用者體驗的多語言區塊主題。

評論留言