#1,134 – Localization XV – Localizing Other Content

You’ll sometimes have content in an application that needs to be localized but is not already present in a XAML file.  Below, a MessageBox uses a hard-coded string.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            string message = "Apples are crunchy, portable and taste great!";
            MessageBox.Show(message, "Apples");
        }

One approach to this is to move the string into a XAML file as a resource and then localize the string when localizing all of the other content in the XAML file.

We start by including an XML namespace that defines an alias for the System namespace.

        xmlns:sys="clr-namespace:System;assembly=mscorlib"

We can now add the string as a resource (e.g. within a <Window> element).

    <Window.Resources>
        <sys:String x:Uid="sys:String_1" x:Key="AppleMessage">Apples are crunchy, portable and taste great!</sys:String>
    </Window.Resources>

At run-time, we can load the resource rather than a hard-coded string.

            string message = (string)this.Resources["AppleMessage"];
            MessageBox.Show(message, "Apples");

#1,133 – Localization XIV – Add Content to Already Localized Application

After localizing your application for multiple languages, you have a main executable and a satellite assembly for each language that you’ve localized for.

If you then make changes to content in your application that is represented as XAML, the changes will show up in the satellite assembly for the neutral language, but not in the other satellite assemblies.  The changes will only be present when running under the neutral language.

After changing XAML content in a localized application, you need to take the following steps:

  • Make changes in Visual Studio, fully test under neutral language
  • Update UIDs using msbuild tool: msbuild /t:updateuid appname.csproj
  • Save and rebuild application
  • Re-extract localizable content using LocBaml tool: locbaml.exe /parse .\en-US\appname.resources.dll
  • Localize new content, integrating changes into existing language-specific .csv files
  • Re-generate satellite DLLs using LocBaml: locbaml.exe /generate .\en-US\appname.resources.dll /trans:.\appname.resources.fr-FR.csv /out:.\fr-FR /cul:fr-FR
  • Run application and test changes

#1,132 – Localization XIII – Verifying Localized Content

Once you integrate localized content back into your application, you’ll want to verify that the new content looks correct.  You could verify the content by running your application on a system having the target culture (e.g. French).  You can also just override the local culture information at run-time, setting it to the target culture for testing purposes.

To override the culture at run-time, you set the CurrentUICulture property of the current thread.  Below, we change the current UI culture at app startup so that we can test localization for the fr-FR (French/France) culture.  We also override metadata for the Language property to force user interface controls to pick up the current culture (rather than UI culture).

    public partial class App : Application
    {
        public App()
        {
            Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");
            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
                        XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
        }
    }

1132-001

#1,131 – Localization XII – Set NeutralLanguageResources Attribute

When you set the UICulture tag in your project, signifying that you want to store resources in a satellite assembly, you also need to set the NeutralResourcesLanguage attribute to indicate the default language to be used when trying to load resources to match the current culture.

Below is a fragment from AssemblyInfo.cs, showing use of the NeutralResourcesLanguage attribute, as well as the comments provided by the New Project wizard.

//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>.  For example, if you are using US english
//in your source files, set the <UICulture> to en-US.  Then uncomment
//the NeutralResourceLanguage attribute below.  Update the "en-US" in
//the line below to match the UICulture setting in the project file.
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]

#1,130 – Localization XI – Satellite Assemblies

After localizing an application, you’ll have a directory structure that looks something like what’s shown below.

\bin – contains AppName.exe

\bin\fr-FR – contains AppName.resources.dll

\bin\en-US – contains AppName.resources.dll

We started by setting the UICulture tag to en-US.  This resulted in the \en-US\AppName.resources.dll file being generated.  This assembly is the satellite assembly containing English/US resources.

We then extracted resources using the LocBaml tool, translated content to French, and then generated a new satellite assembly for the fr-FR culture, again using the LocBaml tool.

At run-time, the current user interface culture (CurrentUICulture property) is read to determine the desired culture to use when loading resources.  This is typically the language used by the version of Windows that is installed.  (Rather than the current regional setting).

If there is a sub-directory whose name matches CurrentUICulture, then the corresponding satellite assembly is loaded.  If none is found, a neutral language assembly is used.

#1,129 – Localization X – Integrating Translations Back into Application

Once you get localized resources back from the translation team, you need to integrate these localized resources back into your application.

