What is the best way to create multi-language database? To create localized table for every table is making design and querying complex, in other case to add column for each language is simple but not dynamic, please help me to understand what is the best choose for enterprise applications
-
See as well : http://stackoverflow.com/questions/2227985/whats-the-best-database-structure-to-keep-multilingual-data http://stackoverflow.com/questions/316780/schema-for-a-multilanguage-database http://stackoverflow.com/questions/3077305/how-to-use-multilanguage-database-schema-with-orm/4745863#4745863 – Maxime Pacary Jan 20 '11 at 10:20
-
4I've found this very helpful to me: [Multilanguage Database Design in MySQL](http://www.apphp.com/tutorials/index.php?page=multilanguage-database-design-in-mysql) – Siamak Motlagh Jul 07 '14 at 07:27
5 Answers
What we do, is to create two tables for each multilingual object.
E.g. the first table contains only language-neutral data (primary key, etc.) and the second table contains one record per language, containing the localized data plus the ISO code of the language.
In some cases we add a DefaultLanguage field, so that we can fall-back to that language if no localized data is available for a specified language.
Example:
Table "Product":
----------------
ID : int
<any other language-neutral fields>
Table "ProductTranslations"
---------------------------
ID : int (foreign key referencing the Product)
Language : varchar (e.g. "en-US", "de-CH")
IsDefault : bit
ProductDescription : nvarchar
<any other localized data>
With this approach, you can handle as many languages as needed (without having to add additional fields for each new language).
Update (2014-12-14): please have a look at this answer, for some additional information about the implementation used to load multilingual data into an application.
-
Yes, no need for multiple columns: key by language. Although here is would be useful to have ProductDescription as nvarchar, I suspect. – gbn May 30 '09 at 09:35
-
Please add more details in creating business objects in this case, creating separate businees object will be suitable for CMS, but creating one localized business object for other cases – Arsen Mkrtchyan May 30 '09 at 11:59
-
16what if the only language-neutral field is the id? and how exactly do you insert the foreign key reference when inserting a row? – Timo Huovinen Sep 18 '10 at 18:16
-
4It's funny, that I was designing a database scheme for a multilingual CMS and had this question in my head aswell. I chose this approach, before I even saw this answer! Thanks for this answer! – Patrick Manser May 29 '13 at 08:50
-
why two table would be require one is product & another one is producttranslation....is there any chance that a product may have multiple detail. thanks – Mou Oct 05 '13 at 19:34
-
6One thing to note here is that there would either be no PK on this table or ID and Language need to be the composite PK. Either that, or you need to add a ProductTranslationId field, probably as an identity. – Daniel Lorenz Aug 06 '14 at 19:38
-
Sorry if I revive this thread, but I'm facing a similar problem and as it happens I already followed this approach, two tables, one for the contents, other for the translation, and the default language flag, but I have a strong doubt on how to query the database to tell "load the user's language, if that translation does not exist, fall back to the one with the default flag" with just one query. I currently load all the translations and iterate over them in my controller, but that's not the best solution, if there is a lot of data and translations to iterate over... – Luca Nov 06 '14 at 09:39
-
@Luca: you should post that as a new question. You can refer to this one, if you like. – DanMan Dec 14 '14 at 11:55
-
Thanks Dan, I did it already, and it is here: http://stackoverflow.com/questions/26765175/multi-language-database-with-default-fallback :) – Luca Dec 14 '14 at 20:50
-
1@Luca: I answered your question, showing what implementation(s) I use to load the data. – M4N Dec 15 '14 at 10:41
-
It seems to me that a model that links the foreign-key should be in the object with the fields to be translated and it should point to a single "translations" table shared by all internationalized entities. (e.g. the way the problem is solved here: http://stackoverflow.com/questions/10693508/database-modeling-for-international-and-multilingual-pruposes) – Ed L Apr 08 '16 at 20:53
-
you can also use encoding for field. In this way you dont need to create separate table – Muneem Habib Jun 23 '16 at 05:00
-
1If you need to perform full-text search on the content then the languages need to be in separate columns. Of course, you can also put them in indexed views with a full-text index. – Jon49 Feb 08 '17 at 22:58
-
@TimoHuovinen I know it has been almost 8 years but, what did you do in that case you mentioned, "what if the only language-neutral field is the id". – Aarón Gutiérrez Sep 04 '18 at 17:59
-
1@AarónGutiérrez Well, funnily enough you create a table with a single column called `id` :D . To explain, each `id` represents a meaning to which you can attach words from any language in a relational table, so you get two tables, `meaning` (id) and `word` (id, meaning_id), the `id` in the `word` table represents the word id, the `id` in the `meaning` represents the meaning that is universal. – Timo Huovinen Sep 17 '18 at 19:27
-
-
If in your system there is an admin user who can determine the language of the system, in addition of this answer you can keep all the fields in the first table and fill them on the language change event from the appropriate record of the second table based on selected language then simply use these fields in all of your queries. – vahid Aug 09 '19 at 21:15
-
This sounds like [Approach #4](https://www.vertabelo.com/blog/data-modeling-for-multiple-languages-how-to-design-a-localization-ready-system/). – AWhitford Apr 24 '20 at 21:53
-
@TimoHuovinen There is a different solution: Simply put "created" and "updated" columns besides the "id".. you never know when you'll need them ;) – Reloecc Aug 27 '20 at 06:21
-
1@M4N I think `IsDefault` language flag should be added in the language table not in the `ProductTranslations` table because for all products default language would be same. – MD. IBRAHIM KHALIL TANIM Mar 01 '21 at 03:43
-
1@MD.IBRAHIMKHALILTANIM: In my case, each product could have a different default language, e.g. depending on where it came from, who created it, etc... – M4N Mar 01 '21 at 21:01
-
-
is it bad practice if i saved the name as JSON FIELD in the database? – Basil Battikhi Sep 26 '22 at 12:06
-
I recommend the answer posted by Martin.
But you seem to be concerned about your queries getting too complex:
To create localized table for every table is making design and querying complex...
So you might be thinking, that instead of writing simple queries like this:
SELECT price, name, description FROM Products WHERE price < 100
...you would need to start writing queries like that:
SELECT
p.price, pt.name, pt.description
FROM
Products p JOIN ProductTranslations pt
ON (p.id = pt.id AND pt.lang = "en")
WHERE
price < 100
Not a very pretty perspective.
But instead of doing it manually you should develop your own database access class, that pre-parses the SQL that contains your special localization markup and converts it to the actual SQL you will need to send to the database.
Using that system might look something like this:
db.setLocale("en");
db.query("SELECT p.price, _(p.name), _(p.description)
FROM _(Products p) WHERE price < 100");
And I'm sure you can do even better that that.
The key is to have your tables and fields named in uniform way.

- 13,580
- 8
- 57
- 85
-
the other question is, to create one business object for product? or to create two... in first case it's easy to work with that item, in 2 nd easy to write CMS – Arsen Mkrtchyan May 30 '09 at 10:52
-
I find this type of approach works for me:
Product ProductDetail Country ========= ================== ========= ProductId ProductDetailId CountryId - etc - ProductId CountryName CountryId Language ProductName - etc - ProductDescription - etc -
The ProductDetail table holds all the translations (for product name, description etc..) in the languages you want to support. Depending on your app's requirements, you may wish to break the Country table down to use regional languages too.

- 5,616
- 10
- 52
- 72
-
I chose this same approach for a project I'm currently working on because my different locales contain very specific information about unit systems and measures to be displayed to users. – califrench Apr 03 '14 at 02:24
-
11Country and language (locales) are different things. And ISO language codes are natural keys, you eliminate unnecessary join from lang to country. – gavenkoa Jun 04 '14 at 06:01
I'm using next approach:
Product
ProductID OrderID,...
ProductInfo
ProductID Title Name LanguageID
Language
LanguageID Name Culture,....

- 1,212
- 1
- 17
- 24
Martin's solution is very similar to mine, however how would you handle a default descriptions when the desired translation isn't found ?
Would that require an IFNULL() and another SELECT statement for each field ?
The default translation would be stored in the same table, where a flag like "isDefault" indicates wether that description is the default description in case none has been found for the current language.

- 51
- 2
-
1@GorrillaApe: see this answer for an example how to fall back to the default language, if the desired language was not found: http://stackoverflow.com/a/27474681/19635 – M4N Apr 21 '17 at 08:38
-