Language strings

A

Alain Dekker

We've got a project that must support about 20 different languages. We're
doing this:
* Have a big Excel spreadsheet with all resource names, then columns for all
languages
* When one or more strings are updated, we run a VBA script which chugs
through the data and produces a "uif_strings.NN.resx" file (where NN is, for
example, "es" for Spanish); the VBA script handles correct XML formatting of
the strings (and works well)
* Each of these "uif_strings.NN.resx" files are added to the project as an
"Embedded Resource"
* At compilation, each resource compiles into a DLL in a sub-path such as
"es", filename PROJECT.resource.dll

Now I think I know what happens at runtime:
* When you load a string, you specify the current culture, say "es"
* .NET finds the resource DLL in the EXE-PATH\es folder, loads that DLL,
extracts the string and returns it

All good so far.

Due to an unforseen situation, the details of which are not relevant to the
question, I'd like to do something along these lines:

* Still have my "uif_strings.NN.resx" resource files added as an "Embedded
Resource"
* Instead of compiling to EXE-PATH\es\ChemLibrary.resource.dll, compile to
EXE-PATH\lang\Spanish.resource.dll
* At runtime, to obey .NET resource DLL paths, have a single folder called
"es"
* At runtime, if user selects "Spanish", then delete the
es\ChemLibrary.resource.dll file; copy the lang\Spanish.resource.dll into
es\ChemLibrary.resource.dll
* Continue as normal
* If user now selects "German", this time copy lang\German.resource.dll

Is this possible?

Alternatively, at runtime, instead of loading the resource in the official
..NET way from es\ChemLibrary.resource.dll, load the resource from
lang\Spanish.resource.dll. In this case, I'd need some way to compile the
resources into a custom path.

Is this possible?

Thanks,
Alain
 
A

Alain Dekker

Thanks Peter. You're probably wondering why I'd want to copy German
resources into the "es" folder. Regardless of why, I want to, for very good
reasons - I've inherited this project from the previous developer who
recently left and we are deploying to a Windows CE build that DOES NOT
SUPPORT CERTAIN CULTURES! If you set the culture to "zh" (Chinese) for
example, the application crashes. I currently trickt he system by telling it
the culture is "fo" (Faorese) but actually put Chinese strings into the
fo\ChemLibrary.resource.dll file. Hey, don't knock it, the system solves a
shortcoming of the system and it works.

We've now run out of supported two-letter cultures. While we are now taking
steps to get the Windows CE build corrected to include the required
cultures, its a bit late, really. We now have thousands of these machines
out in the field. Oops, indeed! I'd like to design a simply system which
doesn't involve the silly step of using Faorese for Chinese and is
future-proof against finding systems which DO support zh and DO NOT.

So back to my question, if I have my uif_strings.de.resx (German) Embedded
resource, is there any way to:
- Get VS to automatically compile it with CultureInfo="es" and NOT "de"?
[This is the key step]
- Copy it to another location other than de\ChemLibrary.resources.dll,
say lang\German.resource.dll? [This step is not critical - I can always
perform the required steps as a Post-Build step in VS]
- Alternatively, get VS to build the resource DLLs as normal (and create
that "de" culture DLL) but modify the CultureInfo of the DLL in some
Post-Build step in VS?

You mention it is possible to get the system to load the resource from
lang\Spanish.resource.dll (instead of the usual
es\ChemLibrary.resource.dll). Do you have any advise to go about doing that?

As far as I can see, the key step is to generate that German resource DLL
with CultureInfo=es, rather than de. Without achieving that, nothing else
will work.

Thanks,
Alain
 
A

Alain Dekker

Hi Peter,

Thanks for the response. Consider this possibility:

* At some stage in the future, a new Afganistani dialect get internationally
recognised, lets say, for argument sake its called Kandastani and its going
to get the code:
0x9999 (ka-KA, fo, Kandastani (Afganistan))
// Note: Just chose ka at random, hope I didn't get unlucky and choose an
existing one!

