Multilanguage application in C# - c#

I am currently building an application in C# which supports French, English and Spanish. I am using resource files (.resx) to store my text following this method I found online. Right now, the resource files I have are the following : TextLabels.resx, TextLabels.en.resx, TextLabels.fr.resx and TextLabels.es.resx.
I use the following method to link my the resource to my form :
manager = new ResourceManager("MyProject.TextLabels", typeof(MyForm).Assembly);
to change the labels when I have selected a new language, I created a refresh method changes the Text attributes of my containers with the method :
Text = manager.GetString("MY_STRING_VARIABLE", culture);
Also, I make sure to change the culture used when the user clicks on the desired using the following method :
culture = CultureInfo.CreateSpecificCulture("es"); //changes the culture to spanish
So here is my problem : I use a 64 bit Windows 7 computer installed in English (I am not sure if it matters) and this method works fine, all my labels are changed in the desired language. The problem occurs when I try use my project on my colleague's computer which is a Windows 7 32 bits computer in French. Using his computer, it looks as if the program (that I have compiled with Visual Studio 2012) can only find the default resource file (TextLabels.resx). So I am at a loss here and wondering 1. Is the 32 bit system or French installation of Windows the reason of my problem or is it something else and how can I make my application work on his machine?

If you are generating localized binaries, be sure that they get deployed with the app.
They would be in the /bin/Debug and /bin/Release folders.

Related

Word no longer embeds after windows update using AxSHDocVw.AxWebBrowser

We have been using AxSHDocVw.AxWebBrowser for some time embed word for mailmerge template creation but as of windows update July 12, 2022—KB5015807, this no longer works.
We expect the windows application to be embedded into the AxWebBrowser control like so :
[Shows an image of the expected result for and embedded word application window][1]
[1]: https://i.stack.imgur.com/tqwNi.png
however since the update the application now opens in a seperate window (its own word instance) and has no ribbin bar menu items :
Shows that the word document is opened it is own instance with 'Document in internet explorer - Word' as the instance title
This has been an issue before but was easily fixed buy running the following registry fix file :
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.Document.8]
"BrowserFlags"=dword:80000024
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.RTF.8]
"BrowserFlags"=dword:80000024
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.Document.12]
"BrowserFlags"=dword:80000024
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.DocumentMacroEnabled.12]
"BrowserFlags"=dword:80000024
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.Sheet.8]
"BrowserFlags"=dword:80000A00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.Sheet.12]
"BrowserFlags"=dword:80000A00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.SheetMacroEnabled.12]
"BrowserFlags"=dword:80000A00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.SheetBinaryMacroEnabled.12]
"BrowserFlags"=dword:80000A00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.Show.8]
"BrowserFlags"=dword:800000A0
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.Show.12]
"BrowserFlags"=dword:800000A0
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.ShowMacroEnabled.12]
"BrowserFlags"=dword:800000A0
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShow.8]
"BrowserFlags"=dword:800000A0
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShow.12]
"BrowserFlags"=dword:800000A0
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShowMacroEnabled.12]
"BrowserFlags"=dword:800000A0
We are using AxSHDocVw.AxWebBrowser to do this, code for loading the file into the browser below
public void LoadDocument(int? documentId, bool hideDocument)
{
_templateVersionDataRow =
Business.BusinessLogic.DocumentTemplate.GetLastVersion(documentId);
_filePath = String.Format("{0}{1}.doc", Path.GetTempPath(), Guid.NewGuid());
File.WriteAllBytes(_filePath, _templateVersionDataRow.Template);
if (!hideDocument)
BrowserFrame.Navigate(_filePath);
}
I have experienced the same issue and think it may be related to a Word update rather than the KB you stated. I have used the WebBrowser control to embed Word documents for many years with different Operating Systems and different versions of Word. We too have used the registry settings to make the Word documents load inside the control and not separately in Word. But it seems to have stopped working after upgrading from O365 version 2205 to a later version (e.g. 2207). I think Windows Defender may also contribute to the issue. I would be interested to get an update on any fix/workaround you may have found. Thanks

Multiple language support in Universal App

