Georg fährt extra nach Berlin um Steve Ballmer zu treffen

31 Tage Mango | Tag #29: Internationalisierung

Die­ser Arti­kel ist Tag #29 der Serie 31 Tage Man­go von Jeff Blan­ken­burg.

Der Ori­gi­nal­ar­ti­kel befin­det sich hier: Day #29: Glo­ba­li­za­ti­on.

Die­ser Arti­kel wur­de in der Ori­gi­nal­se­rie von Gast­au­tor Matt Eland geschrie­ben. Bei Twit­ter kann Matt unter @integerman erreicht wer­den.

Globalisierung und Lokalisierung

Es herrscht oft etwas Ver­wir­rung bei der Dis­kus­si­on von Glo­ba­li­sie­rung und Loka­li­sie­rung. Bei­de haben damit zu tun, Inhal­te für alle Regio­nen der Welt pas­send zu prä­sen­tie­ren. Der Unter­schied ist, dass Glo­ba­li­sie­rung sich mit der For­ma­tie­rung von Ele­men­ten, also z.B. Zeit, Datum, Wäh­rung und Zah­len, beschäf­tigt, wäh­rend es bei Loka­li­sie­rung um die Anzei­ge der Inhal­te in der Spra­che des Anwen­ders geht. In die­sem Arti­kel wer­den wir uns mit bei­den Aspek­ten beschäf­ti­gen, um Anwen­dun­gen zu bau­en, die für ein mög­lichst brei­tes Publi­kum attrak­tiv sind.

Wir wer­den im Lau­fe die­ses Arti­kels eine Bei­spiel­an­wen­dung bau­en, die sowohl Glo­ba­li­sie­rung als auch Loka­li­sie­rung unter­stützt. Die­se Anwen­dung wird eine Email-Nach­richt gene­rie­ren, mit der Sie Ihrer Ver­ab­re­dung über Ihre Ver­spä­tung Bescheid geben kön­nen.

Lokalisierung einrichten

Nach­dem wir ein neu­es C# Win­dows Pho­ne Pro­jekt erstellt haben, müs­sen wir ein paar Kon­fi­gu­ra­ti­ons­ein­stel­lun­gen zur Unter­stüt­zung der Loka­li­sie­rung vor­neh­men.

Eine Neu­tral Lan­guage für das Assem­bly fest­le­gen

Da wir unse­re Anwen­dung für ver­schie­de­ne Spra­chen anbie­ten wol­len, müs­sen wir fest­le­gen, wel­che Spra­che die stan­dard­mä­ßig ver­wen­de­te ist. Hier­zu gehen wir in den Eigen­schafts­dia­log des Pro­jekts und Kli­cken auf „Assem­bly Infor­ma­ti­on…“. Dort kön­nen wir die Neu­tral Lan­guage des Assem­blies fest­le­gen — die­se Spra­che wird ver­wen­det, wenn für die Spra­che des Anwen­ders kei­ne spe­zi­fi­schen Res­sour­cen gefun­den wer­den. In unse­rem Bei­spiel set­zen wir die Neu­tral Lan­guage auf Eng­lish (United Sta­tes).

Unter­stütz­te Spra­chen ange­ben

Als nächs­tes müs­sen wir dem Pro­jekt mit­tei­len, wel­che Spra­chen wir unter­stüt­zen wol­len. Man kann die­se Pro­jekt­in­for­ma­ti­on der­zeit lei­der nicht direkt im Visu­al Stu­dio bear­bei­ten. Wir kön­nen aber leicht die Pro­jekt­da­tei edi­tie­ren. Spei­chern Sie alles, damit alle Ände­run­gen an der .csproj Datei gesi­chert sind, bevor Sie sie bear­bei­ten. Dann gehen Sie in den Ord­ner des Pro­jekts auf der Fest­plat­te, indem Sie z.B. mit rechts auf das Pro­jekt kli­cken und „Open fol­der in Win­dows Explo­rer“ wäh­len. Wäh­len Sie die .csproj Datei Ihrer Anwen­dung (nicht mit der Datei .csproj.user ver­wech­seln!) und öff­nen Sie die­se Datei in einem Text­edi­tor.

