Polylang主题PO文件法语翻译一次性导入插件故障排查及功能完善需求
Polylang主题PO文件法语翻译一次性导入插件故障排查及功能完善需求
问题核心诊断
从你的描述和代码来看,当前导入失败+翻译不生效的核心问题有几个:
- Polylang语言关联缺失:你的代码向
wp_polylang_strings插入数据时,没有指定lang_id(对应法语的语言ID),导致导入的翻译条目没有绑定到法语环境,Polylang根本不会调用这些翻译。 - PO文件解析逻辑不完善:只处理了单数翻译,忽略了复数条目,且没有考虑PO文件的
msgctxt(上下文)字段,同时没有过滤仅处理法语PO文件(你当前会处理en_CA.po,这完全没必要)。 - 重复插入风险:直接用
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();
关键修复点说明
- 语言绑定:通过
pll_get_language获取法语的lang_id,插入时关联到Polylang的语言条目,确保翻译被正确调用。 - 法语文件过滤:只处理目标locale的PO文件(比如
fr_CA.po),避免误处理英语文件。 - 完善PO解析:
- 支持PO文件的
msgctxt上下文,确保相同字符串在不同上下文的翻译被正确区分。 - 处理复数翻译,序列化后存储到Polylang(符合Polylang的存储逻辑)。
- 跳过空字符串/空翻译,避免无效条目。
- 支持PO文件的
- 重复条目处理:用
wpdb->replace替代insert,自动覆盖已存在的相同条目,避免重复数据。 - 前置校验:在导入前检查Polylang是否激活、目标语言是否存在,提前报错避免无效操作。
验证步骤
- 确保Polylang中已添加法语(locale为
fr_CA或你设置的$target_lang值)。 - 激活这个插件,进入工具 > Polylang French Import页面。
- 点击「Run French Translation Import」按钮,等待导入完成。
- 验证:
- 进入Languages > Strings Translations,筛选法语,检查是否能看到导入的翻译条目。
- 切换到法语前端页面,逐一检查页面内容,确保没有英语字符串残留。
- 若有遗漏,检查对应的PO文件中是否存在该字符串的翻译,重新运行导入。
- 验证完成后,立即停用并删除这个插件(因为它是单用途工具)。
常见问题排查
- PO文件解析失败:检查PO文件是否为UTF-8编码(无BOM),格式是否符合Gettext标准。可以用Poedit打开文件,重新保存为标准PO格式。
- 翻译仍不显示:检查Polylang的语言设置是否正确,确保前端切换的语言与导入时的
$target_lang一致;另外确认主题中的字符串已替换为pll_e()/pll__()。 - 重复翻译:如果之前手动添加过翻译,
replace操作会覆盖为PO文件中的内容,这是预期行为。




