Localization Resources .NET - how to keep them synchronized? - c#

When we follow localization guidelines we endup with at least a couple of resource files.
Resource.resx and Resource.CI.resx which is a specific CultureInfo resource.
Lets say we add a hundred string pairs in Resource.resx and want to translate those keys in another resource. we can copy paste them right now and translate them and it might work the first time.
However after we translate strings it becomes hard to keep files synchronized - it reorders strings automatically and I currently don't understand what is the supposed way to make sure each string is localized.
Since resource strings are supposed to be kind of linked with each other and with extra job that is done to make sure satellite assemblies are built correctly I was hoping theres a function like 'make sure each resource string is present in localized resource file' but I am afraid that one is missing..

RESX Synchroniser might do you what you are looking for
When you edit the .NET Resource files
in Visual Studio, either manually and
using the "Generate Local Resources"
command, the IDE updates only the
culture-invariant resources: if you
have a resource file called
Messages.aspx, the files in other
languages, say Messages.it-IT.resx,
are not updated, and you have to do
that manually. RESX Synchronizer will
help you keep the resource files
synchronized, adding the new keys to
the localized files, and removing the
deleted ones. Comments are preserved
during the process.

I just found http://zetaresourceeditor.codeplex.com/ as well seems like a similar idea to the others

may be UnitTest can help you? you know, which text each control should have, once you create them, after just add new strings to list and compare the values. after once hard working you can test your localization works right.

a little old this discussion, but still interesting. have a look at ResXManager

I know this has already been given traditional answers, but I would also like to put forward something completely original we tried (and succeeded) doing ourselves for more efficient localisation of Silverlight:
Localisation of Silverlight projects after completion
(Resx is so "last century")

I suggest you create culture specific resource files programmatically using the Resx file for that Winform.
You can create a small app which you could run time to time.
Create XML kind of file for each culture like fr.XML, fill that with the Union of all the strings in your project.And provide the translations there itself like, for example that file in french might look like the following..
< wordTranslation>
< Word>Hello< /Word>
< Translation>Bonjour< /Translation>
< /wordTranslation>
Create a hashtable or some data structure which would best act as dictionary for each culture, fill it with data from the culture specific XMl files like frDictionary.
For Each Resx file in your project for example wind1.resx , create a culture specific file like wind1.fr.resx.
Read words from wind1.resx, find the translation of the word from the frDictionayry.
Write it to wind1.fr.resx.
You can keep updating your translations in the XML file.
So its a one time effort.
This way you can keep it synchornised and easily maintainable.

You mean synchronize translations between those files? Use http://www.getlocalization.com and upload both as master files, when they are translated the translations are populated to all your files.

I think you can try Amanuens. It's developed by the same author of RESX Synchronizer and besides help keeping resource files synchronized (even automatically into your repository if you set it), can be used to give your translators access to strings to be translated in a very powerful and easy to use web editor.

Related

Creating localizatin .resx files makes empty .Designer.cs files

I'm trying to add localization to my .NET MVC project. As far as I've seen (here, here, and here), I should simply be able to create a total of three files (if I have two languages).
Resources.resx
Resources.en-us.resx
Resources.da-dk.resx
When I open the .resx files, I can add entries to them. Once I've done that (and set "Access Modifier" to either Internal or Public), it generates a Resources.*.Designer.cs file (as it should). However, for en-us and da-dk they are empty. No errors or anything.
As far as I could read (here, here, and here), I cannot have a dot between the file name and the .resx extension. And to my surprise, it's true. If I rename any of those en-us/da-dk files to Whatever.resx the Whatever.Designer.cs file will be created.
I've read a lot of answers, tried my way with T4 templates, and a bunch of other things, but I simply cannot get it to create a working Designer.cs file.
Am I doing it wrong? I feel like I've tried everything now. I just want to be able to do Resources.TestText and have my application do the translation depending on the culture.
It is by design.
The Resources.EN-US.resx file types, doesn't have a designer because the actual designer is in it's "parent" file, Resources.EN-US.resx. The en-us file only holds the key/value XML.
If you are calling your Resource, you probably use it like:
var someVar = Resources.SomeLocalizedString;
You don't have to differentiate between the EN-US types.
If you look at the designer's code, you can see whats happening (hold on, I'll fetch an example)
So, you don't need those designers, and it should work out of the box if you set the culture info of the UI thread.
Thread.CurrentThread.CurrentUICulture = new CultureInfo("EN-US");

Can we skip ResourceManager?