Suchen Sie nach dem Ele­ment <SupportedCultures></SupportedCultures> und fügen Sie dort die Cul­tu­re Codes hin­zu, die Sie unter­stüt­zen möch­ten. Tren­nen Sie die ein­zel­nen Codes durch ein Semi­ko­lon. Die Neu­tral Cul­tu­re des Assem­blies kommt nicht in die­se Lis­te. Wir geben hier nur die über die Stan­dard­spra­che hin­aus­ge­hen­den, zusätz­li­chen Cul­tu­re Codes an. Hier fin­den Sie eine Lis­te der von den ver­schie­de­nen Win­dows Pho­ne Ver­sio­nen unter­stütz­ten Spra­chen: http://msdn.microsoft.com/en-us/library/hh202918(v=VS.92).aspx. In unse­rem Bei­spiel wer­den wir Spa­nisch, ver­ein­fach­tes Chi­ne­sisch und Fran­zö­sisch zusätz­lich zu unse­rer Stan­dard­spra­che Eng­lish (United Sta­tes) untestüt­zen. Unser Kno­ten Sup­por­ted­Cul­tures sieht damit so aus:

<SupportedCultures>es-ES;zh-CN;fr-FR</SupportedCultures>

Nach den Ände­run­gen spei­chern Sie die Datei .csproj und wech­seln zurück ins Visu­al Stu­dio. Kli­cken Sie auf „Rel­oad“ wenn das Visu­al Stu­dio die Ände­rung an der Pro­jekt­da­tei fest­stellt.

Eine Basis-Res­sour­cen­da­tei erstel­len

Jetzt, wo wir unse­re Stan­dard­spra­che und die wei­te­ren unter­stütz­ten Spra­chen defi­niert haben, kön­nen wir anfan­gen, unse­re sprach­spe­zi­fi­schen Res­sour­cen zu defi­nie­ren. Wir begin­nen, indem wir eine Datei für unse­re Stan­dard­spra­che hin­zu­fü­gen. Spä­ter wer­den wir wei­te­re Res­sour­cen für die ande­ren Spra­chen hin­zu­fü­gen. Damit unse­re Anwen­dung voll­stän­dig loka­li­siert ist, soll­te jeder für den Anwen­der sicht­ba­re String in die­sen Datei­en ent­hal­ten sein und nicht hart­ko­diert im XAML oder einer Quell­code-Datei.

Wir fügen eine Res­sour­cen­da­tei zum Pro­jekt hin­zu, wel­che unse­re Strings in der Stan­dard­spra­che ent­hal­ten wird. Rechts-Kli­cken Sie auf das Pro­jekt und wäh­len Sie „Add > New Item“. Dort wäh­len wir Resour­ce File. Die­se Datei kann prin­zi­pi­ell irgend­wie hei­ßen — in unse­rem Bei­spiel nen­nen wir sie Strings.

