网址多语言设计
最近的一个项目中考虑到国际化需要用到多语言。前期需要支持中文和英文两种语言,后期后慢慢增加其他语种。在对数据库设计上,需要做到可拓展性,以下是开发过程中用到的几种方案。
一、 单表冗余字段
就是在一个表中增加对应其他语种的文本信息,比如title
、title_en
等
这种是最简单的,也是最容易实现的。如果语种少,可以考虑该方案。
$locale = app()->getLocale();
$data = Model::select("title_".$locale)->get();
缺点:
- 拓展性差,新增语种,须增加字段。
二、独立表维护
该方案,是存在一个主表信息存公共信息,然后把对应语种的信息放到对应的语种表中。比如posts
表存基本的信息,然后posts_cn
、posts_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()
问题:
- 该方法不要维护多个表,如果语种非常多,导致附加表N倍增长
- 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 协议》,转载必须注明作者和本文链接
没弄过,我可能会用最后一个方法 :+1:
野鸽牛逼
哥们你个人签名的网址被菠菜攻击了
@MArtian 之前域名忘记续费了,被抢注了
涨知识了,总结很到位
现在在用第三种方案
数据量不大的话第三种挺合适的。
你们是对固定数据进行国际化(网站固定内容,如分类名称),还是对用户输入的内容进行国际化?
刚刚完成了双语言的,我是这种弄的。涉及到的每张表里多一个字段(lang)就行了。 语言包放resource,语种存session,前端用中间件拦截session判断即可。 复用方便,破坏性不大。
对于模糊搜索就不行了