Some Practical Tips When Internationalizing WPF Applications

What seems to be the problem?

Hey, sure everybody can speak English and they can read it as well. Did you ever hear something similar when talking with developers, managers and/or sales persons? Today, the western world has become a saturated market for applications with less and less profit to be made. Some experts believe that the new market will be the Far East, some the old Russian satellites, and others the South American market. However, what is constant in all these markets is the fact that they are predominately non-English speaking. Take another example, the USA; today many software companies are being forced into tailoring their software for the burgeoning Spanish-American market – it seems that, statistically speaking, Spanish will become the most spoken language in the USA if the current Spanish-speaking population keeps increasing as it currently is.

Internationalization is easy; all we have to do is…

So, what needs to be considered when preparing an application for an international market? From a naïve perspective we have to translate all the GUI strings into the supported languages. Okay, we can extract all strings out of the source files and put them in RESX files. Additionally we can set the FlowDirection for the application based on the CultureInfo. This will do most of the heavy lifting for you, however it does not go the whole way – what happens when we do not want some of this lifting to happen?

No, it is something more complex than that.

Not everybody reads the same alphabet, not everybody reads in the same direction; right to left or left to right, some cultures are a mixture of both right to left and left to right – or BIDI (bidirectional). The European languages are left to right so when we are supplying software to this market as well as the English speaking world we only need to consider left to right languages and formatting. Additionally, when a string is build using a string parameters such as {0}, {1} etc. as sentence ordering is important in all languages. Then this string itself should also be placed in the RESX file. Moreover, Proper names are usually not translated, i.e., company names, product names, etc.

Additionally, some countries and markets are very protective of their own language and culture, or enforce laws, requirements or standards that define what can and cannot be display to the user.

FlowDirection is also only half the story as FlowDirection defines not only how text flows in a textual element but also the flow direction of almost every other UI element. For example, company logos and other graphics will be mirrored when using right-to-left settings and horizontal gradients will also be reversed. Additionally, gradients will also be effected by FlowDirection definition.

So, now all we have to do is?

From the above we now have the following points to observe when preparing for I18N

  • Isolate all strings as well as their associated string formatting into RESX files. This means all code must be analysed and not just GUI!
  • Isolate all minimum and maximum sizes for UIElements into RESX files as font appearance is also culturally defined
  • Identify all proper names and indicate the preferred flow direction.
  • Identify all UIElements that have a specific flow direction and define.

That is about it then.

No, but we are almost there hopefully.

Colour, or should I say color? Colours are also culturally defined, for example red is not always danger or error (in some countries it is seen as positive rather than negative – just think what effect that has on stock exchange movement in these lands and the same trends being observed in other cultures). Additionally, the wrong use of colour can be insulting. Pictogram and BIDI languages alsi present problems as they are either graphics based or contain elements of two differing cultures. Just think how difficult it is to design word-processing software for Arab or Hebrew – install a version of Office Word and start mixing text as is normal in these countries! Examples are digits in certain Arabic languages and English/Hebrew mixing.

What still has to be done then?

The only thing left is to integrate the whole I18N process into the development process. Here a decision has to be made where the resource assemblies will reside; are they within each project or are they at a level of functionality higher, i.e. their own assembly linked in to all those assemblies that require the resources, or are they placed in one big global resource assembly. Personally, I like the idea of them being at the functionality level associated with all the assemblies that provide a certain business functionality.

There needs to be some standard code executed during the application startup that enquires about the current culture and/or the user’s preferred culture and sets application variables accordingly. When this is done at the top-most application level then the FlowDirection will be correctly set and inherited throughout the application. This is a project decision and may entail providing base classes/singletons/global variables that contain the culture and flow direction details. Care must be taken here to make sure that the artifacts that have defined FlowDirection are also set correctly.

One major point that is often lost in the I18N process is the naming of the resources. Here this is another project specific decision and, if correctly defined and implemented, can lead to reduced maintenance in the later application lifetime. Furthermore, defining an interface that abstracts out the actual resource saving mechanism must be considered if the resource storage medium is not currently defined within the development process. Obviously, this will lead to less maintenance and reduced development times. Grammar is a very difficult thing to correctly understand if it is not either your work or hobby. Therefore, care must be taken to define the semantics of each message to ascertain its correct usage within the application. Depending on the language there is the possibility that two or more usages are required depending context and that in some languages one word will suffice for both, but in others two or more are needed.