Nach dem Hin­zu­fü­gen der Datei wech­selt das Visu­al Stu­dio sofort in den Res­sour­ce­nedi­tor für die­se Res­sour­ce. Der Edi­tor besteht aus einer Tabel­le mit drei Spal­ten: Name, Wert und Kom­men­tar. Name ist der ein­deu­ti­ge Schlüs­sel zur Iden­ti­fi­ka­ti­on. Die­ser wird als Name der Eigen­schaft zum Zugriff auf die Res­sour­ce in der gene­rier­ten code-behind Datei ver­wen­det. Der Wert ist der sprach­spe­zi­fi­sche Wert der Res­sour­ce. Dies ist also der für den Benut­zer sicht­ba­re Text. Das Feld Kom­men­tar wer­den wir in unse­rer Anwen­dung nicht benö­ti­gen. Es ist aber prak­tisch, um die Bedeu­tung der Res­sour­ce und z.B. den Ort der Ver­wen­dung zu notie­ren. Die­se Infor­ma­ti­on kann bei der Über­set­zung in ande­re Spra­chen sehr wert­voll sein. Oben rechts im Res­sour­ce­nedi­tor sehen Sie ein Aus­wahl­feld zur Steue­rung der Sicht­bar­keit der Res­sour­cen. Stan­dard­mä­ßig ist die Sicht­bar­keit auf inter­nal ein­ge­stellt. Wir ändern dies auf public, damit wir im XAML direkt an die Res­sour­cen bin­den kön­nen.

Hier ist unser Bei­spiel, bei dem bereits die nöti­gen Strings ein­ge­tra­gen wur­den und der Access Modi­fier auf public umge­stellt wur­de.

Sprach­spe­zi­fi­sche Res­sour­cen­da­tei­en erstel­len

Nach­dem wir die Res­sour­cen für die Stan­dard­spra­che abge­schlos­sen sind, kön­nen wir uns dar­an machen, wei­te­re Res­sour­cen für die unter­stütz­ten Spra­chen anzu­le­gen. Wir fan­gen mit den spa­ni­schen Res­sour­cen an. Hal­ten Sie Strg gedrückt und kli­cken und zie­hen Sie Strings.resx im Solu­ti­on Explo­rer um eine Kopie der Datei dem Pro­jekt hin­zu­zu­fü­gen. Benen­nen Sie die Datei „Kopie von Strings.resx“ um in „Strings.es-ES.resx“ (es-ES ist der Cul­tu­re Code für Spa­nisch). Die neue Datei muss genau so hei­ßen wie die alte plus dem Cul­tu­re Code für die Spra­che, für die die Res­sour­ce gilt. Wenn der Datei­na­me nicht stimmt, wird die Res­sour­ce für die vor­ge­se­he­ne Spra­che nicht ver­wen­det. Nach­dem Sie die Datei umbe­nannt haben, öff­nen Sie die Datei Strings.es-ES.resx und pas­sen Sie die Spal­te Value für jeden String an. Eine gute Aus­gangs­ba­sis für die Über­set­zung ist Bing Trans­la­tor. Vor einer Ver­öf­fent­li­chung soll­ten Sie den­noch die Über­set­zungs­er­geb­nis­se von einer der Spra­che mäch­ti­gen Per­son prü­fen las­sen. Die Wer­te in der Spal­te Name müs­sen zwi­schen den ver­schie­de­nen Res­sour­cen­da­tei­en über­ein­stim­men, damit die pas­sen­den Über­set­zun­gen gefun­den wer­den.

Wenn Sie die Über­set­zung abge­schlos­sen haben, wie­der­ho­len Sie den Vor­gang für jede wei­te­re unter­stütz­te Spra­che. Ach­ten Sie bei allen Res­sour­cen­da­tei­en dar­auf, dass die Sicht­bar­keit auf public steht, dass die Namen der ein­zel­nen Res­sour­cen unver­än­dert blei­ben und dass die Datei­na­men den ent­spre­chen­den Cul­tu­re Code beinhal­ten. Wei­ter­hin soll­ten Sie wis­sen, dass der Res­sour­ce­nedi­tor nicht alle Zei­chen frem­der Spra­chen kor­rekt dar­stel­len kann (wenn Sie die­se z.B. vom Bing Trans­la­tor kopie­ren). Die Zei­chen soll­ten im Emu­la­tor oder auf einem tat­säch­li­chen Gerät aber ver­nünf­tig dar­ge­stellt wer­den.

Die nicht-loka­li­sier­te Benut­zer­schnitt­stel­le bau­en

