Hexo博客搭建:如何支持多语言切换 | 总字数: 3.4k | 阅读时长: 14分钟 | 浏览量: |
前言
为什么要支持多语言,为了辐射更多的用户。即使理论上互联网将世界各地的人联系起来,但是在互联网中,大多数人依然本能的通过母语语言聚在一起。英文和中文是世界使用最多的两种语言,所以首先支持这两种语言。
本篇属于hexo博客搭建指南系列的V1.4,主要介绍了hexo博客 butterfly 主题,支持多语言的切换的配置和优化方案,整个博客搭建指南系列详见:Hexo博客搭建指南:系统化方案与详细构建过程 。
整体方案
hexo 博客,使用butterfly 主题
中文博客、英文博客使用两个独立项目
中文博客:my-hexo-blog-cn;英文博客:my-hexo-blog-en
好处:相互备份;简化管理,减少中文英文之间相互影响或干扰
中文博客和英文博客,以子目录的形式构建,而不是子域名,有利于两个版本博客的搜索权重整合到一起
参考Hexo博客搭建指南:系统化方案与详细构建过程 中的整体方案,也可以从全局理解当前博客多语言方案,如下:
整体流程:
说明:
整体流程,包括三个阶段:准备、支持多语言配置、支持多余优化,包括四个模块:hexo本地-中文博客、hexo本地-英文博客、Github、Cloudflare
使用 Switch language 切换中文博客和英文博客,增加或去除地址栏中/en/前缀
由于博客只能部署到 cloudflare pages 到根目录,只能使用 cloudflare worker 来实现子目录部署,免费额度100,000次/每天,在切换语言的时候被使用,一般来说足够使用了
准备 搭建并部署中文博客
搭建并部署英文博客
搭建并部署英文博客,总体流程和搭建并部署中文博客一致
注意事项
支持多语言配置 中文博客本地配置 hexo的config文件配置 1 2 3 url: https://blog.dmindie.com root: /
_config.butterfly.yml文件配置
1 2 3 4 5 6 7 8 9 10 11 menu: 首页: / || fas fa-home 分类: /categories/ || fas fa-folder-open 标签: /tags/ || fas fa-tags 归档: /archives/ || fas fa-archive 关于: /about/ || fas fa-heart 友链: /link/ || fas -link 语言||fas fa-language: 简体中文: javascript:switchLanguage('cn') English: javascript:switchLanguage('en')
加入Switch language逻辑
layout.pug(my-hexo-blog-cn/themes/butterfly/layout/includes/layout.pug)增加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 - var globalPageType = getPageType (page, is_home) - var htmlClassHideAside = theme.aside .enable && theme.aside .hide ? 'hide-aside' : '' - page.aside = globalPageType === 'archive' ? theme.aside .display .archive : globalPageType === 'category' ? theme.aside .display .category : globalPageType === 'tag' ? theme.aside .display .tag : page.aside - var hideAside = !theme.aside .enable || page.aside === false ? 'hide-aside' : '' - var pageType = globalPageType === 'post' ? 'post' : 'page' - pageType = page.type ? pageType + ' type-' + page.type : pageType doctype html html (lang=config.language data-theme=theme.display_mode class =htmlClassHideAside) head include ./head.pug body !=partial ('includes/loading/index' , {}, {cache : true }) if theme.background #web_bg (style=getBgPath (theme.background )) !=partial ('includes/sidebar' , {}, {cache : true }) #body-wrap (class =pageType) include ./header/index.pug main#content-inner.layout (class =hideAside) if body div!= body else block content if theme.aside .enable && page.aside !== false include widget/index.pug - const footerBg = theme.footer_img - const footer_bg = footerBg ? footerBg === true ? bg_img : getBgPath (footerBg) : '' footer#footer (style=footer_bg) !=partial ('includes/footer' , {}, {cache : true }) include ./rightside.pug include ./additional-js.pug script. function switchLanguage (targetLang ) { const currentPath = window .location .pathname ; let newPath; if (targetLang === 'cn' ) { if (currentPath.startsWith ('/en/' )) { newPath = currentPath.substring (3 ) || '/' ; fetch (newPath) .then (response => { if (response.ok ) { window .location .href = newPath; } else if (response.status === 404 ) { window .location .href = '/' ; } }) .catch (() => { console .error ('Network error occurred.' ); }); } else { console .log ('Already on the Chinese page.' ); } } else if (targetLang === 'en' ) { if (!currentPath.startsWith ('/en/' )) { newPath = '/en' + (currentPath === '/' ? '/' : currentPath); fetch (newPath) .then (response => { if (response.ok ) { window .location .href = newPath; } else if (response.status === 404 ) { window .location .href = '/en/no-match/' ; } }) .catch (() => { console .error ('Network error occurred.' ); }); } else { console .log ('Already on the English page.' ); } } }
英文博客本地配置 hexo的config文件配置 1 2 3 url: https://blog.dmindie.com/en/ root: /en/
_config.butterfly.yml文件配置 1 2 3 4 5 6 7 8 9 10 11 menu: Home: / || fas fa-home Categories: /categories/ || fas fa-folder-open Tags: /tags/ || fas fa-tags Archives: /archives/ || fas fa-archive About: /about/ || fas fa-heart Link: /link/ || fas fa-link Language||fas fa-language: 简体中文: javascript:switchLanguage('cn') English: javascript:switchLanguage('en')
加入Switch language逻辑
layout.pug(my-hexo-blog-en/themes/butterfly/layout/includes/layout.pug)增加Switch language逻辑,具体代码与中文博客的代码一致
新增 no-match.md 文件
目的:中文切换为英文,若无多对应内容,则统一转到 no-match,再由下面的 cloudflare worker 统一转到到英文博客首页
no-match(my-blog/my-hexo-blog-en/source/no-match.md) 内容如下:
1 2 3 4 5 6 7 8 --- title: No Match Found date: 2025-01-07 17:25:30 description: "The English version of this page is not available. You will be redirected to the homepage." --- The English version of this page is not available. You will be redirected to the homepage.
英文博客cloudflare worker 配置 配置 worker 代码
登录到 Cloudflare Dashboard,在“Workers & Pages”部分创建一个新的 Worker。
使用以下代码将 /en/
的请求代理到英文博客项目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 addEventListener ('fetch' , event => { const url = new URL (event.request .url ); if (url.pathname .startsWith ('/en' )) { url.hostname = 'my-hexo-blog-en.pages.dev' ; url.pathname = url.pathname .replace ('/en' , '' ); event.respondWith ( fetch (url.toString ()).then (response => { if (url.pathname === '/no-match/' ) { return Response .redirect ('https://blog.dmindie.com/en/' , 302 ); } return response; }) ); } else { event.respondWith (fetch (event.request )); } });
绑定 Worker 到主域名 (1)登录到 Cloudflare Dashboard
(2)进入 Workers & Pages
在左侧菜单中,选择 Workers & Pages。
找到您刚刚创建的 Worker(例如用于多语言代理的 Worker)。
(3)配置 worker 的路由规则
点击您创建的 Worker 的名称,进入 Worker 的详细页面。
在页面顶部,选择 Settings(设置)。
在设置页面中,找到 域或路由(Domains & Routes)部分。
点击 Add Route(添加路由)
区域:dmindie.com
路由:blog.dmindie.com/en*
失败模式:失败时自动打开
部署预览
两个版本的博客修改完之后,部署到 GitHub pages 和 cloudflare
打开浏览器访问两个版本博客,例如:
https://blog.dmindie.com/
https://blog.dmindie.com/en
经过以上配置,可以实现首页、分类、标签、归档、关于和友链等主要页面自由切换语言,验证结果可以参考本站。
支持多语言优化 支持博文多语言切换 保持 permalink 一致
为了快捷切换中文博客文章和英文博客文章,需要让中文博客文章和英文博客文章的url 保持一致,即博客的permalink 保持一致,只要/en/前缀的区别,例如:
实现步骤
notion配置:中文版本的 notion 数据库和英文版本的 notion 数据库,都添加字段:urlname
elog 配置:配置同步规则,在elog.config.js中,添加字段:urlname
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 module .exports = { write : { platform : 'notion' , notion : { token : process.env .NOTION_TOKEN , databaseId : process.env .NOTION_DATABASE_ID , filter : true , frontMatter : { enable : true , include : ['title' , 'categories' , 'tags' , 'description' , 'status' , 'cover' ,'urlname' ,'date' ], }, }, }, deploy : { platform : 'local' , local : { outputDir : './source/_posts/' , filename : 'title' , format : 'matter-markdown' , frontMatter : { enable : true , include : ['title' , 'categories' , 'tags' , 'description' , 'status' ,'cover' ,'urlname' ,'date' ], }, }, }, }
基于 SEO 优化 添加 hreflang 标签
中文博客,head.pug(projects/my-blog/my-hexo-blog-cn/themes/butterfly/layout/includes/head.pug)添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //-添加hreflang标签 //- 定义基础 URL - const baseUrl = 'https://blog.dmindie.com' - let currentPath = page.path //- 处理各种页面的路径 - if (currentPath === 'index.html' || currentPath === '/index.html') { - currentPath = '' - } else { - currentPath = currentPath.replace(/index\.html$/, '').replace(/^\/+|\/+$/g, '') - } //- 添加 hreflang 标签 link(rel="alternate" hreflang="zh-CN" href=`${baseUrl}/${currentPath}`) link(rel="alternate" hreflang="en" href=`${baseUrl}/en/${currentPath}`) link(rel="alternate" hreflang="x-default" href=`${baseUrl}/${currentPath}`)
英文博客,head.pug(projects/my-blog/my-hexo-blog-en/themes/butterfly/layout/includes/head.pug)添加代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //-添加hreflang标签 //- 定义基础 URL - const baseUrl = 'https://blog.dmindie.com' - let currentPath = page.path //- 处理各种页面的路径 - if (currentPath === 'index.html' || currentPath === '/index.html') { - currentPath = '' - } else { - currentPath = currentPath.replace(/index\.html$/, '').replace(/^\/+|\/+$/g, '') - } //- 移除路径中的 en/ 前缀(如果存在) - currentPath = currentPath.replace(/^en\//, '') //- 添加 hreflang 标签 link(rel="alternate" hreflang="en" href=`${baseUrl}/en/${currentPath}`) link(rel="alternate" hreflang="zh-CN" href=`${baseUrl}/${currentPath}`) link(rel="alternate" hreflang="x-default" href=`${baseUrl}/${currentPath}`)
其他多语言方案 只部署GitHubpages的多语言简化方案 部署方案调整
第一个版本博客,部署到GitHub pages 的根目录中
剩下的 n 个版本,都部署到 GitHub pages 的子目录中
由于 GitHub pages 中,多个版本都是默认部署到子目录,可以完美多语言的子目录的需求
不再部署到 cloudflare pages
加入Switch language逻辑调整
hexo的config文件和_config.butterfly.yml文件配置,与以上方案一致
对于中文博客和英文博客项目中,layout.pug(my-hexo-blog-cn/themes/butterfly/layout/includes/layout.pug)和layout.pug(my-hexo-blog-en/themes/butterfly/layout/includes/layout.pug)都增加Switch language逻辑,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 - var globalPageType = getPageType (page, is_home) - var htmlClassHideAside = theme.aside .enable && theme.aside .hide ? 'hide-aside' : '' - page.aside = globalPageType === 'archive' ? theme.aside .display .archive : globalPageType === 'category' ? theme.aside .display .category : globalPageType === 'tag' ? theme.aside .display .tag : page.aside - var hideAside = !theme.aside .enable || page.aside === false ? 'hide-aside' : '' - var pageType = globalPageType === 'post' ? 'post' : 'page' - pageType = page.type ? pageType + ' type-' + page.type : pageType doctype html html (lang=config.language data-theme=theme.display_mode class =htmlClassHideAside) head include ./head.pug body !=partial ('includes/loading/index' , {}, {cache : true }) if theme.background #web_bg (style=getBgPath (theme.background )) !=partial ('includes/sidebar' , {}, {cache : true }) #body-wrap (class =pageType) include ./header/index.pug main#content-inner.layout (class =hideAside) if body div!= body else block content if theme.aside .enable && page.aside !== false include widget/index.pug - const footerBg = theme.footer_img - const footer_bg = footerBg ? footerBg === true ? bg_img : getBgPath (footerBg) : '' footer#footer (style=footer_bg) !=partial ('includes/footer' , {}, {cache : true }) include ./rightside.pug include ./additional-js.pug script. function switchLanguage (targetLang ) { const currentPath = window .location .pathname ; let newPath; if (targetLang === 'cn' ) { if (currentPath.startsWith ('/en/' )) { newPath = currentPath.substring (3 ) || '/' ; } else { newPath = currentPath; } } else { if (!currentPath.startsWith ('/en/' )) { newPath = '/en' + (currentPath === '/' ? '/' : currentPath); } else { newPath = currentPath; } } fetch (newPath) .then (response => { if (response.ok ) { window .location .href = newPath; } else { window .location .href = targetLang === 'cn' ? '/' : '/en/' ; } }) .catch (() => { window .location .href = targetLang === 'cn' ? '/' : '/en/' ; }); }
结语 通过以上的配置,相信我们都可以搭建一个支持多语言切换的 Hexo 博客。后续,基于这个多语言方案,我会进一步优化,并同步更新本篇文章的方案。
如果您有更好的方案或想法,请随时与我们分享,我们将持续更新这篇文章,确保其内容保持最新和最优。