网址多语言设计

最近的一个项目中考虑到国际化需要用到多语言。前期需要支持中文和英文两种语言,后期后慢慢增加其他语种。在对数据库设计上,需要做到可拓展性,以下是开发过程中用到的几种方案。

一、 单表冗余字段

就是在一个表中增加对应其他语种的文本信息,比如titletitle_en
这种是最简单的,也是最容易实现的。如果语种少,可以考虑该方案。

$locale = app()->getLocale();

$data = Model::select("title_".$locale)->get();

缺点:

  1. 拓展性差,新增语种,须增加字段。

二、独立表维护

该方案,是存在一个主表信息存公共信息,然后把对应语种的信息放到对应的语种表中。比如posts表存基本的信息,然后posts_cnposts_en分别存每个语种的信息

$locale = app()->getLocale();
$table = 'posts';
$localeTable = $table."_".$locale;
$data = DB::table($table)->join($localeTable,"$table.id","=","$localeTable.post_id");

缺点:

  • 每个表维护各自信息,导致表数量增多。

三、双表维护

该方案还是使用两个表,一个是主表记录公共字段信息,一个附加表记录各个语种的信息, 附加表增加一个列表示该条记录是哪个语种

post_id language title
1 cn 测试
1 en test
//利用model
public function translate()
{
    $class = get_class($this);
    return $this->hasOne(sprintf("%sExtra",$class),$this->getForeignKey(),'id')
            ->where('language','=',app()->getLocale());
}
Posts::with('translate')->get()

问题:

  1. 该方法不要维护多个表,如果语种非常多,导致附加表N倍增长
  2. model查询的时候,分页查询没法利用model

json字段

利用json字段 来存多个语种信息,比如 “title”

{"en":"test","cn":"测试","fr":"fs"}

返回前端的时候,可以直接根据对应的语种输出

$locale = app()->getLocale();
//利用获取器
// 详细参考 https://github.com/spatie/laravel-translatable/blob/master/src/HasTranslations.php#L19
public  function  getAttributeValue($key)
{
    if (! $this->isTranslatableAttribute($key)) {
            return parent::getAttributeValue($key);
        }
    return $this->getTranslation($key, $this->getLocale());
}

优点:

  • 不用维护单独的表,所有的信息都在一个表中,减少关联查询
  • 有对应的composer包 spatie/laravel-translat 支持

缺点:

  • 对应一个字段是大量文本,会导致字段信息过长
本作品采用《CC 协议》,转载必须注明作者和本文链接
闲云野鹤
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 11

没弄过,我可能会用最后一个方法 :+1:

2年前 评论

野鸽牛逼

2年前 评论

哥们你个人签名的网址被菠菜攻击了

2年前 评论
小李世界 2年前
xianyunyehe

@MArtian 之前域名忘记续费了,被抢注了

2年前 评论

涨知识了,总结很到位

2年前 评论

现在在用第三种方案

2年前 评论

数据量不大的话第三种挺合适的。

2年前 评论

你们是对固定数据进行国际化(网站固定内容,如分类名称),还是对用户输入的内容进行国际化?

2年前 评论

刚刚完成了双语言的,我是这种弄的。涉及到的每张表里多一个字段(lang)就行了。 语言包放resource,语种存session,前端用中间件拦截session判断即可。 复用方便,破坏性不大。

2年前 评论

对于模糊搜索就不行了

3个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!