Jetzt, wo wir eine Rei­he loka­li­sier­ter Strings haben, begin­nen wir mit dem Bau der Benut­zer­schnitt­stel­le, die die­se Strings ver­wen­den wird. Unse­re Bei­spiel­an­wen­dung wird eini­ge Fel­der, eine App­li­ca­ti­on Bar und einen Stan­dard-Titel haben. Da wir Datums­wer­te zur Demons­tra­ti­on der Glo­ba­li­sie­rung ver­wen­den wol­len, refe­ren­zie­ren wir das Siler­light Tool­kit for Win­dows Pho­ne und ver­wen­den dar­aus das Tim­ePi­cker Con­trol. Da wir das Sil­ver­light Tool­kit for Win­dows Pho­ne in der Serie schon öfter ver­wen­det haben, spa­re ich mir in die­sem Arti­kel eine Beschrei­bung des Down­loads, der Instal­la­ti­on und Refe­ren­zie­rung des Sil­ver­light Tool­kits for Win­dows Pho­ne. Es ist kos­ten­los ver­füg­bar und online gibt es aus­führ­li­che Hil­fe.

Unse­re nicht-loka­li­sier­te MainPage.xaml sieht so aus:

<phone:PhoneApplicationPage
   x:Class="PhoneApp1.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsMenuEnabled="False">
            <shell:ApplicationBarIconButton IconUri="/icons/appbar.feature.email.rest.png"
                                           IsEnabled="True"
                                           Text="send"
                                           Click="HandleSendClick" />
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot"
         Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel"
                   Grid.Row="0"
                   Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle"
                      Text="I'm Running Late"
                      Style="{StaticResource PhoneTextNormalStyle}" />
            <TextBlock x:Name="PageTitle"
                      Text="Send Message"
                      Margin="9,-7,0,0"
                      Style="{StaticResource PhoneTextTitle1Style}"
                      TextWrapping="Wrap" />
        </StackPanel>
        <ScrollViewer Margin="12,0,12,0"
                     Grid.Row="1">
            <StackPanel x:Name="ContentPanel">
                <TextBlock TextWrapping="Wrap"
                          Text="To"
                          Style="{StaticResource PhoneTextSubtleStyle}" />
                <TextBox x:Name="txtTo"
                        TextWrapping="Wrap"
                        InputScope="EmailUserName" />
                <HyperlinkButton Content="Choose a contact"
                                HorizontalContentAlignment="Left"
                                Foreground="{StaticResource PhoneAccentBrush}"
                                Click="HandleChooseContactClick"
                                Margin="{StaticResource PhoneVerticalMargin}" />
                <TextBlock TextWrapping="Wrap"
                          Text="Subject"
                          Style="{StaticResource PhoneTextSubtleStyle}" />
                <TextBox x:Name="txtSubject"
                        TextWrapping="Wrap"
                        Text="I'm Running Late"
                        InputScope="Text" />
                <CheckBox x:Name="checkIncludeReason"
                         Content="Include a reason" />
                <TextBox x:Name="txtReason"
                        TextWrapping="Wrap"
                        Text="Traffic"
                        InputScope="Text"
                        IsEnabled="{Binding IsChecked, ElementName=checkIncludeReason}" />
                <CheckBox x:Name="checkIncludeETA"
                         Content="I should arrive by" />
                <Controls:TimePicker x:Name="timeArrival"
                                    IsEnabled="{Binding IsChecked, ElementName=checkIncludeETA}"
                                    Margin="0,-12,0,0" />
                <CheckBox x:Name="checkIncludeDiagnosticData"
                         Content="Include extra data" />
            </StackPanel>
        </ScrollViewer>
    </Grid>
</phone:PhoneApplicationPage> 

Wie Sie leicht sehen, ent­hält die­ses XAML eine Rei­he hart­ko­dier­ter Strings. Genau das wol­len wir für unse­re loka­li­sier­te Anwen­dung nicht. Wir müs­sen die Benut­zer­schnitt­stel­le dazu brin­gen, unse­re über­setz­ten Res­sour­cen-Strings zu ver­wen­den.

