缩略图

WordPress主题国际化:让你的主题支持多语言

2025年11月14日 文章分类 会被自动插入 会被自动插入
本文最后更新于2025-11-14已经过去了15天请注意内容时效性
热度42 点赞 收藏0 评论0

本文是《WordPress主题开发从入门到精通》系列教程的第十三篇。我们将学习如何为WordPress主题添加多语言支持,让全世界的用户都能使用你的主题。

你是否想过让你的主题被全世界的用户使用?无论是英语、西班牙语、中文还是其他语言,国际化(Internationalization,简称i18n)让你的主题能够轻松适应不同语言环境。

今天我们就来学习如何为我们的主题添加完整的国际化支持。

什么是国际化?为什么需要它?

国际化(i18n) 是指开发软件时,使其能够无需修改代码即可适应不同语言和地区的过程。本地化(l10n) 则是指为特定语言或地区创建翻译文件的过程。

为什么需要国际化?

  • 全球市场:让你的主题可以被全世界用户使用
  • WordPress官方要求:提交到WordPress官方主题目录必须支持国际化
  • 专业标准:国际化是专业主题开发的基本要求
  • 用户体验:用户可以使用自己熟悉的语言

第一步:基础准备 - 设置文本域

文本域(Text Domain)是国际化的核心,它告诉WordPress哪个翻译文件对应哪个主题。

style.css中设置文本域:

/*
Theme Name: My First Theme
Text Domain: my-first-theme
Domain Path: /languages
*/

/* 其余样式代码... */

functions.php中加载文本域:

/**
 * 加载主题文本域
 */
function mft_load_theme_textdomain() {
    // 加载主题语言文件
    load_theme_textdomain('my-first-theme', get_template_directory() . '/languages');
}
add_action('after_setup_theme', 'mft_load_theme_textdomain');

第二步:准备翻译函数

WordPress提供了一系列翻译函数,我们需要在主题中正确使用它们。

基本翻译函数:

/**
 * 翻译函数示例
 */

// 1. __() - 返回翻译后的字符串
function mft_basic_translation_example() {
    // 错误做法 - 硬编码字符串
    echo '<h1>欢迎来到我们的网站</h1>';

    // 正确做法 - 可翻译字符串
    echo '<h1>' . __('欢迎来到我们的网站', 'my-first-theme') . '</h1>';
}

// 2. _e() - 直接输出翻译后的字符串
function mft_e_translation_example() {
    // 错误做法
    echo '阅读更多';

    // 正确做法
    _e('阅读更多', 'my-first-theme');
}

// 3. _x() - 带上下文的翻译
function mft_context_translation_example() {
    // "Post" 在动词和名词情况下需要不同翻译
    $verb = _x('Post', 'verb', 'my-first-theme');    // 发表
    $noun = _x('Post', 'noun', 'my-first-theme');     // 文章

    echo '<button>' . $verb . '</button>';
    echo '<div>' . $noun . '</div>';
}

// 4. _n() - 单复数处理
function mft_plural_translation_example($comment_count) {
    // 根据数量显示不同的文本
    printf(
        _n(
            '有1条评论',    // 单数
            '有%s条评论',   // 复数
            $comment_count,
            'my-first-theme'
        ),
        number_format_i18n($comment_count)  // 本地化数字格式
    );
}

// 5. esc_html__() - 翻译并转义HTML
function mft_safe_translation_example($user_input) {
    // 安全做法:翻译并转义
    echo '<div>' . esc_html__('用户输入', 'my-first-theme') . ': ' . esc_html($user_input) . '</div>';
}

第三步:全面国际化我们的主题

现在让我们系统地国际化整个主题。我们将从模板文件开始。

3.1 国际化header.php

<?php
/**
 * 头部模板 - 国际化版本
 * 
 * @package My_First_Theme
 */

?><!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <?php
    // 国际化页面标题
    if (is_front_page() || is_home()) {
        $page_title = get_bloginfo('name');
        if (get_bloginfo('description')) {
            $page_title .= ' - ' . get_bloginfo('description');
        }
    } elseif (is_singular()) {
        $page_title = wp_title('', false) . ' - ' . get_bloginfo('name');
    } else {
        $page_title = wp_title('', false);
        if ($page_title) {
            $page_title .= ' - ' . get_bloginfo('name');
        } else {
            $page_title = get_bloginfo('name');
        }
    }
    ?>
    <title><?php echo esc_html($page_title); ?></title>

    <link rel="stylesheet" href="<?php echo get_stylesheet_uri(); ?>">
    <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<!-- 无障碍跳过链接 -->
