I have a class library project (c#, .net 4.0). It has some WPF user controls which show content in english or spanish according to the culture configured in database.
For doing so, in the main window constructor, I receive a CultureInfo parameter, which I use to set the culture to be used in my Localization namespace, like this:
public MainWindow(Entities.TransactionContext transactionContext, CultureInfo culture)
{
Localization.Resources.Culture = culture;
InitializeComponent();
//Some other unrelated code here
}
That is used from the main program wich calls my dll. In there, a query is made to get the default culture. It can be either "en-US" or "es-MX", then it is send as the second parameter. The first one is not important for now.
As I said, I have a namespace named MyProject.Localization (I'm changing my project name since internal policies, you understand). In that folder, I have three resources files:
Resources.resx
Resources.en-US.resx
Resources.es-MX.resx
Default entries in Resources.resx have values in spanish since, you know, I'm mexican.
Also, in my code, when I need to show a message or set a label text, I use something like this:
this.lblStatusMessage.Content = Localization.Resources.OperationCancelled;
In this example: "OperationCancelled" is an entry that exists in all the resources files. In spanish its value is "OperaciĆ³n Cancelada" and in english it says "Operation Cancelled".
After all this story, this works great in my development environment. I run my test project, I see it in english, then I change the language in database, run it again and boom! spanish.
But.
When I commit changes to this project via SVN, it is then deployed to QA environment by some automated process (it's awesome). And then I test there and I always see the contents in spanish (as the default ones). Even when I change the language on the QA database, it always shows labels and messages in spanish.
I tried some options:
Changed the resources dll's Build Action to Resource instead of Embedded Resource. It didn't work.
Right click->Properties, Resources tab shows no Resources, so I created three resx files there and set custom namespace as MyProject.Localization. Next I excluded my original files since now there was some ambiguity errors. Again it worked in my dev machine but in QA didn't.
Any ideas about this? My hipothesis is that it has something to do with the resx files, maybe they're not included in the final built or something like that, and that's why the app cannot get the localized texts.
Thank you in advance.
Heres my answer based on personal experience: Build action "Embedded Resource" should work. All resources will be included.
Localization.Resources.Culture = culture;
// "Overrides's the current thread's CurrentUICulture property for all
// resources lookups using this this strongly typed resource class."
I havent used this method personally, but this also means it could be changed back to Localization.Resources.Culture = null; without you knowing. Instead look into using System.Threading.Thread.CurrentThread.CurrentUICulture = culture;. And heres a suggestion of a call if you intend to have an application with multiple languages:
public void SetUICulture(CultureInfo culture)
{
CultureInfo savedUICultureInfo = System.Threading.Thread.CurrentThread.CurrentUICulture;
try
{
System.Threading.Thread.CurrentThread.CurrentUICulture = uiCultureInfo;
// Do culture-specific stuff...
this.lblStatusMessage.Content = Localization.Resources.OperationCancelled;
}
finally
{
System.Threading.Thread.CurrentThread.CurrentUICulture = savedUICultureInfo
}
}
This is also useful if you later on have several different resource files. In general I would suggest to take a look at what CultureInfo you're actually passing.
Well, at the end it was simple.
This is my explanation, maybe it's incomplete, but I understood it like that and worked for me.
When you use resources files for localization and you build the solution, VS creates a DLL for each of them. They are created in a folder corresponding to its languaje. In my case, two folder were created:
en
es-MX
Inside each folder, ther was a single file: MySolution.resources.dll. Same name in both files. That way, at runtime, the application know which dll to use to load localized texts.
So you need those folders for using localized logic. If they're not present, the app could only use the texts from the default resource file.
In my case, again, when I tested my app, it worked great because the Debug folder had my MySolution.exe file and also the language folders. But it failed at prod environment because the main deployment was not considering those folders.
And also, the deployment configuration was set something like that:
-MainFolder
--MainApp.exe
--MainApp.configfile
--other files
--Folder
----MySolution.dll
----en
------MySolution.resources.dll
----es-MX
------MySolution.resources.dll
So I had to talk with the person in charge of deployments, so that could change to:
-MainFolder
--MainApp.exe
--MainApp.configfile
--other files
--MySolution.dll
--en
----MySolution.resources.dll
--es-MX
----MySolution.resources.dll
That way, my dll could load the language dlls, and the main executable could load everything ok. Happy ending.
I hope I was clear and it can help someone. Cheers.
Related
my Team Project (UWP App in C#) is offered in two languages (de-DE and en-US).
The project has a Resources.resw file stored in
"Model\DataManager\ResourcesManager\Language\de-DE\"
which contains all the strings that related to the GUI.
For my part i need to handle specific tasks differently based on the language of the App, but the problem is, neither me nor my team knows how to really work with the resourceloader.
I have the following problems:
1) I was told that the resourceloader gets automatically the windows language and use it in the app if it is available, otherwise App default will be used.
What i was also told is that this cannot be changed internally, even if the user wants that (like in the settings page or so) and the only solution is to change the windows language. is this true? if not how can it be done?
2) For my part i need to know the current language of the App but i don't know how and i also need to store the language related strings in an appropriate resources file.
I tried to define a new file named LPResources.resw where i added all the strings like:
DBQueryGenerator_DateInterpreter_month-12 means December in the English version.
But trying to access this string with:
ResourceLoader resources = new ResourceLoader("LPResources");
or
ResourceLoader resources = ResourceLoader.GetForCurrentView("LPResources");
and then
resources.GetString("DBQueryGenerator_DateInterpreter_month-01")
throws directly an exception ResourceMap Not Found.
I tried to search for a solution but i couldn't find any helpful information.
If you can answer one of the questions or both i would really appreciate it.
1) I was told that the resourceloader gets automatically the windows language and use it in the app if it is available, otherwise App default will be used. What i was also told is that this cannot be changed internally, even if the user wants that (like in the settings page or so) and the only solution is to change the windows language. is this true? if not how can it be done?
This is not very accurate. The resources that Windows loads for your app and also the language(s) used to format dates, times, numbers, and other components are determined by the app runtime language list and it is made up of these items:
(Optional) Primary Language Override.
The user's languages that are supported by the app.
If 1 and 2 are empty, then the default or first language supported by the app.
The detailed information is introduced in this document: Understand user profile languages and app manifest languages.
2) For my part i need to know the current language of the App but i don't know how and i also need to store the language related strings in an appropriate resources file. I tried to define a new file named LPResources.resw.
As the reply above, to get the current language, you should get the app runtime language list, you can get it use the following three ways.
//First way
string runtimeLanguages = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues["Language"];
//Second way
IReadOnlyList<string> runtimeLanguages1 = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Languages;
//Third way
var runtimeLanguages2 = Windows.Globalization.ApplicationLanguages.Languages;
Then you can make a simple judgement to get the what the user sees in the app. (Of course, you should read and understand the Understand user profile languages and app manifest languages document firstly.)
For getting the resource, I tried the code,
var Loader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("LPResources");
var text1 = Loader.GetString("DBQueryGenerator_DateInterpreter_month-12");
It can return the defined text value, please check you resource file name and make sure it is correct.
Note: "LPResources" is the LPResources.resw file, and "DBQueryGenerator_DateInterpreter_month-12" is the resource string Name.
You can also use the following code to get the resource,
ResourceMap resourceMap = ResourceManager.Current.MainResourceMap.GetSubtree("LPResources");
ResourceContext resourceContext = ResourceContext.GetForCurrentView();
var str = resourceMap.GetValue("DBQueryGenerator_DateInterpreter_month-12", resourceContext).ValueAsString;
Note that: Whether the LPResources.resw file is in the project's root directory or in a folder of the project, you can call it using its name directly.
I'm looking for the best way to create a multi language application. I want to have the language files in a external Class Library so it's reusable for multiple applications so I only have to add it to the References (and probably some code in the .xaml itself).
EDIT 1: With multi language I mean like Dutch, English, German, ...
The goal is to have the computer system to say, if it's in Dutch, the application has to be Dutch, but if it's in French, it takes English as default. This should be done in a dll, so it's not "hard coded" in each application I make.
EDIT 2:
I managed to solve this problem on my own. Thanx to the people who replied to my problem.
I solved it this way:
I made a Class Library and named it "Languages". I added 2 Resources named "Language.nl-BE.resx" and Language.en-US.resx" with both a String in the file named "exDefault". After that I compiled it and added the dll as a Reference to my application.
In the application I used the following code to get the String into my application:
ResourceManager rm = new ResourceManager("Languages.Language", System.Reflection.Assembly.LoadFrom("Languages.dll"));
MessageBox.Show(rm.GetString("exDefault", new System.Globalization.CultureInfo("en-US")));
This will get the content of the "exDefault" String in the en-US source and show it in a MessageBox. To show the other language, just change en-US to nl-BE.
You will notice there is a dll named Languages.dll and 2 folders named en-US and nl-BE with each their own Languages.resources.dll file inside them.
The only thing I'm wondering now is, is there a way to get rid of those 2 folders and embed them inside the Languages.dll?
You might want to read the sections on globalization / localization in the WPF and .Net documentation. Also, you might want to check out this blog, where there are examples of how to use localized resource dlls in WPF:
http://wpfglue.wordpress.com/category/localization/
I managed to solve this problem on my own. Thanx to the people who replied to my problem.
I solved it this way:
I made a Class Library and named it "Languages". I added 2 Resources named "Language.nl-BE.resx" and Language.en-US.resx" with both a String in the file named "exDefault". After that I compiled it and added the dll as a Reference to my application.
In the application I used the following code to get the String into my application:
ResourceManager rm = new ResourceManager("Languages.Language", System.Reflection.Assembly.LoadFrom("Languages.dll"));
MessageBox.Show(rm.GetString("exDefault", new System.Globalization.CultureInfo("en-US")));
This will get the content of the "exDefault" String in the en-US source and show it in a MessageBox. To show the other language, just change en-US to nl-BE.
You will notice there is a dll named Languages.dll and 2 folders named en-US and nl-BE with each their own Languages.resources.dll file inside them.
The only thing I'm wondering now is, is there a way to get rid of those 2 folders and embed them inside the Languages.dll?
I have an ASP.NET3.5 (C#) ASPX page that is internationalized in 10 different languages.
The page is very complex in its structured with dozens of nested views driven by a state machine pattern.
EDIT: I am using the meta:resourcekey syntax in every asp control, which allows to use declarative syntax for Implicit Resource expressions.
I have been asked to "brand" the page based on some query string parameter. Branding will mean not just loading different CSS files, but also having different text blurbs (in all languages).
Is there an easy way to "swap" resx files without having to get resources manually for each of the hundreds of literals and images that I have on this page?
In other words, let's say I have the following RESX files:
brand1_myPage.aspx.en-US.resx
brand1_myPage.aspx.de-DE.resx
brand1_myPage.aspx.fr-FR.resx
brand2_myPage.aspx.en-US.resx
brand2_myPage.aspx.de-DE.resx
brand2_myPage.aspx.fr-FR.resx
myPage.aspx will be looking for resx files named myPage.xx-XX.resx.
Is there a way to load instead either the brand1xxx.resx files or the brand2xxx.resx based on some value?
Thanks in advance.
You can use custom cultures to achieve this effect.
First, create and register custom cultures in the system, for example:
CultureAndRegionInfoBuilder builder = new CultureAndRegionInfoBuilder("en-US-brand1", CultureAndRegionModifiers.None);
CultureInfo parentCI = new CultureInfo("en-US");
RegionInfo parentRI = new RegionInfo("en-US");
builder.LoadDataFromCultureInfo(parentCI);
builder.LoadDataFromRegionInfo(parentRI);
builder.Parent = parentCI;
// set other properties of the custom culture (CultureEnglishName, CultureNativeName, possibly other ones)
// ...
builder.Register();
Note that you might want to build a simple tool to automate this, since those cultures need to be installed on every system where your aplication will be compiled or executed. Administrative rights are needed to be able to register the cultures.
Once you have the cultures installed, create resx files like you would normally do, but use the custom culture names (myPage.aspx.en-US-brand1.resx etc).
Now all that's left to do is to set System.Threading.Thread.CurrentThread.CurrentUICulture based on some parameter (the sooner the better, BeginRequest is a good place; or Page_PreInit if you want this only for some pages):
CultureInfo ci = new CultureInfo(Request.QueryString["paramname"]);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
(setting CurrentCulture is not really necessary, as resources work in terms of CurrentUICulture, but setting both allows you to further customize the page for each brand, e.g. use different date/time format settings for each custom culture/brand)
Some notes:
this solution gives you great flexibility, since normal culture fallback is in effect - if an entry is not found for en-US-brandX, the runtime will fall back to en-US and so on; this can greatly reduce duplicate resx entries if the brands are mostly similar, as you can put some entries only in the parent (en-US) resx file,
you can create more levels of inherited cultures, eg en-US-brandX-variantY,
all methods for accessing resources work as expected,
changing the culture of the worker thread means you will get localized exception messages if you set the culture to, say, de-DE-brandX and you have de-DE localization installed in the OS,
for the above reason, you might want to reset the current (UI) culture to CultureInfo.InvariantCulture in Application_Error, or even better also as soon as you catch an exception which you know will lead to Application_Error; this will prevent localization of the standard yellow page of death and at least part of the exception stack,
you might consider building a service tool which will register/unregister/update the cultures, especially if you anticipate frequent changes,
this solution might be problematic if you use client-based culture detection.
If you reference resources in your code like this: Resources.brand1_myPage.WelcomeMessage then it may be difficult.
But you can also retrieve resources programmatically: GetGlobalResourceObject ("brand1_myPage", "WelcomeMessage"). Here you have some room for manipulation with the resource file name.
I have a WinForms application which I want to translate into multiple languages. However, I do not have any experience with localizing a WinForms app, and I find very contradictory information about this subject.
Basically, what I want is:
In the source code, I want only one file per language
This file gets compiled into the main application on compilation - no satellite assemblies or external data files after building the application
The user can select the language, I do not need/want auto-detection based on the operating system
This should mainly contain strings and ints, but also a CultureInfo
Most solutions I've seen either have one .resx file per Form and/or external satellite assemblies.
Do I have to roll my own?
Or is there something in the framework already?
.net Framework 3.5 SP1 if that matters.
Edit:
For the most part, Visual Studio already offers support for what I want, but there are two issues. When I set Form.Localizable to true I have this nice Designer support, but this generates one resx per Form. The idea of manually overriding it in InitializeComponent fails because it's designer-written code that will regularly be overwritten.
Theoretically, I only want to :
a) override the creation of the ComponentResourceManager to point it to my global resx and
b) change the call to ApplyResources to the overload that takes a CultureInfo as third parameter.
It seems as if I have to add a function call to my constructor that gets called after InitializeComponent() and overrides its behaviour. That seems terribly inefficient, but Visual Studio is right when it warns about touching InitializeComponent().
At the moment, I am indeed rolling my own WinForms localization Framework...
I've just completed a C# .Net 3.5 project with a similar problem. We were writing WinForms plugin for an existing multi-lingual application with 8 languages (including English).
This is how we did it:
Create all our forms and UI in the default language, English.
Put all our internal strings in a resource file (stuff not tied directly to a form like custom error messages and dialog box titles etc)
Once we had completed most of the work and testing we localised it.
Each form already had a .resx file but this was empty. We set the property 'Localizable' to true, the .resx file was filled with things like button sizes & strings.
For each of the other languages, we changed the 'Language' property on the form. We chose the basic version of each language eg: 'Spanish' instead of 'Spanish (Chile)' etc. so that it would work for every 'Spanish' dialect, I think.
Then we went through each control, translated its text and resized, if needed. This created a .resx per language and form combination.
We were then left with, for 8 languages, 8 .resx for each form and 8 .resx for the general strings. When compiled the output folder had the .dll we were creating and then a sub folder for each language with a .resources.dll in it.
We were able to test the versions of the UI in the designer by just changing the language property to check that we had the correct strings & layout.
All in all once we got our heads around it, it was quite easy and painless.
We didn't need to write any custom tweaks to the form loading
I was asking a similar question about ASP.NET and got a first answer - this tool and its workflow might also be something for you - have a look: Lingobit Localizer
It seems to be able to load your Winforms app and allows you to start translating your labels etc. and see the forms while you do it. Lots of other features, too, like incremental translation and translation memory (if you use the same terms over and over again).
Looks quite promising (for Winforms) - haven't used it myself, though.
Here's an extensive list of potential .NET localization tools - not sure, how well they work and what they cover - have a look, maybe you'll find what you're looking for.
Marc
I dont have a solution for your first and second requirement but keep in mind that localizing a form is not as simple as translating each word. You need to check that each translated text fits in their respective control. Also, maybe you have an icon or an image which need to be change in another culture.
For your point three, you can change the language manually with the following lines:
CultureInfo ci = new CultureInfo("fr");
Thread.CurrentThread.CurrentUICulture = ci;
This is a huge subject and there are many ways to accomplish what you want. The framework does provide the basis but a complete solution requires that you implement certain elements yourself.
For example the default framework implementation is to create a .resx file for every resource. In ASP.Net this means each user/server control or page. This doesn't lend itself to easy maintenance and if you want to move resources to a database you need to implement your own provider.
My familiarity with Winforms is limited but if you are using Silverlight or WPF then have a read of Guy Smith-Ferrier's work on the subject at: http://www.guysmithferrier.com/category/Internationalization.aspx. He also has some toolsets that can make your life easier at: http://www.dotneti18n.com/Downloads.aspx.
I've worked with him before and have never come across anyone else with a better depth of understanding of the subject.
What you are asking for:
no satellite resource files
only one size and control placement per form.
lots of languages embedded in the executable.
Is not do-able in vanilla Visual Studio's IDE.
What it would require is some custom work, basically fulfilling all these steps:
Acquire a custom resource manager that handles TMX resource files.
Put all your localizable strings in a TMX file.
Make this TMX file an embedded resource in your project.
In your Form constructor, create your TMX ResourceManager, loading the TMX file from your embedded resources.
In your code, use your tmx ResourceManager instead of the default ResourceManager for getting localized strings.
Let the Form use the default ResourceManager for getting all the designer things except the strings.
Get your TMX file fleshed out with the new language translations.
More can be added in the next release of your project, just by adding them to this TMX file before you compile.
RESOURCES: (not an exhaustive list, by any means)
http://en.wikipedia.org/wiki/Translation_Memory_eXchange
http://sourceforge.net/projects/tmx-editor/
The right way to do this is, suppose you want to add Arabic support witch is RightToLeft language:
Double click the form
Set localizable prop. to true
Change Language prop. to Arabic //This will automatically open a new version of the form so you can customize.
Set RightToLeft prop. to Yes
Set RightToLeftLayout prop. to True
Start renaming controls, and save the form.
Handle Messages/Errors in code // Sorry I don't have a quick solution for now, try duplicate them and If/Else the current local.
Greetings all,
I'm trying to localize a .NET/C# project. I'm using string resource files and setting the "Localizable" property on all my forms to 'True'. The assembly culture is empty. The resx/resource files are successfully passed through Lingobit, resgen, and al.
When running the localized executables, some of my forms are not localized (ones in which I know the Localizable flag is set) while others are. There are even a few forms which are localized but a button or two isn't. I cannot tell any difference between the non-localized forms/controls with the localized ones.
Anyone have an idea what I might be missing? Thanks!
When you open the form in Visual Studio, if you change the Language property of the Form to the language you are localizing to, does the same problem exist there? Could it be possible that the non-localized forms/buttons still have the English text set even in the localized resources?
Yeah, I'd go with Andy on this and be suspicious of the contents of the resource files. We dabbled with localisation for a time, and encountered a number of issues, but this certainly wasn't one of them.
If that isn't it, then how are you testing your app? If you haven't tried this already I'd suggest firing up a set of VMs with foreign language versions of Windows installed (rather than just changing the language settings on your machine) and seeing if that makes any difference.
Okay, I figured it out. You guys were correct. We were not generating the translated resx files correctly from Lingobit. Some of the files would get translated while others had the English text still in the resx.
Thanks for your help!
EDIT: Just to expand upon this, we specifically were messing up the al.exe command which takes the binary .resources file and creates a satellite assembly adding it to the executable's manifest. In the /embed command, you have to bind the resources file to a namespace. Our top-level name spaces were mapped correctly, but we weren't binding to sub-level namespaces on all of the resource files.