Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

ResourceProvider Localization Sample posted


:P
On this page:

I’ve been talking for some time about about a localization provider I’ve been working on off and on for my session at ASP.NET Connections next week. I was finally able to post a small sample of what the provider does and what the admin interface looks like as part of my wwHoverPanel AJAX samples here:

 

www.west-wind.com/presentations/wwhoverpanel/sample/ResourceProvider/CustomerList.aspx

 

This actually worked out well as I can use the Resource Admin form both in my Intro to Ajax and the Data Driven Localization session <s>. Here's a screen shot of the Web based localization administration interface:

 

 

There's more information on the provider etc. that can be found here:

http://www.west-wind.com/tools/wwDbResourceProvider/docs/index.htm

 

The provider is a data-driven ASP.NET ResourceProvider and ResourceManager implementation against SQL Server data. It pulls data through a data layer into ResourceProvider. Building a ResourceProvider is pretty straight forward in ASP.NET although it’s not well documented – most of the code to implement a ResourceProvider is completely boiler plate and in fact there are only 2 data interface points in my provider code. The hard part I suppose is coming up with the ResourceProvider code that works in all situations both at compile time (ASP.NET uses the REsourceProvider at compile time to actually stick the Resource Expressions into the Control Tree code of the page both for Implicit and Explicit Resources) as well as at runtime.

 

ASP.NET internal resource access goes only through ResourceProvider, so in theory you can build a ResoruceProvider and be done with it but if you build a custom provider you may also need to access the Resources outside of ASP.NET pages. The ASP.NET ResourceProvider is only used by the page framework and as far as I can tell it’s not accessible outside of it even in the HttpPipeline. I also don’t seen anyway to indirectly get access to the Provider other than Control.GetLocalResourceObject() and Control.GetGlobalResourceObject(), so while the provider works well in that context it’s also limited in scope.

 

So in addition to implementing a ResourceProvider a ResourceManager implementation is useful so that the resources can be accessed in non-ASP.NET environments. ResourceManager implementation is a bit more complicated as there are a few more pieces to implement and the implementation is uh – shall we say non-intuitive because there are no explicit interfaces, but only a ResourceManager base class to inherit from. To override a REsourceManager you subclass the stock .NET ResourceManager and override key methods. This is a little better documented than the ASP.NET code and my .NET Internationalization Book has been helpful in this process. This book is very good for general .NET Localization principles, but really weak on the ASP.NET portion of things. Hence my efforts here <s>… Nevertheless I’ve found the book extremely helpful in getting up to speed on localization issues in general.

 

As it turns out I created two ResourceProviders: wwDbResourceProvider and wwDbSimpleResourceProvider. The main provider implements a custom ResourceManager that talks to the data access layer, while the simple provider simply uses the ASP.NET ResourceProvider interface and directly talks to the data access layer bypassing the ResourceManager. Operation of both providers is identical, however, the simple provider is slightly faster as it avoids the overhead of passthrough calls to the ResourceManager.

 

Performance

I’ve read a bunch of information regarding performance of custom providers/managers including a reference in the above book that seems to suggest that a data-driven provider is going to be slower than the stock manager/provider.

 

I ran a bunch of performance tests and I was very pleasantly surprised that using the databased provider incurred no performance hit at all when using the simple provider (in fact it was slightly faster than the stock ResX provider) and about 1.5-2% slower operation using the full ResourceManager based implementation.

 

I’m not surprised by this really – the way ResourceProviders and ResourceManagers work in .NET is through caching, so the database is realistically accessed only for initially retrieving resources – after that .NET manages the resources in memory via the cached resourcekeys retrieved. So initial hit might be different although I doubt it’s any slower to look up records from a database vs. reading resources out of a ResX file on disk. In any case, performance is not really an issue between providers. However I found that turning off localization altogether has a more signifant 5% performance increase for pure rendering purposes.

 

Even that is not all that significant IMHO. These tests were set up with control only pages so they don’t do any data lookups or other ‘heavy lifting’. In fact, even with providers hooked up I was running these pages with 35 controls on them at around 1300 requests a second on my laptop (Running IIS 7/Vista Intel Core-Duo 2ghz). Adding any data access to these requests are going to have way more of an overhead hit than any of these localization hits.

 

Interactive Resource Editing

Anyway, this provider I built is for a project that requires localization to be accessible to localizers and ultimately to the end-users (or rather admins) of to the application, so what was needed is a rich mechanism for finding localizable resources on a page and being able to edit them interactively through a Web interface.

 

The sample form I posted is a small example form that includes a wwDbResourceControl on the content page. This control is optional, but when globally enabled (via Configuration Section switch), the control causes each localizable control on a page to show an icon next to it. You can click on the icon and it takes you straight to the localization form and if the resource exists highlights it and allows editing it.

 

The form is meant to help easily see what translations exist and make it easy to save and add new values. The form is AJAX driven with my wwHoverPanel library and the wwCallbackMethod component. Without AJAX functionality this interface would have been pretty clunky so most of the updates occur over simple proxy page callbacks of the AJAX interface which makes the application fairly responsive. I was toying with using ATLAS instead of HoverPanel but given the recent Beta 1 debacle I sure am glad I stuck with my own custom control and didn’t break my code. <s>

 

