網址多語言設計

xianyunyehe 發表於 2021-07-04

最近的一個專案中考慮到國際化需要用到多語言。前期需要支援中文和英文兩種語言,後期後慢慢增加其他語種。在對資料庫設計上,需要做到可擴充性,以下是開發過程中用到的幾種方案。

一、 單表冗餘欄位

就是在一個表中增加對應其他語種的文字資訊,比如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 協議》,轉載必須註明作者和本文連結
閒雲野鶴