Notice: This site is no longer being updated!

For more recent posts, please visit my blog.

ControlBuilderFaq
   > Home
   > Search
   > About

Links
   > MSDN
   > ASP.net Forums

Search

Custom localization resource provider using an Access database
by Eilon Lipton
8/23/2005 11:30:07 PM

Localizing page content is now easier than ever with ASP.net 2.0 and Visual Studio 2005. In this article a sample localization resource provide that uses a database will be built. It works at runtime as well as in the designer to allow easy creation of resources.

Here is a sample page that uses all three declarative methods of binding to resources, as well a code-based method of accessing resources:

<%@ Page Language="C#" Culture="auto" UICulture="auto" %>

<script runat="server">
    private void Page_Load() {
        CodeBasedResourceLabel.Text = (string)HttpContext.GetGlobalResourceObject("MyGlobalStrings", "AnotherGlobalResource");
    }
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Resource Sample Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            Explicit local resource:
            <asp:Label ID="ExplicitLocalResourceLabel" runat="server" Text="<%$ Resources:ExplicitLabelResource %>"></asp:Label>
            <br />
            Implicit local resource:
            <asp:Label ID="ImplicitLocalResourceLabel" runat="server" meta:resourceKey="ImplicitLabelResource1"></asp:Label><br />
            Explicit global resource:
            <asp:Label ID="ExplicitGlobalResourceLabel" runat="server" Text="<%$ Resources:MyGlobalStrings, GlobalResourceString %>"></asp:Label><br />
            Code-based resource:
            <asp:Label ID="CodeBasedResourceLabel" runat="server"></asp:Label>
        </div>
    </form>
</body>
</html>

Download this sample page and resource files.

This sample works straight out of the box because ASP.net 2.0 ships with a standard ResX-based provider for reading resource files from disk. Although this solution works very well for many sites, often times the pages have to run against a pre-existing database that already contains resources. Using a database also allows for better maintenance and versioning of the resources. The solution to this problem is to write a custom ASP.net resource provider.

The Access database sample you can download is admittedly quite simple. There are several scenarios it doesn't support well and in some cases doesn't support at all. For example, the indexing of local resources is based strictly on filename, so the folder name is not used. The result is that if you have two files called Default.aspx in two different folders, their resources will conflict. Another scenario that isn't supported is a proper culture fallback mechanism. For example if the es-mx(Spanish - Mexico) culture is not available, it does not know to fall back to just es(Spanish - International Sort). Nevertheless these are features that could be added later if one desired to do so.

Download the sample Access localization resource provider.

Since the sample is relatively long (about 600 lines of code), only the key points will be addressed.

Starting with the runtime components, the provider follows a factory model. A ResourceProviderFactoryhas to be able to create two types of providers: local resource providers, and global resource providers. A new local resource provider will be created for each page that uses local resources, and a new global resource provider will be created for each global class key that is used. The resource providers' responsibility is to perform two basic tasks:

  1. Enumerate all known culture-neutral resources for the given store.
  2. Retrieve a culture-specific localized resources given a resource key and a CultureInfo object.

In the sample, this is implemented in App_Code\AccessResourceProvider.cs. All the runtime database code is located in App_Code\AccessResourceHelper.cs.

If you take the ASPX page seen at the top of this page and add the following data to the Access database, you should get the same results as you did before:

Although the Access database can be edited manually to add new resources, Visual Studio 2005 can also be used to pre-populate the database with culture-neutral resources. A design-time extensibility mechanism is available to serve this purpose. Although not available in Visual Web Developer Express, there is a Visual Studio menu item under the Tools menu called Generate Local Resource. This calls on the design-time resource providers and resource writers to add all the culture-neutral resource to the localization store. In this sample, culture-specific localized resource need to be added manually. The expectation is that eventually someone would write custom tools to manage and version the data in the database.

