问题描述

只要创建一个 child-theme 就足够了 – 让我们在技术上说没有添加任何其他东西,但最低限度的 style.css – 为 child-theme 自动使用 parent-theme 的翻译?

child-theme/style.css

/**
 * Theme Name:     Child-Theme Child
 * Theme URI:      http://example.com/
 * Description:    Child theme for the Twentytwelve theme
 * Author:         Theme Author
 * Author URI:     http://example.com/
 * Template:       twentytwelve
 * Version:        0.1.0
 */

二十二主题有标准的语言翻译文件。

如果这不会在我的网站上自动发生,那么开始 trouble-shooting 的翻译是什么?

最佳解决方案

Is it enough to just create a child-theme – let’s say technically without adding anything else but the bare minimum style.css – to have the translation of the parent-theme being used automatically for the child-theme as well?

基本上,答案是 NO,… 但… 有一个选择:

添加一个 mu-plugin 。

这个 (MU-) 插件有几件事情:

  1. 它以 20 的优先级挂接到 after_setup_theme 中,假设父文本域/i18n .mo 文件以正确挂钩的默认优先级正确加载。

  2. 然后它检索 instanceof WP_Theme – 在这种情况下是儿童主题。

  3. 然后它检查是否真的有一个孩子主题在使用。

  4. 如果这是真的,那么它只会从父文件加载文本域。

实际上很容易,因为核心类对我们进行了大量的检查:它检索了父主题的另一个 WP_Theme 实例。然后检查 TextDomain 标题是否已设置,使用:$current_theme->get( 'TextDomain' ); 。因此,这个游戏有一个约定:这个插件只能工作,如果父主题得到了一个 Text Domain 和 (!) 一个 Domain Path 标题集。

<?php
/**
 * Plugin Name: (#113391) Parent Theme i18n Autoloader
 * Description: Load Twenty12 Child theme translation files automagically from Parent
 */
add_action( 'after_setup_theme', 'wpse113391_parent_theme_i18n_autoloader', 20 );
function wpse113391_parent_theme_i18n_autoloader()
{
    $current_theme = wp_get_theme();
    if ( is_child_theme() )
        $current_theme->parent()->load_textdomain();
}

现在这里出现了问题:由 core 提供的默认/标准的二十*主题不 (!) 具有 Domain Path 标题条目。这是我们必须立即修复的东西,因为 load_theme_textdomain()其他搜索不在父主题文件夹中的翻译文件,但是

  • 首先在子主题文件夹:get_stylesheet_directory().WP_Theme::get( 'DomainPath' ),这意味着 (A)Domain Path 需要设置,它需要以斜杠为前缀:/

  • 然后在子主题文件夹中:`get_stylesheet_directory() 。’/languages’ 。

  • 并在 WP_LANGUAGE_DIR.'/themes'目录中。

注意:我猜这只是”backwards compatibility” 永远不会被修复的错误,换句话说,这意味着有一个错误,但可能已经有开发人员在使用它了。 :P

那还有另外一个问题。 WP_Theme 类方法 load_textdomain()内部通过 $pathload_theme_textdomain()。而这个参数是 $this->get_stylesheet_directory()。此方法返回 $this->theme_root . '/' . $this->stylesheet 。所以这个功能实际上会很好,但是它只是简单地调用 get_stylesheet_directory()的内部替换 (这是可以过滤的) 。人们现在可以想想

“Hey! The class implements ArrayAccess! So simply set the missing array key of Domain Path!”

错误。所有类的属性都标记为 private,无法访问。

那你可能会想

“Why not simply extend the WP_Theme class and define a set() Method so we can manually set the missing header entries?”

错误。该类本身是 final,不可扩展。

结果:我们留下了什么 load_theme_textdomain() – 呼叫链中的最后一个功能 – 提供给我们。现在我们收到一个更大的插件来拦截 load_theme_textdomain()调用来加载正确的文件。为了不打扰其他 i18n 文件加载,它会立即从过滤器中删除回调,以保持您的环境整洁。

<?php
/**
 * Plugin Name: (#113391) Parent Theme i18n Autoloader
 * Description: Load Twenty12 Child theme translation files automagically from Parent
 */

add_action( 'muplugins_loaded', array( 'WPSE113391Parenti18nLoader', 'getInstance' ) );
class WPSE113391Parenti18nLoader
{
    public static $instance = null;

    private $theme = null;

    public static function getInstance()
    {
        null === self::$instance AND self::$instance = new self;
        return self::$instance;
    }

    public function __construct()
    {
        add_action( 'after_setup_theme', array( $this, 'i18nAutoloader' ), 20 );
    }

    public function setTheme( $theme )
    {
        return $this->theme = $theme;
    }

    public function getTheme()
    {
        return $this->theme;
    }

    public function i18nAutoloader()
    {
        if ( ! is_child_theme() )
            return;

        $current_theme = wp_get_theme();
        if ( '' === $current_theme->parent()->get( 'DomainPath' ) )
        {
            $this->setTheme( $current_theme->parent() );
            add_filter( 'override_load_textdomain', array( $this, 'overrideI18nLoader' ), 10, 3 );
        }
        $current_theme->parent()->load_textdomain();
    }

    public function overrideI18nLoader( $activate, $domain, $mofile )
    {
        // Don't intercept anything else: Self removing
        remove_filter( current_filter(), __FUNCTION__ );

        // Rebuild the internals of WP_Theme::get_stylesheet_directory() and load_theme_textdomain()
        $theme  = $this->getTheme();
        $path   = trailingslashit( $theme->get_theme_root() ).$theme->get_template();
        $locale = apply_filters( 'theme_locale', get_locale(), $domain );

        load_textdomain( $domain, "{$path}/{$locale}.mo" );

        // Return true to abort further attempts
        return true;
    }
}

次佳解决方案

默认情况下,这只是开箱即用。如果父主题提供翻译,child-theme 将会结束。

如果它不工作的东西是错误的。这是在我的情况,这里是我做了 trouble-shoot:

  1. 我激活了父主题,看看翻译是否在那里工作 – 没有。

  2. 然后我安装了 Debug Translations 插件来了解哪些语言文件被加载。

  3. 然后,我启动了一个 Xdebug 调试会话 (?XDEBUG_SESSION_START=1),并通过在其中放置一个断点来验证报告已被破坏的加载位置。

然后,结果是 Wordpress 正在寻找一个不同的 file-name 。我更正了文件名,然后工作。

故事的士气:主题中的语言文件应该只用本地命名,就像我的情况下的 de_DE.mo


故障:

+ wp-content
+--+ themes
|  +--+ child-theme
|  |  `--- style.css
.  .    ...
|  `--+ twentytwelve
|     +--+ languages
|     |  `--- twentytwelve-de_DE.mo    <<<
.    ...

加工:

+ wp-content
+--+ themes
|  +--+ child-theme
|  |  `--- style.css
.  .    ...
|  `--+ twentytwelve
|     +--+ languages
|     |  `--- de_DE.mo    <<<
.    ...

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。