views:

390

answers:

2

Recently I was delving into Localization with .NET. Essentially, I learnt how to customize a form (using the Language and Localizable property) and then change the culture accordingly.

However, I found that when migrating my hard coded English strings into the auto-generated resource files, and use .GetString("Key") -- well, let's just say it wasn't happy :P.

I decided to make a separate set of resx files dedicated purely to the hard coded string translations. They followed the convention/requirement of [name].[culture-code].resx. I made of of these for each relevant language; e.g. appstrings.de.resx (For German) and appstrings.resx (as invariant baseline).

To utilise these new resources, I created an instance of ResourceManager and Resource Set

Dim resManager As New ResourceManager("LanguageTest.appstrings", Assembly.GetExecutingAssembly)
Dim resSet As ResourceSet = resManager.GetResourceSet(My.Application.UICulture, True, True)

The current UI culture was set (for example, to German) using

My.Application.ChangeUICulture("de")

Original issue

Unless the resSet.GetString("Key") is explicitly defined in the appstrings.de.resx, it will return a blank string. Is there anyway I can make it fallback to the appstrings.resx (where "Key" does exist), which I assumed would be the default baseline?

Update

Rhapsody made a suggestion below, while the actual tip itself didn't work, it did in-fact spark an interesting point, using resManager.GetString("Key") as opposed to resSet.GetString("Key"). This appears to work without flaw so far. That is, values present in the specialized language file are returned, while 'missing' values fall-back to the default culture when accessed by a single key.

Subsequent Issue

The only remaining issue would be whether the performance impact of using ResourceManger as opposed to a cached ResourceSet will be that detrimental?

+1  A: 

Try

Public Function GetString(ByVal Name As String) As String
    Return My.Resources.Strings.ResourceManager.GetString(Name)
End Function

Where Strings is the name of the resx files in your project. This will automatically return the baseline value when it's not available for the current culture.

It's an easy example, you might want to make it more fool proof.

Rhapsody
Unfortunately the 'appstrings' resources weren't present in the My.Resources namespace. However your code solution does raise an interesting point (see updated question) :).
Shadow
A: 

I once created a web application which had en-US as the fallback language but have other more specific ones like .de based on the settings in the users web browser

Basically to get it working I set the xml in web.config

<globalization uiCulture="auto" culture="auto" requestEncoding="utf-8" responseEncoding="utf-8"/>

From there I used the internal static ResourceManager from the .cs file which is provided with your default language, e.g.

Resources.<ResourceFileName>.ItemSearchNoResultsErrorText

and in .aspx files:

<%$ Resources:<ResourceFileName>, TimeSelect %>

As I understand it then it is significant where your .cs file which contains the ResourceManager class lives, is it behind the .de language file or the fallback language ? Since it's compiles as a seperate satellite assembly then it is depended on where the .cs class is compiled and what satellite assembly it is a part of.

As a rule I've always had the ResourceManager class as a code behind on the en-US language because that's the one I want to use as the fallback language if the more specific ones are not found

Using this setup I've never got a blank value, it's always used the fallback language, even though I swap out the satellite assemblies at runtime.

armannvg
I've read however that using the Resources namespace is costly (in terms of overhead performance). I've read that its better to create a separate resource set to cache the strings, thus improving performance.Rhapsody is on the right track with his answer. It's just a final detail that needs to be resolved (see the comment to that answer).
Shadow