<a class="skip-link screen-reader-text" href="#main-content">
    <?php esc_html_e('跳过导航直接到内容', 'my-first-theme'); ?>
</a>

<header class="site-header" role="banner">
    <div class="header-inner">

        <div class="site-branding">
            <?php if (has_custom_logo()) : ?>
                <div class="site-logo">
                    <?php the_custom_logo(); ?>
                </div>
            <?php else : ?>
                <h1 class="site-title">
                    <a href="<?php echo esc_url(home_url('/')); ?>" rel="home">
                        <?php bloginfo('name'); ?>
                    </a>
                </h1>
                <?php
                $description = get_bloginfo('description', 'display');
                if ($description || is_customize_preview()) : ?>
                    <p class="site-description">
                        <?php echo $description; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
                    </p>
                <?php endif; ?>
            <?php endif; ?>
        </div>

        <nav class="main-navigation" role="navigation" aria-label="<?php esc_attr_e('主导航', 'my-first-theme'); ?>">
            <?php
            wp_nav_menu(array(
                'theme_location'  => 'primary',
                'menu_class'      => 'primary-menu',
                'container'       => false,
                'fallback_cb'    => false,
            ));
            ?>
        </nav>

    </div>
</header>

3.2 国际化index.php

<?php
/**
 * 主模板文件 - 国际化版本
 * 
 * @package My_First_Theme
 */

get_header(); ?>

<div class="content-wrapper">
    <main id="main-content" class="main-content" role="main">

        <?php if (have_posts()) : ?>

            <header class="page-header">
                <?php
                if (is_home() && !is_front_page()) :
                    ?>
                    <h1 class="page-title">
                        <?php single_post_title(); ?>
                    </h1>
                    <?php
                elseif (is_search()) :
                    ?>
                    <h1 class="page-title">
                        <?php
                        printf(
                            /* translators: %s: 搜索关键词 */
                            esc_html__('搜索结果:%s', 'my-first-theme'),
                            '<span>' . get_search_query() . '</span>'
                        );
                        ?>
                    </h1>
                    <?php
                elseif (is_archive()) :
                    the_archive_title('<h1 class="page-title">', '</h1>');
                    the_archive_description('<div class="archive-description">', '</div>');
                endif;
                ?>
            </header>

            <?php
            // 主循环
            while (have_posts()) : the_post(); ?>

                <article id="post-<?php the_ID(); ?>" <?php post_class('article-item'); ?>>

                    <header class="article-header">
                        <?php
                        if (is_singular()) :
                            the_title('<h1 class="article-title">', '</h1>');
                        else :
                            the_title('<h2 class="article-title"><a href="' . esc_url(get_permalink()) . '">', '</a></h2>');
                        endif;
                        ?>

                        <div class="article-meta">
                            <?php
                            // 作者
                            if ('post' === get_post_type()) :
                                printf(
                                    '<span class="byline">%s <span class="author vcard"><a class="url fn n" href="%s">%s</a></span></span>',
                                    esc_html__('作者:', 'my-first-theme'),
                                    esc_url(get_author_posts_url(get_the_author_meta('ID'))),
                                    esc_html(get_the_author())
                                );
                            endif;

                            // 发布时间
                            $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
                            if (get_the_time('U') !== get_the_modified_time('U')) {
                                $time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
                            }

                            printf(
                                '<span class="posted-on">%s %s</span>',
                                esc_html__('发布于:', 'my-first-theme'),
                                $time_string
                            );

                            // 分类
                            $categories_list = get_the_category_list(esc_html__(', ', 'my-first-theme'));
                            if ($categories_list) :
                                printf(
                                    '<span class="cat-links">%s %s</span>',
                                    esc_html__('分类:', 'my-first-theme'),
                                    $categories_list
                                );
                            endif;
                            ?>
                        </div>
                    </header>

                    <?php if (has_post_thumbnail()) : ?>
                        <div class="article-thumbnail">
                            <?php the_post_thumbnail('large'); ?>
                        </div>
                    <?php endif; ?>

                    <div class="article-content">
                        <?php
                        if (is_singular()) {
                            the_content();

                            // 分页链接
                            wp_link_pages(array(
                                'before' => '<div class="page-links">' . esc_html__('页面:', 'my-first-theme'),
                                'after'  => '</div>',
                            ));
                        } else {
                            the_excerpt();
                        }
                        ?>
                    </div>

                    <footer class="article-footer">
                        <?php
                        // 标签
                        $tags_list = get_the_tag_list('', esc_html_x(', ', '标签分隔符', 'my-first-theme'));
                        if ($tags_list) :
                            printf(
                                '<span class="tags-links">%s %s</span>',
                                esc_html__('标签:', 'my-first-theme'),
                                $tags_list
                            );
                        endif;

                        // 评论链接
                        if (!is_singular() && !post_password_required() && (comments_open() || get_comments_number())) :
                            ?>
                            <span class="comments-link">
                                <?php
                                comments_popup_link(
                                    esc_html__('发表评论', 'my-first-theme'),
                                    esc_html__('1 条评论', 'my-first-theme'),
                                    esc_html__('% 条评论', 'my-first-theme')
                                );
                                ?>
                            </span>
                            <?php
                        endif;

                        // 编辑链接
                        edit_post_link(
                            esc_html__('编辑', 'my-first-theme'),
                            '<span class="edit-link">',
                            '</span>'
                        );
                        ?>
                    </footer>

                </article>

            <?php endwhile; ?>

            <?php
            // 分页导航
            the_posts_pagination(array(
                'prev_text' => esc_html__('上一页', 'my-first-theme'),
                'next_text' => esc_html__('下一页', 'my-first-theme'),
                'before_page_number' => '<span class="meta-nav screen-reader-text">' . esc_html__('第', 'my-first-theme') . ' </span>',
            ));
            ?>

        <?php else : ?>

            <section class="no-results not-found">
                <header class="page-header">
                    <h1 class="page-title">
                        <?php esc_html_e('没有找到内容', 'my-first-theme'); ?>
                    </h1>
                </header>

                <div class="page-content">
                    <?php if (is_search()) : ?>

                        <p><?php esc_html_e('抱歉,没有找到匹配的搜索结果。请尝试其他关键词。', 'my-first-theme'); ?></p>
                        <?php get_search_form(); ?>

                    <?php else : ?>

                        <p><?php esc_html_e('看起来没有找到您要的内容。或许搜索可以帮助您。', 'my-first-theme'); ?></p>
                        <?php get_search_form(); ?>

                    <?php endif; ?>
                </div>
            </section>

        <?php endif; ?>

    </main>

    <?php get_sidebar(); ?>