* Microsoft, Linux and all the other major OSes update to support the new
OS. But, for obvious reasons hundreds of millions of computers out there do
not support the "ka" culture

* Miraclulous economic advance in Afganistan mean many software companies
want to write software localised in Kandastani.

* Existing .NET applications based on anything up to current .NET 4.0 will
(as far as I know) crash when you ask for the OS to derive a new culture
based on "ka".

It might not be uber-realistic but it might happen. I'm in the situation
where this is happening (our existing Windows CE build that does not support
Chinese (zh) amongst other cultures).

I've now tried to write the custom build step to get around this and so far
I'm having some moderate success. I perform these steps:
* Take the uif_strings.NN.resx files out of the project (so that VS no
longer automatically builds them)

* As a post-build step, rename uif_strings.de.resx to uif_strings.es.resx

* Call
<PATH_TO_RESGEN>resgen
<PATH_TO_SOURCE>uif_strings.es.resx
<PATH_TO_OUTPUT>ChemLibrary.uif_strings.es.resources
(above all on one line)

* Call <PATH_TO_AL>AL.exe
/culture:es
/out:ChemLibrary.resources.dll
/template:<PATH_TO_EXE>ChemLibrary.exe
/embed:ChemLibrary.uif_strings.es.resources

* Rename ChemLibrary.resources.dll to GERMAN.resources.dll

* Repeat for all other cultures

I think there's still lots of testing / development to do but so far it
works. The only snag I've come across so far, is that once I've loaded the
es\ChemLibrary.resources.dll file, it resides in memory and cannot be
removed (for the next language to be copied there). Is there a way to unload
the DLL so it can be deleted?

Thanks again,
Alain

Peter Duniho said:
Thanks Peter. You're probably wondering why I'd want to copy German
resources into the "es" folder. [...]

No, not really. Your first post made it clear you didn't consider that
relevant to the question, so I ignored that question as best I could.
[...]
So back to my question, if I have my uif_strings.de.resx (German)
Embedded
resource, is there any way to:
- Get VS to automatically compile it with CultureInfo="es" and NOT
"de"?
[This is the key step]

Not as far as I know. I can't even imagine a reason why Microsoft would
spend time implementing such a feature in Visual Studio. It would only
encourage people to use the built-in localization support in weird,
non-standard ways.

But nothing is stopping you from implementing your own custom build
process
that builds localization DLLs however you want.
- Copy it to another location other than
de\ChemLibrary.resources.dll,
say lang\German.resource.dll? [This step is not critical - I can always
perform the required steps as a Post-Build step in VS]
Ditto.

- Alternatively, get VS to build the resource DLLs as normal (and
create
that "de" culture DLL) but modify the CultureInfo of the DLL in some
Post-Build step in VS?
Ditto.

You mention it is possible to get the system to load the resource from
lang\Spanish.resource.dll (instead of the usual
es\ChemLibrary.resource.dll). Do you have any advise to go about doing
that?

Yes. Write your own resource manager from scratch.
As far as I can see, the key step is to generate that German resource DLL
with CultureInfo=es, rather than de. Without achieving that, nothing else
will work.

Sounds like you've got your work cut out for you.

Pete
 
G

Gene Wirchenko

[...]
* Existing .NET applications based on anything up to current .NET 4.0 will
(as far as I know) crash when you ask for the OS to derive a new culture
based on "ka".

Programs only crash when they have bugs in them. If you're not catching an
exception that can happen, that's your fault.

I have seen programs crash due to an error in the processor. The
firmware for the machine language was incorrectly changed (for a type
of branch instruction IIRC), and this resulted in many programs
written in PL/C to crash.

This was in the 1970s at the University of British Columbia.

[snip]

Sincerely,

Gene Wirchenko
 
A

Alain Dekker

Hi Peter,

Try this on the standard desktop version:
CultureInfo m_currentCulture = new CultureInfo("zz-AB"); // Not a real
culture

