Localization using resource file - c#

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.

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

Identify unlocalized text

In ASP.NET, an application can be localized using resource files. Resource files hold different translations. For example, one might have an English resource file and a Spanish resource file. When resource files are used, an attribute can be applied to controls on a web page to automatically populate that control with values from a resource file. Alternatively, the values can be programmatically loaded from a resource file and assigned to a control's property.
ASP.NET uses a fallback mechanism for loading translations. It tries to find the resource file that is most similar to the current user's culture. If the current user's culture is Spanish, ASP.NET tries to load the appropriate resource from the Spanish resource file. If the Spanish resource is not available, it falls back to a default resource file. Because of this behavior, text for a Spanish user may be shown in the default language for two reasons:
No Spanish translation is available. (The translators haven't provided a translation for this item yet.)
The text is not localized. (This may be the result of plain text appearing in the page or the message being hard-coded somewhere.)
If text appears in the default language, I want to know whether it was because of reason 1 or because of reason 2.
For every missing translation, I could insert some kind of placeholder text in a resource file. However, this means that I am throwing away the fallback mechanism. Even worse, if placeholder text accidentally makes it through to production, it looks much worse than showing the default text.
Does anyone have any suggestions (or solutions) for determining which of these two conditions is the reason for default text appearing during manual testing?
If I understood you correctly you want to verify that every localizable text is indeed in fact localizable and not burned in the code. To do this you should not be using a real culture (Spanish), instead you should create resources for a fake unsupported culture and provide an automatic translation for every localizable resource entry available in the default resources.
For example, if you have a default resource containing:
Entry1: This is a test!
you should create a resource in your fake culture containing:
Entry1: Th1s 1s # t€st!
You could even (and should) perform the creation of the fake resources automatically using a simple character mapping. This way, when you set the application to use your custom fake culture you know that every entry has a translation so you can find harcoded text. This strategy is used by Windows and is known as pseudo-locales. The use of pseudo translated strings makes it possible do development using the fake culture because the text is still readable and this improves your probability of finding hardcoded text.
Windows supports pseudo-locales since Windows Vista and Windows 2008 R2, so if your build and testing environment uses these operating systems you can associate your fake culture to one of these pseudo locales (for example qps-ploc). If you have unsupported operating systems just associate your fake resources to a real culture that you probably will never be supporting or just create your own culture.
Also note that even in a supported operating system, Visual Studio will not create satellite assemblies for these pseudo-locales unless you enable them on the registry.

Localization Resources .NET - how to keep them synchronized?

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.

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...

Categories