Drupal 8自定义模块language.po文件通过update.php自动更新翻译的实现问题
解决Drupal 8.9.x自定义模块翻译在update.php中自动更新的问题
我之前也踩过这个坑——你用locale_translation_check_projects_local()的思路没错,但这个函数本质上只是标记项目需要更新翻译,并不会实际执行导入操作,所以update.php跑完后翻译没变化很正常。下面给你两种亲测有效的程序化实现方式,以及背后的逻辑说明:
方法一:直接调用翻译导入API(最可靠)
在你的hook_update_N里,跳过状态检查,直接调用Drupal的locale导入函数,手动导入指定的.po文件。这种方式不依赖后台任务,能确保update流程执行时翻译同步更新:
function custom_module_update_8049() { // 确保locale模块已启用并加载必要的文件 if (!\Drupal::moduleHandler()->moduleExists('locale')) { \Drupal::moduleHandler()->enable('locale'); } \Drupal::moduleHandler()->loadInclude('locale', 'inc', 'locale.import'); // 配置参数:目标语言、模块路径、PO文件位置 $langcode = 'de'; $module_name = 'custom_module'; $module_path = drupal_get_path('module', $module_name); $po_file_path = $module_path . '/translations/' . $langcode . '.po'; // 先检查PO文件是否存在,避免更新报错 if (!file_exists($po_file_path)) { throw new \Exception(t('Translation file @file not found. Update aborted.', ['@file' => $po_file_path])); } // 设置导入选项:覆盖现有翻译(包括自定义和系统默认的) $import_options = [ 'langcode' => $langcode, 'overwrite_options' => [ 'customized' => LOCALE_OVERWRITE_CUSTOMIZED, 'not_customized' => LOCALE_OVERWRITE_NOT_CUSTOMIZED, ], 'replace' => TRUE, // 完全替换现有翻译条目 ]; // 执行导入 $import_result = locale_import_one_file($po_file_path, $import_options); if ($import_result !== FALSE) { return t('Successfully updated @language translations for @module.', [ '@language' => $langcode, '@module' => $module_name, ]); } else { throw new \Exception(t('Failed to import @language translations for @module. Check the PO file format.', [ '@language' => $langcode, '@module' => $module_name, ])); } }
关键细节说明:
- 必须加载
locale.import.inc,因为locale_import_one_file()函数定义在这里 overwrite_options确保新翻译会覆盖旧的(不管是用户自定义的还是系统之前导入的)- 抛出异常能让update.php明确展示失败原因,方便排查
方法二:调用Drush命令(简洁但依赖环境)
如果你的服务器环境允许Web进程执行Drush命令,也可以在update hook里直接调用Drush的翻译导入命令,代码更简洁:
function custom_module_update_8049() { $module_path = drupal_get_path('module', 'custom_module'); $po_file = $module_path . '/translations/de.po'; // 执行Drush导入命令 $command = "drush locale:import custom_module de --file='$po_file' -y"; exec($command, $output, $return_var); if ($return_var === 0) { return t('Translations imported via Drush: @output', ['@output' => implode('\n', $output)]); } else { throw new \Exception(t('Drush translation import failed. Command output: @output', ['@output' => implode('\n', $output)])); } }
注意事项:
- 确保Web服务器用户(比如www-data)有执行Drush的权限,且Drush路径正确
- 生产环境使用前要测试,避免权限或路径问题导致更新失败
为什么原来的代码不生效?
locale_translation_check_projects_local()的作用是触发Drupal检查本地翻译文件的版本,把项目标记为“需要更新”,但实际的导入操作需要依赖:
- 后台 cron 任务执行
locale_translation_fetch_projects() - 手动在后台点击“更新翻译”按钮
在update.php流程中,这些后续操作不会自动触发,所以翻译不会同步更新。
内容的提问来源于stack exchange,提问作者Patrick Michiels
相关产品推荐
相关产品推荐

