When porting applications from Windows Phone to Windows 8, you
will benefit greatly from having developed your applications in C#
and XAML since most of the architecture and technologies are more
or less the same. Naturally there are some differences but my
experiences in porting applications tells me that most of the
investments is in the design surface and overall experience of the
application, not in the code.
Localization do have some differences, the first is that there's
a new file extension called .resw instead of the previous .resx.
The new .resw file has some improved behavior but also lacks the
nice auto-generation of property-based localization that could be
used in Windows Phone. One behavior I'm really fond of is the
possibility to add a resources with the ID "LoginButton.Content"
and a value of "Login" which will make sure that the
Content-attribute/element of the Button with the additional
XAML-attribute x:Uid="LoginButton" is set to the text "Login". This
can also be used with other properties which is very suitable for
advanced localizations. But the lack of auto-generated properties
is something that causes the need for some additional code,
especially for the use of getting localized resources from
"code-behind".
In Windows Phone I simply use the following syntax to get a
localized resource:
MessageBox.Show(Strings.WelcomeMessage);
Here is three slightly different approaches that can be used to
simplify getting a hold of the local resources and mimic the
behavior above as close as possible:
1) A static class with a method call.
public static class StaticLocalized
{
private static readonly ResourceLoader _loader;
static StaticLocalized()
{
_loader = new ResourceLoader();
}
public static string Strings(string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");
return _loader.GetString(key);
}
}
The client code can then use the following syntax to get the
local resource:
var dialog = new MessageDialog(StaticLocalized.Strings("WelcomeMessage"));
2) A singleton with an indexer.
The next suggestion is to create a class which implements the
Singleton-pattern to be able to expose an indexer:
public class Localized
{
private static readonly ResourceLoader _loader;
private static Localized _instance;
public static Localized Strings
{
get
{
if (_instance == null)
_instance = new Localized();
return _instance;
}
}
static Localized()
{
_loader = new ResourceLoader();
}
public string this[string key] {
get {
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");
return _loader.GetString(key);
}
}
}
Then the client code can look like this (very minor change I
agree):
var dialog = new MessageDialog(Localized.Strings["WelcomeMessage"]);
3) A dynamic-class with properties.
A pretty neat alternative is to derive your resource wrapper
from DynamicObject as follows:
public class DynamicLocalized : DynamicObject
{
private static readonly ResourceLoader _loader;
static DynamicLocalized()
{
_loader = new ResourceLoader();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (string.IsNullOrEmpty(binder.Name))
throw new ArgumentNullException("Name");
result = _loader.GetString(binder.Name);
return true;
}
}
And in each page/class that requires localized resources I
create an instance of the dynamic object as follows:
dynamic Strings = new DynamicLocalized();
Then the client code can be pretty much the same as the previous
Windows Phone alternative:
var dialog = new MessageDialog(Strings.WelcomeMessage);
I still haven't investigated any performance issues with the
latter solution but I find it quite appealing since the code is so
close to it's Windows Phone alternative. I still miss the strong
typing which also gives IntelliSense support when coding, but then
again, none of the solutions above have strong types. I hope that
Microsoft changes this behavior in a near future or I will try to
leverage T4 to create a similar solution.