If your project is large then I suggest that enough time is planned to produce guidelines on the I18N process within the development process and what is expected of the developers and other users/customers in the process. Clearly demarked lines of responsibility will reduce the possible chaos that can result in I18N processes.

There are some that believe that testing cannot be performed within an I18N process. This is really not the case. Today’s GUI test applications allow the tester to defined expected display results during a test. Hence it is possible to test that the correct phrase or word appears and that it is not the default provided by the developer. Of course this will take resources and time – however there seems to be no partial buy-in to I18N as the target markets can be massive and a bad impression lasts (see the use of colour above).

So what have I to do?

Tip 1: Isolate those static strings and place them in RESX files.

Tip 2: Isolate those formatting strings and place them in RESX files.

Tip 3: Isolate the minimum and maximum widths and heights for the replaced string when they appear in the GUI.

Tip 4: Isolate those graphics that have a defined left to right or right to left and mark the XAML appropriately. Also extract graphics to the RESX file.

Tip 5: Review the use of colour and extract colours for information, warning, error and the like into culturally defined string or values in the RESX file.

Tip 6: Define the Neutral Resource Language and prefix each entry with a marker such as “>>>”. This helps isolating missing resources. Do a similar thing for graphics.

Tip 7: Define the test coverage goals for I18N as well as allocating enough test time with native language speakers and human interaction design experts.

Resource Fallback Process

Finding resources within an application follows a defined process and only if the appropriate resource is not found will the application issue an exception to that end. MSDN defines the fallback process as:

“The resource fallback process is described in the following steps:

  1. The runtime first checks the global assembly cache for an assembly matching the requested culture for your application.

    The global assembly cache can store resource assemblies that are shared by many applications. This frees you from having to include specific sets of resources in the directory structure of every application you create. If the runtime finds a reference to the assembly, it searches the assembly for the requested resource. If it finds the entry in the assembly, it uses the requested resource. If it does not find the entry, it continues the search.

  2. The runtime next checks the directory of the currently executing assembly for a directory matching the requested culture. If it finds the directory, it searches that directory for a valid satellite assembly for the requested culture. The runtime then searches the satellite assembly for the requested resource. If it finds the resource in the assembly, it uses it. If it does not find the resource, it continues the search.
  3. The runtime next searches the global assembly cache again, this time for the parent assembly of the requested resource. If the parent assembly exists in the global assembly cache, the runtime searches the assembly for the requested resource.

    The parent is defined as the appropriate fallback culture. Consider parents as best-fit candidates; providing any resource is preferable to throwing an exception. This process also allows you to reuse resources. You need to include a particular resource at the parent level only if the child culture does not need to localize the requested resource. For example, if you supply satellite assemblies for en (neutral English), en-GB (English as spoken in the UK), and en-US (English as spoken in the US), the en satellite would contain the common terminology, and the en-GB and en-US satellites could provide overrides for only those terms that differ.

  4. The runtime next checks the directory of the currently executing assembly to see if it contains a parent directory. If a parent directory exists, the runtime searches the directory for a valid satellite assembly for the parent culture. If it finds the assembly, the runtime searches the assembly for the requested resource. If it finds the resource, it uses it. If it does not find the resource, it continues the search.
  5. The runtime next searches parent assemblies, as in the previous step, through many potential levels. Each culture has only one parent, but a parent might have its own parent.
  6. If the culture that was originally specified and all parents have been searched and the resource is still not found, the resource for the default (fallback) culture is used. Beginning with the .NET Framework version 2.0 release, you can specify that the ultimate fallback location for resources is a satellite assembly, rather than the main assembly. By using the NeutralResourcesLanguageAttribute with the UltimateResourceFallbackLocation enumeration, you can control whether the ultimate fallback location for resources is in the main assembly, or in a satellite assembly.”

Fallback example using the Spanish-US Culture:

  • UltimateResourceFallbackLocation is en (in Assembly.cs) i.e. [assembly: NeutralResourcesLanguage(“en”, UltimateResourceFallbackLocation.Satellite)]
  • es-US (avail/not avail) es (avail/not avail) en (always available otherwise exception thrown)

That’s all Folks…


~ by Intelligence4 on April 21, 2011.

%d bloggers like this: