This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C# localization , really confusing me
Could someone please share their localization steps for huge C# applications?
I'm pretty sure that the basic resource-based strategy might work when talking about small to medium projects.
However, if we speak about large products, this approach should be paired up with custom build steps and some 3rd party applications used specifically by linguists.
So, could you please advise / share some global localization strategy that is used in your applications (big enough, obviously :)
Thank you.
Basic resource-based strategy works even in large enterprise applications. This is built-in and easily understandable solution, therefore each and every programmer could use it without a problem.
The only problem is, you need to somehow transform your resource files into Translation Memory files (i.e. tmx) and back - so that translators could use their standard tools.
So what you need is actually a Localization process. Is it different for large applications? Well, if you set-up correct process it would scale. Now onto process. From my point of view it should look like this:
Copy resource files into appropriate folder structure (Localization Engineers should not work directly with application code base). The appropriate folder structure should be somehow similar to:
[Project Name]
.
.
[neutral] [German] [Japanese] [French]
.
.
(each folder contains translatable resources in given language, neutral is usually English)
Of course you would need to transform your code base into folder structure somehow, but this could be automated.
Process your translatable resources and create transkits - zip archives containing files that need to be translated (in this case it seems like all of them). The files should be probably transformed, so you won't end-up sending out resx files. The transformation application should read contents of resx files and put translatable strings into some file of format agreed with translators (it could be simply Excel but I won't recommend this solution). Now, I can't give you the names of such tools, although I know that some commercial applications exist, for I have only worked with custom ones.
Send transkits to the translators (most likely translation vendors).
Upon receiving translated files (transkit) back, you need to verify it (this step is crucial). You need to ensure that transkit is complete (i.e. no translatable strings are missing) and technically correct (i.e. file encoding is correct, usually UTF-8 or UTF-16). Also it is at least good to take a glance at the file to see if there are no strange characters like 1/2, 3/4 or something - this usually mean broken encoding.
Import your transkit. This is the reverse step of 2 - you need to put translated strings back to appropriate files.
Copy translated files back to the original code base and run "Localization" build.
Test your application for Localization problems (i.e. overlapping controls, clipping strings, incorrect encoding, etc. - this usually mean that i18n is not done right).
Fix Localization/Internationalization (Localizability) defects.
Proceed to 1 until UI/String freeze period. This assumes that translators would use Translation Memory of some kind and won't charge (or charge less) you for re-translating previously translated strings.
Automate all possible steps and your done.
Apart from that you might won't to establish your common glossary of terms and do linguistic review on translated content.
I think you can rely heavily on the resource framework provided by .NET with a few modifications to make it more appropriate for large projects, namely to build and maintain resources independently of the application and to eliminate the generated properties that refer to each resource by name. If there are other goals appropriate for large project localization that aren't addressed below, please describe them so I can consider them too.
Create a stand-alone project to represent your resources that can be loaded as a separate DLL.
Add a "Resources" file to your project by selecting the link on the Resources tab of the project properties: "This project does not contain a default resources file. Click here to create one."
Add another resource with the same root name to represent another language, for example "Resource.de.resx" for German. (Visual Studio apparently uses the filename to determine the language that the resource file represents). Move it to the same directory/folder as the default Resources file. (Repeat for every language.)
In the properties of the Resources.resx file, delete "ResXFileCodeGenerator" from the Custom Tool property to prevent default code generation in the Application's "Properties" namespace. (Repeat for every language.)
Explicitly/manually declare your own resource manager that loads the newly created resources with a line like:
static System.Resources.ResourceManager resourceMan =
new System.Resources.ResourceManager(
"LocalizeDemo.Properties.Resources", typeof(Resources).Assembly);
Implement a file that can be generated that contains a list of all the resources you can refer to (see figure 1)
Implement a function to retrieve and format strings (see figure 2).
Now you have enough that you can refer to translated strings from any number of applications (see figure 3).
Use System.Resources.ResXResourceWriter (from System.Windows.Forms.dll) or System.Resources.ResourceWriter (System.dll) to generate the resources instead of having the Resx files be your primary source. In our project, we have an SQL database that defines all of our strings in each language and part of our build process generates all the Resx files before building the resources project.
Now that you can generate your Resx files from any format, you can use any format you want (in our case an SQL database, which we export to and import from Excel spreadsheets) to provide files to send out to translators.
Also notice that the translated resources are building as satellite DLLs. You could conceivably build each language independently with the right command line tools. If that is part of your question (how to do that) let me know. But for the moment, I'll assume you know about that since you already mentioned custom build steps.
Figure 1 - enum identifying all available resources:
namespace MyResources
{
public enum StrId
{
Street
....
}
}
Figure 2 - Code to load and return formatted resource strings:
namespace MyResources
{
public class Resources
{
static System.Resources.ResourceManager resourceMan =
new System.Resources.ResourceManager("MyResources.Properties.Resources",
typeof(Resources).Assembly);
public static string GetString(StrId name,
System.Globalization.CultureInfo culture = null, params string[] substitutions)
{
if (culture == null) culture = System.Threading.Thread.CurrentThread.CurrentUICulture;
string format = resourceMan.GetString(name.ToString(), culture);
if (format != null)
{
return string.Format(format, substitutions);
}
return name.ToString();
}
}
}
Figure 3 - accessing resources:
using MyResources;
namespace LocalizationDemo
{
class Program
{
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo("de-DE");
Console.WriteLine(Resources.GetString(StrId.Street));
}
}
}
Related
Having rather large project using Resources for internationalization (following this guide: ASP.NET MVC 2 Localization complete guide, using things like data attributes, and so on) we run into the need of translating the resource files. In the beggining of project I selected approach to have lot of small resource files - for each view, viewmodel, controller, ... So I ended up having hundreds of resources. During the translations (which is done by our partners using ResXManager tool we run into trouble identifying the context of the string (where is it displayed, to find out the correct form of translation to make sense when displayed).
So I was asked to make the mutation of application which do not display the localized values, but the keys (or string names). E.g. having string in resources TBL_NAME used somewhere in the view like #ResX.TBL_NAME and translated into english as "Name", I would like to show it in this special mutation as "TBL_NAME", so the translator may see the context - where exactly this string is used.
The best would be, if this is not special build of application, but rather the another "language" of the application available for translators, so he can switch between english and this "unlocalized" languages.
I'm looking some easy ideas of doing this. So far I was thinking of these approaches:
Override ResourceManager.GetString - cannot use, because we use generated Designer classes to access strings massively and so far I haven't find a way to change created ResourceManager (see this answer). Did I miss something?
Create resources for some unused language, which will contain pairs string name/translated value as TBL_NAME/TBL_NAME - viable, but very exhausting since we have hundreds of resources. Also the addition of new resource will require us to remeber that we need to add also this unused language resource will exact same strings name. You also have to do twice much work when adding single string to application.
At the moment, it seems for me, that using resources and current approach it is impossible to solve this task, so I decided to ask this as question (and I'm aware it is rather discussion than question) here, hoping, someone will give me some hint about other approach to solve this problem.
My preferred option would be to give the translators an environment where they can see what they are translating. Rigi requires a bit of setup (basically you need to add an additional UI language), but once you have done that translators can work within the live website - or in a test instance, which is what we did.
They can also work in screenshots, which is convenient when translators would have to access admin or other role specific pages but you do not want to bother giving them all kinds of user rights. These screenshots can be generated as part of automated UI tests or during manual UI testing.
I am afraid I can't say anything about the cost of the solution, but our translators are really happy with it. I am not sure if this is what you are looking for since you asked for an easy solution, but it definitely solves the issue of giving translators the context they need to do their job - better than displaying resource IDs.
In my particular scenario, different users have different requirements of what the text of messages, labels, etc are, even though there's no language change. ie: the language always remains en-US.
Currently, I have all my string resources in an internal resources file and I use strongly-typed in my code.
To move the string resources to a satellite assembly I'm following the following MSDN article. So far I've managed to create a .resources file and the corresponding satellite assembly. In this article, the example to get a string resources uses GetString() instead of strongly-typed.
So how do I tell the app do use a different satellite assembly without losing the ability to use strongly-typed access?
It may not be the ideal solution, but our approach to this problem was simply to have the resource keys as public static strings, and this list is the canonical source for key value names.
So while they are just string values, it's easy to verify in code review that names aren't being simply free-formed in, and an acceptance test can verify that all of the keys which should be present in the source file do exist.
I'm working with an MVC 4 app that was originally created with the intention of possibly requiring language localisation so there's a heavy use of .resx files and corresponding embedding of references throughout the project. As it turns out, the app will only ever be used by English speaking audiences and indeed no other languages were ever loaded in. What we've got now is an overhead every time we need to put text on a page and increasing inconsistency as English language is hard-coded into places which can't directly access the resource files such as .js files and reference data in the DB.
Short of a lot of copying and pasting, is there any automated way to extract the English language values from the resource files and replace their references in the views? In a perfect world there'd be a tool to do this and certainly it's conceptually scriptable, does anything like this exist already?
You will have to script it. I have done similar stuff with the O2 Platform AST manipulation Mono.Cecil and mono Cecil APIs.
If you give me a small project with the use can you need (a resx file and an MVC view) I can show you a code snippet example
I haven't seen anything that would take care of this. My first thought is because of the localization issues that could be presented in most "out of the box" solution.
This maybe far fetched, but giving it a shot. Could you write a C# app that would load the assembly that holds the resource file, then loop through every file in the project and replace the resource keys with the values?
As you said, it is possible to be scripted, and this seems like the easiest yet crudest way to complete the task in my mind. Depending on the number of resources you're talking about, obviously it maybe easier and safer to copy/paste.
Satellite assemblies..If you have all app resources placed in a project then create the non-default language you want to implement. For example fr_ca.ErrorMsg | en_gb.ErrorMsg and en_Us.ErrorMsg. The default language can be specified in the main Thread.CultureInfo If en_us then fill you en_us file with all entries need and other resources will only be loaded if it does not exist in the default resource->en_us.
We are localizing our forms and strings in a project and are having a problem; Visual Studio creates a resource file for each form when setting Localizable to true.
It's nothing more than a minor nuisance having to send all of the resource files to translators, but is it possible to get VS to use a global resources file instead?
Thanks!
Like Yoda would say, possible it is.
You will have to dynamically translate the dialogs when they are loaded. I did this on several projects and I would say it's much better than having localized resource files.
As others already said, it is possible to use global resource file manually. I believe that it is actually more problematic and less maintainable but still possible.
Now onto why MS decided on one resource file per form. Well, from Internationalization point of view, this solution is better. On one hand it gives translators one important thing: the context. On the other hand, it is typical for project to grow. It is really unlikely that you will make changes to all forms at once. And you know what? Depending on your deal with translation vendor, you can usually spend less on Localization if just few percent of strings would change. That is just because they can use Translation Memory (TM) software.
With one global resource file, there is usually no context and no way to reasonably use TM. The result is, translations are less accurate and take longer (one needs to actually read large blocks of text to make sure everything is correctly translated).
By the way, you do not need to send out individual resource files. Instead you can use some kind of translation kit generator (or translation manager software) to create something useful for translators (for example translation memory friendly file). Sadly, I cannot give you the names of such tools (although I know that there are few of them) since my employer is using custom system for that and I didn't have a chance to work with other tools.
WinFrom doesn't support generating a global resources for Forms automatically in VS.
You must assign the strings by yourself. For example:
Add a Resources.resx with Resources.designer.cs to your project;
Define your strings in Resources.resx.
In your form.cs code, assign the strings in constructor like:
Label1.Text = Resources.Label1Text;
I've recently found the resx resources feature of C#/VS2008. However, I have trouble finding information about what they are normally used for.
For example, I want to have a "static string" defined somewhere in my project, such as a CSS class that should be used in certain circumstances. Is it a good idea to define that string as a resource for my project? Or should I just define a class with a bunch of const string for these purposes?
Resource files should generally be used for strings that need internationalisation (user interface messages typically).
Where you have strings like file paths and such like that need to be changeable without re-compiling the application these should go in the app configuration files.
Where you have genuine constants (such as your example looks like) these should be defined as const strings in the code.