Multilingual winforms application - c#

I want my C# (winforms) application to be multilingual. My idea is:
I will have my translations in some text file(s), each "sentence" or phrase will have it's unique ID (integer)
at the start-up of the app I will iterate through all controls on all forms I have in my app (I suppose this should be done in each form's 'Load' event handler) and I will test the control of it's type
i.e. if it is a button or menu item, I will read it's default 'Text' property, locate this phrase in one text file, read it's unique ID and through this ID will locate translated phrase in (other) text file
then I will overwrite that 'Text' property of the control with translated phrase
This enables me to have separate text file with phrases for each and every language (easy to maintain individual translation in the future - only 1 txt file)
I would like to hear from you - proffesionals if there is some better / easier / faster / more 'pro' way how to accomplish this.
What format of translation text file should I use (plain text, XML, ini....) - it should be human readable. I don't know if finding a phrase in XML would be in C# faster than going line-by-line in plain text file and searching for given phrase/string...?
EDIT - I want users (community) to be able to translate my app for them into their native language without my interaction (it means Microsoft's resources are out of the game)
Thank you very much in advance.
CLOSED - My solution:
Looks like I'm staying at my original concept - every phrase will be in separate line of plain text file - Unicode encoding (and ID at the beginning of the line). I was thinking about deleting ID's too and to use only the line numbers, but it would need advanced text editor (Notepad shows no line numbers) and if somebody accidentaly hits shortcut for "Delete line" and doesn't notice that, whole app would go crazy :)
//sample of my translation text file for one language
0001:Text of my first button
0002:Text of my first label
0003:MessageBox title text
...etc etc

Why not use Microsoft's resource file method? You won't need to write any complex custom code this way.

It sounds like you are somewhat invested in the "one text file" idea, or else you would probably lean towards the standard way and use Microsoft's resource files. Handling for resource files is built-in, and the controls are already keyed to support it. But, as you are probably aware, each translation goes into it's own resource file. So you are left juggling multiple files to distribute with your app.
With a custom, roll-your-own solution, you can probably trim it down to one unicode file. But you will have to loop through the controls to set the text, and then look up the text for each one. As you add control types, you will have to add support in your code for them. Also, your text file will grow in large chunks as you add languages, so you will have to account for that as well.
I still lean towards using the resource files, but your phrasing suggests you already don't like that solution, so I don't think I have changed your mind.
Edit:
Since you want the solution separated from the app to avoid having to recompile, you could distribute SQL-CE database files for each language type. You can store the text values in NVARCHAR fields.
That will make your querying easier, but raises the self-editing requirements. You would have to provide a mechanism for users to add their own translation files, as well as edit screens.
Edit 2:
Driving towards a solution. :)
You can use a simple delimited text file, encoded in Unicode, with a convention based naming system. For example:
en-US.txt
FormName,ControlName,Text
"frmMain","btnSubmit","Save"
"frmMain","lblDescription","Description"
Then you can use the CurrentUICulture to determine which text file to load for localization, falling back to en-US if no file is found. This lets the users create (and also change!) their own localization files using common text editors and without any steep learning curve.

If you want the users to edit the translations through your application while keeping things simple and quick, resource file is best. If you don't like it, the second best option is XML file.
Still, to answer you question on how to do it best with a text file, it is pretty straight forward: You just make sure that your unique identifier (int probably) are in order (validate before using the file). Then to search quickly, you use the technique of the halves.
You look for number X, so you go to the file's middle line. If id > x, to go to ΒΌ of the file, etc.
You cut in two until you get to the right line. This is the fastest know research method.
NOTE: Beware of the things that are external to the application but need translation: External file items, information contained in a database, etc.

Related

Merge Conflicts and Poor UI with .Net Resource Strings

Resource strings are quite irritating.
You have to copy the text into Notepad++ to edit them
Scrolling through large strings is near impossible
When you press F12 on a resource string reference, it brings you to the proxy to the resource store, but no way to edit, nor can you see the full text of long strings.
As more developers fill the list of resource strings, merge conflicts occur more and more on the XML resource files.
Is there a way to stop merge conflicts in the XML resource string files? Is there a better way?
You have to copy the text into Notepad++ to edit them
Visual Studio also provides an XML editor view for resource files. I use this almost exclusively over datasheet view. Give it a try.
Scrolling through large strings is near impossible
Probably easier in XML view.
When you press F12 on a resource string reference, it brings you to the proxy to the resource store, but no way to edit, nor can you see the full text of long strings.
I just use ctrl+F and type in the resource ID.
As more developers fill the list of resource strings, merge conflicts occur more and more on the XML resource files.
Merge problems are greatly reduced if all developers ensure that resources are added or inserted to the file in alphabetical order. We wrote a script to do it and put it into the automated build.
Also, consider organizing your resources into separate files for different purposes, e.g. control labels can go in one file and large text sections can go in a different file. This will reduce contention as well.
Yes, there is - code.
Create a separate static class, I like to suffix "Queries" if it's full of SQL, or "Resources" if it's more general.
In C#, you can use #"", that's enough, but the more recent $#"" is nice if you want to interpolate.
Example:
public class ApplicationStructureCacheQueries
{
public static readonly string ChangeOverNew = $#"
delete from ApplicationStructureCache
insert into ApplicationStructureCache
select * from #NewApplicationStructureCache
";
}
Code Control works very well with line-based coding languages (rather than structured data with multi-line associations - XML). You get the full power of your coding language to work with your strings, including inheritance if you need to (but make it a singleton object, instead of static reference), or perhaps an interpolating function, so it's nice and typesafe and cohesive.

String resource data in User Control .resx getting destroyed

I'm building a User Control using C#/Winforms and have struck a bit of an issue with localization.
I have added a number of strings to the resource file "inside" the user control, using the UserControl.resx file created automatically by Visual Studio. For the immediate term, these strings provide the Text values for the various buttons in the user control. I have tested this with location specific suffixes (ie, UserControl.zh-HK.resx), and all appears to work perfectly.
What I have found, though, is that the UserControl.resx file I am using gets wiped out, or cleared, at irregular intervals (I haven't nailed down exactly when it does and does not get cleared).
A big clue is that the IDE throws a message box when I attempt to edit this file. It says, in essence, that my changes may be lost. Experience has taught me that this is certainly the case.
For various reasons, the idea of having the resource file tightly coupled to the user control seems attractive. There are several of us, all developing user controls that are destined for the same product.
Is there any way to stop VS from smashing my string resources? Is there a better way, allowing for the fact that we want a separate set of resource files for each user control?
Thanks.
Long story short, everything I was doing was wrong.
In the end, what I have done is create a Resources folder in my project, with a separate set of resource files for each discrete component (form, user control, etc). Then in each component I retrieve the strings like buttonFoo.Text = Resources.UserControl.buttonFoo_Text.
This method seems to be working well enough for now and provides the separation of resource files that I wanted, while making the integration of the code from multiple sources semi-painless.

Reading from a text file and updating

I am new to programming and I came across a problem and I'm not sure how to deal with it.
I use the line
textBox2.Text = System.IO.File.ReadAllText(path);
To read from a text file and paste the contents in textBox2.
Now the issue is that the text file I'm try to read is a large (couple megabytes) text file. This text file contains logs from a program, new logs are always added at the bottom of the file.
Now I want to update textBox2 if the text file is updated. However I am not sure how to do this in an efficient way. One way is to just read the whole text file again, but since the text file is so big, this is a very slow process.
I am interested in finding out a different and faster way to handle this. I'm not really interested in the exact code, I just hoped to find out in what direction I should look and what options I can consider.
Well, two obvious things you could check:
The size of the file (FileInfo.Length)
The last write time (FileSystemInfo.LastWriteTimeUtc)
If you keep track of those, you should be able to detect when the file has changed - at least with a reasonable degree of confidence.
Additionally, you can use FileSystemWatcher to watch for changes.
Also, you might want to consider keeping track of where you've read to - so you could just read the new data, by seeking to the right place in the file.
Finally, a TextBox may not really be the best user interface for a huge log file. If this is a structured log file, it would be good to have that structure represented in the UI - for example, one row in a table per log entry, potentially with filtering options etc.
You can check every X seconds. If the file changed then update, if not, do nothing. You can keep the modification time of the file to know if it changed or not.

Proper localization of a WinForms application

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.

C#: How to bind the text of a winforms button to a resource

We have a resource file with lots of translated strings used various places in our application. Is there a better way for binding for example the text of a button to a certain string?
Currently we are usually just doing something like this in the constructor, in a Load event handler or in a method called by one of those:
someButton.Text = CommonTexts.SomeString;
someMenuItem.Text = CommonTexts.SomeOtherString;
Is there a better way to do it? Maybe in the designer? Or is this the recommended way of doing it?
Just to let you know how we do the actual translation: We have one Class Library project which only contains resx files. The main resx files are written in english (of course). We then open up those base resx files in an application called ResEx where we (or someone else) does the translation to other languages. When compiled Visual Studio automatically creates assemblies for each language which are used automatically depending on the current culture set. This works pretty well, so I don't really need info on how to do the translation and such (although I am always curious to improvements of course). What I am asking is if there is a better way for getting those translated strings from the resource assembly and into all the various Text properties.
I understand, it's an old question, but still, I had the same issue (VS 2010), and one of the first links in google is this topic.
In order to move all the texts to forms resource file - you need to set the winform Localizable property to True. And that's it. :)
(c) Cap. O.
You can do:
using System.Resources;
using System.Reflection;
Assembly assembly = this.GetType().Assembly;
resman = new ResourceManager("StringResources.Strings", assembly);
btnButton.Text = resman.GetString("ButtonName");
There is a good tool called LingoBit Localizer that does the job for the fraction of the time it would take to build all the reasources files.
You don't have to care about other languages while in development process, you simply code and set properties as you would if you were programming for a unilingual software. After you're done, or whenever you wish, you run LingoBit Localizer over your DLL or Windows Form application. This will get user-displayable strings out to a grid for you within its GUI. Now, perhaps a professional translator could use to translate the words if your programmers don't know the language for which the applicaiton have to be translated. Then, you simply save the project when you're done. This will create a DLL file which you simply add to your binary deployment directory, then your application will automatically set itself to the right language depending on the current culture information on which the app. is installed or so. This saves a lot of programming time and headaches.
Hope this helps even though it is not resource-based solution.
This will extract the the value of Home keyword and populate into the Text1 Box.
Text1.Text= Resource.Home.ToString();
Try this:
someButton.DataBindings.Add("Text", CommonTexts, "SomeString");
Your way is the best way to do this if you have developers who are not personally fluent in the languages you're translating your application into. I've done this before with an English application that had to be translated into Spanish, Portuguese and Chinese (I only speak one of these semi-fluently). The original forms were all created in English, and in the form's Load event the code iterated through every control and searched for each control's Text property in a translations spreadsheet, and replaced it with the appropriate translation.
The built-in way of internationalizing a form (which is basically a variant of form inheritance) assumes that the programmer is fluent in the language you need to translate to, which is pretty much of a stretch, and it requires you to manually enter all the translated text values for each form and each language. It also makes your binary larger (potentially much larger), since it adds a .resx file for each form for each language that you support.

Categories

Resources