前言
通过上一篇文章 如何基于 Typecho 实现中英双语网站(上),我们已经把 中英双语网站 的基本框架搭建好了。实际上很多支持多语言的网站,也就这样了,例如著名的 YouTube 就是如此,至于具体的内容显示什么语言,则完全是由内容的创作者决定的。
上一篇文章也提到了,Typecho 其实并不是很适合做多语言网站,因为,一方面需要修改源码,另一方面,开发一个不同国家的人都来发布创作内容的网站,想想也不是个人应该考虑的。 Typecho 还是更适合作者自己创作,然后向用户展示的场景,这时如果要实现多语言,就不得不将文章的内容也进行翻译了。
1. 方案选择
起初,我打算借助一些翻译相关的 JS
库或者API接口简单处理,因为通过上一篇文章我们已经知道,getLang()
方法可以获取当前所属的语言,现在只需要在必要的地方调用一下翻译接口就可以了,无需修改 Typecho 源码,即使后续希望支持更多国家的语言,也可以轻松实现,似乎一切都很美妙,但具体实现时,我发现并没有那么简单。
如果只是一个记录日常生活,或者说记录一些没有什么特殊词汇的博客网站,那么翻译工具应该是可行的。但很多稍微专业一点的网站可能就不行了,例如我的 博客网站 中有代码(哪怕是编程中最常见的 类
也往往不会被翻译成class
),一起学笛子 网站中有歌名、歌词,甚至剧名,翻译工具都会乱翻译,实在是很不靠谱。举个更具体的例子,学笛子网站中有首曲子叫《浮光》,其英文名叫《The History》,还有一首《香蜜沉沉烬如霜》中的片尾曲《左手指月》,英文版的剧名叫《Ashes of Love》,歌名叫《Upwards to the Moon》,不难想象,翻译工具都是无法很好的将它们对应上的。
因此,考虑再三之后,我还是决定修改源码,这样虽然麻烦一点,但控制起来更加灵活,下图是开发完成后的最终效果。
2. 实现思路
通过上一篇文章我们已经把网站的大部分地方都翻译过了,现在掰着手指头数也就只剩下文章标题、文章内容、独立页标题、独立页内容、分类名以及标签名六个地方还没翻译了。实际上,稍微了解一下数据结构就不难发现,文章标题、文章内容、独立页标题、独立页内容 都属于 contents
表,对应了 title
和 text
两个字段,而 分类名 和 标签名 都属于 metas
表,对应了 name
字段。
了解到这一步就简单了,我们只需要在 contents
表中加上 title_en
和 text_en
两个字段,在 metas
表中加上 name_en
字段,然后在代码中完善对这三个字段的 CRUD
操作就可以了。具体的实现完全可以直接参考不带 _en
结尾的原始字段,因为它们地位是一样的,所以实现方式理应也是一样的。
下面简单举几个例子说明一下。
2.1 文章编辑页面
编辑文章时,我们需要同时编辑中英文内容,因此,需要在 write-post.php
文件中将如下代码:
<p class="title">
<label for="title" class="sr-only"><?php _e('标题'); ?></label>
<input type="text" id="title" name="title" autocomplete="off" value="<?php $post->title(); ?>"
placeholder="<?php _e('标题'); ?>" class="w-100 text title"/>
</p>
修改为:
<p class="title">
<label for="title" class="sr-only"><?php _e('标题'); ?></label>
<input type="text" id="title" name="title" autocomplete="off" value="<?php $post->title(); ?>"
placeholder="<?php _e('中文标题'); ?>" class="w-100 text title" />
<input type="text" id="title_en" name="title_en" autocomplete="off" value="<?php $post->title_en(); ?>"
placeholder="<?php _e('英文标题'); ?>" class="w-100 text title" />
</p>
并将如下代码:
<p>
<label for="text" class="sr-only"><?php _e('文章内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text); ?></textarea>
</p>
修改为:
<p>
<label for="text" class="sr-only"><?php _e('文章内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" placeholder="<?php _e('中文内容'); ?>" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text); ?></textarea>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" placeholder="<?php _e('英文内容'); ?>" id="text_en"
name="text_en" class="w-100 mono"><?php echo htmlspecialchars($post->text_en); ?></textarea>
</p>
修改完成后的效果如下图所示:
整个操作完全可以通过复制粘贴来完成,独立页面相关的 write-page.php
文件改法也是一样的。
2.2 字段编辑
这里的编辑包括新增和修改,因为删除和具体字段无关,所以不需要考虑。针对文章和独立页的操作都在 Contents.php
这个文件中,其中,新增操作改动如下图所示:
修改操作改动如下图所示:
也就是把 title
和 text
复制了一份,其它地方处理方式也是类似的。
2.2 数据库查询
查询的地方会比较多,而且应用场景也比较多,例如查询条件拼接、前端界面显示、后端编辑页面数据回写等,但好在都比较直观,有没有遗漏界面上点几下,一眼就能看出来,所以边修改边看效果是最好的解决办法。
值得一提的是,对语言的判断应该尽可能在最底层,这样上层调用时就不用再判断语言了,可以避免修改范围进一步扩散,具体代码如下图所示:
这里的 isZH()
是为了简化对语言的判断,代码所在位置和 getLang()
一样,具体实现如下:
function isZH()
{
return $this->getLang() == 'zh_CN';
}
说起来麻烦,但实际上,大部分情况都是在出现 title
或 text
字段时候,对应的改一下就可以了。
不过有两个例外,一个是需要在 PrepareEditTrait.php
文件中加入如下高亮的代码:
另一个是需要在 Metas.php
文件中加入如下高亮的代码:
这两个地方由于是新增代码,对 Typecho 原理不了解的可能不容易想到,但其它需要修改的地方顺藤摸瓜都可以很容易找到,毕竟说破个天,也就是对 title_en
、 text_en
以及 name_en
三个新增字段的操作而已。
结语
好了,这篇文章就写这么多,由于改动的地方比较多,有十几个文件,把所有改动的代码都贴出来既不现实也没必要,所以只能简单说一下我的实现思路。
需要强调的是,这只是我的个人实现,未必是最优方案,不过,对有相似需求的同学,或许可以参考一下。不过话说回来,如果既想实现一个多语言网站,又不希望跟我一样修改源码,那或许就应该考虑一下其它产品,而不是死磕 Typecho 了。
评论2
RuiBlog
看着好麻烦啊,我要想实现多语言halo装个插件就ok了,我比较懒,不喜欢改源码🤣
老朱
是的,原生不支持,改起来就很麻烦😂