Res­sour­cen-Strings im XAML ver­wen­den

Der Res­sorce­nedi­tor gene­riert auto­ma­tisch Klas­sen zum Zugriff auf die Res­sour­cen. Unglück­li­cher­wei­se kön­nen wir die­se nicht ohne wei­te­res im XAML bin­den, da die gene­rier­te Klas­se Strings einen inter­nal Kon­struk­tor und sta­ti­sche Eigen­schaf­ten hat. Wir bau­en also ein klei­nes Wrap­per-Objekt, wel­ches die Res­sour­cen so zur Ver­fü­gung stellt, dass wir dar­an bin­den kön­nen.

Fügen Sie dem Pro­jekt eine neue C#-Datei hin­zu und nen­nen Sie die­se StringProvider.cs. Fügen Sie dort den fol­gen­den Code ein:

namespace PhoneApp1
{
   public class StringProvider
   {
      private readonly Strings _resources = new Strings();

      public Strings Resources
      {
         get { return _resources; }
      }
   }
} 

Gehen Sie jetzt in die Datei App.xaml und fügen Sie der Anwen­dung die neu erstell­te Res­sour­ce hin­zu. Hier­zu müs­sen Sie noch ein xmlns Name­space-Ali­as für den Default-Name­space der Anwen­dung hin­zu­fü­gen. Die Res­sour­ce wird in der gan­zen Anwen­dung zur Ver­fü­gung ste­hen und uns den ein­fa­chen Zugriff auf die über­setz­ten Strings ermög­li­chen. Am Ende soll­te unse­re App.xaml etwa wie folgt aus­se­hen:

<Application
   x:Class="PhoneApp1.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:local="clr-namespace:PhoneApp1">

    <!--Application Resources-->
    <Application.Resources>
        <local:StringProvider x:Key="Strings" />
    </Application.Resources>

    <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <shell:PhoneApplicationService
           Launching="Application_Launching" Closing="Application_Closing"
           Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>

</Application> 

Mit dem String­Pro­vi­der als Res­sour­ce kön­nen wir in der Main Page an die­ses Objekt bin­den. In unse­rem Fall bin­den wir an eine Unt­er­ei­gen­schaft der Eigen­schaft Resour­ce, die dem Namen der Res­sour­ce in unse­rer Res­sour­cen­ta­bel­le ent­spricht. Den anwen­dungs­weit zugreif­ba­ren String­Pro­vi­der ver­wen­den wir als Bin­ding Source. Aus dem Page­Tit­le Text­Block unse­res Bei­spiels wird daher:

<TextBlock x:Name="PageTitle" Text="{Binding Resources.PageTitleSendMessage, Source={StaticResource Strings}}" TextWrapping="Wrap" />

Sowohl Blend als auch das Visu­al Stu­dio soll­ten das Bin­ding erken­nen und den String der neu­tra­len Spra­che im Desi­gner anzei­gen (also den aus der Datei Strings.resx). Hier­zu muss das Pro­jekt seit dem Hin­zu­fü­gen der Res­sour­ce erstellt wor­den sein.

Wenn Sie eine loka­li­sier­te Anwen­dung bau­en, beden­ken Sie, dass über­setz­te Tex­te län­ger sein kön­nen als in der neu­tra­len Spra­che. Aus die­sem Grund soll­ten Sie z.B. an geeig­ne­ten Stel­len TextWrapping=„Wrap“ set­zen und fle­xi­ble Lay­outs, wie z.B. Scroll­View­ers und Stack­Pa­nels ver­wen­den. Die­se kön­nen sich an umge­bro­che­ne Tex­te anpas­sen.
Eine wei­te­re Mög­lich­keit zum Umgang mit lan­gen Tex­ten ist das Set­zen von SupportedOrientations=„PortraitOrLandscape“ für das Sei­ten­ele­ment bei geeig­ne­ten Sei­ten.