The design-time components follow almost exactly the same model as the runtime. In order to locate the design-time resource factory, the runtime factory has the DesignTimeResourceProviderFactoryAttribute attribute on it. Similar to the runtime factory, the design time factory has tobe able to create three types of objects: design time local resource providers, design time global resource providers, and design time local resource writers.

The job of the design time resource providers is the same as the job of the runtime resource providers. This is implemented in App_Code\AccessDesignTimeResourceProvider.cs.

The design time resource writer's responsibility is to perform two basic tasks:

  1. Create resource keys for arbitrary objects.
  2. Add resource keys and values to a resource store.

Visual Studio will use the design-time readers and writers to populate the resource store with the new culture neutral resources. It will also automatically add the UICulture="auto" and Culture="auto" attributes to the page directive to turn on browser culture detection. This is a particularly useful feature since it tells ASP.net to automatically set the culture of the request to be the user's browser setting. The user can configure this setting in Internet Explorer by clicking on the Tools menu, then Options, and selecting the Languages button.

To support this using the Access database, simply add additional rows to the Localization table and set the culturename column to the desired culture, for example es-mx for Spanish (Mexico).

The localization model in ASP.net 2.0 is already powerful straight out of the box, and with the use of custom resource providers its power is greatly enhanced. By abstracting away the actual storage and retrieval of resources, there is no reason not to use ASP.net's localization system.

- Eilon




Comments
The resource object with key 'GlobalResourceString' was not found.
by Kaan Öztürk
(Posted on 8/29/2005 2:25:00 AM)
"I get this error message when I fill the database like in the example and open the default.aspx.

"
Extending the Provider
by deedee
(Posted on 12/6/2005 5:49:00 AM)
Hello, this Example AccessProvider works like a charm, and even supports the auto-GenerateLocalResource Option in VS2005 (all localizable Controls are mapped in the db). Do you have any plans to extend the provider for the missing fallback-option and including the foldername or eventually supporting binary resources (images). I´ll try to convert the Provider for SQLServer and maybe add a Management Tool for the DB to add other cultures.
Thank you
by Sean Feldman
(Posted on 3/3/2006 12:21:00 PM)
The example was the only one I could find on the web. Thank you for doing an excellent example where MSDN failed to do so.
Thanks For This Great Example
by Brian C
(Posted on 3/27/2006 8:25:00 AM)
This example is exactly what I have been looking for. I have adapted it to work with an Oracle database and it works wonderfully. The only annoyance is, as the previous poster mentioned, that every global resource object produces an error at compilation time. Looking at the code, I think this is occurring because the GetObject() and ResourceReader() functions in the DesignTimeGlobalResourceProvider class were not implemented (they both return null). I would very much appreciate it if you could direct me to a resource that explains more about how the design time functionality works or if you could provide source code with these functions implemented. Thanks for providing this very useful example.
This is very good....
by Gord M
(Posted on 5/11/2006 5:57:00 PM)
"Great example.

As others have noted, there are no other examples as good or even close to this one (that I have found).

If you can provide any advice on how to debug the application it would be appriciated. I am trying to attach a debugger to the devenv.exe and can't seem to get anything worthwhile to happen. Should I just switch to logging debug statements or is it possible to debug interactivly? I figure you didn't write the code blind, so let us know if you have some tips? Hints?

Thanks again for the great example.
"
Object permanence and scope
by Tyrven
(Posted on 5/12/2006 6:11:00 PM)
"I originally implemented this using the SDK sample which explicitly caches the data at the page level using the Cache object. In looking for a fix to some other issues I came across your code and noticed that you don't explicitly cache your objects - and yet they appear to be cached according to the scope of the IResourceProvider objects (globally and locally respectively). Given this, my assumption is that your _resourceCache variable will persist as long as the application.

What I'm curious about is what establishes and manages these instances? My assumption is that this handled by the ResourceProviderFactory abstract class. Yes?

