Enhanced C#
Language of your choice: library documentation
Public static fields | Properties | Static Public Member Functions | List of all members
Loyc.Localize Class Reference

Localize is a global hook into which a string-mapping localizer can be installed. It is designed to make internationalization exceptionally easy for developers. TODO: expand I18N features based on Mozilla's L20N. More...


Source file:

Remarks

Localize is a global hook into which a string-mapping localizer can be installed. It is designed to make internationalization exceptionally easy for developers. TODO: expand I18N features based on Mozilla's L20N.

All Loyc code should call this hook in order to localize text (although as of June 2015, no one has made any translation tables). Use it like this:

string result = "Hello, {0}".Localized(userName);

If no localizer is installed, the format string is left unchanged.

Whatever localizer is installed will look up the text in its database and return a translation. If no translation to the end user's language is available, an appropriate default translation should be returned: either the original text, or a translation to some default language, e.g. English.

Alternately, assuming you have the ability to change the table of translations, you can use a Symbol in your code and call the other overload of Localize() to look up the text that should be shown to the end user:

string result = ((Symbol)"MY_STRING").Localized();
string result = @@MY_STRING.Localized(); // Enhanced C# with #useSymbols

This is most useful for long strings or paragraphs of text, but I expect that some projects, as a policy, will use symbols for all localizable text.

Localize.Formatter() is then called to make the completed string, unless the variable argument list is empty. It is possible to perform formatting separately, for example:

Console.WriteLine("{0} is {0:X} in hexadecimal".Localized(), N);

Here, writeline performs the formatting instead. However, Localize's default formatter, StringExt.FormatCore, has an extra feature that the standard formatter does not: named arguments. Here is an example:

