2010-12-02 6 views
13

In meiner WPF-Anwendung, würde Ich mag, etwas zeigen, das wie folgt aussieht:Wie kann ich eine formatierte TextBlock Breite Datenbindung lokalisierbar machen?

Benutzer Bob hat bei 22.17 abgemeldet.

Dabei sind "Bob" und "22:17" datengebundene Werte.

Der offensichtliche Weg, dies zu tun, um eine StackPanel mit mehreren TextBlock Kinder zu verwenden wäre, gebunden einige Daten von ihnen:

<StackPanel Orientation="Horizontal"> 
    <TextBlock Text="The user"/> 
    <TextBlock Text="{Binding Path=Username}" TextBlock.FontWeight="Bold" /> 
    <TextBlock Text="has logged off at"/> 
    <TextBlock Text="{Binding Path=LogoffTime}" TextBlock.FontWeight="Bold" /> 
</StackPanel/> 

Dies funktioniert, aber es ist hässlich. Das Programm soll in verschiedenen Sprachen lokalisiert sein, und separate Strings für "Der Benutzer" und "hat sich abgemeldet" ist ein Rezept für Lokalisierungs-Desaster.

Im Idealfall würde Ich mag so etwas tun:

<TextBlock> 
    <TextBlock.Text> 
     <MultiBinding StringFormat="{}The user <Bold>{0}</Bold> has logged off at <Bold>{1}</Bold>"> 
      <Binding Path="Username" /> 
      <Binding Path="LogoffTime" /> 
     </MultiBinding> 
</TextBlock> 

So ist der Übersetzer einen vollständigen Satz The user <Bold>{0}</Bold> has logged off at <Bold>{1}</Bold> sehen würde. Aber das geht natürlich nicht.

Dies muss ein häufiges Problem sein, was ist die richtige Lösung dafür?

Antwort

4

Ich habe versucht, noch nie so etwas zu tun, aber wenn ich mich wahrscheinlich und einen Converter verwenden würde, wenn versuchen, die die Multibinding nimmt und bricht es auf und kehrt Beispiel ein Stackpanel der Stücke

Für wäre die Bindung so etwas wie:

<Label> 
    <Label.Content> 
      <MultiBinding Converter={StaticResource TextWithBoldParametersConverter}> 
       <Binding Source="The user {0} has logged off at {1}" /> 
       <Binding Path="Username" /> 
       <Binding Path="LogoffTime" /> 
      </MultiBinding> 
    </Label.Content> 
</Label> 

Und der Konverter so etwas wie

tun würde
public class TextWithBoldParametersConverter: IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     // Create a StackPanel to hold the content 
     // Set StackPanel's Orientation to Horizontal 

     // Take values[0] and split it by the {X} tags 

     // Go through array of values parts and create a TextBlock object for each part 
      // If the part is an {X} piece, use values[X+1] for Text and make TextBlock bold 
      // Add TextBlock to StackPanel 

     // return StackPanel 
    } 
} 
12

Das Problem, das ich sehe, ist, dass Sie eine einzige String noch mit einer anderen Benutzeroberfläche Anwesenheit über die String wollen.

Eine Option könnte sein, die Notwendigkeit für fett und einfach die einzige String innerhalb der Resources.resx Datei zu verwerfen. Das String wird dann in der Eigenschaft referenziert, an die die TextBlock gebunden ist, und die Werte nach Bedarf zurückgibt; {0} und {1} gegebenenfalls.

Eine andere Option könnte darin bestehen, einen Satz Run Werte zurückzugeben, die innerhalb der TextBlock gehalten werden. Sie können nicht auf eine Run aus der Box in 3,5 binden aber ich glaube, können Sie in 4.

  <TextBlock> 
        <Run Text="The user "/><Run FontWeight="Bold" Text="{Binding User}"/><Run Text="has logged at "/><Run FontWeight="Bold" Text="{Binding LogoffTime}"/> 
      </TextBlock> 

Die letzte Option here gefunden werden kann und beinhaltet einen dynamischeren Ansatz zur Run Konzept zu schaffen, so dass Sie Binden Sie Ihre Werte und binden Sie sie dann an eine String.

0

Es ist unwahrscheinlich, dass eine einzige Lösung für dieses Problem zu sein, weil es so viele verschiedene Wege gibt, wie es sich manifestieren kann, und es gibt so viele verschiedene Wege, es zu lösen.

Wenn Sie Microsoft sind, besteht die Lösung darin, alle Ihre Vorlagen in ein Ressourcenwörterbuch zu übernehmen, ein Projekt zu erstellen, das Expression Blend verwenden kann, und dann Ihre Übersetzer mit Blend arbeiten zu lassen Hilf ihnen, sie zu benutzen), um den Text im Ressourcenwörterbuch zu übersetzen und die Elemente in der Vorlage neu zu ordnen, wo es idiomatische Unterschiede in der Wortstellung gibt. Dies ist natürlich die teuerste Lösung, aber es hat den Vorteil, Formatierungsprobleme zu bekommen (wie jemand vergessen hat, dass französischer Text etwa 20% mehr Platz beansprucht als englischer Text), der gleichzeitig mit der UI-Übersetzung gelöst wird. Es hat auch den Vorteil, dass es jede Präsentation von Text in der Benutzeroberfläche behandelt, nicht nur die Präsentationen, die durch das Zusammenstapeln von Textblöcken erstellt werden.

Wenn Sie nur Stapel von Textblöcken reparieren müssen, können Sie eine einfache XML-Darstellung von markiertem Text erstellen und XSLT verwenden, um Ihr XAML aus einer Datei in diesem Format zu erstellen. Zum Beispiel so etwas wie:

<div id="LogoutTime" class="StackPanel"> 
    The user 
    <strong><span class="User">Bob</span><strong> 
    logged out at 
    <strong><span class="Time">22:17</span></strong> 
    . 
</div> 

Durch einen erstaunlichen Zufall, dass Markup-Format ist eine, die auch in einem Web-Browser angezeigt werden kann, so kann es mit einer wirklich breiten Palette von Werkzeugen bearbeitet werden und Korrektur gelesen, ohne, sagen wir, Expression Blend. Und es ist relativ einfach, wieder in XAML zu übersetzen:

<xsl:template match="div[@class='StackPanel']"> 
    <DataTemplate x:Key="{@id}"> 
     <StackPanel Orientation="Horizontal"> 
     <xsl:apply-templates select="node()"/> 
     </StackPanel> 
    </DataTemplate> 
</xsl:template> 

<xsl:template match="div/text()"> 
    <TextBlock Text="{.}"/> 
</xsl:template> 

<xsl:template match="strong/span"> 
    <TextBlock FontWeight="Bold"> 
     <xsl:attribute name="Text"> 
     <xsl:text>{Binding </xsl:text> 
     <xsl:value-of select="@class"/> 
     <xsl:text>}</xsl:text> 
     </xsl:attribute> 
    </TextBlock> 
</xsl:template> 
Verwandte Themen