To integrate localized changes, once you have the new .csv file containing localized resources, do the following:

  • Open a Visual Studio command prompt
  • Change directory to be directory containing main application .exe file (e.g. \bin\Release)
  • Copy .csv file containing translations into this directory (e.g. WpfApplication1.resources.fr-FR.csv)
  • Create a sub-directory matching the desired culture name  (e.g. fr-FR)
  • Ensure that locbaml.exe is also present in this directory
  • Execute this command: locbaml.exe /generate .\en-US\WpfApplication1.resources.dll /trans:.\WpfApplication1.resources.fr-FR.csv /out:.\fr-FR /cul:fr-FR

You should see a new WpfApplication1.resources.dll file in the fr-FR sub-directory.

#1,128 – Localization IX – Localizing Content

After you’ve created .csv files containing the English-based property values, including text, the next step is to have the content actually localized.  This most often consists of translating the English text into another language.

The steps taken for actual localization of content are typically something like:

  • You hand off neutral (e.g. English) .CSV file to translators  (e.g. WpfApplication1.resources.csv)
  • Translators make a copy of the file, typically naming it to indicate culture  (e.g. WpfApplication1.resources.fr-FR.csv)
  • Translators translate all textual content
  • Translators send the file back to development team for integration into the application

Below is an example, show the .csv file before and after translation from English to French.  Note that three different strings have been translated.

English:

1128-001

French:

1128-002

 

#1,127 – Localization VIII – Passing Comments On to the Translator

When you have an application that will be localizable, you use localization attributes to explicitly mark which elements need to be localized.  You may want to also add a comment for a particular element, to help the translator in localizing the content.

You can add a comment for the translator in a XAML file using the Localization.Comments attribute.  The property can contain comments for multiple attributes and the comments will be written to the .csv file with the corresponding attribute.

Below, we specify a comment to be associated with the Content property.

        <Button x:Uid="Button_1" Content="Learn More" Margin="5"
                Click="Button_Click"
                Localization.Attributes="$Content(Unmodifiable) Margin(Unmodifiable)"
                Localization.Comments="Content(Should be an imperative--a command)"/>

Now, after generating the .csv file with LocBaml, we see that the comment shows up.

1127-001

#1,126 – Localization VII – Preventing Translator from Modifying Certain Elements

By default, when a .csv file is created using the LocBaml tool, the fifth parameter on each line is set to True.  This parameter indicates whether a particular property should be modifiable by the translator.

You can change the value of this modifiable field by setting the Localization.Attributes property for an element.  This property is set to a string of the form “propname(locvalue1 locvalue2) propname(locvalue1 locvalue2)”.

One of the localizability values that you can set is Unmodifiable, to indicate that the specified property should not be modified by the translator.

Below, we set Unmodifiable for various property values.

<Window x:Uid="Window_1" x:Class="WpfApplication1.MainWindow"
        Localization.Attributes="$Content(Unmodifiable) SizeToContent(Unmodifiable)"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="The App" SizeToContent="WidthAndHeight">

    <StackPanel x:Uid="StackPanel_1" Margin="15"
                Localization.Attributes="Margin(Unmodifiable)">
        <Label x:Uid="Label_1" Content="Hello, I like apples."
               Localization.Attributes="$Content(Unmodifiable)"/>
        <Button x:Uid="Button_1" Content="Learn More" Margin="5"
                Click="Button_Click"
                Localization.Attributes="$Content(Unmodifiable) Margin(Unmodifiable)"/>
    </StackPanel>
</Window>

After running the LocBaml tool, we see that the modifiable field is now false for these properties.

1126-001

#1,125 – Localization VI – Interpreting CSV File That Is Output by LocBaml Tool

As part of the localization process, you can use the LocBaml tool to extract localizable content into a text-based .csv file.

Below is a snapshot of a sample .csv file containing localizable content.

1124-001

Each line in the .csv file represents a single property of some user interface element.  The line contains the following elements (separated by commas):

  • The name of the BAML resource containing the property
    • (e.g. WpfApplication1.g.en-US.resources:mainwindow.baml)
  • Fully qualified property name, including the element’s UID
    • (e.g. Label_1:System.Windows.Controls.ContentControl.Content)
  • Localization category  (e.g. Button, Label, Text, etc).
  • Whether property is visible to user (T/F).
  • Whether property can or should be modified by translator (T/F)  (defaults to true for all elements)
  • Comments provided for translator  (defaults to blank)
  • Property value  (the thing that should be localized)