Är det någon som har erfarenhet av databas design för databaser som lagrar data på flera språk? Såhär kör vi: <b> Jag tycker Marcus har ett bra förslag på data design. JAg är av prestandaskäll skeptisk till natruliga nycklar av text. MEn det är en smak sak. <b>Jag tycker Marcus har ett bra förslag på data design. JAg är av prestandaskäll skeptisk till natruliga nycklar av text. MEn det är en smak sak.</b>Flerspråkig databasarkitektur?
Kommentera tänkbara lösningar nedan. Vilken lösning är att föredra?
1. En kolumn per sträng på ett språk i vaje tabell. "Create
table title (id, en_string, fr_string)"
2. En rad för varje språk. "Create table title(id, value,
LanguageId(foreign key))"
3. En tabell för varje språk. "Create table en_title (id,
en_string), Create table fr_title (id, fr_string)"
4. Tecken-delade strängar i varje cell i raderna. "Create table title (id,
title)", "hello|salut|"
5. Olika databaser för varje språk. "Create database
en_database", "Create database fr_database"
Övriga synpunkter och rekommendationer för flerspråkig databasarkitektur?
CarlSv: Flerspråkig databasarkitektur?
id, code, string, lang
Dataexempel:
1, 1, Company, ENG
2, 1, Företag, SWE
3, 1, Firma, GER
4, 2, Project, ENG
5, 2, Projekt, SWE
6, 2, Projekte, GERSv: Flerspråkig databasarkitektur?
1. En kolumn per sträng på ett språk i vaje tabell. "Create
table title (id, en_string, fr_string)"
</b>
Dumt... Du måste ändra tabellstruktur när du lägger till språk.
2. En rad för varje språk. "Create table title(id, value,
LanguageId(foreign key))"
<b>
3. En tabell för varje språk. "Create table en_title (id,
en_string), Create table fr_title (id, fr_string)"
</b>
Ger mig rysningar... Normaliseringsregler har varit uppe tidigare på pellesoft... ;-)
<b>
4. Tecken-delade strängar i varje cell i raderna. "Create table title (id,
title)", "hello|salut|"
</b>
En databas är bra på att lagra data, låt den lille stackaren göra sitt job på ett bra sätt. ;-)
<b>
5. Olika databaser för varje språk. "Create database
en_database", "Create database fr_database"
</b>
Nä....
Hur du skall göra beror lite på vad det är för data som skall lagras, är det fasta texter (tex för labels och knappar) eller är det fritexter som en användare kan mata in och göra det på flera språk?
<b>Fasta texter </b>
två tabeller skapas
<code>
Lang: LangId(räknare), LangNamn
Metadata: TextCode, LangID, Text
</code>
Data i Lang ser ut så här:
<code>
1|English
2|French
2|Swedish
</code>
Metadata
<code>
WelcomeText|1|Welcome
WelcomeText|2|Bienvinue (eller hur det stavas)
WelcomeText|3|Välkommen
</code>
Dett gör att du bygger upp det på ett relativt enkelt sätt och dynamiskt sätt, tex kan du lägga till språk utan att göra förändringar.
Hur får du då ut texter? Jo, tex genom en SP som tar två argument TextCode och LangId. Vi använder något liknande men läser ut alla texter från DB och lägger en hashtabell. Hashtabellen innehåller langId som Key och en annan hashtabell som Value, den innehåller i sin tur TextCode som Key och översättningen som Value.
En funktion för översättnming på klienten i C# kan då se ut så här:
<code>
public string getText(string aLngCode, string aTextCode)
{
// lngMap = ett objekt som innehåller översättninganrna, kan vara ett staticobject för Winforms eller en applicationvariabel för web
Hashtable textMap = (Hashtable)lngMap[aLngCode];
if (textMap != null)
{
string result = (string)textMap[aTextCode];
if (result != null)
{
return result;
}
}
return aTextCode + " NOT FOUND";
}
</code>
Motsvarande SP om man vill anropa Db jämt:
<code>
CREATE PROCEDURE gettext(@idlang Varchar, @TextCode varchar)
AS
select text from Metadata
where idlang = @idlang
and textCode = @textcode
GO
</code>
Hur gör jag då med tex språken i Lang? Har jag en dropdown där man väljer språk kanske jag vill att alla skall stå på det valda språket. Dvs har jag valt svenska vill jag att alla tre alternativen skall stå "Englelska, Franska, Svenska". Jo, lägg till en kolumn i Lang:
<code>
Lang: LangId(Unik identifierare), LangNamn, TextCode
</code>
Data i Lang ser ut så här:
<code>
1|English|EnglishText
2|French|FrenchText
2|Swedish|SwedishText
</code>
Metadata
<code>
EnglishText|1|English
EnglishText|2|French
EnglishText|3|Swedish
Swedishtext|1|Engelska
Swedishtext|2|Franska
Swedishtext|3|Svenska
Orkar inte skriva franska... ;-)
</code>
När jag fyller comboboxen så (pseudokod så det sjunger om det):
<code>
foreach (lang in Languages)
{
DropDown.Items.Add(getText("1", lang("TextCode")))
}
</code>
Obs, det nedan förutsätter att texterna läses över till "klient" och övwersättningen sker där
Hur göra med översättningar på olika språk där man vill ha variabler med och de kanske hamnar på olika ställen, tex "Det kostar 34,50" jämfört med "34,50 is the cost"?
Ett lite annat tänk för hur vi lagrar data i metadata. Vill vi har parametrar lagrar vi dem med en avgränsare där vi vill ha en parameter, tex %1% för parameter 1 osv.
Data i metadata med exemplen ovan blir då
Metadata
<code>
CostText|1|%1" is the cost
CostText|3|Det kostar %1%
</code>
Och vi utökar med en funktion
<code>
public string getTextWithOptions(string aLngCode, string aTextCode, string aOptions)
{
string text = getText(aLngCode, aTextCode);
if ((aOptions != "") && (aOptions != null))
{
string[] optionsArray = aOptions.Split('|');
for (int i=0; i<optionsArray.Length; i++)
{
text = text.Replace("%" + (i + 1) + "%", optionsArray[i]);
}
}
//remove any trailing options
return optionsregex.Replace(text, "");
}
</code>
Denna funktionen tar en parameter aOptions som är en sträng med en avgränsare "|". dvs vill man skicka in fler parametrar blir det "34,50|78,50|en till".
<code>
getTextWithOptions("1", "CostText", "34,50") = "34,50 is the cost"
getTextWithOptions("3", "CostText", "34,50") = "Det kostar 34,50"
</code>
Vet inte om det besvara din fråga, förhoppningsvis ger det en del uppslag på hur du kan göra. Det jag ha skrivit ovan är något liknande som vi har och det fungerar utmärkt, det är jobbigare att förklara det än vad det faktiskt är. Antal språk varierar beroende på projekt, men mellan 4-20 språk har vi alltid och de skall kunna läggas till utan att behöva ändra applikationen eller DB. Orkar inte skiva mer om hur man kan översätta fritextfält just nu. Av dina alternativ ovan är det bara alt. 2 som låter någorlunda rinmligt att jobba med. Skälet till att vi äversätter allt data i "klienten" och inte i DB är att vi inte vill behövaladda om allt data från DB utifall användaren byter språk i applikationen.
Om jag antar lite fritt, så av ditt exempel med "Title" på en tabell... Antar att du har en tabell med titlar på personer, tex Herr, Fru, Fröken.
Data i Metadata
Metadata
<code>
MrText|1|Mr
MrText|3|Herr
MissText|1|Miss
MissText|3|Fröken
MrsText|1|Mississ... elelr hur de nu stavar det
MrsText|3|Fru
</code>
Data i Title
<code>
TittleId|TextCode
1|MrText
2|MissText
3|MissText
</code>
och i en person tabell
<code>
perosnId|Namn|TitleId
666|Kalle Anka|1
667|Kajsa Anka|2
668|farmor Anka|3
</code>
Läser du ut för personer kan det se ut så här
<code>
Select person.*, Title.textCode as TitleCode
from person, Title
where person.titleid = title.titleid
</code>
Skriva ut data
<code>
foreach (person in Persons)
{
string _text = gettext("1", _person("TitleCode")) + " " + _person("namn")
}
</code>Sv:Flerspråkig databasarkitektur?
Vill kompletera att man kan skapa en fråga som slår upp rätt värden:
SELECT person.PersonId, person.Namn, Metadata.Text AS TitleText
FROM person LEFT JOIN
(Title ON person.TitleId = Title.TittleId LEFT JOIN
Metadata ON (Title.TextCode = Metadata.TextCode) AND (Metadata.LanguageId = @LanguageId))
Sv: Flerspråkig databasarkitektur?
Ddet ovan är mer en översiktilig bild av hur det kan fungera, ändrat och förenklat för att det skall vara lättare att förstå. I en webbapplikation så läser vi upp aktuella språk en gång och lagrar dem i en hashtabell i en applikationvariabel. Åtkomsten sker sedan mot den hashtabellen vilket gör att db-anropen minskar ordentligt och att prestanda på appen blir bättre. Det finns många variantioner man kan göra på det ovan, tex bygga usercontrols som själva sköter översättningen (det enda man anger på dem är ny property som är textid) mm.