Proper localization of a WinForms application
Asked Answered
P

7

41

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...

Prophylactic answered 9/8, 2009 at 11:44 Comment(5)
Not so sure if you are asking for a 'proper' of for a 'very custom' way of localization.Weaponless
What's wrong with the "one .resx per form, one satellite assembly per language and assembly" approach? That's really the way .NET works - if you don't like that, you'll have to roll a lot of code on your own, I'm afraid.Hi
Wrong means that the "one .resx per form" (+at least one for all the stuff that is not part of a form) grows exponentially rather than linear, and one assembly per language is just additional clutter if new/corrected localizations are only allowed with new releases of the application. Also see redsolo.blogspot.com/2006/11/localisation-gone-wrong-in-c.htmlProphylactic
Well, this is the standard .NET way of doing things, and therefore, you have support for these things in the framework. If you want something completely different, you're on your own and you'll have to create a lot of "plumbing" software just to get what the .NET framework would have offered already. I think it's quite an undertaking, and I'd seriously reconsider if you want to spend all that time and effort on doing it "some other way"....Hi
@MichaelStum - technically it grows geometrically not exponentially. :) the number of languages is a multiplier, not an exponent. :) :) the REASON there is one resx per language per form is that for a specific language the form size may have to change, control placements may have to change, the icons may have to change, basically ANYTHING about the form may have to change on a per-language basis. So the RESX file has to multiply regardless. The strings are in the same file for that form as everything else specific to that form.Ency
A
19

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:

  1. Create all our forms and UI in the default language, English.

  2. 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.

  1. 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.

  2. 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.

  3. 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

Aloft answered 24/1, 2013 at 11:35 Comment(6)
Sorry, but I can't recommend this technique. It becomes a maintenance nightmare when fields need to be added, removed, or moved around on a form.Ropy
Sadly, for the most part this IS what the MSDN recommends for WinForms localization. :( msdn.microsoft.com/en-us/library/y99d1cd3(VS.80).aspxEncy
This is the Microsoft recommended way to do it and it's horrible.Broad
In the first step 1, you can determine your default (fallback) language by checking your neutral language setting. In a WinForms application, the default value for 'Neutral language" is "(None)". When localizing an application, you should change "(None)" to one of the many languages offered in the list box (e.g., "English (United States)".)Georgiegeorgina
@Ropy I don't get it. If you delete a field on a form, its corresponding resources are deleted. Same happens for renaming. I'm using this technique for an app that needs to support 3 languages (of which one is just the neutral language and won't be used). The only tedious bit is having to "select" the form and a language that you want to change localization for every time but it just works imo.Thibaud
@RenniePet, so what technique you recommend. From MarioDS info it seems this is really horrible way.Cut
H
4

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

Hi answered 9/8, 2009 at 12:1 Comment(2)
Well this software creates a satellite and the OP said he does not want any satellite files.Gree
Yes, I know - I was trying to show that maybe with the proper tool support, the satellite assembly approach wasn't so bad after all.Hi
G
4

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; 
Gree answered 9/8, 2009 at 12:18 Comment(0)
C
3

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.

Canna answered 9/8, 2009 at 12:6 Comment(0)
E
1

What you are asking for:

  1. no satellite resource files
  2. only one size and control placement per form.
  3. 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)

Ency answered 13/5, 2015 at 13:31 Comment(0)
D
1

The right way to do this is, suppose you want to add Arabic support witch is RightToLeft language:

  1. Double click the form
  2. Set localizable prop. to true
  3. Change Language prop. to Arabic //This will automatically open a new version of the form so you can customize.
  4. Set RightToLeft prop. to Yes
  5. Set RightToLeftLayout prop. to True
  6. Start renaming controls, and save the form.
  7. Handle Messages/Errors in code // Sorry I don't have a quick solution for now, try duplicate them and If/Else the current local.
Dixson answered 15/6, 2021 at 23:18 Comment(0)
K
0

Although this is a pretty old post, it's still very interesting. I came up with a solution for my project that in the end means very little effort and leaves the code of the controls free of localisation stuff...

Create an interface for everything that needs to be localized

public interface ILocalizable
{
    void Localize();
}

Now create sub classes of the controls you want to use (forms, buttons, labels, menues...) and let them implement the interface.

public class LocalizableForm : Form, ILocalizable
{
    public LocalizableForm() => Load += LocalizableForm_Load;

    private void LocalizableForm_Load(object? sender, EventArgs e) => Localize();

    [Browsable(true)]
    [Category("Localization")]
    public string? TextResourceKey { get; set; }

    public void Localize()
    {
        if (!string.IsNullOrWhiteSpace(TextResourceKey))
            Text = TextResources.ResourceManager.GetString(TextResourceKey);

        Controls.LocalizeCollection();

        if(IsMdiContainer)  
            MdiChildren.LocalizeCollection();
    }
}

This frees your actual forms from localization code since all you have to do is set the ResourceKey in the designer:

screeshot of Properties section in VS designer

At runtime the actual strings will be taken from the central resource files (TextResources.resx and TextResources.DE.resx in my case)

For convenience I added an extension method to call Localize() on elements in collections like sub controls or menu items

public static void LocalizeCollection(this IEnumerable collection)
{
    foreach (var item in collection)
    {
        if (item is ILocalizable localizable)
        {
            localizable.Localize();
        }
    }
}
Kahler answered 8/5 at 12:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.