You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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检查本地翻译文件的版本,把项目标记为“需要更新”,但实际的导入操作需要依赖:

  1. 后台 cron 任务执行locale_translation_fetch_projects()
  2. 手动在后台点击“更新翻译”按钮

在update.php流程中,这些后续操作不会自动触发,所以翻译不会同步更新。

内容的提问来源于stack exchange,提问作者Patrick Michiels

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 02:42:36