The application will crash. Sure, you could put that (and everything else)
inside a try/catch block, and thats a fair point, but its still a crash.

The application developer might be developing on the full-blown version of
Windows XP, say, and would expect (to take an example) Vietnamese "vi" to be
supported. The software passes through multiple tests. The code happens not
to be enclosed in a try/catch block (at least not one that captures control
in the vicinity of the crash).

Now the application is deployed to a Windows XP Embedded system and due to
some error / oversight / cost-cutting / lack of sleep due to crying child,
the person who built the XP Embedded build did not include the "vi" culture.

That software that went through multiple tests and passed them all with
flying colours will now crash and burn back to the OS. Maybe you blame the
developer, maybe you blame the tester, maybe, maybe.

Now, lets say your software has never supported Vietnamese and there are now
thousands, maybe tens of thousands, of your systems out there on systems
that do NOT support "vi". Now you need to support Vietnamese. What are you
going to do? Blaming the developer or anyone else is not going to help.
Putting a try/catch block around the "new CultureInfo("vi");" call might
help you display English resources and prevent a catastrophic crash, but it
isn't going to solve the problem.

The developer has to come up with a workaround. The standard .NET satellite
assembly method will not work.

Thanks for the suggestions on workarounds. I will be implementing and
testing one or more of them.
Alain
 
A

Alain Dekker

Hi Peter,

I made the mistake of overstressing the "crash" aspect in the reply. Its not
about the crash - thats a triviality. Its about how you're going to support
Vietnamese on systems where asking for the "vi" culture doesn't work in the
standard .NET way.

It comes back to the example:
* You've got thousands of systems where the OS does not support "vi"
* You've never tested for "vi" before, it just wasn't thought about
* You've got tonnes of code that relies on the standard .NET method for
displaying localised strings
* How are you going to show Vietnamese?

Not a trivial problem to solve.

Thanks again,
Alain
 
A

Alain Dekker

And again: when you use .NET for localization support, you do so with an
implicit agreement that you will not support languages that .NET doesn't
support.

True. As with most developers, experienced or not, you check your code and
others' code for ideas, trawl the web, go through examples on the MSDN
website or in the VS IDE itself. As you gain experience, you do this less
often, but programming is a vast and complex field and I'm sure all
developers need to do this every so often.

Looking for examples on string localization in .NET (a technology that I am
learning more all the time) I can find no examples other than the standard
..NET way. There isn't even a hint anywhere in the ".NET satellite
assemblies" or "String Localization" documentation on MSDN or elsewhere I've
seen about doing it in any other non-standard way. As I've discovered from
these forums and elsewhere, simply asking about doing it in a non-standard
way tends to get the default response of "Why would you want to do that?"
with an implication along the lines that you're probably not a very good
programmer.

Do you happen to know of a good code example showing how to load strings
from a resource container like a DLL, perhaps using an AppDomain, or
something like that?

Regards,
Alain
 
A

Alain Dekker

Hi Peter,

Thanks. Yes, at this point, I do not intend to run any code in the satellite
assembly, just extract localised strings. Right now, they're just simple
repositories. At some stage that may expand.

I'll check out that references and thank you again for your time and help.
It is very much appreciated.

Regards,
Alain

Peter Duniho said:
[...]
Do you happen to know of a good code example showing how to load strings
from a resource container like a DLL, perhaps using an AppDomain, or
something like that?

No, not off the top of my head. However, you should look at the
documentation for the System.Reflection.Assembly and System.AppDomain
classes for relevant information.

In the Assembly class are members that allow you to discover and retrieve
resource data from an assembly. In the AppDomain class are members that
allow you to create new AppDomain instances, into which you can load
Assembly instances (so that you can unload them later if you want).

I have used these classes myself. My recollection is that while there are
one or two places where cross-AppDomain security issues complicate issues,
the documentation is reasonably clear and any issues are surmountable (in
fact, you may not run into them at all, since you're not likely to
actually
be executing code in the localization-specific AppDomain).

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top