The form provides an overall resource editing interface so you can edit, add, delete resources. The interface pops up additional ‘popup’ windows inline so it’s a very client centric form (although there are a few tasks that go back to the server). For example to Add a new resource a window pops up that lets you enter the new resource as well as upload file based resources. Similarily there’s a Translation option that goes out to Google  or BabelFish and provides a base translation option and lets you fill values.

 

Some of the more intrusive operations like deleting or renaming a resource set, and generating ResX based resources from the data resources post back to the server, but those requests are minimal.

 

A session at Asp.NET Connections?

I’m not exactly an expert at Localization – far from it. But I’ve been involved in a few projects that involve localization and I’ve found that for my own vertical applications it’s a tremendous asset to have a localization engine built into the application. I would say for several of my tools the number one question is how to localize the application. While in the past I’ve pointed people at ‘simply use ASP.NET Localization’ now there’s a better alternative. It’s also forced me to be a little more strict in terms of page layout to make sure that pages CAN be localized (ie. no static literals in text etc. <s>).

 

So, the session I’m doing at ASP.NET connections is not a typical Localization/Internationalization session in that I won’t be delving into every aspect of localization (heck that’s topic for a whole day’s worth of sessions <s>), but rather focus on the improvements in ASP.NET 2.0 and more specifically on the features that relate directly to creating custom resource providers. I’ll be talking about how resources are used in ASP.NET and then delve into how ResourceProviders work behind the scenes and how to implement one like the one shown in the demo. And the resource provider is of course provided so you can actually use the thing without fully understanding how it works.

 

So if you’re coming out to DevConnections this week, stop by the sessions (it’s a loony 8am session on Wednesday morning) and try to keep me from falling asleep…

 

I’ll be posting more information and probably download links after the conference next week.

 

Now if you’ll excuse me, I’ll have to pack for my red-eye flight this evening…

Posted in ASP.NET  Localization  AJAX  

The Voices of Reason


 

Marc Brooks
November 05, 2006

# re: ResourceProvider Localization Sample posted

Very, very cool, Rick. One gotcha for you to watch for (personal experience here), the Locale code in the database should NOT be merely five characters. Even in simple situations, that's not sufficient for Chinese/China, which is zh-CHT (for traditional Chinese)... and once you start seeing locale selections that include script-preferences, you can get things like "de-Latn-DE" (German, Latin script, as used in Germany).

Please consider lengthing the locald code to something around 16 characters or so...

Rick Strahl
November 05, 2006

# re: ResourceProvider Localization Sample posted

Hi Marc. Actually I was aware of that, but hadn't actually updated the database table width. The only requirement is supposed to be a valid LocaleId. I think 10 chars should be sufficient? I assume 7 would be the maximum (3 and 3 plus the dash).

Rick Strahl
November 05, 2006

# re: ResourceProvider Localization Sample posted

Well the fun was bound to be short: Some dickhead decided to delete the resource sets. <s> I suppose I'll have to keep people from wholesale deletions for the demos. <sigh>

Such a pain to see people always doing that with any demo. If there's a delete button surely somebody will go to it!

I'll add a button to restore the data, but i don't have much time to screw with this at the moment unfortunately.

Steve from Pleasant Hill
November 07, 2006

# re: ResourceProvider Localization Sample posted

A very fine and noble contribution!

Carl Olson
November 08, 2006

# re: ResourceProvider Localization Sample posted

Most excellent. Is the sample available for download? Yes, I'm being a code-leach :)

Adnan Masood
November 08, 2006

# re: ResourceProvider Localization Sample posted

Excellent presentation Rick, I'm posting this comment actually while sitting in the localization session at devConnections. You've covered a wide variety of topics pertaining to localization and its exciting to see the db provider model. Can't wait to get rid of these resx files and "empower" our BSA's to handle the string handling / localization.

Rick Strahl
November 13, 2006

# re: ResourceProvider Localization Sample posted

The sample and provider source are now available along with my slides from ASP.NET Connections here:

http://www.west-wind.com/weblog/posts/8746.aspx

Chetan Chaphekar
April 21, 2010

# re: ResourceProvider Localization Sample posted

Its working fine in aspx file but its not working if i place controls inside user control. please help me

Andreas
February 20, 2015

# re: ResourceProvider Localization Sample posted

Hi

The keynames seems case sensetive. Some strings in our application only show the keynames. And when we turn of the provider it all works. If we change the resource key name to match what is on the webpage it works.

Is there a way to turn case sensitive off?

Andreas

Rick Strahl
February 20, 2015

# re: ResourceProvider Localization Sample posted

@Andreas - Resource Managers and Providers are case sensitive so you have to match key names explicitly, since they are based on dictionary lookups. If you turn the provider off you're getting the default values you have in controls I'm guessing but it's not actually using any resources at all. Even Resx resources names are case sensitive.

In the database the key case sensitivity depends on the database character set settings. If you're using Sql server you can use a case insensitive character set which is the default.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024