I've working on a project where I'm using ResourceManager extensively and this question just crossed my mind.
Can we read from .resx files without using ResourceManager? I mean, is there another way?
ResourceManager is a convenience class, it works very well with the way the build system supports .resx files. No, it is not a strict necessity.
A .NET assembly has the generic capability of embedding arbitrary data into the manifest of the assembly. Just a blob of bytes, it can be anything you want. Directly supported by the build system as well, just add a file to your project and set its Build Action to "Embedded Resource". At runtime, you retrieve the data in that file with Assembly.GetManifestResourceStream().
You can stop right there, but that's just a single file, it doesn't scale very well if you have many small resources you want to embed. Which is where a .resx file starts, it is an XML file that contains resources in a friendly format. One that gives you a fighting chance to recover the source again when the original got lost.
But an XML format is not a very good format for resource data, it is bulky and it is expensive to find data back. So .NET has resgen.exe, a build tool that turns the XML file into a binary file, a .resources file. Compact and easy to find stuff back. And fit to be embedded directly as a single manifest resource.
What you don't want to do is having to read the .resources data yourself. You'll want to use a helper class that can find specific resources back from the blob of bytes. You want use the ResourceReader class, its GetResourceData() lets you specify the resource name and it will spit the resource type and data back out.
You can stop right there, but an app often has a need for different sets of resources. A very common localization need. Which is what satellite assemblies are all about, different assemblies that contain nothing but resources, each for a specific culture. They are separate so you don't pay for the virtual memory that's required to store all the localized resources when you need only one set of them. What's needed here is a helper class that automatically locates and loads the correct satellite assembly and retrieves the resource for you, based on the current culture.
That helper class is ResourceManager.
If you choose to skip the use of the ResourceManager you can let Visual Studio handle code generation for you. Ultimately the generated code uses a ResourceManager, but you're no longer writing that code manually. Additionally, you get compile-time checking since you're referencing a generated static class.
If you add a resource file to your project and double click it from the Solution Explorer, Visual Studio presents you with a dialog where you can enter a name for a resource, and its value. The dialog presents you with options to add resources as strings, images, audio, etc. (look at the dropdowns at the top of the dialog). Next, to get the code generation bit, you need to set the Access Modifier to either "Public" or "Internal". The third option is "No code generation."
For example, add a resource file called "MyResources", then add a string resource with the name Greeting and a value of Hello! With one of the former two options selected for code generation (start off with public to test it, restrict the access as needed), you should now be able to reference the resources from your code via MyResources.Greeting. If you don't see it right away, make sure you've saved the file and try compiling.
string greeting = MyResources.Greeting; // "Hello!"
If you add other resource types (image, audio, etc.) then the return types will differ, of course.
At this point you could inspect the generated .cs file and see that the generated code is using a ResourceManager. The other use for resource files is localization. Let's say you wanted a Spanish version of MyResources. You would add a new file called MyResources.es.resx, where es corresponds to the language code desired (Spanish in this case). Now add the same resource name of Greeting with a Spanish value of Hola!.
If you change the thread culture to Spanish, referencing the resource will now return the Spanish version:
string defaultGreeting = MyResources.Greeting; // "Hello!"
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
string spanishGreeting = MyResources.Greeting; // "Hola!"
Note that you only really need to set the access modifier to one of the code generation options for your default resource file (i.e., MyResources.resx), not for all the other localized versions you add. There's no harm in doing so, but in my opinion it's cleaner to have the main file generated while the others just have the resource values desired without code generation.
Well, Resources are compiled into the assembly. You could try to read the assembly by reading the bytes (or the IL), and extract the resources from there.
ResourceManager does this all for you, so I could not think of any reason you want to do this... Maybe one, if you don't want to load the assembly in memory, you could do it without ResourceManager.
Ref Microsoft: Represents a resource manager that provides convenient access to culture-specific resources at run time.
I expect, I'd you use multi Lang, you will get a more consistent result and better compatibility.
IMHO

Localization using resource file