As I'm looking to publish a custom SQL resource provider on a high profile site I'm curious as to the mechanics of this. I've reviewed the SDK articles on each object involved but it's not clear at what level or what approach these use for managing scope. Perhaps you could give me some pointers?"
Remove Items from cache
by Ryan
(Posted on 6/7/2006 7:59:00 PM)
Does anyone know how to remove items from caching with this, whenever I change a resource, the items still stay cached for quite a while and the only way I can seem to bust it is to RESET IIS?
Translation to VB.NET
by Dirk
(Posted on 7/11/2006 2:43:00 AM)
"Hi,

i have translated it to VB.NET and now the Problem,
that the Resources only shows his names at Designtime
and not the values from the Access-DB.

Anyone on idea? Here my sources:
http://www.kemper.de/vb-version.zip

Dirk"
Object permanence and scope / Remove Item from cache
by John
(Posted on 11/12/2006 11:55:00 AM)
"Hi, i would also be interested in knowing how to make IIS reload these resources.

thanks
John
"
How to do it with the designer?
by jbmixed
(Posted on 7/16/2007 7:10:00 AM)
Hi, if you want to do it from tools->generate local resource, it does not nothing. Somebody knows what is needed to be done to enable this?
Compile Errors after converting C# to VB
by Dan
(Posted on 9/26/2007 3:48:55 PM)
I was able to convert the three sources in App_Code to VB, but I am getting errors (8) in the AccessDesignTimeResourceProvider and (2) in the AccessResourceProvider module during the VS compile.
Has anyone successfully used the VB version of this "Custom localization resource provider using an Access database"?
Errors when customize it for oracle
by Shakeel
(Posted on 4/29/2008 8:24:47 AM)
This is a nice article. When I customized it for oracle database by changing the AddResourceToStore function of DesignTimeLocalResourceProvider and GetResources function of AccessResourceHelper classes. But when I click on Tools->Generate Local Resources, it do nothing and also when I execute the site, Localization don't apply on pages, even CreateDesignTimeGlobalResourceProvider / CreateDesignTimeLocalResourceProvider don't be executed.

Any help will he highly appriciated.
Custom resource provider
by Murali
(Posted on 5/26/2008 3:05:45 AM)
Hi go through the following link, it will help u to design the better custom resource provider.

http://msdn.microsoft.com/en-us/library/aa905797.aspx
How to Debug
by liming
(Posted on 4/8/2009 5:55:31 AM)
Hello to all who is reading this blog:

On a related issue. I'm able to follow the example and modify it so the db is normalized and include fallback features.

Although it works, I would like to debug the design time class a bit, I tried Diagnostic.Debug.Writeln and Diagnostic.Debug.Trace, but I'm not able to see any messages in my "output" window nor "immediate" window.

At runtime (meaning when the website is running), I use log4net and what not, so log messages generates fine. I just can't get it to spit out anything at design time.

Any clues to it is greatly appreciate it.
Sql Server Modification
by Olivier Voutat
(Posted on 8/24/2010 6:40:11 AM)
Shakeel, did you finished adapting for Oracle? I've been trying to adapt it for Sql Server. When I click generate local resource, it looks which is my web.config class, since if it is wrong, it won't accept to execute the generation. But when it is right, it doesn't write anything to database and still creates the resource file.
doesn't work very well in compilation
by walter
(Posted on 3/22/2006 10:12:00 AM)
This is good example, but while I try to play with the code, I found particularly for the global resource, if I reference the global key prior to adding it into access database, I got a compilation error which is understandable. Note here is the problem, after I add it into database and compile , it still end up the same error. The only way to solve it is to restart the VS2005. The same situation also occurs when you perform compilation and add resource multiple times. This make me feel that only Microsoft can create a reliable provider :=). Not sure if you have a updated version. Thanks


Post a comment:
Name:  
E-mail:
(Optional; Will not be shown)
Title:
 
Content:  

(Maximum length 1000 characters. Newlines will be preserved, and HTTP URLs will become links automatically.)
Post Comment