Wei­ter­hin soll­ten Sie beach­ten, dass nicht alle Spra­chen alle Fonts unter­stüt­zen. Um auf Num­mer sicher zu gehen, soll­ten Sie auf spe­zi­el­le Fonts ver­zich­ten und sich auf die ein­ge­bau­ten Styles ver­las­sen. Für mehr Infor­ma­ti­on sie­he hier: http://msdn.microsoft.com/en-us/library/hh202920(v=VS.92).aspx.

Loka­li­sier­te Strings im Code-Behind ver­wen­den

Die­ser Ansatz funk­tio­niert für die meis­ten Strings. Die Metro Design­richt­li­ni­en sehen aber bei­spiels­wei­se vor, dass der Anwen­dungs­ti­tel ganz oben auf der Sei­te in Groß­buch­sta­ben geschrie­ben ist. In unse­rem String in der Res­sour­cen­da­tei sind nur die Anfangs­buch­sta­ben groß geschrie­ben. Wir könn­ten natür­lich einen neue Res­sour­ce für den Anwen­dungs­ti­tel defi­nie­ren oder einen Value­Con­ver­ter zur Umwand­lung in Groß­buch­sta­ben schrei­ben. Statt­des­sen set­zen wir den Titel ein­fach im Code-behind. Damit kön­nen wir demons­trie­ren, wie man die loka­li­sier­ten Res­sour­cen aus dem Code zugrei­fen kann. Wir fügen im Kon­struk­tur der Main­Page die fol­gen­de Zei­le ein:

ApplicationTitle.Text = Strings.AppTitle.ToUpper(CultureInfo.CurrentCulture);

App­li­ca­ti­on Bars loka­li­sie­ren

Ele­men­te der App­li­ca­ti­on Bar unter­stüt­zen zur Zeit kein Bin­ding, da sie eigent­lich gar kei­ne Sil­ver­light-Ele­men­te sind. Wir müs­sen hier also die Tex­te für die App­li­ca­ti­on­Ba­rIcon­But­ton Ele­men­te hän­disch im Code-Behind set­zen, indem wir die auto­ma­tisch gene­rier­ten Eigen­schaf­ten für unse­re Res­sour­cen­na­men unse­rer Strings Res­sour­ce wie folgt ver­wen­den:

public MainPage()
{
   InitializeComponent();

   // Ensure that the app title uses all caps
   ApplicationTitle.Text = Strings.AppTitle.ToUpper(CultureInfo.CurrentCulture);

   // Specify the text explicitly on the app bar using our resource string.
   var button = (ApplicationBarIconButton)ApplicationBar.Buttons[0];
   button.Text = Strings.ButtonSend;

   // By default, we're going to be 15 minutes later than now
   timeArrival.Value = DateTime.Now.AddMinutes(15);
} 

Wir haben jetzt eine loka­li­sier­te Anwen­dung. Ein Test der Anwen­dung im Emu­la­tor mit fran­zö­si­schen Sprach­ein­stel­lun­gen ergibt das fol­gen­de:

Globalisierung unterstützen

Wir haben jetzt eine loka­li­sier­te Anwen­dung — wen­den wir uns der Glo­ba­li­sie­rung zu. Glo­ba­li­sie­rung hat damit zu tun, die loka­len Ein­stel­lun­gen des Anwen­ders zu respek­tie­ren. Wir müs­sen also an geeig­ne­ten Stel­len IFor­mat­Pro­vi­der für die For­ma­tie­rung von Strings ange­ben. Zum Glück bie­tet uns .NET mit CultureInfo.CurrentCulture einen ein­fa­chen Zugriff auf die aktu­el­len Ein­stel­lun­gen. Die­se kön­nen wir ver­wen­den, um die Strings für die Benut­zer­ober­flä­che zu for­ma­tie­ren. Bei Ver­glei­chen, Seria­li­sie­rung oder ande­ren Ope­ra­tio­nen, die nichts mit dem Benut­zer­inter­face zu tun haben, soll­ten Sie die CultureInfo.InvariantCulture ver­wen­den, damit Ihre Anwen­dung sich bei allen loka­len Ein­stel­lun­gen gleich ver­hält.

