Download source, executable and sample
Introduction
Oh no! Is this another localization article?
Yes, it is.
But why? Don’t we have enough solutions already?
I have read several articles about localization and tried different solutions. Most of them are really good but none of them solved my problems. I needed something that would help me share resources between a WPF application and a Windows Store application. Also I wanted it to work in Windows Phone.
OK. So what’s the differences between these platforms?
WPF and Windows Phone (I think, I haven’t much phone development) both could use resx-files with the auto generated class file to access the resources. In Windows Store application resx-files are called resw-files, and no class file is generated. You work a bit different with strings on these platform.
I see. So how did you solved it?
I simply developed my own tool, ResToCode that converts resx/resw-file to a class file with all strings embedded directly in the class. It also contains properties to access the string easily. When you use the class it’s very similar to what resgen.exe normally generates.
OK. But I have heard that you could use a Portable Library to shared resources between these platforms. Why didn’t you use that?
It’s true, this works well but Portable Library isn’t available in the Express editions of Visual Studio that I’m using.
Aha! So the real problem is that you are greedy!
I also added some extra features. Like some methods to change language on the fly, verification that all keys exists on all platforms, etc.
But you are still greedy, aren’t you?
-
OK. Can you give me more details about your solution?
Sure! Here we go...
Features
ResToCode
has the following features:
Using ResToCode
ResToCode
is a console application. You could very easily integrate this in Visual Studio
with Pre-build event (see below). The following parameters is supported:
/namespace
YourNamespace
YourNamespace is the namespace you want to use for the
generated class.
/classname
YourClassName
YourClassName is the name of the class ResToCode
generate.
/commonfile
commonstrings.resx
Use
all strings from commonstrings.resx as common strings, i.e. they are used in all
languages.
/fileX
language-culture,filename.resx
X
is the id of the file. First file should have id 1, the next id 2 and so on.
Language-culture should be in the format en-US (American English), or just
language like sv (Swedish). Note that file 1 will be the default language – this
is used as language if the system language doesn’t match any of you languages.
Strings will also be used from the default language if they are missing in the
current language.
/output
outputfile.cs
Write
the output to outputfile.cs
/vsmode
Use
the option when you run ResToCode from Visual Studio. This will make errors and
warnings visible in Visual Studios Error list.
/notifymode
ResToCode
make all the properties to access strings static by default, just like
resgen.exe. One problem with this is that you can’t fully data bind to static
properties, if you try to do this you will notice that you will get no
notification when a property is changed. ResToCode will therefore use
none-static properties if this flag is used. This will make it easy to change
language on the fly.
/verifyonly
Just
verify your strings, but don’t generate any output.
/noverify
Don’t
verify anything.
/force
Force
rebuild of the output. ResToCode will not regenerate the output file unless
something was changed. Use this flag to always rebuild the output.
Example
1:
This
example run ResToCode from a prompt. It will generate the file MyStringClass.cs,
with the merged data from an English and Swedish resource file:
restocode /namespace MyNameSpace /classname MyStringClass /outputfile "C:\My code\MyStringClass.cs" /file1 en-US,"C:\My code\Resource-english-us.resx" /file2 sv,"C:\My code\Resources-swedish.resx"
Example
2:
This
example is more realistic and is an example how it could be executed from Visual
Studio. $(ProjectDir) will be replaced with your project directory automatically
by Visual Studio.
restocode /vsmode /namespace MyNameSpace /classname MyStringClass /outputfile "$(ProjectDir)testcode.cs" /commonfile "$(ProjectDir)CommonStrings.resx" /file1 en-US,"$(ProjectDir)Resource-english.resx" /file2 sv,"$(ProjectDir)Resource-swedish.resx"
Visual
Studio integration
As
said ResToCode is supposed to be used as a Pre-build event. You find this setting
by:
Enter the command line something like this:
When
you build you project you will get warnings in Visual Studio (if the /vsmode flag
is used):
When you are Writing code you will get a tool tip containing the real strings for each language.
Using the code
The
syntax is slightly different if you are using “static mode” or
“notify mode”.
Static mode
In
C# it’s super easy to get access to the strings:
string mystring = MyGeneratedClass.NameOfKey;
In
XAML you should create an instance of the class in your viewmodel:
public class MyModel
{
private TestClass _MyStrings = new TestClass();
public TestClass MyStrings
{
get
{
return _MyStrings;
}
}
}
Then
you use it like this in XAML:
<Label Content="{Binding MyStrings.ColorBlack}"/>
In
desktop applications you could do a short cut. You don’t need to create an
instance the string class, you could access static properties directly. Note
that this doesn’t work in Windows Store applications:
<Window x:Class="ResToCodeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rt="clr-namespace:ResToCodeTest"
Title="MainWindow">
<Grid>
<Label Content="{x:Static rt:TestClass.ColorGreen}"/>
</Grid>
</Window>
Notify mode
In
C# you should access the strings like this:
string mystring = MyGeneratedClass.Instance.NameOfKey;
In XAML you should create an instance of the class in your viewmodel:
public class MyModel
{
private TestClass _MyStrings = new TestClass();
public TestClass MyStrings
{
get
{
return _MyStrings;
}
}
}
Then you use it like this in XAML:
<Label Content="{Binding MyStrings.ColorBlack}"/>
Example
projects
I
have provided examples for WPF, Windows Store and Windows Phone application.
It’s very simple but should be enough to understand how to use this. These are
mode in the express editions of Visual Studio 2013. I think the desktop application will start in Visual Studio 2012, but I'm not sure about the other projects.
Windows Desktop
Windows Phone
Windows Store
Hint a tips
- If you are using “Notify mode”, you could access all strings from YouClassName.Instance.
Final notes
The code in ResToCode is kind of ugly. But it’s also quite straight forward so I haven’t spent much time to design it. Internally it uses System.Resources.ResXResourceReader to read resx-files. This works fine as long as it is only strings in your resx-file. If you add some other types of data you might get some strange problems – so don’t do that :-).
If you find any bugs just let me know. ResToCode was written in a few hours, but it working surprisingly well so I haven’t done any deep and careful testing. It does what I need it to do so I’m quite happy with it.
Changing language on the fly is a cool feature but it has two disadvantages as I see it. First it breaks the compatibility with resgen.exe a bit, since key properties aren’t static. Second it’s very hard to update all strings in the GUI. Labels, buttons are often quite easy since they are often databounded with the strings the directly. It’s harder with for instance list items were you generate the list in code. So use this feature wisely.
Credits
This
article had a nice code snippet to parse the command line arguments which I
used:
http://www.codeproject.com/Articles/3111/C-NET-Command-Line-Arguments-Parser
History
2014, 16 March
First edition.
PEK is one of the millions of programmers that sometimes program so hard that he forgets how to sleep (this is especially true when he has more important things to do). He thinks that there are not enough donuts in the world. He likes when his programs works as they should do, but dislikes when his programs is more clever than he is.