You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Polylang主题PO文件法语翻译一次性导入插件故障排查及功能完善需求

Polylang主题PO文件法语翻译一次性导入插件故障排查及功能完善需求

问题核心诊断

从你的描述和代码来看,当前导入失败+翻译不生效的核心问题有几个:

  1. Polylang语言关联缺失:你的代码向wp_polylang_strings插入数据时,没有指定lang_id(对应法语的语言ID),导致导入的翻译条目没有绑定到法语环境,Polylang根本不会调用这些翻译。
  2. PO文件解析逻辑不完善:只处理了单数翻译,忽略了复数条目,且没有考虑PO文件的msgctxt(上下文)字段,同时没有过滤仅处理法语PO文件(你当前会处理en_CA.po,这完全没必要)。
  3. 重复插入风险:直接用insert会导致重复条目,应该用replace或者先校验存在性。

修复后的完整插件代码

我把你的代码做了核心修复,解决了上述问题,同时添加了法语过滤、语言绑定、复数翻译处理、重复条目处理等功能:

<?php
/**
 * Plugin Name: Polylang French Translation Importer
 * Description: One-time plugin to import French translations from theme .po files into Polylang database
 * Version: 2.0
 * Author: Your Name
 */

if (!defined('ABSPATH')) exit;

class PolylangFrenchImporter {
    private $import_path;
    private $target_lang = 'fr_CA'; // 改成你Polylang中实际的法语locale,比如fr或fr_CA

    public function __construct() {
        $this->import_path = WP_CONTENT_DIR . '/languages/themes/';
        add_action('admin_menu', [$this, 'add_admin_page']);
    }

    public function add_admin_page() {
        add_management_page(
            'Polylang French Import',
            'Polylang French Import',
            'manage_options',
            'polylang-french-import',
            [$this, 'render_import_page']
        );
    }

    public function render_import_page() {
        echo '<div class="wrap"><h1>Polylang French Translation Importer</h1>';
        
        // 检查Polylang是否激活
        if (!function_exists('pll_languages_list')) {
            echo '<p style="color:red; font-size:1.2em;">Error: Polylang is not active or not installed!</p>';
            echo '</div>';
            return;
        }

        // 检查目标语言是否在Polylang中存在
        $lang_exists = in_array($this->target_lang, pll_languages_list(['fields' => 'locale']));
        if (!$lang_exists) {
            echo '<p style="color:red; font-size:1.2em;">Error: Target language ' . esc_html($this->target_lang) . ' is not added in Polylang!</p>';
            echo '<p>Please go to Languages > Languages and add/verify the language with locale ' . esc_html($this->target_lang) . '</p>';
            echo '</div>';
            return;
        }

        if (isset($_POST['run_import'])) {
            $this->run_import();
        }

        echo '<form method="post">';
        submit_button('Run French Translation Import', 'primary', 'run_import');
        echo '</form></div>';
    }

