Klingon language on Window Phone

After a recent post about how to allow the Resource Manager to use a non-supported culture I wondered how difficult it would be to support the usual  localisation binding. So, in the great tradition of computer science I wanted to bind to Klingon. Whilst I can see that the correct solution would involve writing a custom tool I wanted a quick ‘hack’ and this is what I’m presenting here. To keep the post size down, I’m assuming you’ve followed the previous project and have that project available.

  1. Create the Klingon resx. Copy AppResource.en-GB.resx over to AppResources.klingon.resx
  2. Add the custom tool PublicResXFileCodeGenerator to AppResources.klingon.resx (see the properties of the file)
  3. Write some klingon – open the resx and change the ApplicationTitle to the following Klingon (it’s not rude) – TLHO’
  4. Create a new String Library class;
  5.  public class AlienLocalizedStrings
        {
            private static AppResources_klingon _localizedResources; 
            static AlienLocalizedStrings()
            {
                _localizedResources =  new AppResources_klingon();
                Type type = _localizedResources.GetType();
                FieldInfo info = type.GetField("resourceMan", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.SetField);
                info.SetValue(null, new AlienResourceManager("klingon"));
            }
            public AppResources_klingon LocalizedResources { get { return _localizedResources; } }
        }
    

  6. Add the resource to App.xaml
  7.     <Application.Resources>
            <local:LocalizedStrings  x:Key="LocalizedStrings"/>
            <local:AlienLocalizedStrings x:Key="AlienLocalizedStrings"/>
        </Application.Resources>
    

  8. Now you can bind to Klingon, e.g.

 <TextBlock Text="{Binding Path=LocalizedResources.ApplicationTitle , Source={StaticResource AlienLocalizedStrings}}" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>

image

The solution works pretty well, obviously the string component is hardcoded to ‘klingon’ which isn’t ideal but I’m sure that can also be resolved with a little more effort. Enjoy Klingon on the phone Smile

Using a resource for an unsupported culture in Windows Phone

I was talking to a fellow dev about why the Resource Manager cannot support languages that the phone platform itself does not support. However, I thought that there probably would be a workaround…and here it is.

Step 1 – Create your basic project

Create phone project, by default this will create;

Resources\AppResources.resx

Step 2 – Add a test resource

Open the AppResources and add a new string called ‘ColourLabel’. I’m making the horrible assumption that you have defaulted to en-US so please enter the value of ‘Color’.

Step 3 – Add a new resource culture

Project->Add->Resource, e.g. AppResources.en-GB.resx

This should have copied our resource string from the master resource, so please change ‘ColourLabel’ to the correct spelling of ‘Colour’ Winking smile

Step 4 – Add a new unknown resource culture

Copy AppResource.en-GB.resx over to AppResources.en-XX.resx

Change ‘ColourLabel’ value from ‘Colour’ to our alien value of ‘ColourXX’

Step 5 – Change Build Action

If you try to use the ResourceManager to access en-XX it will fail because the culture is alien to the platform. So starts the workaround, change the BuildAction of en-XX to ‘Content’

Step 6 – Execute the resource manager

Running the following code…

 
AlienResourceManager britishResourceManager = new AlienResourceManager("en-GB");  
System.Diagnostics.Debug.WriteLine("en-GB: " + britishResourceManager.GetString("ColourLabel")); 
AlienResourceManager alienResourceManager = new AlienResourceManager("en-XX");  
System.Diagnostics.Debug.WriteLine("en-XX: " + alienResourceManager.GetString("ColourLabel"));  

results in the following output;

 
en-GB: Colour  
en-XX: ColourXX  

all done?

It’s fairly obvious that isn’t standard code, but it’s actually just a little over-riding of the standard ResourceManager. Here is my quick version, hope you find it useful.

  
public class AlienResourceManager : ResourceManager     
{         
  private string alienCultureName;         
  private Dictionary alienStrings = null;         
  private CultureInfo currentCulture;         
  public AlienResourceManager(string alienCultureName) :  base("MyPhoneApp.Resources.AppResources", typeof(AppResources).Assembly)         
  {             
    this.alienCultureName = alienCultureName;              
    try             
    {                 
      CultureInfo ci = new CultureInfo(alienCultureName);                 
      this.currentCulture = ci;             
    }             
    catch (Exception)             
    {                 
      LoadAlienStrings(alienCultureName);                 
      this.IsAlienCulture = true;             
    }         
  }          

  private void LoadAlienStrings(string alienCultureName)         
  {             
    var localisation = Application.GetResourceStream(new Uri("Resources/AppResources." + alienCultureName + ".resx", UriKind.Relative));             
    StreamReader resx = new StreamReader(localisation.Stream);             
    string resXml = resx.ReadToEnd();             
    XElement resourceFile = XElement.Parse(resXml);             
    this.alienStrings = new Dictionary();             
    var resourceStrings =              
      (from r in resourceFile.Descendants("data")              
      select new  { Name= r.Attribute("name").Value, Value = r.Element("value").Value}).ToList();              

    resourceStrings.ForEach(r => this.alienStrings.Add(r.Name, r.Value));          
  }           

  public bool IsAlienCulture { get; set; }          
  
  public override string GetString(string name)         
  {             
    if (this.IsAlienCulture)             
    {                 
      return this.alienStrings[name];             
    }             
    else             
    {                 
      return base.GetString(name, currentCulture);             
    }         
  }     
}