Reputation: 27595
After reading the very nice Globalization tutorial for WPF in CodeProject, I plan to apply the same technique in my own projects.
The tutorial shows how to create a Strings.resx
containing named strings for some default language, and advises to DUPLICATE the whole .resx
file, adding some localization code to the filename, and translating the strings to the target language.
That way, Strings.resx
would contain a register named name_entry_label
with value Write your name
, and the same-named register in Strings.pt-BR.resx
would have the value Escreva seu nome
, and so on for any additional language.
The problem I found is: if you ADD a register in one of the resource files, the others don't update. They require the entries to be manually controlled, which is dumb, repetitive and error-prone.
The most logical way to do that, in my point of view, would be to have a table resource dictionary, where each name would contain one value per column, and each column would correspond to a given language. Other way would be that each resx file would be a view of a "master" one, which would keep the views in sync. I am not aware if it's possible to get any of these behaviours, though.
Any help on how to get the described behavior (records always in sync between different lenguage resources) is much appreciated, thanks for reading.
Upvotes: 1
Views: 561
Reputation: 1532
Just to improve visibility I'll post hbarck's link here:
It is a very lightweight and straightforward app that creates an XML with your project's resx files, and puts them in a nice Excel file with each language in a column, and a sheet for each sub-project's files.
Warning: when opening the file in Excel, say YES to "open anyway" dialog. When saving say NO to "convert?" dialog (keep Excel XML 2003 format or you will have a hard time getting your translations back to your project).
For instructions see the documentation at CodePlex. If you have any problem, don't come crying to me, I'm just posting the link :-P
Hope this helps someone else too!
Upvotes: 1
Reputation: 2944
You could do one of the following:
Get a merge tool like TortoiseMerge (comes with TortoiseSVN), compare each language's resx file to the master file (e.g. the resx file for the neutral language), and use the tool to create the missing entries in the localized files. Then you can edit the localized files in the VS resx editor to add the proper translations.
Or: If TortoiseMerge doesn't do the job, write a small program that uses XPath to find the resource elements in the master resx, map them to their counterparts in the different language files, and copy the ones that are missing. That way, you could even empty the Texts in order to make the entries you need to edit later stick out. Since the naming conventions for resx files are quite rigid, you could probably make this a batch program and add it to VS as an external tool in the tools menu.
Or: Create a master XML file which contains an element for each entry and a subelement for each language, so the original term and its translations are grouped together. Then, use XSLT to create the resx file for each language.
Or: Create a table which has columns for key, language and translation in a database, and use SQL to create empty entries for missing keys in localized languages, then generate the resx files from the table. You could even use a table like that directly for localization, without using resx files at all.
Anyway, I'd strongly advise against a design with one column per language: we have done it that way in one of our applications, and it comes back and bites us as we want to add more languages. I'd probably choose the option with a batch program that synchronises resx entries, it seems the best compromise between programming effort and ease of use to me.
Upvotes: 2
Reputation: 1532
I followed the same tutorial and I face the same problem... if you look in your Solution Explorer, open the node for Strings.resx and you'll find an autogenerated class called Strings.Designer.cs.
This is just a static class with a couple of simple methods to choose where to get the correct string from when you ask for the public name_entry_label.
What I thought: I save the current language as a Setting, so it is available for all my app. I could create my custom static class with all the translated strings, and make those strings check for the culture in the Settings before retrieving the correct string. Something like:
public static string WriteYourName_Label
{
get
{
switch(currentLanguage) //currentLanguage should be the definition in the Settings (a string for me), a private field in the static class that gets the culture and returns something useful
case en-US: return "Write your name";
case es-ES: return "Escriba su nombre";
default: return "Escreva seu nome"; //portuguese by default
}
}
Advantages: you have all your different languages in one file, and every translation next to the other (not in separate files).
The problems: you loose the nice "table" editor, it's just code. If you add a new language you'll have to create a new case for all your strings (which is not so much of a problem, since you would have to create a new resource dictionary anyway).
I have not implemented it yet so I can't speak about performance (it's a static class with everything inside, should be better), but I found no other good solutions (not so simple as compared to having EVERYTHING in one place). On a first glance doing it all "manually" seems like a nightmare, but the alternative of having several unrelated tables is even scarier to me.
I really hope somebody posts an answer that is much better than mine, I'd be SO happy. Good luck!
Upvotes: 1