This is not a question about standard localization - I know how to localize the app, use resources, Uid's and so on - this works perfectly.
The problem is that the app comes within a bundle, therefore when the user installs the app it covers only languages that are selected in device/phone settings. But I would like to provide an option in settings that would allow choosing a language regarding the settings. For this purpose, I can use ApplicationLanguages.PrimaryLanguageOverride, which works very nice when deployed via VS, but as I've mentioned - version from the store lacks resources, as not all are installed.
Does anybody know how to bypass this bundle behavior?
The problem is also that I'm using MAT (multilingual app toolkit) and my translation comes with xliff files. I've spent quite a lot of time to find a way to convert them to resw files, without success. Is there any way to do it (or I've to write my own converter)?
You need to use ResourceContext:
var context = new ResourceContext(); // deliberately not using getForCurrentView()
context.Languages = new string() {"fr-fr"};
ResourceMap resourceMap = ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
String str = resourceMap.GetValue("string1", context).ValueAsString;
More info at:
'How to load string resources' and
'ResourceContext class'ResourceContext class'.
PS. I have app in store and there is no problem with changing language without reinstall so all resources must be there
Check out this: UWP: Resource file for languages is not deployed correctly you need to get rid of bundle in order for my code from above to work. Or you could check if chosen language is installed in OS and if not you could not allow user to choose it using:
Windows.System.UserProfile.GlobalizationPreferences.Languages

Localization not properly working

I wrote a small application that shall automatically start in either English or German. English is default and German would be used on a German Windows.
The problem:
The German strings aren't loaded on a German Windows, although the program recognizes the client as German.
Explicitly setting the current culture (in code) to German however will result in a German UI.
What I did:
I followed this guide: http://www.codeproject.com/Articles/299436/WPF-Localization-for-Dummies
I created copies of the Resources.resx in the Properties section
Now there are: Resources.resx, Resources.en-US.resx, Resources.de-DE.resx
I put all Strings in the three Resources files. Resources.resx and *.en-US.resx contain the exact same strings
The name of the strings are consistent, Access Modifier on all files set to Public
File Properties of the Resources: Build Action: Embedded Resource; Do not copy; Custom Tool: PublicResXFileCodeGenerator
Code:
private void InitLocalization() // Executed on startup
{
if (CultureInfo.CurrentCulture.Name != "de-DE") // only use german on german systems. Otherwise use english
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en-US");
}
else
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("de-DE");
}
rm = new ResourceManager("SaveEye.Properties.Resources", Assembly.GetExecutingAssembly());
// Manually assign the correct text to XAML-elements
_SettingsTextBlock.Text = rm.GetString("Settings");
_StartWithWindowsCheckBox.Content = rm.GetString("Startup");
_SaveButton.Content = rm.GetString("SaveAndClose");
}
Basically, I just want to make sure that either the Resources.en-US.resx or Resources.de-DE.resx is loaded from the ResourceManager.
In the rest of the code I grab the Strings I need with rm.GetString("").
This works just fine with English. I can even manually set the CurrentCulture to de-DE at the beginning of the InitLocalization-Method and then all German strings are loaded. But as I said, on other systems that are de-DE by default, the German strings are not loaded.
What am I doing wrong?
Regards
It is the CurrentUICulture that will affect which resources are loaded, and the CurrentCulture that will affect date and number formatting. A lot of people get these two confused.
You should probably be testing CurrentUICulture if you're trying to either set, or determine what string resources to retrieve. There is a big difference between a machine running with German date and number formats (CurrentCulture) and a machine running with a full German Language Pack installed and activated (CurrentUICulture).
Your sample code is using CultureInfo.DefaultThread(UI)CurrentCulture which will control the behaviour of all new threads created but this will default to whatever the main thread is using anyway so if it was already in German, you shouldn't need to explictly set it as such.
You can test the resource loading behaviour by updating your InitLocalization() method and setting Thread.CurrentThread.CurrentUICulture explicitly to "de-DE" to see if the German resources start loading. Then verify that the CurrentUICulture is really set to "de-DE" and not just the CurrentCulture. It's possible the German machine has German date/number formatting (CurrentCulture) but isn't using a German language pack (CurrentUICulture).
EDIT: In response to your comment, if you're already using CurrentUICulture correctly and the machine really has a full German UI but the German resources still aren't appearing, you should check that the German satellite resource file is actually being deployed.
The German resources are contained within a separate assembly named de-DE\MyApp.resources.dll and must reside in the same folder as the executable and stay within the de-DE folder (so you have \Folder\MyApp.exe and \Folder\de-DE\MyApp.resources.dll). The default resources (the ones in Resources.resx stay in the main executable and are the ones the ResourceManager falls back to if no more appropriate resource is found).
You didn't specify how you were deploying the application, but if you run you can use the 'Open in Explorer' (or Dateipfad Öffnen on the German machine) feature of Task Manager to take you to deployed folder of the running application so you can check that the de-DE folder is there (I only mention doing it this way because if you ClickOnce deploy the application it can be hard to find the installation folder).
If you are using ClickOnce and you publish with Visual Studio, you can control the files included during publishing by right-clicking the project and selecting properties then navigating to the 'Publishing' tab. The 'Application Files' button will show you a list of all the files included when publishing. Your de-DE satellite resource file should be set to 'Include'.