I use a *.resx file for the localization purpose. The Name - it's a phrase or word in English. The Value - the translation to another language of that phrase. I choose this approach to have a one localization file for the whole application. And anyone who have this file can make translation by themselves.
But in the Visual Studio 2010 resx editor, each record with name which have spaces in it, have a warning: "The resource name is not a valid identifier."
Though it compiles and works, but please tell me if I am doing something wrong here.
First of all, the idea of the resx files is to have a separate resource file for each culture. You can provide the new translation by creating a new file with different values for the same keys.
For example, you can create Forms.en-GB.resx, Forms.pl-PL.resx, Forms.de-DE.resx and the appropriate file will be picked up based on the current UI culture without you having to do anything (except ensuring relevant culture is set).
Visual Studio will generate a resource class that contains all your key/value pairs from resource file as properties - that makes it easier to use in code. The warning you get means that the keys you've provided in resource file are not a valid identifiers (they contain spaces). You might want to use _ instead of space in the keys.
If you don't want to use the generated class you can ignore this warning - your resx files are fine and can be used directly. You can remove ResXFileCodeGenerator from 'Custom Tool' property of your resx file (properties windows) or set 'Access Modifier' to 'No code generation' in resx file editor if you do not need to generate a class, but you will still get the warning.
The strength of localization with resx files is that the culture on your computer decides what language your application should be in. If you keep to one resx file, according to me, you ignore it's power. Instead, try making a resx file for each language you want to integrate. for example: the default language is english, then you have a default page localization.resx where you only keep english sentences. Say you need a French translation, make another resx file called localization.fr-FR.resx. So users who have the fr-FR culture enabled on there computer will have that language on the program without any code specific work. If someone with a culture not integrated in your application starts the program, it will look for it, and if it doesn't find it, it chooses the default, ie english, one.
So to my opinion, don't use 1 resx file for different languages, but use the powers given in the framework.
I suppose it works, but it's not really the strategy you are supposed to follow.
Take a look here; the basic idea is that you take advantage of the controls in .NET to automatically get the correct localisation themselves, so you kind of don't need to worry about doing the translating.
Though, I don't use this all the time, and I do somewhat do as you do, but I tend to use an identifier, so I may have:
UserWelcome Hey, {name}, thanks for dropping by ...
And then I'll translate that. It's helpful because it allows generality in the languages (say, for example, some languages should be greeted formally, and others not, you don't want to be contrained by a direct translation of, "You", say).
Hope this is clear.
If what you've got works, then I suppose that's something, but it's not the "general" way of doing it.

adding different language strings to a single resource file

I have a small application, which includes a resource (.resx) file.
This file contains an icon, and a string, which is used by another application. The icon will be displayed on a button, and the string is the mouseover text.
What I want is in some way, to add strings in multiple languages, without having to crate additional .resx files.
Is there any way to do this?
I am writing my application in C#, and I would like to keep it in the .Net environment, and keep the resource managed.
Any help is appreciated - thanks in advance.
This would be an abuse of the way localization works in .net. It is meant to work like that - you create a resource file AND localized resource files containing .languageid. in the middle.
Of course, you can code your own "reader" method which appends some prefix to the resource name and then save several values in your file (for instance lv-formtitle, en-formtitle, ru-formtitle etc) , but - why?
If the problem is you do not want to copy the icon to several resource files - make 2 resources, one for icons, other for strings. Localize only the one containing strings.
Of course you can add more strings to your resource file, but they will have to have a different name and managed in your application that way (for example - "title" and "title-he") .
Doing this however, defeats the point of resource files.
You should use additional resource files, one per locale, even though you don't want to...

Use external file or resource?

I am writing a C# application that uses a long "hard-coded" string.
For maintainability reasons I have decided to put this string in an external text file and load it. Is this a good idea? The extra I/O does not seem big in this case.
I realize that I also have an option to embed this file as a .resx resource. Is this a better idea? The file will never need to be localized.
If you intend to allow users/administrators to change the string, I agree with the other answers, and I'd suggest putting it in settings.
If you don't want it to be editable after deployment and it will only be modified by you and your developers, then I would put it in an embedded resource (note, this is not the same as a .resx file). You would read it at runtime like this:
Assembly assembly = Assembly.GetExecutingAssembly();
Stream stream = assembly.GetManifestResourceStream(“MyAssemblyNamespace.MyTextFile.txt”);
StreamReader reader = new StreamReader(stream);
string theText = streamReader.ReadToEnd();
Update: This is solution that is easy to maintain. The .txt file will just be another file in your solution explorer in Visual Studio and you can edit it just like any other file, keep it under source control like any other file, etc. To turn it into an embedded resource by changing the Build Action in the properties window to "Embedded Resource".
The end result is that your file(s) get embedded in your DLL so that you only have 1 DLL to distribute instead of a DLL and a folder of files that have to move around together.
Update 2: Regarding "production debugging", this is a very static solution, and so you won't be able to change the contents of the text file at runtime because the file is baked into the DLL at compile time. For reading the contents of the file, you can use tools like reflector to view the embedded resources of a DLL. You could also write a simple command line tool that dumps all the embedded .txt files from a DLL into individual files for you to look at.
For memory usage, there isn't a solution more efficient than "I load it from a file into memory only exactly when it is needed". You have to decide whether the improved maintainability and deployment is worth the cost of a little extra memory when your DLL is loaded into memory for your specific situation. That said, you haven't said how large these files are. If they are really huge (megabytes+), I would probably not use this solution and would go with loose files on the hard drive. If they are generally pretty small (hundreds of kilobytes), I wouldn't worry about the extra memory unless you are in some kind of embedded device situation where RAM is really tight.
Why not make it an appSetting in your web/app.config file?
<appSettings>
<add key="MyLongString" value="This is a really long string value that I don't want hardcoded" />
</appSettings>
Then, in code:
using System.Configuration; //To ease your typing pains
var myReallyLongString = ConfigurationManager.AppSettings["MyLongString"];
I would suggest to use Application Settings.
You can follow this MSDN link how to use Application and User Settings.
I would put this in an application configuration file.
Even better would be to add a Settings file to your project. You can then easily add configuration settings through Visual Studio.
See this link.
You could then access your string by using the following:
Settings.Default.MyString;
In addition, settings are strongly typed, so you don't need to do any conversions when you retrieve them.
To more directly answer your question, the "best practice" would be to use a resource file for any localizable (even if you're not going to localize it) string in your application. This allows you compile-time access to the string and keeps it from being externalized as a separate file to deploy with your application.
I suggest using this approach; settings are similar, but should not be used unless what you're storing there actually represents a setting. Constants are the other option, but in the case of a long string, I'd stay away from them, just for the sake of maintainability.

Categories