</div>

<?php get_footer(); ?>

3.3 国际化footer.php

<?php
/**
 * 页脚模板 - 国际化版本
 * 
 * @package My_First_Theme
 */

?>

    </div><!-- .content-wrapper -->

    <footer class="site-footer" role="contentinfo">

        <?php if (is_active_sidebar('footer-1') || is_active_sidebar('footer-2') || is_active_sidebar('footer-3')) : ?>
            <div class="footer-widgets">
                <div class="footer-widgets-inner">
                    <?php if (is_active_sidebar('footer-1')) : ?>
                        <div class="footer-widget-area">
                            <?php dynamic_sidebar('footer-1'); ?>
                        </div>
                    <?php endif; ?>

                    <?php if (is_active_sidebar('footer-2')) : ?>
                        <div class="footer-widget-area">
                            <?php dynamic_sidebar('footer-2'); ?>
                        </div>
                    <?php endif; ?>

                    <?php if (is_active_sidebar('footer-3')) : ?>
                        <div class="footer-widget-area">
                            <?php dynamic_sidebar('footer-3'); ?>
                        </div>
                    <?php endif; ?>
                </div>
            </div>
        <?php endif; ?>

        <div class="site-info">
            <div class="site-info-inner">

                <?php
                // 版权信息 - 支持多语言
                $copyright_text = get_theme_mod('footer_copyright', sprintf(
                    /* translators: 1: 当前年份, 2: 网站名称 */
                    esc_html__('© %1$s %2$s. 保留所有权利。', 'my-first-theme'),
                    date('Y'),
                    get_bloginfo('name')
                ));
                ?>

                <div class="footer-copyright">
                    <?php echo wp_kses_post($copyright_text); ?>
                </div>

                <div class="footer-credits">
                    <?php
                    printf(
                        /* translators: %s: WordPress */
                        esc_html__('自豪地采用 %s', 'my-first-theme'),
                        '<a href="' . esc_url(__('https://wordpress.org/', 'my-first-theme')) . '">WordPress</a>'
                    );
                    ?>
                    <span class="sep"> | </span>
                    <?php
                    printf(
                        /* translators: 1: 主题名称, 2: 主题作者 */
                        esc_html__('主题: %1$s by %2$s', 'my-first-theme'),
                        'My First Theme',
                        '<a href="https://example.com/">Your Name</a>'
                    );
                    ?>
                </div>

                <?php if (get_theme_mod('back_to_top', true)) : ?>
                    <button id="back-to-top" class="back-to-top" aria-label="<?php esc_attr_e('回到顶部', 'my-first-theme'); ?>">
                        <?php esc_html_e('↑', 'my-first-theme'); ?>
                    </button>
                <?php endif; ?>

            </div>
        </div>

    </footer>

    <?php wp_footer(); ?>