Anders als bei der Loka­li­sie­rung müs­sen wir nicht expli­zit ange­ben, wel­che Sprach­ein­stel­lun­gen wir unter­stüt­zen wol­len. Wir über­ge­ben ein­fach die aktu­el­len Ein­stel­lun­gen an das .NET Frame­work und die­ses über­nimmt die meis­te Arbeit der sprach­spe­zi­fi­schen For­ma­tie­rung. Trotz­dem ist es emp­feh­lens­wert, an den betref­fen­den Stel­len pas­sen­de For­mat Strings zu über­ge­ben und die CultureInfo.CurrentCulture in Form eines IFor­mat­Pro­vi­der zu über­ge­ben.

Der Code zur Gene­rie­rung einer Email bei­spiels­wei­se macht expli­zi­ten Gebrauch der Cur­rent­Cul­tu­re und von For­mat Strings:

private void HandleSendClick(object sender, EventArgs e)
{
   // Build the E-Mail body from the user's selections
   var body = new StringBuilder();
   body.AppendLine(Strings.EmailHeader);

   // Include reason if applicable
   var culture = CultureInfo.CurrentCulture;
   if (checkIncludeReason.IsChecked == true)
   {
      body.AppendLine();
      body.AppendLine(string.Format(culture, "{0}: {1}", Strings.EmailReason, txtReason.Text));
   }

   // Include eta if applicable
   if (checkIncludeETA.IsChecked == true)
   {
      body.AppendLine();
      // Since we've specified our ValueFormatString for the Time Picker, we can just rely on the ValueString here.
      body.AppendLine(string.Format(culture, "{0}: {1}", Strings.CheckShouldArriveBy, timeArrival.ValueString));
   }

   // Include extra globalization examples if applicable
   if (checkIncludeDiagnosticData.IsChecked == true)
   {
      body.AppendLine();
      // this is the standardized culture name such as en-US or zh-CH
      body.AppendLine(culture.Name);
      body.AppendLine(string.Format(culture, "pi: {0}", Math.PI));
      body.AppendLine(string.Format(culture, "number: {0}", -1));
      body.AppendLine(string.Format(culture, "currency: {0:c}", 4200.00));
      body.AppendLine(string.Format(culture, "date: {0:D}", DateTime.Today));
      body.AppendLine(string.Format(culture, "time: {0:t}", DateTime.Now));
   }

   // Now that we have our message body, do something with it. What we do depends on what we're running on.
   if (Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator)
   {
      // The emulator doesn't currently support sending E-Mails so we'll just output the text to a message box
      MessageBox.Show(body.ToString());
   }
   else
   {
      // Compose the E-Mail and show it to the user to preview before sending
      var task = new EmailComposeTask {Subject = txtSubject.Text, To = txtTo.Text, Body = body.ToString()};
      task.Show();
   }
} 

Da die Glo­ba­li­sie­rung unab­hän­gig von der Loka­li­sie­rung ist, wird unse­re App auch bei Sprach­ein­stel­lun­gen, für die wir kei­ne loka­li­sier­ten Res­sour­cen defi­niert haben, die kor­rekt glo­ba­li­sier­ten Wer­te aus­ge­ben. Im Bei­spiel unten wer­den die deut­schen Sprach­ein­stel­lun­gen ver­wen­det:

For­mat Strings in XAML

