25-08-2012: artikel oprettet.
25-04-2013: rettelse af engelsk mønster (tak til olebole), samt
tilpasning af indledningsteksten.
29-04-2013: tilføjelse af link til konkret løsningsforslag i C#
Hvis man skal lave et site der kan håndtere forskellige sprog er der mange måder at gøre dette på.
En metode er at vedligeholde flere sites i de forskellige sprog man ønsker at understøtte. En fordel ved dette er, at man så kan styre sitets udseende 100% indenfor hvert sprog. Det samme kan dog også være en ulempe, når man skal lave den samme ændring på alle sprogversioner.
En anden metode kunne være at benytte samme sideskabeloner og blot indsætte tekst-pladsholdere fra en ordbog de steder, hvor indholdet skal sprogstyres. Fordelen er her, at man kun skal vedligeholde layout ét sted, men omvendt er differentiering af layoutet, afhængig af sprogvalget, mere komplekst.
Jeg vil i denne artikel beskrive en version af den sidste metode.
Når man vedligeholder en ordbog skal der ofte tages højde for en eller flere variable værdier i formuleringerne af teksterne i de forskellige sprog. Dette kunne f.eks. komme til udtryk i flg. tekst:
Dette ser lidt anderledes ud, hvis der kun findes 1 person
Håndteringen af forskellen her, er til at overkomme, men man skal trods alt tage stilling til om der skal bruges flertals- eller entalsform for ordet "person". Dette kan gøres inline på siden:
if antalPersoner <> 1 then
personEndelse = "er"
end if
Translate("Der findes " & antalPersoner & " person" & personEndelse)
Translate er her den funktion, som tager teksten og finder en tilsvarende oversættelse i ordbogen til det aktuelt valgte sprog og returnerer den.
Der er umiddelbart tre udfordringer her:
1. Teksten indeholder en variabel (antalPersoner)
2. Placeringen af variablen er ikke nødvendigvis den samme på alle sprog
3. Teksten findes i 2 varianter, hvis man ser bort fra variablen
Den første og anden udfordring kan løses ved at indsætte en pladsholder for variablen i teksten og så sende værdien med i en parameter til Translate.
Dette giver dog kun mulighed for at sende én parameter med til oversætteren. Det er givetvis ikke nok i mere komplekse oversættelsesscenarier. Overvej f.eks. flg. tekst:
hvor X er antal personer og Y er antal registre, altså to forskellige værdier.
Pladsholdere til værdier
Dette kan løses ved at sende et array af værdier med til Translate-funktionen.
Som man kan måske kan se er udfordring 3 fra tidligere blevet endnu større, da der nu findes 4 varianter af den sidste tekst
1. ental af person
2. flertal af person
3. ental af register
4. flertal af register
Det begynder at blive noget omstændigt at vedligeholde disse tekster!
For at det ikke skal være løgn, kan der endda være forskel på hvormange former et ord har afhængig af sproget, så man kan altså ikke altid regne med at det er en eller flere der adskiller om der skal flertalsendelse på.
Der er altså brug for endnu mere fleksibilitet i formateringen af den oversatte tekst.
Mere fleksibilitet
Jeg har flg. forslag til hvordan man kan håndtere formendelser i tekster.
Der anvendes en form i den oversatte tekst, som tillader at angive ord eller endelser alt efter hvilken værdi der sendes med til funktionen. Det kunne se således ud:
Ovenstående er altså ikke tekst-pladsholderen, men den oversatte tekst som hentes frem via pladsholderen sammenholdt med sproget (som her er dansk). Pladsholderen kunne se således ud:
Den engelske oversættelse kunne se nogenlunde således ud:
Som man kan se, er der ikke behov for de samme betingelser i den engelske oversættelse, som i den danske. Derfor er det vigtigt at forstå, at det er i OVERSÆTTELSEN betingelserne skal indsættes og ikke i tekst-pladsholderen. Tekst-pladsholderen er blot en nøgle til at få fat i oversættelsen med og kunne i princippet være et tal. Personligt foretrækker jeg bare, at tekst-pladsholderen giver mening i den kontekst hvor den skal bruges. Der ligger naturligvis nogle performance- og resurseovervejelser i formatet af tekst-pladsholderen, da lange tekstuelle tekst-pladsholdere givetvis kræver flere resurser (RAM, database, netværk osv.) at benytte.
Betinglser i oversættelserne
Formatet af betingelserne er således:
[#<feltnummer><betingelse>{|<betingelse>}]
<feltnummer> := et tal fra 0 og opefter, som peger på en
af de medsendte værdier
<betingelse> := <operator><værdi>:<indsæt tekst>
<operator> := !|=|<|>
<værdi> := et heltal
<indsæt tekst> := vilkårlig tekst der skal indsættes
hvis udtrykket er sandt
Dvs. værdien af feltnummer kan enten være
! : forskellig fra
= : lig med
< : mindre end
> : større end
den numeriske værdi og hvis betingelsen er opfyldt, så indsæt teksten efter kolon (og frem til næste pipe-karakter, dvs. lodret streg) og afslut evalueringen af det aktuelle udtryk.
Hver betingelse ud over den først foranstilles med en pipe-karakter.
Med ovenstående format kan vi specificere meget mere komplekse oversættelsesmønstre med meget færre oversættelser (dvs. 1 pr. tekst der skal oversættes pr. sprog). Det er umiddelbart en optimal situation!
Fleksibilitet for en pris
Denne teknik kommer dog med nogle omkostninger, nemlig at der skal ske en fortolkning af formatet hver gang oversættelsen til en tekst skal hentes. Der kan foretages caching i forskellige grader, men det ændrer ikke på at oversættelse af en tekst involverer et funktionskald og en fortolkning af hvilken betingelse der er gældende.
Det vigtigste er umiddelbart, at kompleksiteten vedr. det, at oversætte en tekst, er pakket ind i en funktion og dermed er oversættelseslogikken også lettere at optimere, fordi den er samlet ét sted.
Hvordan den egentlige implementering til dette ser ud, afhænger af sproget man ønsker at implementere det i og jeg vil undlade at forsøge i denne artikel, men du kan evt. kigge i denne artikel, hvis du koder i C#: Parameteriseret tekstformatering i C#, hvor jeg kommer med et bud.


