Answered Windows 8 Metro XAML Localization

  • Thursday, April 12, 2012 8:17 PM
     
      Has Code

    I am converting a silverlight XAML/C# app to Metro. For C# code there is no problem. For XAML, from what I read there is new support for XAML to simplify the process. However, I hope to reuse the same resx files so I prefer the old silverlight mechanism for XAML, i.e. Markup Extension or Binding. I just tried MarkupExtension but it doesn't seem to support. How do I convert the resource binding. Note my goal is to reuse the name-value pairs in the resource files so I won't be able to use the new Metro binding mechanism.

    Any suggestion?

    Something like this in silverlight:

    XAML:

    <sdk:TabItem Header="{Binding Path=Resource.charts, Source={StaticResource LocalizedStrings}}"/>

    LocalizedStrings.cs

        public partial class LocalizedStrings
        {

            private static Resources.Resource resource = new Resources.Resource();

            public Resources.Resource Resource { get { return resource; } }
        }

    New Metro style localization that I won't be able to use due to old code reuse:

    <TextBlock x:Uid="HelloWorld" />

All Replies

  • Friday, April 13, 2012 12:35 AM
     
     

    If you want to reuse, why not just rename the .resx file to .resw ? As far as I can tell, the file format is the same, and you thereby get to reuse the file (albeit a copy of it).

    I've generally found that code-reuse for anything UI related is almost impossible between SL/WPF and WinRT. Microsoft likes to tell you that your skillset might be preserved (and I like to add: but your code and xaml sure isn't :)

    I used to do what you do and tried to reuse as much as possible (I even started a whole blog series on it). However it become very forced, and quite a struggle. I later just started to embrace WinRT fully and start from scratch. The result is that I have a much nicer day, much cleaner code (albeit a lot more of it), and a better app in the end.
  • Friday, April 13, 2012 3:40 AM
     
     

    You could still use your databinding method for localization if you wanted.  However you won't be getting the benefit of the resource APIs doing a lot of heavy lifting for you.  While the RESW format is the same as RESX as @Morten points out, you aren't getting stronly-typed code classes for your resources...so your class that you are binding to would likely have to change a bit anyway to call into the ResourceLoader.GetString APIs. 


    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Friday, April 13, 2012 5:29 AM
     
     

    Tim & Morten,

    Thanks for the replies.  I am still not sure how to do it on XAML.  The key question is how to declare the Resource property in LocalizedStrings.cs in my example above?  I can do it in C# by using ResourceLoader.GetString(key).  But how to do it in XAML?  In silverlight, it seems the code is automatically generated based on Directory structures.  In my example above, Resource.resx lives in a directory called "Resources" and that's why I can reference it as Resources.Resource in LocalizedStrings.  It generates a Resource.Designer.cs. But in Metro, the resources are compiled into a single binary PRI file.

    A simple example or code would be helpful.

    As for Morten's point for code reuse, I just finish my first cut today and quite happy with it.  I spent about 3 months spare time building my silverlight app.  Then I only spent one day to make the model and view model reusable for both SL and Metro.  Here are my solution.

      1. Add SL model and view model source file as soft link into Metro project

      2. use #if NETFX_CORE macro for breaking changes

    I found that I can reuse 80-90% of my code.  The breaking changes are:

      1. Reflection.  Have to rewrite most code.

      2. Json.  Wished I used JSON.NET instead of system built in one.  JSON.NET has good support for every platform and claims to be faster.

      3. WebClient.  Wished I had used HttpWebRequest exclusively.

      4. Dispather v.s. CoreDispatcher.

    As for localization, I have hundreds of strings in 12 languages and don't want to invest more energy to convert them all!  My worst case is to give up XAML and assign them in C#!

  • Friday, April 13, 2012 6:01 AM
     
      Has Code

    Are you asking for how the new feature works?  Have you seen: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh771181.aspx ?

    Basically you assign an x:Uid to the UIElement you want to localize...then in your RESW file you enter the properties that would be replaced.  An example (as indicated in the docs) is like this:

    <Button x:Uid="MyButton" Content="Default Text" />

    And if you had a key in your RESW file of "MyButton.Content" with the text set to "Hello World" then at runtime this button's content would be set to "Hello World" as you've indicated that property to be replaced.  Almost like a mail merge :-).  No code to write, just set the x:Uid values.  We think this will cover most localization cases, but perhaps not all...and for those that it may not cover, you are still in complete control of extracting resources using the ResourceLoader APIs.

    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Friday, April 13, 2012 6:11 AM
     
      Has Code

    No, I am not asking for how the new feature works.  I understand that part.

    Let me try to clarify again.  Here is my requirement.  I have name value pairs in my resource files converted from Silverlight app that I don't want to change.  I want to look up the value based on the given key.  Here is how I do it in C#

    ResourceLoader loader = new ResourceLoader();
    loader.GetString(key);

    I want the equivalent in XAML.  Again, the new feature won't help because that would require me rewriting all the resource files.  My first post shows how I did it in SL and I want to equivalent in Metro.  Is it possible?  Your last post "so your class that you are binding to would likely have to change a bit anyway to call into the ResourceLoader.GetString APIs.  " makes a lot of sense but any details how to achieve that?  How to pass the parameter key to the binding? 

    Thanks for your help!

  • Friday, April 13, 2012 2:44 PM
     
     Answered

    Ah, I see.  The only *automatic* way in XAML to do this is the new x:Uid feature which requires your resources to have specific naming conventions.  If you don't want to change your resource names at all.  The way you were doing it in Silverlight was basically that the data context represented a class with a bunch of static variables.  Since RESW doesn't automatically do code-generation you'd have to re-create this class yourself.  Then you could use your databinding method.

    Bottom line -- you are responsible for creating the class that the RESX generator previously did if you want that method.


    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

    • Marked As Answer by Poker Income Friday, April 13, 2012 7:15 PM
    •  
  • Friday, April 13, 2012 7:16 PM
     
     

    Tim,

    That's very disappointing.  I will do it in C# then.


    Twitter: @LuoChang

  • Friday, April 13, 2012 8:24 PM
     
     
    LuoChang - what part is disappointing.  What I'm saying is that you can use the same XAML you have...it is just the backing class that you have to create.  Resx doesn't exist in Metro so that is the missing part in keeping all your XAML the same.

    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Friday, April 13, 2012 8:50 PM
     
     

    It's disappointing because I have to create and maintain SL auto generated class Resource.Designer.cs.  Whenever I modify the Resources.resw file, I have to remember to modify the Resources.Designer.cs file as well.  That's extra work compared to SL.  Even worst, I am not sure if I need to manually create cs files for all my 12 languages and not sure if it will work.

    So I will just give up the idea of localizing XAML and assign the text in the code behind C# file.  It's still extra work because I have to give every label and control a x:Name in order to reference it in C# but it seems the easiest way.


    Twitter: @LuoChang

    • Marked As Answer by Poker Income Friday, April 13, 2012 8:51 PM
    • Unmarked As Answer by Poker Income Saturday, April 14, 2012 5:10 AM
    •  
  • Friday, April 13, 2012 9:08 PM
     
     

    @LuoChang - if you are going to do work anyway, then why not just create a better RESW file and let XAML do the work for you.  You aren't adding any extra cost for localizing because you already have your string.  This would be less code to write for the app, but a little upfront work in managing string key names.


    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Friday, April 13, 2012 10:59 PM
     
      Has Code

    Interesting idea!  I can write a converter to convert RESX to RESW by appending ".Content" to the keys.  Then it will take care of all controls with a property "Content", e.g. Button.  Now my new question to this approach is, how to reference it in C# code.  I tried both key.Content and key and it doesn't work.  The workaround is to keep both key and key.content pointing to the same value string but it seems wrong.

    Resources.resx

    <data name="HelloWorld">Hello World!</data>


    Resources.resw

    <data name="HelloWorld.Content">Hello World!</data>

    XAML:

    <Button x:Uid="HelloWorld"/>

    // How to reference it in C#?

    new ResourceLoader().GetString("HelloWorld"); // Name key not found exception new ResourceLoader().GetString("HelloWorld.Content");// Name key not found exception

    My workaround:

    Resources.resw

    <data name="HelloWorld.Content">Hello World!</data>

    <data name="HelloWorld">Hello World!</data>



    Twitter: @LuoChang

  • Friday, April 13, 2012 11:53 PM
     
     Answered Has Code

    @LuoChang

    Appending "Content" to the keys would only apply to those appropriate controls :-).  For example if it was a TextBlock, there is no Content property...it would be Text.

    Given your example above with two keys "HelloWorld.Content" and "HelloWorld" they are actually different resources.  Using the API the "." is translated to a "/" in the PRI file (the binary file which contains all your resource strings and path references):

    var resources = new ResourceLoader();
    var myContent = resources.GetString("HelloWorld/Content"); // this is for something that would be HelloWorld.Content in resw
    

    How this works in XAML is your x:Uid would still be "HelloWorld" and the XAML parser will look for properties to replace...in this case it will see ".Content" and replace that value at runtime with the appropriate resource string (or value).

    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

    • Marked As Answer by Poker Income Saturday, April 14, 2012 5:11 AM
    •  
  • Monday, July 16, 2012 1:50 AM
     
     

    Tim

    Whilst I like the intent behind the .resw it seems that this breaks what little design time support we have for building apps in xaml. The only way I can see of getting design time experience is to specify a value in the page xaml eg <TextBlock x:Uid="MyTextBlock" Text="Initial Value" /> and then having the runtime value in the .resw file. This is a horrible duplication and again reduces the value of the designer. Do you know if this will be fixed in the RTM version of the dev tools?

    Thanks


    Nick Randolph ~ Built to Roam

  • Monday, July 16, 2012 4:48 PM
     
     
    @Nick - we didn't have the ability to deliver the tooling experience you are describing (where the design-time surface reads from the RESW) due to other higher priorities unfortunately.  The workaround is as you describe by providing a design-time value.

    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Sunday, December 09, 2012 7:43 AM
     
     

    Hi Tim,

    What is the reason behind specifying the property as well? I am a Windows Phone App developer, I have a similar problem as LuoChang, previously we did not have to worry about the property we are assigning the string to, it could be Button's Content property of TextBlock's Text property, but now with this resw format, I would have to rewrite, appending Content to all Button Texts and Text to all TextBlock's Text. I dont mind rewriting but I would want to know the reason behind this, because this is just extra and more importantly unnecessary work for all the developers out there...

  • Sunday, December 09, 2012 10:57 PM
     
     

    @Haresh - you do not *have* to use this method.  In fact the same databinding method that you use in Windows Phone can still be used here.  The primary difference is that you don't have a strongly-typed resource in the RESX file like you had in the Windows Phone world.  You could, however use a portable class library to manage the resources and do this to get the strongly-typed class values.

    The x:Uid mechanism is another method that people can use that we designed to make it easier.  The issue of localizing one value and using it in multiple places is known to us and we didn't have a reliable solution for Windows 8 to solve that for developers.  The x:Uid method does the merging of the values for you so if you use that method, you don't have to do any databinding, etc.


    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)

  • Friday, March 01, 2013 2:02 PM
     
     

    Is this functionality not possible using attached properties?  I would use add an attached property for any customization on XAML elements with a minimum impact to code.

    I'm going to try out your problem scenario and get back to you.  Off the top of my head, I can't see a reason why it would not be possible using AP.


    • Edited by Sidney A Friday, March 01, 2013 2:26 PM forgot word
    •  
  • Monday, May 06, 2013 12:45 PM
     
     

    It's disappointing because I have to create and maintain SL auto generated class Resource.Designer.cs.  Whenever I modify the Resources.resw file, I have to remember to modify the Resources.Designer.cs file as well.  That's extra work compared to SL.  Even worst, I am not sure if I need to manually create cs files for all my 12 languages and not sure if it will work.

    Maybe it's possible to drop the resources.resw files in a Windows Phone 8 project, rename them as .resx files, build the project and retrieve the autogenerated class to include it back in the Windows Store App project?

  • Monday, May 06, 2013 1:45 PM
     
     

    Maintaining your own designer.cs file is not necessary.  If you want to totally re-use resources across multiple projects, use a Portable Class Library.  In doing so you can use the resx/generated class method and when added as a reference to a Win8 app, the conversion happens in the PRI file, but you still get the static class benefit in code.


    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)