...
string verb = (IsFileLoaded ? "parse" : "load").Localized();
MessageBox.Show(
"Not enough memory to {load/parse} '{filename}'.".Localized(
{Message}", "load/parse", verb, "filename", FileName));
}

As you can see, named arguments are mentioned in the format string by specifying an argument name such as {filename} instead of a number like {0}. The variable argument list contains the same name followed by its value, e.g. "filename", FileName. This feature gives you, the developer, the opportunity to indicate to the translator person what a particular argument is for.

The translator must not change any of the arguments: the word "{filename}" is not to be translated.

At run-time, the format string with named arguments is converted to a "normal" format string with numbered arguments. The above example would become "Could not {1} the file: {3}" and then be passed to string.Format.

Design rationale

Many developers don't want to spend time writing internationalization or localization code, and are tempted to write code that is only for one language. It's no wonder, because it's a relative pain in the neck. Microsoft suggests that code carry around a "ResourceManager" object and directly request strings from it:

private ResourceManager rm;
rm = new ResourceManager("MyStrings", this.GetType().Assembly);
Console.Writeline(rm.GetString("HEXER"), N);

This approach has drawbacks:

The idea of the Localize facility is to convince programmers to support localization by making it dead-easy to do. By default it is not connected to any translator (it just passes strings through), so people who are only writing a program for a one-language market can easily make their code "multiligual-ready" without doing any extra work, since .Localized() is no harder to type than string.Format().

The translation system itself is separate, and connected to Localized by a delegate, for two reasons:

  1. Multiple translation systems are possible. This class should be suitable for any .NET program, and some programs using this utility will want to plug-in a different localizer.
  2. I personally don't have the time or expertise to write a localizer at this time. So until I do, the Localize class will make my code ready for translation, although not actually localized.

In the open source world, most developers don't have a team of translators ready make translations for them. The idea of Loyc, for example, is that many different individuals–not one big team–of programmers will create and maintain features. By centralizing this translation facility, it should be straightforward for a single multilingual individual to translate the text of many modules made by many different people.

To facilitate this, I propose that in addition to a translator, a program should be made to figure out all the strings/symbols for which translations are needed. To do this it would scan source code (at compile time) for calls to methods in this class and generate a list of strings and symbols needing translation. It would also have to detect certain calls that perform translation implicity, such as IMessageSink.Write(). See LocalizableAttribute.

Public static fields

static ThreadLocalVariable< LocalizerDelegate > _localizer = new ThreadLocalVariable<LocalizerDelegate>(Passthru)
 
static ThreadLocalVariable< FormatterDelegate > _formatter = new ThreadLocalVariable<FormatterDelegate>(StringExt.FormatCore)
 

Properties

static LocalizerDelegate Localizer [get, set]
 Localizer method (thread-local) More...
 
static FormatterDelegate Formatter [get, set]
 Formatting delegate (thread-local), which is set to StringExt.Format by default. More...
 

Static Public Member Functions

static string Passthru (Symbol msgId, string msg)
 This is the dummy translator, which is the default value of Localizer. It passes strings through untranslated. A msgId symbol cannot be handled so it is simply converted to a string. More...
 
static string Localized (this Symbol resourceId, [Localizable] string message, params object[] args)
 This is the heart of the Localize class, which localizes and formats a string. More...
 
static string Localized (this Symbol resourceId, params object[] args)
 
static string Localized ([Localizable] this string message, params object[] args)
 
static string Localized (this Symbol resourceId)
 
static string Localized ([Localizable] this string message)
 
static string Localized (this Symbol resourceId, [Localizable] string message)
 
static string Localized (this Symbol resourceId, object arg1)
 
static string Localized ([Localizable] this string message, object arg1)
 
static string Localized (this Symbol resourceId, [Localizable] string message, object arg1)
 
static string Localized (this Symbol resourceId, object arg1, object arg2)
 
static string Localized ([Localizable] this string message, object arg1, object arg2)
 
static string Localized (this Symbol resourceId, [Localizable] string message, object arg1, object arg2)
 

Member Function Documentation

static string Loyc.Localize.Localized ( this Symbol  resourceId,
[Localizable] string  message,
params object[]  args 
)
inlinestatic

This is the heart of the Localize class, which localizes and formats a string.

Parameters
resourceIdResource ID used to look up a string. If it is null then message must be provided; otherwise, message is only used if no translation is available for the specified ID.
messageThe message to translate, which may include argument placeholders (e.g. "{0}").
argsArguments given to Formatter to fill in placeholders after the Localizer is called. If args is null or empty then Formatter is not called.
Returns
The translated and formatted string.

References Loyc.Localize.Formatter, Loyc.Localize.Localizer, and Loyc.Threading.ScratchBuffer< T >.Value.

Referenced by Loyc.Collections.Impl.CPByteTrie< TValue >.Add(), Loyc.Collections.MSet< Symbol >.Add(), Loyc.Collections.Impl.CPIntTrie< TValue >.Add(), Loyc.Collections.AListBase< K, T >.AListBase(), Loyc.Collections.Set< Loyc.LLParserGenerator.AndPred >.Find(), Loyc.Collections.VListBlock< T >.FindNextBlock(), Loyc.Collections.WListProtected< T >.IndexOf(), Loyc.Syntax.BaseParser< Token >.LaIndexToMsgContext(), Loyc.LLPG.Macros.LllpgMacro(), Loyc.MessageSink.LocationOf(), Loyc.Syntax.Les.Les2Lexer.ParseNumberCore(), Loyc.Syntax.ParsingService.ParseSingle(), Loyc.Collections.DList< Pair< LNode, int > >.RemoveAll(), Loyc.LLParserGenerator.LLParserGenerator.Run(), Loyc.Syntax.StreamCharSource.Slice(), Loyc.Syntax.Les.Les2Lexer.SupportDotIndents(), Loyc.Collections.CPStringTrie< TValue >.TryAdd(), Loyc.Collections.Impl.CPByteTrie< TValue >.TryAdd(), and Loyc.Syntax.Les.Les2Lexer.UnescapeQuotedString().

static string Loyc.Localize.Passthru ( Symbol  msgId,
string  msg 
)
inlinestatic

This is the dummy translator, which is the default value of Localizer. It passes strings through untranslated. A msgId symbol cannot be handled so it is simply converted to a string.

References Loyc.Symbol.Name.

Property Documentation

FormatterDelegate Loyc.Localize.Formatter
staticgetset

Formatting delegate (thread-local), which is set to StringExt.Format by default.

Referenced by Loyc.Localize.Localized().

LocalizerDelegate Loyc.Localize.Localizer
staticgetset

Localizer method (thread-local)

Referenced by Loyc.Localize.Localized().