The Right Approach to Exceptions

Nick Sabalausky a at a.a
Mon Feb 20 15:33:08 PST 2012


"Jose Armando Garcia" <jsancio at gmail.com> wrote in message 
news:mailman.672.1329758926.20196.digitalmars-d at puremagic.com...
>
> This may not be D. Gettext says to solve it as follow:
>
> throw new Exception(gettext("Cool English message at
> %s.").format(DateTime.now()))
>
> The gettext "compiler" goes through the code an generates all the strings
> that need to be localized. The translation teams modifies those string and
> you store them in file/map for that language. At runtime the i18n library
> turns gettext(...) into a query into that map and returns the actual
> localized string. There is a map for the entire process.
>
> Localization can also be disable at compile time by making gettext a
> template and generating a "noop" for that operation.
>
> I have been thinking of making a module for i18n model after gettext but
> taking advantage of D's language features. Is there some interest in this?
>

I have some comments on that, but first a little story:

At a previous job with a company that shall remain unnamed, our flagship 
product was this VB6 thing that handled i18n by wrapping all strings 
intended to be seen by the user like this:

XLate("Hello, all ") + (UBound(customerArr)-LBound(customerArr)) + XLate(" 
of you suckers!")

For non-english users, that XLate function would then lookup the right 
localization for the given message. IIRC, any missing translation just 
returned the original english text.

This was the first time I had actually dealt with i18n, and yet I was pretty 
certain that was a completely moronic approach (not that it was a stretch to 
believe: there wasn't much going on at main sequence techn...errmm...I mean 
at unnamed company, that wasn't completely moronic).

I always felt it would be far better ("better" == "won't screw up everytime 
someone sneezes near the code" and "doesn't make certain things impossible 
to translate correctly") to have a statically-checked *identifier* that 
represented a particular message (and not message fragments, either). And 
then the user-facing string would be looked up via identifier and any 
appropriate values substituted in. A fairly obvious way to improve^Wfix the 
system, really.

Ok, end of story.

Your mention of gettext, and specifically a "gettext 'compiler'", does 
introduce a way that the same basic idea could be made to actually work:

Obviously, the big problems with XLate above are:

1. No way to make sure all messages actually *are* translated (or to prune 
unused translations).

2. Changing the english text embedded in the code will automatically break 
all translations.

3. It fails to handle cases where two inserted values need to be rearranged.

4. If two messages happen to have a common message fragments, the fragments 
will always be translated the same even if their differing context dictates 
they be translated differently

The issues #3 and #4 can obviously be solved by using only full messages 
with named placeholders and passing the substitution data into xlate(). So 
those issues are alredy out of the way.

By "gettext 'compiler'" I assume you're taking about some preprocessor. 
Probably appropriate for C/C++, but seems kinda sloppy, potentially error 
prone, and inefficient. Fortunately, D has kick-ass metaprogramming, so if 
you require all translations be compiled in (not sure how realistic that is 
in general), you could do:

xlate!"Hello world"

And then generate a compile-time error (or a mere notice) for all messages 
that are unhandled. Of course, if you're loading localizations at runtime, 
you could still do something similar and just throw a runtime error, or log 
a warning, etc., that lists all unhandled messages upon loading a 
localization. Or, hell, a hybrid approach: Compile-time errors for built-in 
localizations and runtime for the rest. Or generate a list of all messages 
when compiled with a special version(), which is then handed off to the 
translation team. All sorts of possibilities. That's all sufficient to solve 
#1 and #2.

Although there is still the other problem Andrei mentioned of over-eagerness 
(not an issue in the compile-time case, though).




More information about the Digitalmars-d mailing list