Manch­mal wol­len Sie viel­leicht einen For­mat String im XAML als Para­me­ter, als Value­Con­ver­ter oder als Eigen­schaft eines ein­ge­bau­ten Con­trols defi­nie­ren. In unse­rem Bei­spiel set­zen wir den For­mat String unse­res Tim­ePi­cker Con­trols auf das kur­ze Zeit­for­mat der aktu­el­len Sprach­ein­stel­lun­gen („t“). Hier­zu stel­len wir dem For­mat String ein Paar von Klam­mern vor­ne an:

<Controls:TimePicker x:Name="timeArrival" ValueStringFormat="{}{0:t}" />

Man kann das auch im Code-Behind machen. Ent­we­der so:

var info = CultureInfo.CurrentCulture.DateTimeFormat;
timeArrival.ValueStringFormat = "{0:" + info.ShortTimePattern + "}"; 

oder etwas kom­pak­ter:

timeArrival.ValueStringFormat = "{0:t}"; 

Verschiedene Spracheinstellungen testen

Wir haben jetzt eine voll funk­ti­ons­fä­hi­ge Anwen­dung gebaut, die Glo­ba­li­sie­rung und Loka­li­sie­rung unter­stützt. Sie fra­gen sich viel­leicht, wie man die ver­schie­de­nen Sprach­ein­stel­lun­gen am bes­ten tes­tet. In Ihrem Gerät wer­den Sie mög­li­cher­wei­se die Anzei­ge­spra­che gar nicht ver­än­dern kön­nen. Glück­li­cher­wei­se bie­tet der Emu­la­tor die­se Mög­lich­keit.

Gehen Sie im Emu­la­tor auf die App für Ein­stel­lun­gen und dort in den Bereich Regi­on & Spra­che um die Sprach­ein­stel­lun­gen zu ver­än­dern.

Auf dem Bild­schirm Regi­on & Spra­che kön­nen Sie die Anzei­ge­spra­che umstel­len, indem Sie die Spra­che aus der Aus­wahl­box wäh­len und dann oben auf das Link „Tip­pen Sie hier, um die Ände­run­gen zu über­neh­men und das Han­dy neu zu star­ten“. Dadurch wird der Emu­la­tor neu geboo­tet und wird mit den gewähl­ten Sprach­ein­stel­lun­gen neu gestar­tet. Es kann viel­leicht etwas ver­wir­rend sein, die Ein­stel­lun­gen in einer Ihnen unbe­kann­ten Spra­che vor­zu­neh­men. Mer­ken Sie sich des­halb das Aus­se­hen und die Anord­nung der Ein­ga­be­fel­der, bevor Sie die Spra­che umstel­len. Sobald der Emu­la­tor neu geboo­tet wur­de, kön­nen Sie Ihre Anwen­dung im Emu­la­tor star­ten, um das Ver­hal­ten mit den neu­en Sprach­ein­stel­lun­gen zu tes­ten.

Veröffentlichung

Wenn Sie eine Anwen­dung ver­öf­fent­li­chen, die ver­schie­de­ne Spra­chen unter­stützt, stel­len Sie sicher, dass Sie die betref­fen­den Märk­te zur Ver­öf­fent­li­chung Ihrer App aus­wäh­len. Sie kön­nen natür­lich auch gleich „World­wi­de Dis­tri­bu­ti­on“ wäh­len.

Zusammenfassung

Sie wis­sen jetzt, wie Sie eine kom­plet­te Anwen­dung für den glo­ba­len Markt ent­wi­ckeln kön­nen.

Um ein Win­dows Pho­ne Pro­jekt mit dem gan­zen Code die­ses Arti­kels her­un­ter­zu­la­den, drü­cken Sie den Down­load Code But­ton:

Mor­gen wen­den wir uns wie­der den Daten zu. Wir wer­den uns anschau­en, wie man eine loka­le Daten­bank in der App ver­wen­den kann.

Bis dahin!

Kommentare sind geschlossen.