Har en webbapplikation som ska stödja flera språk. Hej, jag byggde en liknande sådan funktion för pellesoft och faktiskt var det urtypen för språkinställning för EPiServer när den var i sin tidigare version. Suveränt, tack för ditt svar (din artikel) :) Varsågod,Språkhantering
Tycker inte resource hanteringen känns bra, skulle man kunna ha språkstödet i constant class?
Eller andra tips?Sv: Språkhantering
Exempel: språkhantering vb.net
Många pratar om språkhantering och för att få till en sådan på ett bra sätt tänkte jag helt enkelt skriva en artikel för att hjälpa dig på traven. Det finns inbyggt i .net men jag tyckte att det var enklare att ha en extern xml-fil som jag kunde skicka upp till servern i tid och otid för att snabbt kunna göra ändringar.
Vi börjar helt enkelt med att skapa oss en xml-fil som till en början inte blir speciellt märkvärdig. Denna kan sedan byggas på mer och mer, med fler språk och du kan till och med separera dessa så en xml-fil tillhör respektive språk. I mitt syfte kör vi i alla fall två språk, men vi har allt data samlat på en och samma sida.
<?xml version="1.0" encoding="utf-8" ?>
<languages>
<language name="Svenska" id="SV">
</language>
<language name="Engelska" id="EN">
</language>
</languages>
Nu har vi vår första xml-fil som du har skapat i notepad eller någon annan editor. Som du ser här så har vi starttaggen languages, där efter kommer language-taggen för svenska och därefter engelska. Som du förstår nu så kan du alltså bygga denna fil hierarkiskt hur djup som helst för att gruppera din information. Vi börjar med att fylla på några små objekt för såväl svenska som engelska och därefter skall vi plocka ut informationen och använda den i vår applikation.
<?xml version="1.0" encoding="utf-8" ?>
<languages>
<language name="Svenska" id="SV">
<page>
<language>In English</language>
</page>
</language>
<language name="Engelska" id="EN">
<page>
<language>På Svenska</language>
</page>
</language>
</languages>
Nu har vi lagt en rubrik som vi kallar page, och under page några objekt - typiska menyalternativ i toppen på pellesoft som du ser. Nu är det dags att bygga en funktion som hjälper oss att växla mellan språk. Enklast är att använda sig av ett sessionsobjekt och det börjar vi med genom att ha en link som vi trycker på om vart annat för att växla språket.
<asp:linkbutton id="lnkLanguage" runat="server">LinkButton</asp:linkbutton>
När vi klickar på denna länken så har vi en funktion kopplad till den i codebehind som ser ut som följer:
Private Sub lnkLanguage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkLanguage.Click
If Session("UserCurrentLanguage") = Language.English Then
Session("UserCurrentLanguage") = Language.Swedish
Else
Session("UserCurrentLanguage") = Language.English
End If
Response.Redirect(Request.Url.ToString, True)
End Sub
Först tittar vi lite på response.redirect här. Den används för att ladda om hela sidan igen då koden troligast ligger i en usercontrol som visar menyn. Genom att ladda om sidan kommer informationen att presenteras igen men eftersom vi bytt språk ser man även ändringarna. Det står Language.English och .Swedish. Dessa har jag lagt i min basklass för att enkelt nå den. Du kan göra samma sak genom att lägga till följande.
Public Enum Language
Swedish = 1
English = 2
End Enum
Nu behövs vår magiska kontroll för att hämta rätt språk för rätt inställning. Vi börjar med funktionen som hämtar rätt språk.
Shared Function GetLanguage() As String
Select Case System.Web.HttpContext.Current.Session("UserCurrentLanguage")
Case Language.English : GetLanguage = "en"
Case Else : GetLanguage = "sv"
End Select
End Function
Rutinen returnerar helt enkelt en eller sv som vi sedan kommer använda oss av i vår språkfunktion när vi hämtar ut datat från vår xmlfil. Om nu anvädaren tittar på sidan och inte har påbörjat sin session än kan man också ta reda på vad webbläsaren har default för språk. Detta gör du exempelvis genom att kalla en rutin som nedan men endast en gång.
Shared Function GetLanguageId() As Integer
GetLanguageId = CInt(System.Web.HttpContext.Current.Session("UserCurrentLanguage"))
If GetLanguageId < 1 Then
' vilket språk är webbläsaren inställd på som default, visa då det först?
Dim webbrowserlanguage As String = System.Web.HttpContext.Current.Request.ServerVariables("HTTP_ACCEPT_LANGUAGE")
Select Case Left(LCase(webbrowserlanguage), Language.English)
Case "sv"
System.Web.HttpContext.Current.Session("UserCurrentLanguage") = Language.Swedish
Case "en"
System.Web.HttpContext.Current.Session("UserCurrentLanguage") = Language.English
Case Else
System.Web.HttpContext.Current.Session("UserCurrentLanguage") = Language.English
End Select
End If
End Function
Denna rutinen kan du exempelvis kalla på initiellt för att sedan användas vidare i dina rutiner. Den skall alltså kallas första gången, såvida du inte alltid vill påtvinga språket som webbläsaren initiellt använder. Därefter behöver vi också få reda på var filen finns placerat rent fysiskt på disk i vår applikation.
Shared Function GetLanguagePath() As String
If InStr(HttpContext.Current.Request.Url.ToString, "localhost") > 0 Then
GetLanguagePath = ConfigurationSettings.AppSettings("LanguageFileLocal")
Else
GetLanguagePath = ConfigurationSettings.AppSettings("LanguageFile")
End If
End Function
Denna hämtar helt enkelt ut sökvägen där vi placerat vår xmlfil. Du kan antingen använda dig av mappath eller så lägger du det helt enkelt i web.config. Jag förordar web.config eftersom mappath faktiskt gör en findfile som i sin tur tar cpu och disk IO i onödan. Det kommer bli ganska många anrop när folk surfar på sidan så allt sådant som är tidsbesparande skall användas.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="LanguageFile" value="c:\server\wwwroot\include\extended.xml" />
<add key="LanguageFileLocal" value="c:\inetpub\wwwroot\include\extended.xml" />
</appSettings>
<system.web>
Sådär, nu har vi även våra sökvägar i web.config. Nästa moment är nu aktiskt att återanvända till vår linkbutton ovan, för den skall ju byta språk på texten varje gång man klickar på denna. Vi tar helt enkelt och på vår huvudsida, exempelvis default.aspx att lägga till denna funktion.
lnkLanguage.Text = Namespace.Klassnamn.GetLangMessage("/page/language", True)
Vi är nu bara en liten bit kvar från vår färdiga språkfil och den sista funktionen är alltså GetLangMessage som vi använder för att få tag på vår xml-fils specifika post beroende på vilket språk vi valt. Den här rutinen är lite mer avancerad än dom tidigare och en kort förklaring krävs innan vi summerar allting.
XML-filen läses in i cacheobjektet rakt upp och ner. Så länge den finns kommer vi hämta den och plocka ut vår översättning. Men om den inte finns där, läses den upp igen och läggs in. Jag har valt att med 15 minuters intervall döda denna cache och ladda om den automatiskt. Anledningen till det är att om jag skickar in en ny språkfil exempelvis via FTP så vet jag att inom 15 minuter kommer den nya användas. Hur du gör får du bestämma själv förstås. men jag tycker det är ett smidigt sätt.
En sak till, jag har något som kallas fallback. Det innebär att om jag står på sidan på Engelska och skall visa namnet där och det inte finns, då går jag vidare till Svenska och visar det. Finns inte det heller så skriver jag helt enkelt [nyckeln saknas]. På detta sätt vet du att du kanske missat ett stavat fe l på något tagg i din xml-fil, eller helt enkelt glömt den när du hoppar mellan dom olika språken. Nu tar vi en titt på vår funktion.
Shared Function GetLangMessage(ByVal KeyName As String, Optional ByVal FixBlankingSpace As Boolean = False) As String
' // Hämtar ur translate.xml ett namn eller en text beroende
' på hur användaren ställt in sin webbläsare, eller via
' hemsidan. Dokumentet läggs även i en application-cache
' så den endast efterfrågas då vid av applikation/iis.
' ------------------------------------------------------
' KeyName är case-sensitive
' rooten anges ej, är <languages>
' ------------------------------------------------------
Dim XMLdoc As XmlDocument = New XmlDocument
Try
' // Om hela xmldokumentet är cachat så använder vi det, annars öppnar vi
' det bara igen och läser igenom våra värden
If Not HttpContext.Current.Cache("languagefile") Is Nothing Then
' läs ut xmlfilen från cache
XMLdoc = HttpContext.Current.Cache("languagefile")
Else
' skriv ner xmlfilen i cache, cacha i 15 minuter
XMLdoc.Load(GetLanguagePath)
HttpContext.Current.Cache.Insert("languagefile", XMLdoc, Nothing, DateTime.Now.AddMinutes(15), TimeSpan.Zero)
End If
' // Finns något data?
If XMLdoc.DocumentElement Is Nothing Then
Exit Function
End If
Catch ex As Exception
' vi fick något fel
System.Web.HttpContext.Current.Response.Write("Fel vid hämtning av xml-fil till siten. " & Err.Source & "<br>" & Err.Description)
HttpContext.Current.Response.End()
End Try
' // Söker ut rätt data baserat på frågan. En fallback finns vilket innebär
' att om inte något annat språks värde finns, söker den efter det svenska
' och finns inte det - returneras texten [nyckel saknas]
Dim returnvalue As String
Try
returnvalue = XMLdoc.SelectSingleNode("/languages/language[@id='" & UCase(pellesoft.Site.GetLanguage,) & "']/" & KeyName).InnerText
Catch ex As Exception
' fallback på språk
If pellesoft.Site.GetLanguageId >= 1 Then
Try
returnvalue = XMLdoc.SelectSingleNode("/languages/language[@id='SV']/" & KeyName).InnerText
Catch ex
returnvalue = "[nyckel saknas]"
End Try
Else
returnvalue = "[nyckel saknas]"
End If
End Try
' // rensar objektet
XMLdoc = Nothing
' // returnerar resultatet
If FixBlankingSpace = True Then
returnvalue = Replace(returnvalue, "-", "-")
Return Replace(returnvalue, " ", " ")
Else
Return returnvalue
End If
End Function
Det som kan vara lite främmande här är ett scriptspråk som heter XPath och kan användas för att arbeta med just xml-filer. Funktionen SelectSingleNode söker den först matchande noden som kan finnas och vi skickar in data som säger att language skall vara SV/ därefter skall noden vara något som vi skickar med från vår funktion när vi skall skriva vår label. Det bör även tilläggas att Cache.Insert motsvarar gamla asp's Application("namn") men är nu mycket mer avancerad och effektivare.
Lycka till!
/Pelle Johansson
Sv:Språkhantering
En fråga bara, när det gäller språkhantering och mest effektisvaste o prestanda snålaste metod. Hur står sig xml vs databas?Sv: Språkhantering
Idag går anropen så snabbt i en databas att du oftast inte behöver tänka på det. Dock, om det nu är så att du skall läsa en mängd labels i en databas för varje sidvisning så kommer det nog bli några anrop. dock kan du säkert som jag gjort, läsa ut information från databasen till ett dataset som du sedan cachar på sajten och läser från. Det blir i princip samma effekt som att ha xml-dokumentet cachat.
Det är inte så svårt att skriva om samma sak från XML till ett select-anrop från en tabell och därefter ändra själva "uttaget" av den/de labels som du behöver komma åt.