データベーススキーマで多言語アプローチをサポートする方法は?
-
22-09-2019 - |
質問
データベースに、テーブル内のすべてのテキスト値のマルチ言語をサポートしてほしい。
それで、それを行うための最良のアプローチは何ですか?
編集1 ::
例えば
私はこの「人」テーブル:
ID int
FirstName nvarchar(20)
LastName nvarchar(20)
Notes nvarchar(max)
BirthDate date
...........
したがって、私のプログラムに新しい言語をサポートしたい場合は、「フランス語としましょう」。
新しい言語を追加するたびに新しい列を追加する必要がありますか?だから私の「人」のテーブルは次のようになります
ID int
FirstName_en nvarchar(20)
FirstName_fr nvarchar(20)
LastName_en nvarchar(20)
LastName_fr nvarchar(20)
Notes_en nvarchar(max)
Notes_fr nvarchar(max)
BirthDate date
...........
または、言語用に2つの新しいテーブル1つを追加する必要があります。
だからこれは次のようになります:」 言語 " テーブル:
ID int
Lang-symbol nvarchar(4)
" 人 " テーブル:
ID int
BirthDate Date
そして最後に " person_translation " テーブル:
LangID int
PersonID int
Translation nvarchar(max)
または何か良いものがありますか?
.
解決
私はこれを尋問データベースで扱わなければなりませんでした。複数の質問を複数の言語(英語、日本、中国語)で翻訳する必要がありました。
最初に、質問に印刷されるすべてのテキスト列を特定しました。これらすべてについて、翻訳を保存できる必要があります。翻訳を必要とするテキスト列を持つ各テーブルについて、_ translationsテーブルを作成しました。元のテーブルの主キー、言語テーブルの外部キー、次に各テキストフィールドのユニコード列を指す外部キーを作成しましたそれには翻訳が必要です。これらのテキスト列には、必要な各言語の翻訳を保存します。
したがって、典型的なクエリは次のようになります。
select p.id
, pt.product_name
, pt.product_description
from product p
inner join product_translations pt
on p.id = pt.product_id
and 'fr' = pt.language_code
したがって、常に1つだけ(各テーブルに対して)参加して翻訳を取得します。
限られた量のテーブルを扱うだけだったので、いくつかの余分な%_translationsテーブルを維持することは大きな問題ではありませんでした。
新しい言語の列を追加することを検討しましたが、理由の合計でそれに反対しました。まず第一に、サポートされる言語の数は不明でしたが、実質的なものである可能性があります(10、20言語など)。ほとんどのテーブルには少なくとも3つの異なる人間の読み取り可能な列があるという事実と組み合わされて、非常に広い行になる多くのテキスト列を追加する必要があります。だから私たちはそうしないことにしました。
列を持つ1つの大きな「ラベル」テーブルを作成するために私たちが検討した別のアプローチ:
(table_name、id_of_table、column_name、language_id、translated_text)
すべての翻訳をデータベース内のどこにでも保存するためのテーブルが1つあります。それは、クエリの書き込みを複雑にするので、それに反対しました(「通常」の列ごとに翻訳テーブルに1つの行があるため、既に大きな翻訳テーブルのマルチアップ時間を通常のテーブルに効果的に結合するため(それぞれ1回翻訳された列)。例のテーブルでは、次のようなクエリが取得されます。
select product.id
, product_name.translated_text product_name
, product_description.translated_text product_description
from product p
inner join translations product_name
on p.id = product_name.id
and 'product' = product_name.table_name
and 'product_name' = product_name.column_name
and 'fr' = product_name.language
inner join translations product_description
on p.id = product_name.id
and 'product' = product_description.table_name
and 'product_description' = product_description.column_name
and 'fr' = product_description.language
ご覧のとおり、本質的にこの種のエンティティアトリブと価値のデザインのようなもので、クエリが面倒になります。
その最後のアプローチのもう1つの問題は、翻訳されたテキストに制約を実施することが不可能ではないにしても難しくなるということです(この場合は主に不安の制約)。翻訳用の別のテーブルを使用すると、これらの問題を簡単かつきれいに克服できます。
他のヒント
私は非常にうまく機能しているものを実装したばかりです。
他の多くの人と同様に、私は最初からきれいなスレートを持っていませんでした、そして、すべてのテーブルは英語のテキストを保存するために準備されていました。
多言語のデータベースを実現するために、テーブルの数や列を2倍にすることができていませんでした。
XMLをすべての翻訳を保存する方法として、単一のフィールドに使用することにしました。
<text>
<translation lang="EN-GB">good day</translation>
<translation lang="FR-FR">bonjour</translation>
</text>
たとえば、私は英語のみを保持するテーブルから始めました:
ProductId INT
ProductName varchar(200)
ProductDescription varchar(1000)
次に、多言語フィールドを作成しました。
ProductId INT
ProductNameTranslation xml
ProductDescriptionTranslation xml
元のフィールドの読み取り専用値を取得できるようにしたい場合は、単に永続的な計算列を追加できます。
ProductId INT
ProductNameTranslation xml
ProductDescriptionTranslation xml
ProductNameDefaultLang = dbo.GetDefaultLanguage(ProductNameTranslation)
ProductDescriptionDefaultLang = dbo.GetDefaultLanguage(ProductDescriptionTranslation)
ビジネス/データレイヤーでは、XMLフィールドは辞書タイプのビジネスクラスに変換され、キーは言語列挙です。
ProductName {
get {return this.ProductNameTranslation[selectedLanguage];}
set {...}
}
このアプローチにより、データベースを完全に再計算する必要がないことができました。また、データベースとの相互作用が少なく、1つのメイン行の代わりに保存する1つの行、3つの翻訳行を意味します。
また、メインの行に翻訳行がないケースを処理しなければならないという問題を回避します
XMLには、パフォーマンスを高めるためのスキーマとXMLインデックスがあることに注意する必要があります。
このアプローチは、言語変換を徐々に1つのフィールドに徐々に実行したい場合に非常に便利です。