WordPress 主题国际化(i18n)完全指南

WordPress 主题国际化(Internationalization,缩写 i18n)指的是让主题中的文本能够被翻译成其他语言的技术实践。这不是一个可选项,而是现代 WordPress 主题开发的标准要求——无论你使用哪种语言开发主题,都应该遵循这套规范。

本文会从头讲解国际化在 WordPress 主题中的运作方式:什么是文本域(text domain)、如何定义它、怎样在代码中正确包裹可翻译字符串,以及翻译文件该如何加载。文中不堆砌术语,每个概念都配有代码演示,适合对 WordPress 主题开发有基本了解的读者。

如果你是一次接触主题开发,建议先掌握 WordPress 主题的基本文件结构(style.css、functions.php、模板文件等),再回来看这篇。文章后会附上官方手册的延伸阅读链接。


一、为什么你的主题需要国际化

WordPress 在全球范围内被广泛使用,用户来自不同语言背景。如果你的主题代码中写死了英文(或其他语言)的文本,那么:

  1. 非该语言用户无法直接使用,除非他们修改你的源代码——这会导致无法安全更新主题。
  2. 提交到 WordPress 官方主题目录时,审核会被直接拒绝,因为国际化是提交规则里的硬性要求。
  3. 限制了主题的潜在受众,不利于传播和商业价值。

注意:即便你只打算给自己的网站用,也建议养成国际化的习惯。WordPress 内置的翻译系统允许用户在不修改主题源码的情况下切换语言,这意味着用户既可以获得翻译后的界面,又能随时安全地更新主题。


二、准备文本域(Text Domain)

什么是文本域?

文本域是一个标识符,WordPress 用它来区分哪些翻译文件属于你的主题,哪些属于插件或其他主题。翻译文件(.mo 文件)的文件名中就包含文本域,WordPress 根据当前加载的主题和插件的文本域去查找对应的翻译。

文本域的命名规则

文本域必须与主题目录名(主题 slug)保持一致。这是官方要求,也是翻译系统正常工作的前提。

命名规范如下:

  • 全部使用小写字母
  • 多个单词之间用连字符(-)分隔(kebab-case 风格)
  • 不要使用下划线、空格或大写字母

举例:如果你的主题名为“Fabled Sunset”,那么主题的文件夹名称和文本域都应该命名为 fabled-sunset。

在 style.css 中声明文本域

主题的 style.css 文件头部需要添加 Text Domain 字段。另外还有一个可选的 Domain Path 字段,用于指定翻译文件存放的目录(相对于主题根目录),默认是 /languages。

示例:

css

/**
 * Theme Name:        Fabled Sunset
 * Theme URI:         https://example.com/fabled-sunset
 * Description:       一个优雅的博客主题
 * Author:            你的名字
 * Text Domain:       fabled-sunset
 * Domain Path:       /assets/lang
 */

这段声明有两个作用:

  • Text Domain 告知 WordPress 这个主题的文本域是什么。
  • Domain Path 帮助 WordPress 在主题未激活时也能找到翻译文件(例如在后台“外观 > 主题”预览界面中展示翻译后的主题描述)。

三、用国际化函数包裹文本

这是国际化工作中频繁的操作。你需要将所有在主题中直接写死的文本,改为通过特定的 WordPress 函数输出。

基础示例

原始写法(无法翻译):

html

<h2>新文章</h2>

国际化写法:

php

<h2><?php _e( '新文章', 'fabled-sunset' ); ?></h2>

这里用到了 _e() 函数,它接受两个参数:

  • 一个参数是要翻译的文本字符串。
  • 二个参数是文本域,告诉 WordPress 这个字符串属于哪个主题/插件。

注意:所有国际化函数都必须带上正确的文本域。如果文本域写错或漏写,翻译系统将无法匹配到对应的翻译文件。

常用的国际化函数

不同的使用场景需要选择不同的函数:

1. __() — 返回翻译后的字符串

适用于需要将翻译结果赋值给变量或作为函数参数的情况。

php

$read_more_text = __( '阅读全文', 'fabled-sunset' );
echo $read_more_text;

2. _e() — 直接输出翻译后的字符串

与 __() 的区别是 _e() 会直接打印到页面,而 __() 只是返回。

php

<h2><?php _e( '新文章', 'fabled-sunset' ); ?></h2>

3. _n() — 处理单复数形式

某些语言(如英文)有单复数变化,这个函数能根据数字选择合适的翻译形态。

php

printf(
    _n( '找到 %s 篇文章', '找到 %s 篇文章', $count, 'fabled-sunset' ),
    number_format_i18n( $count )
);

注意这里两个字符串表面看起来一样(中文单复数形式相同),但对其他语言(如英文)来说,一个会被翻译为 “Found %s post”,二个为 “Found %s posts”,WordPress 会根据 $count 的值自动选择。

4. esc_html__() / esc_html_e() — 翻译并转义

输出到 HTML 中的文本,建议使用转义函数包裹,防止 XSS 攻击。

php

<h2><?php echo esc_html__( '新文章', 'fabled-sunset' ); ?></h2>

或者直接输出:

php

<h2><?php esc_html_e( '新文章', 'fabled-sunset' ); ?></h2>

WordPress 建议在输出翻译文本时尽量配合转义函数使用,这是安全编码的基本原则。

完整的模板文件示例

php

<?php
/**
 * 文章列表模板
 */
get_header();
?>

<main>
    <h1><?php esc_html_e( '文章归档', 'fabled-sunset' ); ?></h1>
    
    <?php if ( have_posts() ) : ?>
        <ul>
            <?php while ( have_posts() ) : the_post(); ?>
                <li>
                    <a href="<?php the_permalink(); ?>">
                        <?php the_title(); ?>
                    </a>
                    <span>
                        <?php
                        printf(
                            esc_html__( '发布于:%s', 'fabled-sunset' ),
                            get_the_date()
                        );
                        ?>
                    </span>
                </li>
            <?php endwhile; ?>
        </ul>
    <?php else : ?>
        <p><?php esc_html_e( '暂无文章', 'fabled-sunset' ); ?></p>
    <?php endif; ?>
</main>

<?php get_footer(); ?>

四、在主题中加载翻译文件

官方主题目录 vs 自用主题

如果你的主题提交到了 WordPress 官方主题目录,不需要在主题中主动加载翻译文件。WordPress 会自动从 wp-content/languages/themes/ 目录加载官方翻译,用户可以通过 WordPress 后台直接安装语言包。

如果你自己分发主题(不在官方目录中),或者你需要让主题自带翻译文件,就需要用 load_theme_textdomain() 函数手动加载。

翻译文件是什么格式?

WordPress 使用两种翻译文件格式:

  • .po 文件:人类可读的翻译源文件,可以用 Poedit 等工具编辑。
  • .mo 文件:机器可读的编译文件,WordPress 实际读取的是 .mo 文件。

加载翻译的两种方式

WordPress 默认在两个位置查找翻译文件:

  1. wp-content/themes/你的主题/{Domain Path}/{语言代码}.mo
  2. wp-content/languages/themes/{文本域}-{语言代码}.mo

如果你的主题不在官方目录,或者你需要加载额外的翻译,可以在 functions.php 中添加如下代码:

父主题的翻译加载

php

add_action( 'after_setup_theme', 'fabled_sunset_load_textdomain' );

function fabled_sunset_load_textdomain() {
    load_theme_textdomain(
        'fabled-sunset',
        get_parent_theme_file_path( 'assets/lang' )
    );
}

子主题的翻译加载

如果你开发的是子主题,使用 load_child_theme_textdomain() 替代:

php

add_action( 'after_setup_theme', 'fabled_sunset_child_load_textdomain' );

function fabled_sunset_child_load_textdomain() {
    load_child_theme_textdomain(
        'fabled-sunset-child',
        get_stylesheet_directory() . '/languages'
    );
}

注意:load_theme_textdomain() 必须挂在 after_setup_theme 钩子上,这是 WordPress 加载主题后早可用的钩子之一,能确保翻译在页面渲染前被加载。

完整的翻译加载示例

php

add_action( 'after_setup_theme', 'fabled_sunset_setup' );

function fabled_sunset_setup() {
    // 加载翻译
    load_theme_textdomain(
        'fabled-sunset',
        get_parent_theme_file_path( 'languages' )
    );
    
    // 其他主题设置...
    add_theme_support( 'title-tag' );
    add_theme_support( 'post-thumbnails' );
}

五、翻译文件的存放与命名

语言代码(Locale)

WordPress 中的语言代码遵循标准格式,例如:

  • zh_CN — 简体中文
  • zh_TW — 繁体中文
  • ja — 日语
  • en_US — 美式英语(默认)
  • fr_FR — 法国法语

翻译文件名格式为:{文本域}-{语言代码}.mo

例如,fabled-sunset-zh_CN.mo 就是该主题的简体中文翻译文件。

存放位置

  • 官方主题目录的主题:翻译文件由 WordPress 自动下载到 wp-content/languages/themes/。
  • 自用或私人分发的主题:放在主题目录下的 languages/(或你在 Domain Path 中指定的目录)。

六、延伸阅读与官方资源

国际化的内容不止于此,WordPress 官方手册中还有更的讲解,包括:

  • 字符串中占位符的处理(使用 sprintf() 配合翻译函数)
  • 上下文注释(使用 _x() 为同一个英文单词在不同场景提供不同的翻译提示)
  • JavaScript 中的国际化(使用 wp.i18n 模块)

如果你准备将主题提交到官方目录,建议通读以下资料:


总结

  • 为什么要做国际化:全球用户都能用、官方目录强制要求、更新安全。
  • 文本域是关键:必须与主题文件夹名称一致,在 style.css 中声明,并在所有翻译函数中作为参数传入。
  • 代码中不要直接写死文本:全部用 __()、_e()、_n() 等函数包裹,并尽量配合转义函数(如 esc_html__())。
  • 翻译文件加载:官方目录的主题无需手动加载;自用主题在 after_setup_theme 钩子上调用 load_theme_textdomain()。
  • 翻译文件位置:Domain Path 指定存放目录,默认是 /languages,文件命名为 {textdomain}-{locale}.mo。

把国际化当作主题开发的基础配置,就像注册导航菜单或添加缩略图支持一样自然。养成习惯后,你会发现这套机制简洁而强大,既保护了代码的可维护性,也打开了一扇面向全球用户的门。