    private function run_import() {
        // 获取法语的lang_id
        $lang = pll_get_language($this->target_lang, 'object');
        $lang_id = $lang->term_id;

        // 只过滤法语的PO文件
        $files = glob($this->import_path . $this->target_lang . '.po');
        if (empty($files)) {
            echo '<p style="color:red;">No French PO file found in: ' . esc_html($this->import_path) . '</p>';
            return;
        }

        require_once ABSPATH . 'wp-admin/includes/translation-install.php';
        if (!class_exists('PO')) {
            require_once ABSPATH . 'wp-includes/pomo/po.php';
        }

        $total_imported = 0;
        foreach ($files as $file) {
            echo '<h3>Processing File: ' . esc_html(basename($file)) . '</h3>';
            
            $po = new PO();
            $loaded = $po->import_from_file($file);
            
            if (!$loaded) {
                echo '<p style="color:red;">Failed to parse PO file. Check file encoding/format!</p>';
                error_log('Polylang Importer: Failed to load PO file ' . $file);
                continue;
            }

            $imported_count = 0;
            global $wpdb;
            $strings_table = $wpdb->prefix . 'polylang_strings';

            foreach ($po->entries as $entry) {
                // 跳过空原字符串或空翻译
                if (empty($entry->singular) || empty($entry->translations)) {
                    continue;
                }

                // 处理上下文:用PO文件中的msgctxt,默认'theme'
                $context = !empty($entry->context) ? $entry->context : 'theme';
                // 生成Polylang标准的唯一标识(string + context的MD5)
                $name = md5($entry->singular . $context);

                // 处理翻译内容:单数或复数
                if (count($entry->translations) === 1) {
                    $value = $entry->translations[0];
                } else {
                    // 复数翻译序列化存储(符合Polylang的存储逻辑)
                    $value = maybe_serialize($entry->translations);
                }

                // 插入/更新翻译:用replace避免重复
                $result = $wpdb->replace(
                    $strings_table,
                    [
                        'string'    => $entry->singular,
                        'context'   => $context,
                        'name'      => $name,
                        'value'     => $value,
                        'lang_id'   => $lang_id,
                        'group'     => 'theme-import',
                        'multiline' => (strpos($entry->singular, "\n") !== false) ? 1 : 0,
                    ],
                    [
                        '%s', '%s', '%s', '%s', '%d', '%s', '%d'
                    ]
                );

                if ($result) {
                    $imported_count++;
                }
            }

            echo '<p style="color:green;">Successfully imported ' . intval($imported_count) . ' translations from this file.</p>';
            $total_imported += $imported_count;
        }

        echo '<h2 style="color:green;">Import Complete! Total Translations Imported: ' . intval($total_imported) . '</h2>';
        echo '<p>Please verify French pages now. Once confirmed working, you can deactivate and delete this plugin.</p>';
    }
}

new PolylangFrenchImporter();

关键修复点说明

  1. 语言绑定:通过pll_get_language获取法语的lang_id,插入时关联到Polylang的语言条目,确保翻译被正确调用。
  2. 法语文件过滤:只处理目标locale的PO文件(比如fr_CA.po),避免误处理英语文件。
  3. 完善PO解析
    • 支持PO文件的msgctxt上下文,确保相同字符串在不同上下文的翻译被正确区分。
    • 处理复数翻译,序列化后存储到Polylang(符合Polylang的存储逻辑)。
    • 跳过空字符串/空翻译,避免无效条目。
  4. 重复条目处理:用wpdb->replace替代insert,自动覆盖已存在的相同条目,避免重复数据。
  5. 前置校验:在导入前检查Polylang是否激活、目标语言是否存在,提前报错避免无效操作。

验证步骤

  1. 确保Polylang中已添加法语(locale为fr_CA或你设置的$target_lang值)。
  2. 激活这个插件,进入工具 > Polylang French Import页面。
  3. 点击「Run French Translation Import」按钮,等待导入完成。
  4. 验证:
    • 进入Languages > Strings Translations,筛选法语,检查是否能看到导入的翻译条目。
    • 切换到法语前端页面,逐一检查页面内容,确保没有英语字符串残留。
    • 若有遗漏,检查对应的PO文件中是否存在该字符串的翻译,重新运行导入。
  5. 验证完成后,立即停用并删除这个插件(因为它是单用途工具)。

常见问题排查

  • PO文件解析失败:检查PO文件是否为UTF-8编码(无BOM),格式是否符合Gettext标准。可以用Poedit打开文件,重新保存为标准PO格式。
  • 翻译仍不显示:检查Polylang的语言设置是否正确,确保前端切换的语言与导入时的$target_lang一致;另外确认主题中的字符串已替换为pll_e()/pll__()
  • 重复翻译:如果之前手动添加过翻译,replace操作会覆盖为PO文件中的内容,这是预期行为。

火山引擎 最新活动