Are resx files a suitable way to customise for different customers? - c#

I'm looking at customising the various pieces of text in an application for different customers. It seems like .resx resources would be a sensible way to do this. However, all the literature for resx I come across seems to be about localising for language differences (as in English, French, Spanish, etc.), so just want to check it is the best thing simply for customer differences in text as well.
And, hypothetically, could it also deal with different languages for different customers, e.g.:
CustomerA.resx
CustomerA.en-US.resx
CustomerA.de-DE.resx
CustomerB.resx
CustomerB.en-US.resx
CustomerB.de-DE.resx
... etc
Is resx the way to go for customer differences?

You can use them for storing different strings per customer - it will work. I imagine you don't have many customer to cater for and they do not require the strings to be modified very often. Otherwise the management of multiple files may become a real pain.
Storing per-customer strings in the database (with caching) may be a better option, especially if you want the customers to modify their strings.

I wouldn't customize like this per customers, how do you specify then if you have to loadCustomerA or CustomerB resources? Resx are ok for languages localizations but if you want to have different texts for different customers, I would probably read the strings from a database table which would contain initially the default values then you customize values in the customer specific database.

Yes, it is possible to do what you need with resx files. You can use custom cultures to achieve that. Please take a look at How to load different RESX files based on some parameter.

Related

C# Resources: display resource string names instead of localized values

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.

Loading .resx file by custom string that doesn't map to a culture

I'm making a website for use by multiple clients and I need to offer the flexibility to change labels on various places. For example, if one client wants to call the login "Email" and another wants to call it "Employee ID." Though I've never used them, I thought that resx resource files used for localization would be a good idea, but I'm having problems setting it because what I'm doing isn't a real localization that maps to any culture.
My testing has these resource files:
Global.resx
Hello "Hello!"
Global.Casual.resx
Hello "Sup!"
Global.Formal.resx
Hello "Greetings!"
Then in my cshtml view, I can say #Resources.Global.Hello and that works as expected. My question is, how can I set it to display Casual by default? If I rename Casual and Formal to es and ru, I can do something like this:
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("es");
And that works just fine. But if I try that with "Casual" I get that it "is an invalid culture identifier." I can explicitly show it by saying #Resources.Global_Casual.Hello in the view, but that's obviously not what I'm after.
Am I going the complete wrong direction here, trying to use something for a purpose contrary to its design? I just want to load resource files by arbitrary string values. Do I need to roll my own database-driven approach?
This looks very similar to this SO question, which never got an answer: How to specify a custom culture?
Personally I feel that this kind of customisation belongs in the database - not least because you can then allow the clients to customise it themselves if required. If you are concerned about performance then you can cache the terms into a dictionary and even create a class that will expose the strings either from the dictionary (if the client has customised them) or from a resource file if not. This allows you to present reasonable defaults which can be changed on demand. Alternatively you could present a number of alternatives in the database, and a flag to allow selection per term of the word to be displayed in the UI.
I had a similar problem of allowing customisation within an application in the SO question Localization vs Customization which you may find useful.

Windows forms localization using *.resx and Common.resx

Lets say there are bunch of forms: A.cs, B.cs, C.cs...
Each form is localized - A.resx, A.NL-nl.resx, etc.
These forms contain some specific labels and some common in all forms used labels. So specific strings go to A.resx (A.NL-nl.resx) and common ones - to lets say Common.resx (Common.NL-nl.resx)
Is there any way to force when form is initialized to use resource strings from A.resx and from Common.resx where all common strings go? Of course I could in some OnLoad method set captions for my form layout items, but then built in localization functionality would be lost.
The reason I would like such functionality, because there are lot of commonly used strings in different forms and it would much easier to manage/translate these *.resx files.
I've done some reading about localization in C#, but probably I am missing something.
From my experience I can say:
You will be better of to create one locatization resx file for all the forms.
Assign all localizable strings manually (I did that in constructor).
Store each string for each form in different localizable property, like Form1_OkButtonText, Form2_OkButtonText.
The last one really does matter, when you translate your app to different languages, because translation may really depend on context. And on one form default button may be named OK and on the other it should be named Accept. While in English both buttons may be named Ok, in some other languages, this will sound awkward, and different names will be required. This is be problematic, if you use same resource strings for all buttons.
And to mitigate the problems of translating several same strings many times, you should use some software for translator, that keep dictionary of string, and supply you with already translated ones.
Resources have a fully qualified name. Which means they have one source. If you want to use texts from Common.resx in your form, you must write code for that. Easy code but code nonetheless.

Using only 1 resource file instead of 1 resource file per form/other strings

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;

Internationalization in the database

Do you guys think internationalization should only done at the code level or should it be done in the database as well.
Are there any design patterns or accepted practices for internationalizing databases?
If you think it's a code problem then do you just use Resource files to look up a key returned from the database?
Thanks
Internationalization extends to the database insofar as your columns will be able to hold the data. NText, NChar, NVarchar instead of Text, Char, Varchar.
As far as your UI goes, for non-changing labels, resources files are a good method to use.
If you refer to making your app support multiple languages at the UI level, then there are more possibilities. If the labels never change, unless when you release a new version, then resource files that get embedded in the executable or assembly itself are your best bet, since they work faster. If your labels, on the other hand, need to be adjusted at runtime by the users, then storing the translations in the database is a good choice. As far as the code itself, the names of tables & fields in the database, we keep them in English as much as possible, since English is the "de facto" standard for IT people.
It depends a lot of what you are storing in your database. Taking examples from a recent project I was on, a film title that is entered at a client site and only visible to that client is fair game to store as-is in the database. A projector error code, on the other hand, because it can be viewed by the client, as well as by network operations centers that might be in different countries, should be stored as an error code (and supporting data, like lamp hours and the title of the movie being shown) which can be translated at the gui level depending on the language setting of the viewer.
#hova covers the technicalities, but something you might want to consider is support of a system showing a language you don't understand.
One way to cope with this is to have English as the default language, and a user setting that switches into a different language. That way your support users can log in and see the system in a natural way (assuming English as their first language), and your actual users can see the system in their first language. IMO, the data should always be 'natural' - in the language of the users.
Which raises another interesting point - should your system allow multiple languages for cross-border installations? In my experience, for user interface yes, but for data, no. To take a trivial example of address formatting, a letter to a French third party from a Swiss system should still have a Swiss-format address instead of a French one, as it has to go through the Swiss postal system first.
If your customers are Japanese and want to see their names in Kanji and Katakana (and sometimes in most formal Gaiji), you've got to store them as Unicode. No way around that.
Even things like addresses are very different between the US and Japan. One schema won't cut it for both.

Categories