Based on a novel by Michael Ketting
MultiLingualResources attribute and classes
You can specify more than one
MultiLingualResources attribute for a class. Each attribute associates the class with a resource file.
If you derive more classes from the attributed class, you can combine the attributes along the line of ancestry. Resources for sub-classes extend the resources of their base-classes. Identical resource-IDs in sub-classes override those in the base-class.
The page, or user control, shall implement
IObjectWithResources as follows:
Usually this facility is provided in a common base-page, or a common base-user control. The derived pages or user controls only the
MultiLingualResources attribute is specified. If a base-class can be used, the implementation of
IObjectWithResources is stored in the corresponding code-behind files.
For accessing resources we recommend the
The utility iterates over the control hierarchy, starting at the control passed as a parameter, going up to the page if necessary. If
IObjectWithResources is implemented as part of the control or the page, the
IResourceManager will be queried and cached. Finally, the
IResourceManager objects of the control hierarchy will be combined and passed as a single instance of
Querying a resource entry (identified by
Res1 in this example) works like this:
For unique resource-IDs we recommend enumerating them, as in this example:
The enum can be part of a page or a user control or can be defined as "stand-alone".
The typical place where to put resources is into resource files identified by a
MultiLingualResources attribute. The demand outlined above for pages or user controls accessing the resource applies to resource-IDs as well: They shall be accessed via
The resource entry itself is identified by the enum value:
In the resource file itself the entry is identified by
- its namespace
- a class name
- an enum value
If an enum is not within a page, the following string is used as a substitute:
MyProject.ResourceIdentifiers.ID1. In other words, the resource-ID is composed of
- its namespace
- the enum type
- the enum value
You can derive a list of all resource-IDs defined with a
ResourceIdentifiersAttribute in a module with the resource summary utility. Xquestion
Defining global resources
If resources are required outside an ASP.NET page, you can use the global
ResourceManagerProvider is a singleton where you can register your implementations of
Registering global resources
The mechanics should be obvious from the following sample snippets. For
ResourceManagerProvider caches the registered
IResourceManager|s in a static hash-table, using the passed type parameter as key. Therefore
you should only register
IResourceManager s that don't change between post-backs. What's more, there should be no dependencies between those
IResourceManager objects, because hashing makes the order of evaluation unpredictable. For ASP.NET we recommend to register global resources through the
Accessing global resources
ResourceManagerProvider gives you the registered
IResourceManager implementations as a combined
IResourceManager object. Due to hashing, their order is unpredictable. Here is a sample code snippet:
The resource entry itself is identified by a string or an enum value, just as with page- or control-local resources:
By default, the
ResourceManagerUtility includes the
ResourceManagerProvider in the returned
IResourceManager instance. The global resources have the lowest priority of those, i.e. resources of a page or control can override them.
Multilingual ASP.NET applications
You can define resources for each control individually, for example the
Text property for a label. This requires the
facility. You specify the resource-IDs for a uniquely identified control on the page, for example:
The best place where to dispatch a resource is in the pre-render phase of the page. Sample code:
Defining resources for properties of the page itself is also possible, the page is simply called
this, as in
You can assign a resource to multiple controls (e.g. a validator message) by simply using its ID in the property's value. Examples:
It is usually more convenient to set the property in Visual Studio's designer; just use the resource-ID instead of the message itself.
In the resource file itself the prefix
$res is redundant and not allowed. For the example above, the ID is written as
RequiredValidationError in the resource file.
This feature is implemented by the controls themselves, not the resource manager. However, the controls in
Remotion.ObjectBinding.Web do support this feature.
The controls in the
Remotion.ObjectBinding.Web assemblies come with standart text for English and German. For those languages you need to localize only the field identifiers of your application.
A good place for localizing strings for other languages is in the resources for the
BasePage. A better place is in the globally defined resources. The IDs of the desired resources can be determined with the resource summary utility.
Selecting a language
For enabling the correct language for resources you must set the thread's
CurrentCulture is only used for formatting (dates, numbers, etc.) The culture should be set during the load phase (or earlier), otherwise complete coverage of all affected stages by the correct language cannot be assured. Sample code:
There are two ways to find out which language to select for the user:
- Provide options in the application (hyperlinks, user settings).
- Inspect the
UserLanguagescollection of the
Page.Requestobject. It holds the language selected in the user's browser.
If you don't set the culture in your code, the framework inspects the
globalization section in the
Web.config file. If no entry is found, the setting in the process is used as the default culture.