本文详细记录了在 Hexo 博客中使用 hexo-multiple-language-generate 插件对 Volantis 主题进行多语言国际化时遇到的各种问题,包括目录结构调整、配置文件适配、导航链接错误、样式冲突等,以及从初步尝试到最终放弃该方案的全过程。

国际化需求与初步方案

我希望对现有 Hexo 博客进行国际化,支持中文(zh-CN)和英文(en)两种语言。初步方案是利用 hexo-multiple-language-generate 插件,并调整项目结构和配置文件。

核心变动点:

  1. 安装插件: hexo-multiple-language-generate
  2. 调整项目结构: 为每种语言创建独立的 source 目录(source-zh/source-en/)。
  3. Hexo 配置文件: 为每种语言创建独立的 Hexo 配置文件(config.zh.ymlconfig.en.yml)。
  4. 插件配置文件: 在项目根目录创建 hexo-multiple-language.yml
  5. 主题配置文件: 为每种语言创建独立的主题配置文件(config.volantis.zh.ymlconfig.volantis.en.yml)。
  6. 使用新命令: 生成博客时使用 hexo multiple-language-generate

阶段一:基础配置与内容迁移

按照初步方案,我安装了插件,创建了 hexo-multiple-language.yml 配置文件,并调整了目录结构,将中英文内容分别迁移到 source-zhsource-en 目录。为了确保英文站点有内容可以生成,我还在 source-en/_posts/ 下手动创建了一篇英文测试文章 hello-world-en.md

同时,我创建了 config.zh.ymlconfig.en.yml,分别配置了各自的语言、URL、源目录等信息,并确保 public_dir 指向统一的 public 目录,以便插件能正确地将英文内容生成到 public/en/ 子目录下。

阶段二:问题浮现与排查

完成基础配置并生成站点后,一系列问题开始出现。

问题一:导航栏文字被挤压

当我访问英文站点 http://localhost:5000/en/ 时,导航栏上的链接文字被挤压,只显示图标。通过浏览器开发者工具发现,<a> 标签的 display 属性计算结果为 block

  • 尝试与解决: 起初尝试通过外部 CSS 文件覆盖样式,但未生效。最终,我直接修改了 themes/volantis/layout/_partial/header.ejs,在导航链接的 <a> 标签中添加行内样式 style="display: inline-flex; align-items: center;",成功解决了文字挤压问题。

问题二:导航链接错误

这是最核心的问题。在 Volantis 主题的 Hexo 博客中,导航栏上的语言切换链接(“简体中文”和“English”)显示和跳转异常。

  • 具体表现: 当访问英文文章页面(例如 http://localhost:5000/en/hello-world-en/)时,导航栏中的“简体中文”链接本应指向 http://localhost:5000/,却错误地指向了 http://localhost:5000/en/;而“English”链接本应指向 http://localhost:5000/en/,却错误地指向了 http://localhost:5000/en/en/

  • 初步排查: 我检查了所有相关的配置文件:

    1. themes/volantis/layout/_partial/header.ejs:确认了链接是通过 <%- url_for(value.url) %> 动态生成的。
    2. _config.ymlconfig.*.yml:确认了多语言和永久链接的设置。
    3. config.volantis.*.yml:确认了导航菜单的 url 属性值(//en/)在配置层面是正确的。

这些检查表明,问题出在 Hexo 的 url_for 辅助函数上。它在渲染链接时,会基于当前页面的 root 路径(如 /en/)对相对路径进行拼接,从而导致了 URL 路径的重复。

阶段三:关键发现与终极解决方案

在排查过程中,我偶然发现了一个来自 Butterfly 主题的 switch-language.js 脚本。这个脚本揭示了一个关键信息:在某些主题中,多语言切换并非简单地依赖 url_for 生成的静态链接,而是通过 JavaScript 动态处理的。

该脚本中的 initLanguageSwitchLinks 函数会遍历所有带有特定类(multiple-language-switch)的链接,并为其添加点击事件监听器。当点击发生时,handleLanguageSwitch 函数会被调用,它会根据目标语言,手动构建正确的 URL(例如 http://localhost:5000/http://localhost:5000/en/)并进行跳转。

这完美解释了为什么 url_for 生成的链接不正确,因为正确的跳转逻辑被设计为由前端 JavaScript 控制。

最终解决方案

基于以上发现,最终的解决方案是,结合 switch-language.js 的工作原理,对主题进行以下修改:

  1. 修改 EJS 模板: 在 themes/volantis/layout/_partial/header.ejs 中,为语言切换链接的 <li><a> 标签添加 multiple-language-switch 类。这使得 switch-language.js 能够识别并处理这些链接的点击事件。

    1
    2
    3
    4
    5
    6
    <!-- 示例:找到生成语言切换链接的地方,添加 class -->
    <li class="menu-item menu-item-type-post_type menu-item-object-page multiple-language-switch">
    <a href="<%- url_for(value.url) %>">
    ...
    </a>
    </li>
  2. 引入 JS 脚本: 将 switch-language.js 脚本引入到主题中。最稳妥的方法是在 Hexo 的主配置文件 _config.yml 中,通过 inject 选项将其注入到页面底部。

    • 首先,将 switch-language.js 文件放置在 themes/volantis/source/js/ 目录下。
    • 然后,在 _config.yml 中添加注入配置:
    1
    2
    3
    inject:
    bottom:
    - <script src="/js/switch-language.js"></script>

通过这些修改,语言切换功能将由 switch-language.js 脚本接管。它会忽略 href 属性中由 url_for 生成的错误链接,并在用户点击时,动态计算并跳转到正确的语言根路径。

虽然通过自己DIY可以实现,但是后续还有需要可以调整的地方,所以,如果想要真正好用,最好还是直接使用buffterfly这类直接支持国际化的主题。

经验总结

本次排查和解决 Hexo 多语言导航链接问题的过程,使我深刻认识到:

  • 理解主题和插件的内部工作机制至关重要。 表面上简单的链接问题,背后可能涉及到复杂的 JavaScript 逻辑和前端路由处理。不能只停留在模板和配置层面。
  • 调试是解决问题的关键。 通过分析浏览器开发者工具中的元素、网络请求和控制台日志,可以更准确地定位问题根源。
  • 跨主题借鉴解决方案。 当遇到棘手问题时,参考其他成熟主题(如 Butterfly)对相似功能的实现,可能会带来意想不到的启发。
  • 主题与插件的兼容性是重要考量。 在选择技术栈时,应优先考虑其对目标功能的官方支持和社区适配案例,以减少不必要的开发和调试工作。