</body>
</html>

3.4 国际化comments.php

<?php
/**
 * 评论模板 - 国际化版本
 * 
 * @package My_First_Theme
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 如果文章需要密码保护,不显示评论
if (post_password_required()) {
    return;
}

if (have_comments() || comments_open()) : ?>

    <div id="comments" class="comments-area">

        <?php if (have_comments()) : ?>

            <h2 class="comments-title">
                <?php
                $comment_count = get_comments_number();
                if ('1' === $comment_count) {
                    printf(
                        /* translators: 1: 标题 */
                        esc_html__('有一条评论', 'my-first-theme'),
                        '<span>' . get_the_title() . '</span>'
                    );
                } else {
                    printf(
                        /* translators: 1: 评论数量, 2: 标题 */
                        esc_html(_n('%1$s 条评论', '%1$s 条评论', $comment_count, 'my-first-theme')),
                        number_format_i18n($comment_count),
                        '<span>' . get_the_title() . '</span>'
                    );
                }
                ?>
            </h2>

            <ol class="comment-list">
                <?php
                wp_list_comments(array(
                    'avatar_size' => 60,
                    'style'       => 'ol',
                    'short_ping'  => true,
                    'reply_text'  => esc_html__('回复', 'my-first-theme'),
                ));
                ?>
            </ol>

            <?php
            the_comments_pagination(array(
                'prev_text' => esc_html__('上一页', 'my-first-theme'),
                'next_text' => esc_html__('下一页', 'my-first-theme'),
            ));
            ?>

        <?php endif; ?>

        <?php if (!comments_open()) : ?>
            <p class="no-comments">
                <?php esc_html_e('评论已关闭。', 'my-first-theme'); ?>
            </p>
        <?php endif; ?>

        <?php
        // 评论表单
        comment_form(array(
            'title_reply'          => esc_html__('发表评论', 'my-first-theme'),
            'title_reply_to'       => esc_html__('回复 %s', 'my-first-theme'),
            'cancel_reply_link'    => esc_html__('取消回复', 'my-first-theme'),
            'label_submit'         => esc_html__('提交评论', 'my-first-theme'),
            'comment_notes_before' => '<p class="comment-notes">' .
                esc_html__('您的电子邮箱地址不会被公开。', 'my-first-theme') . '</p>',
        ));
        ?>

    </div>

<?php endif; ?>

第四步:国际化JavaScript文件

创建assets/js/i18n.js文件处理前端国际化:

/**
 * 前端国际化处理
 */
var MFT_i18n = MFT_i18n || {};

MFT_i18n = {

    // 翻译字符串
    strings: {
        loading: '加载中...',
        loadMore: '加载更多',
        noMorePosts: '没有更多文章了',
        searchPlaceholder: '搜索...',
        readMore: '阅读更多',
        close: '关闭',
        expand: '展开',
        collapse: '收起'
    },

    // 日期格式
    dateFormat: 'Y年m月d日',

    // 初始化
    init: function() {
        this.localizeStrings();
        this.localizeDates();
    },

    // 本地化字符串
    localizeStrings: function() {
        // 这里可以通过PHP传递翻译后的字符串
        if (typeof mft_l10n !== 'undefined') {
            this.strings = {...this.strings, ...mft_l10n};
        }
    },

    // 本地化日期
    localizeDates: function() {
        // 日期本地化处理
        jQuery('.localized-date').each(function() {
            var date = new Date(jQuery(this).data('timestamp') * 1000);
            var formattedDate = date.toLocaleDateString();
            jQuery(this).text(formattedDate);
        });
    },

    // 获取翻译字符串
    __: function(string) {
        return this.strings[string] || string;
    },

    // 带上下文的翻译
    _x: function(string, context) {
        var key = string + '|' + context;
        return this.strings[key] || string;
    },

    // 单复数处理
    _n: function(single, plural, number) {
        if (number === 1) {
            return this.strings[single] || single;
        } else {
            return this.strings[plural] || plural;
        }
    }
};