How to get same variable from multiple resource files

I am developing a small project about using multiple language.
I have three resource files
MainForm.resx // Default version => English
MainForm.US.resx // English version
I define
MainForm.JP.resx // Japanese version
I define
I want to get value of each variable (btnCancel, btnLogin, lbPassword, lbUsername, ...)
Now, I do
From MainForm.US.resx, I build to MainForm.US.designer.cs (MainForm_US class)
From MainForm.JP.resx, I build to MainForm.JP.designer.cs (MainForm_JP class)
I make another class MainFormResource.cs. Here, I will check Thread.CurrentThread.CurrentUICulture.Name value
If is equal "ja-JP", I get value from MainForm.JS.designer.cs (MainForm_JP class)
If is equal "en-US", I get value from MainForm.US.designer.cs (MainForm_US class)
But if my project is large, it will take me more time to do that.
How should I do to get the value of lbUsername, lbPassword, ...?
p/s: I use Windows Form Application in Visual Studio Ultimate 2012
When creating RESX files you only need to activate the automatic code generation on the root file (MainForm.resx in your case).
Visual Studio will generate the code which includes the usage of RescourceManager.
The satellite assemblies will also be generated automatically.
So as NightOwl888 already mentioned, you should read the documentation about using Resx files and globalization / localization features of .NET

C#/Windows: Get localized default name of "New Folder"

I am using a FileSystemWatcher to check if new directories are created in the watched one. If the user creates it per Explorer -> Rightclick -> New Folder at first a directory "New Folder" is created that the user can rename instantly. Nevertheless I get the Created event on "New Folder", which I can handle.
My problem is that running the software differently localized Windows machines makes it impossible to check against "New Folder". How can I get the name of new folder as used by the explorer in the current language.
Thanks.
See these:
Find localized Windows strings
http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx
What you need to do is discover the "ID" of the string that is used for "New Folder"....then you can use LoadString to load it from the string table resource inside Shell32.dll.
However, the ID isn't necessarily stable and has changed between editions of Windows.
For instance...XP has the string table set up as follows:
http://www.askvg.com/customize-new-folder-and-new-shortcut-text-in-windows-xp/
On Windows 7 64 bit...the "New Folder" string has an ID of 16888.
You can try 2 different ways to do this ID discovery:
1. By discovering the ID of the "New Folder" string in advance on each edition of Windows you want to support
You would need to write a utility that just called this function on each English/US edition of Windows (XP, Vista, Windows 7, etc)...to find out the ID.
UINT new_folder_id = FindResourceStringId(shell_handle, L"New Folder", 0x409);
You can then do a switch inside your code that used the correct ID depending on the current version of Windows that is running.
2. dynamically at runtime
By looking up the "New Folder" string in the English resource to find its ID. However this would need the English MUI language pack to be installed on the system.
Use this C# code to load a particular "string" given a particular ID.
http://khason.net/blog/how-to-load-unmanaged-native-resources-from-managed-c-code/
To test if your code is working....you could install the MUI language packs and could then attempt to load the string for a different locale.
http://www.microsoft.com/en-gb/download/details.aspx?id=22108
http://support.microsoft.com/kb/972813
http://www.froggie.sk/7lp64sp1.html
http://technet.microsoft.com/en-us/library/cc766472(v=ws.10).aspx
Alternatively you could use SHChangeNotifyRegister to listen to changes made "in the shell"...Explorer calls SHChangeNotify when it does certain things.
Use the code here:
http://www.codeproject.com/Articles/3054/Shell-Notifications-in-C
Use the suitable flags e.g. SHCNRF_ShellLevel, SHCNE_MKDIR.

Categories