Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Strongly Typed Localized Strings In Universal Apps

DZone's Guide to

Strongly Typed Localized Strings In Universal Apps

· DevOps Zone ·
Free Resource

Download the blueprint that can take a company of any maturity level all the way up to enterprise-scale continuous delivery using a combination of Automic Release Automation, Automic’s 20+ years of business automation experience, and the proven tools and practices the company is already leveraging.

Back in the old days when the need for localized string arose, I would add a new string and use AppResources to access the correct string in code.

In Windows Phone application (known today as Windows Phone Silverlight 8.0/8.1) I would do something like this:

public void SomeMethod()
{
    var localizedString1 = AppResources.MyFirstSring;
    var localizedString2 = AppResources.AnotherString;
}

In the new universal apps the story is a bit different:

  • Only strings are allowed in the resource files (which are .resw instead of .resx)
  • Using a directory for each supported language (i.e. Strings\en-US\)
  • Access to localized strings is string based

I can live with the first two (I actually prefer it that way) but I have huge problems withStringly Typed API calls – it’s easy to get it wrong, and even worse a trivial rename can cause problems that would only show during application run.

Luckily a co-worker of mine has put together a T4 template that fixes this problem (thanks Noam):

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
 
<# string str = this.Host.ResolvePath("strings\\en-us\\Resources.resw");
    System.Xml.Linq.XElement resXml = System.Xml.Linq.XElement.Load(str); // Read a data file here. "%aaa%/string/en-us/Resources.resw"
   IEnumerable<XElement> appElement = (from dataElements in resXml.Descendants("data") select dataElements); #>
 
using Windows.ApplicationModel.Resources;
 
namespace UniversalApp
{
    public class StringsResourceManager
    {
        private static readonly ResourceLoader _resourceLoader = new ResourceLoader();
        public StringsResourceManager()
        {
        }
 
<# foreach (var element in appElement) { #>  
        public static string <#= element.Attribute("name").Value.Replace(".","_")#>  
        {
            get
            {
                return _resourceLoader.GetString("<#= element.Attribute("name").Value#>");
            }
        } 
<# } #>
    }
}

Using the class created from this template I can get from this:

public void SomeMethod()
{
    var resourceLoader = new ResourceLoader();
 
    var string1 = resourceLoader.GetString("MyFirstSring");
    var string2 = resourceLoader.GetString("AnotherString");
}

To this:

public void SomeMethod() 
{ 
    var string1 = StringsResourceManager.MyFirstSring; 
    var string2 = StringsResourceManager.AnotherString; 
}

Happy coding...


Download the ‘Practical Blueprint to Continuous Delivery’ to learn how Automic Release Automation can help you begin or continue your company’s digital transformation.

Topics:

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}