// 初始化
jQuery(document).ready(function($) {
    MFT_i18n.init();
});

functions.php中传递翻译字符串给JavaScript:

/**
 * 传递翻译字符串到JavaScript
 */
function mft_localize_script() {

    wp_localize_script('mft-main-js', 'mft_l10n', array(
        'loading'       => esc_html__('加载中...', 'my-first-theme'),
        'loadMore'      => esc_html__('加载更多', 'my-first-theme'),
        'noMorePosts'   => esc_html__('没有更多文章了', 'my-first-theme'),
        'readMore'      => esc_html__('阅读更多', 'my-first-theme'),
        'close'         => esc_html__('关闭', 'my-first-theme'),
        'expand'        => esc_html__('展开', 'my-first-theme'),
        'collapse'      => esc_html__('收起', 'my-first-theme'),

        // 带上下文的翻译
        'Post|verb'     => _x('发表', 'verb', 'my-first-theme'),
        'Post|noun'     => _x('文章', 'noun', 'my-first-theme'),
    ));
}
add_action('wp_enqueue_scripts', 'mft_localize_script');

第五步:创建POT文件和翻译

5.1 安装gettext工具

首先需要安装gettext工具来生成POT文件:

# Ubuntu/Debian
sudo apt-get install gettext

# macOS with Homebrew
brew install gettext

# Windows: 下载Poedit软件

5.2 创建POT文件

在主题根目录创建languages文件夹,然后使用WP-CLI生成POT文件:

# 使用WP-CLI(推荐)
wp i18n make-pot . languages/my-first-theme.pot

# 或者手动创建makepot.php文件

手动创建makepot.php文件:

<?php
/**
 * 生成POT文件的脚本
 */

require_once 'wp-load.php';

$domain = 'my-first-theme';
$pot_file = get_template_directory() . '/languages/' . $domain . '.pot';

// 确保languages目录存在
if (!is_dir(get_template_directory() . '/languages')) {
    mkdir(get_template_directory() . '/languages', 0755, true);
}

// 使用WordPress的翻译工具
if (!class_exists('WP_Translations')) {
    require_once ABSPATH . 'wp-admin/includes/translation-install.php';
}

// 生成POT文件的基本命令
$command = sprintf(
    'xgettext --package-name="%s" --package-version="%s" --msgid-bugs-address="%s" --from-code=UTF-8 -o %s -L PHP %s',
    escapeshellarg('My First Theme'),
    escapeshellarg('1.0.0'),
    escapeshellarg('your-email@example.com'),
    escapeshellarg($pot_file),
    escapeshellarg('*.php')
);

exec($command, $output, $return_var);

if ($return_var === 0) {
    echo "POT文件生成成功: " . $pot_file . "\n";
} else {
    echo "POT文件生成失败\n";
}

5.3 创建翻译文件

创建中文翻译文件languages/zh_CN.po

# Chinese (Simplified) translations for My First Theme
# My First Theme 的中文(简体)翻译
# Copyright (C) 2024 Your Name
# This file is distributed under the same license as the My First Theme package.
# Your Name <your-email@example.com>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: My First Theme 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-01 12:00+0800\n"
"PO-Revision-Date: 2024-01-01 12:00+0800\n"
"Last-Translator: Your Name <your-email@example.com>\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"

#: header.php:15
msgid "跳过导航直接到内容"
msgstr "跳过导航直接到内容"

#: header.php:32
msgid "主导航"
msgstr "主导航"

#: index.php:25
msgid "搜索结果:%s"
msgstr "搜索结果:%s"

#: index.php:55
msgid "作者:"
msgstr "作者:"

#: index.php:67
msgid "发布于:"
msgstr "发布于:"

#: index.php:75
msgid "分类:"
msgstr "分类:"

#: index.php:109
msgid "标签:"
msgstr "标签:"

#: index.php:118
msgid "发表评论"
msgstr "发表评论"

#: index.php:119
msgid "1 条评论"
msgstr "1 条评论"

#: index.php:120
msgid "% 条评论"
msgstr "% 条评论"

#: index.php:128
msgid "编辑"
msgstr "编辑"

#: index.php:140
msgid "上一页"
msgstr "上一页"

#: index.php:141
msgid "下一页"
msgstr "下一页"

#: index.php:142
msgid "第"
msgstr "第"

#: index.php:151
msgid "没有找到内容"
msgstr "没有找到内容"

#: index.php:156
msgid "抱歉,没有找到匹配的搜索结果。请尝试其他关键词。"
msgstr "抱歉,没有找到匹配的搜索结果。请尝试其他关键词。"

#: index.php:161
msgid "看起来没有找到您要的内容。或许搜索可以帮助您。"
msgstr "看起来没有找到您要的内容。或许搜索可以帮助您。"

使用Poedit编译为MO文件,或使用命令行:

msgfmt languages/zh_CN.po -o languages/zh_CN.mo

第六步:测试国际化功能

6.1 设置网站语言

wp-config.php中设置语言:

define('WPLANG', 'zh_CN');

或在后台"设置"→"常规"中设置网站语言。

6.2 创建语言切换器(可选)

创建多语言切换小工具:

/**
 * 语言切换器小工具
 */
class MFT_Language_Switcher_Widget extends WP_Widget {

    function __construct() {
        parent::__construct(
            'mft_language_switcher',
            __('语言切换器', 'my-first-theme'),
            array('description' => __('显示可用语言列表', 'my-first-theme'))
        );
    }

    public function widget($args, $instance) {
        echo $args['before_widget'];

        if (!empty($instance['title'])) {
            echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
        }

        $languages = apply_filters('wpml_active_languages', null);

        if (!empty($languages)) {
            echo '<ul class="language-switcher">';
            foreach ($languages as $language) {
                $class = $language['active'] ? 'class="active"' : '';
                printf(
                    '<li %s><a href="%s">%s</a></li>',
                    $class,
                    esc_url($language['url']),
                    esc_html($language['native_name'])
                );
            }
            echo '</ul>';
        }

        echo $args['after_widget'];
    }

    public function form($instance) {
        $title = !empty($instance['title']) ? $instance['title'] : __('选择语言', 'my-first-theme');
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>">
                <?php _e('标题:', 'my-first-theme'); ?>
            </label>
            <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" 
                   name="<?php echo $this->get_field_name('title'); ?>" 
                   type="text" value="<?php echo esc_attr($title); ?>">
        </p>
        <?php
    }

    public function update($new_instance, $old_instance) {
        $instance = array();
        $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
        return $instance;
    }
}

// 注册小工具
function mft_register_language_switcher() {
    register_widget('MFT_Language_Switcher_Widget');
}
add_action('widgets_init', 'mft_register_language_switcher');

第七步:国际化最佳实践

7.1 代码规范

// ✅ 正确做法
printf(
    _n(
        '%d 条评论',
        '%d 条评论',
        $comment_count,
        'my-first-theme'
    ),
    $comment_count
);

// ❌ 错误做法
echo $comment_count . ' 条评论';

// ✅ 正确做法 - 带HTML转义
printf(
    '<a href="%s">%s</a>',
    esc_url($link),
    esc_html__('阅读更多', 'my-first-theme')
);

// ❌ 错误做法 - 不安全
echo '<a href="' . $link . '">阅读更多</a>';

7.2 上下文使用

// 菜单标签
_x('Home', 'menu item', 'my-first-theme');
_x('Blog', 'menu item', 'my-first-theme');

// 按钮标签
_x('Save', 'button', 'my-first-theme');
_x('Delete', 'button', 'my-first-theme');

// 日期格式
_x('F j, Y', 'date format', 'my-first-theme');

总结:国际化完整流程

通过今天的学习,你已经掌握了WordPress主题国际化的完整技能:

  1. 文本域设置:在style.css中定义文本域
  2. 翻译函数使用__(), _e(), _x(), _n()
  3. 模板文件国际化:系统化处理所有字符串
  4. JavaScript国际化:前端字符串本地化
  5. POT文件生成:创建翻译模板
  6. 翻译文件创建:制作PO/MO文件
  7. 测试和优化:确保翻译正确工作

国际化检查清单:

  • [ ] 所有用户可见的字符串都使用了翻译函数
  • [ ] 正确设置了文本域和语言路径
  • [ ] 创建了POT翻译模板文件
  • [ ] 提供了至少一种语言翻译
  • [ ] 测试了不同语言环境下的显示
  • [ ] 处理了单复数形式和上下文翻译

现在你的主题已经具备了国际化的能力!在下一篇文章中,我们将学习WordPress主题安全开发最佳实践,确保主题的安全性。

正文结束 阅读本文相关话题
相关阅读
评论框
正在回复
评论列表
暂无评论,快来抢沙发吧~
sitemap