>
 Friday, May 13, 2005
« Back to Basics: Relationship between Web... | Main | The Many New Faces of Visual Studio »

My latest globalization article is now live on The Server Side .NET, and I'm working on some new code samples for 2.0, for my upcoming talks at Tech Ed, so stay tuned for more updates on my globalization resource pages!

http://www.theserverside.net/articles/showarticle.tss?id=LocalizationPractices

5/13/2005 9:03 PM .NET | Globalization  | Comments [20]  |  View reactions  |  Trackback
Tuesday, May 24, 2005 5:08:53 PM (GMT Standard Time, UTC+00:00)
Hello,
I'm currently working with ASP.NET 2.0 to re-create one of our projects to have multi-lingual capabilities. I find pretty handy the fact that VS.NET 2005 generates the resources file per form automatically, however I've found some troubles while doing this generation.
I need to create static text content for some drop down lists. I put these resources in a global resources file and tried to access the resource unsuccesfully.
Here is what I did:
On the Global resources file I crated a resource for each item of the drop down list. On the drop down list I set the Expressions property for the DataText Field to be of type Resources (ie, Expression type: Resources), then on the ClassKey property I put the name of the Global resources file (App_GlobalResources, the name of the file is App_GlobalResources.en-US.resx) and on the ResourceKey the name of the resource (IndustryTypeItem).
My resources strings on the App_GlobalResources.en-US.resx look like this:
IndustryTypeItem1 All Industries
IndustryTypeItem2 Agricultural
IndustryTypeItem3 Industrial/Construction
IndustryTypeItem4 Outdoor Power
IndustryTypeItem5 Forestry
IndustryTypeItem6 Vehicles
IndustryTypeItem7 Recreational

Somehow the Explicit expressions are not properly generated and the drop down list shows and error on the Design View.
How can I troubleshoot this issue, is there a name convention that I'm missing somehow?
Thanks in advance,
Lizet
Tuesday, May 24, 2005 5:13:57 PM (GMT Standard Time, UTC+00:00)
I forgot to mention the error I get on the design view:
"There was an error rendering the control. Property accessor DataTextField on object industryType threw the following exception: 'Object does not match target type'"
Wednesday, May 25, 2005 3:02:05 PM (GMT Standard Time, UTC+00:00)
Nevermind to previous comments/questions, I finally found this site with the QuickStart app code and documentation:
http://beta.asp.net/QUICKSTART/aspnet/doc/localization/localization.aspx

Saturday, May 28, 2005 9:11:55 AM (GMT Standard Time, UTC+00:00)
Why not bind the dropdown list to an XML file, that is translated in appropriate resources. This way, you can just edit the XML file to add new values, and not have to touch the ASPX. This way, your resource fallback process will insure you get the correct XML file based on the current culture.
Monday, May 30, 2005 2:55:46 PM (GMT Standard Time, UTC+00:00)
Hrmmm, but the idea I got from the new meta:resourcekey="LocalResourceX" attribute and the implicit linking was that I didn't need any extra coding, that just by defining that LocalResourceX on each item of the dropdownlist, it would be automatically linked with the translated resource. So the translation team would just get this .resX files and do the translation.
It works now. It looks like before I had it linked (wrongly linked) to the global resource file and now I moved those dropdownlist items to the local resouce file. However, I would like to group most of my resources in the Global resources file (using just one file per culture in the web application would be a plus) This is a web app with several pages and it'll be hard to maintain if there is a resource file per page. Should I use the Explicit resource expression to link to the Global Resources always then? So the advantage of the automatic resource creation and linking is lost?
If I get your suggestion correctly, you would create an extra XML file for each list in the app and have an entry on the Global resource file for each of these xml files? I don't see how it could help, adding extra xml files to the existing resources.
Thanks for your reply,
Lizet
Lizet Pena de Sola
Wednesday, June 01, 2005 1:43:28 AM (GMT Standard Time, UTC+00:00)
Couple comments on the article. First, I can’t believe anyone anywhere would ever recommend (or even think of) the idea of having database tables named dynamically per-culture. To make matters worse, I’m pretty sure you are recommending keeping said table names in a resource file. Wouldn’t that then impose the user of such a model to exclusively use dynamic SQL? Whatever your feeling is of dynamic SQL, surely we can all agree that a localization “architecture” shouldn’t have such a profound implementation impact on the entire system? To boot, you didn’t give any examples or explore this in any detail. Frankly, this is a core issue with localization which simply cannot be omitted in an article which is ‘All about the architecture’. Please reconsider telling people this is “best practice”, for a far more flexible and elegant solution, take a look at: http://www.codeproject.com/aspnet/LocalizedSamplePart2.asp#databasedesign

While I haven’t played with localization features of 2.0 in great depth, I don’t believe they actually offer “strongly-typed resources”. All ASP.Net 2.0 offers is a strongly-typed resource manager and access to weakly-typed resources. I could be wrong, and I certainly hope I am. However, “strongly-typed resources” would imply that you could do: MyImageClass image= content.Login; and content.Login would return an “image”. As I understand it, resources are still either strings or binaries. If you want to localize the information about an image (height, width, alt, title, src) you’re SOL. Perhaps we are simply using different terminology, but if you truly can’t get a strongly-typed custom class, I would certainly advise, as best practice, against using the built-in resource manager.

Here are a couple more questions about 2.0. Is it easier to create custom cultures? Anyone who’s done real work on localization in 1.x should know that setting the thread’s UICulture is great, except for 1 thing…you are limited to supported CultureInfo types. Believe it or not, there are some unsupported cultures in .net. If you need to support such a culture (or ever plan on doing it), you’ll have to create your own culture (painfully). Alternatively you can create your own ResourceManager.

Another question, is the fallback/default culture still loaded with the main application assembly? If so does it still require a full recompile and deployment (app recycle in asp.net)? This can be costly for any shop that requires full/partial QA on any release.

It’s a shame controls still don’t support localization as first class properties. asp:literal resourceKey=”UserName” runat=”server” / is much considerably nicer than the %$ approach. What about handling substitution? For example, when your string is “Your password must be {minlength} character’s long”. Also for maintaining user’s culture information, it would be foolish to stray-away from the much-used (Microsoft.com) url rewriting approach.

So, to recap…specifically to your own work, I believe your data model to be of very poor design. As for the localization features in 2.0, I’d be interested to know if there’s a way to localize something other than a string/binary? How are unsupported cultures supported? Is a main-assembly recompile still necessary? And is there a way to set a control’s property declaratively other than %$ and support for substitution?

Yes, I’ve authored what I think is good best practice guide for 1.x at http://www.codeproject.com/aspnet/localization_websites.asp and http://www.codeproject.com/aspnet/LocalizedSamplePart2.asp much of the ideas come from the CommunityServer project…the ultimate best-practice guide. Unless 2.0 solves any of the real pitfalls of the resource manager and resource files, best practice will continue to be to not use it.
Wednesday, June 01, 2005 6:01:02 PM (GMT Standard Time, UTC+00:00)

"Couple comments on the article. First, I can’t believe anyone anywhere would ever recommend (or even think of) the idea of having database tables named dynamically per-culture. To make matters worse, I’m pretty sure you are recommending keeping said table names in a resource file."


I agree with Karl about that, we use a locate table version of the tables to be translated in our DB, and send the culture asa parameter of the stored procedurs we call, this way we can use the following construction on our SPs to get the translated strings we need:
select case when l.description is not null then l.description else q.description end as description
from default_table q left join default_table_locate l
where l.culture=@culture

In ASP.NET 1.1 I used to group all the application resources in a single file, to do this in ASP.NET 2.0 I should use Global_Resources then and Explicit linking the resources, correct? Are this resources compiled as satellite assemblies? or I should recompile the web app each time a resource is changed?
I think I'll figure that out as soon as I pass all my Local REsources to the Global Resources file, but just wanted to know if this is a recommended practice for 2.0

regards,
Lizet
Lizet
Friday, June 03, 2005 9:03:29 AM (GMT Standard Time, UTC+00:00)
Lizet, some comments:

"defining that LocalResourceX on each item of the dropdownlist"

This means you are buring the dropdownlist items inside a page, instead of loading them dynamically, leaving room for flexibility if you add new items. Would you rather edit the page directly, or edit a "data file" that contains the list? I think the latter.

"So the translation team would just get this .resX files and do the translation."

Well, the translation team would also edit your database, and XML files for example.

"This is a web app with several pages and it'll be hard to maintain if there is a resource file per page. "

2.0 makes it easier to generate local resources per page, and the story around managing runtime lifecycle of each resource manager is much better here...however I agree that there are not tools that make it easy to manage getting those individual resources to the translator. Sophisticated translation companies will have their own in-house tools to help with this, but if you are going the low-budget route, you'll have many individual XML files to manage.
That said, you'll spend the same effort organizing your project management initiatives around localization and translation for a few files, as for 100s of files. So, distributing the "right files" to the translator, and performing "merge" checks on those files as they are returned, would be automated in the same way for 1 or more files. Certainly fewer files might reduce the need to automate this, I don't dispute. So you have to ask yourself if the ability to generate page resources and leverage the resource management lifecycle now built-in to 2.0 is valuable enough for you to take extra steps on automating other tasks that simplify the management of many resource files.

"If I get your suggestion correctly, you would create an extra XML file for each list in the app and have an entry on the Global resource file for each of these xml files? I don't see how it could help, adding extra xml files to the existing resources."

I don't know the details of your application, and it sounds like you have lots of lists on each page. The question to ask is if those lists might change, or if they can be safely hard-coded into that page and draw from individual resources as you suggest. How much flexibility do you need around those lists? With 2.0 you can use XMLDataSource and use caching on it directly, to reduce the load of hitting the file system each request, to grab the list.

-Michele



Friday, June 03, 2005 9:57:06 AM (GMT Standard Time, UTC+00:00)
Karl,

"Whatever your feeling is of dynamic SQL, surely we can all agree that a localization “architecture” shouldn’t have such a profound implementation impact on the entire system?"

I'm not sure what you're seeing as a "profound" impact? First of all, when you plan your system, you actually DO have to think up front about localization, that means planning database structure, where data will be stored and how it will be accessed, patterns of access through the data access layer from the application, etc etc. I believe you had to think about that before you attached a CultureId to each of your tables? So, what is the difference between that mixed culture table approach and the separation of tables for culture?

"To boot, you didn’t give any examples or explore this in any detail."

Easy now, it is an article, not a book. I didn't state "best practice" a phrase I have come to dislike intensely, anywhere in my article. I simply use an example that relies on separate tables. I did not state anywhere that it was the ONLY way to design your database.

"Wouldn’t that then impose the user of such a model to exclusively use dynamic SQL?"

No, we are not tied to dynammic SQL exclusively with my recommended approach. I have read your article before, and you did a very nice job describing the pattern. This pattern means that you have mixed cultures per table, and this can work in many cases, but is not always an acceptable design. It depends on the amount and type of data you're working with. Remember that collation must also be set per row then, and this can be complicated by independent row settings.

I am not sure why you would recommend that it is always better to use your pattern for associating a CultureId field in every table. How is this any more flexible than having separate tables or entire databases? The entire query remains the same for my model, except for the specified table. This does not require a redesign of the entire system, any more than you must propogate the culture preference to the database. In fact, it is better decoupling to remove the knowledge of the user's preferred culture from the DALC or SPROC layer if you can.

Yes, 2.0 has strongly typed resources. Read my article on MSDN:

http://msdn.microsoft.com/asp.net/community/authors/mlb/default.aspx?pull=/library/en-us/dnvs05/html/asp2local.asp

I would like to address your other questions, but right now I'm heading off to Tech Ed. I'll come back to this when I have some more time.

"much of the ideas come from the CommunityServer project…the ultimate best-practice guide"

Well, I'm not sure I agree that the community server project is anythine near a best practice guide. It is serving a very specific need, that does not at all look like most corporate sites in terms of data storage and architecture requirements. Remember, there is no "ONE" best practice...only "better" practices for the situation at hand.

Friday, June 03, 2005 10:03:12 AM (GMT Standard Time, UTC+00:00)
Lizet,

"In ASP.NET 1.1 I used to group all the application resources in a single file, to do this in ASP.NET 2.0 I should use Global_Resources then and Explicit linking the resources, correct? Are this resources compiled as satellite assemblies? or I should recompile the web app each time a resource is changed?"

To access shared application resources, use App_GlobalResources and explicit binding <%$ Resources: MyGlobalResource, ItemName %>

You can deploy source (for your grandmother's site) or deploy precompiled site. Both will distribute code into many assemblies, and associated satellites. Assembly names are dynamically generated, and satellites are generated as well following the same subdirectory and naming conventions as in 1.1.

If you already have global resources to bring into your 2.0 application as you migrate, use them.

If you don't, use page resources to take advantage of automatic resource generation.

I need a more compelling argument to be convinced that page resources are that difficult to manage. Frankly I think it is just as difficult to manage localization process for 1 file as for 100 files...the process and automation is king.

Friday, June 03, 2005 2:22:39 PM (GMT Standard Time, UTC+00:00)
I hope we can talk more about this at TechEd. I know Michael Kaplan has a talk which will cover part of this. He is planning on talking about best-practice database design for localization.

I certainly don't want to say that there's only one way for all situations, but I really can't get past my vision of the implementation required for your approach (ie, dynamic sql). Say the current user's UICulture is "en-US" and you need to get all the products name/ids from the database, wouldn't your code look something like:

string tableName = tablesResourceManager.GetString("products");
string sql = "SELECT ProductId, ProductName From [" + tableName + "]"

Perhaps I'm missing something fundamental, but I just don't see how else you could do it. Even if you simply implied the table name from the culture, you'd still need to do something like:

"SELECT ProductId, ProductName FROM Products_" + @CultureName


The only alternative I can think of is to have huge if/else chains..

if @cultureName "en-US" begin
SELECT * FROM Products_en-US..
end else if @cu.....
...
end

Again, it can certainly be a limit in my own mental capability to come up with something clever :)

Something else of concern would be the maintenance aspect, changes to one schema need to be made to xxx tables. How do you split out globalized-specific information as to not replicate it, and how to deal with unique ids (guids?)
Friday, June 03, 2005 4:55:10 PM (GMT Standard Time, UTC+00:00)
Karl, good discussion. Would enjoy speaking with you at Tech Ed, in fact, I'll be at the internationalization cabana on Monday from 9am-11am, and myself and members of the localization team for ASP.NET have an advanced localization chalk talk style slot on Friday at 9am, also in the cabana area.

Regarding your question: using dynamic SQL...

In your first example, it is true I would be generating a query that builds in the table name based on the value retrieved through resource fallback. This code, however, should be encapsulated in a data access component that knows the user's preferred culture.

But, you could also use a stored procedure here, and make that selection based on resources or the current thread's culture as well.

No if/else...yikes!!!

Database schema changes are always a painful thing post deployment. Updates to the schema must be scripted to be reproducable for QA and production deployment, therefore the same script would be applied to all applicable tables, and the same code (data access layer) would be accessing these tables. Data access layer is always impacted by changes to schema (if you want to take advantage of new return values, in particular) but no other element of the application should be affected. Same goes for changing data access layer, if you modify it, the business logic tier will be impacted. Presentation is only affected if businesss logic tier is modified, again, which may happen once you take advantage of new features in lower layers.

I do believe that the choice of mixed row, separate table and separate database is truly application specific. If you are gathering information from users of all languages, chances are you store those in mix table rows. If you have large (millions of records) product databases that require translation, you are likely to use separate tables or even databases. It is all a matter of perspective on the application.

My example in the article was not focused on all of the perspectives for database design, it was focused on component architecture and ASP.NET.

Friday, June 03, 2005 6:17:34 PM (GMT Standard Time, UTC+00:00)
Michele,
"I need a more compelling argument to be convinced that page resources are that difficult to manage. Frankly I think it is just as difficult to manage localization process for 1 file as for 100 files...the process and automation is king."

I thought the versioning/deployment of the generated satellite assemblies would become a nightmare.

None of my grandmothers have websites, unfortunately, they had become good bloggers.

Lizet
Lizet Pena de Sola
Friday, June 03, 2005 9:04:34 PM (GMT Standard Time, UTC+00:00)
Michele,
"To access shared application resources, use App_GlobalResources and explicit binding <%$ Resources: MyGlobalResource, ItemName %> "

I always get an error when try to use that construction on my Source View, and end up using a literal:
"open tag" asp:literal runat="server" Text="<%$ Resources: MMLSiteMaster.master, Title %>" "/close tag"

Lizet

"open tag" = '<'
"close tag" = '>'
Lizet Pena de Sola
Friday, June 03, 2005 10:21:26 PM (GMT Standard Time, UTC+00:00)
Wow, my name was invoked and everything!

I should explain a bit about what Karl was referring to when he said:

"I know Michael Kaplan has a talk which will cover part of this. He is planning on talking about best-practice database design for localization. "

Karl may not be as happy with my talk as he thinks he will be -- most of what I talk about is *globalization* issues, rather than localization ones (his question that he sent to me was not specific to this particular issue being discussed here).
Sunday, June 05, 2005 3:11:37 PM (GMT Standard Time, UTC+00:00)
Hey Michael:
Yes, I might have misunderstood the specific topics of your session. I still think anyone reading this blog and attending TechEd would be grateful for the heads up about your presentation. Regardless of whether it discusses this particular issue, it should be worth while for those of us creating multilingual applications.

Karl
Monday, June 06, 2005 5:04:22 PM (GMT Standard Time, UTC+00:00)
Michele, Karl and Michael,
Is there a way we could get the DVD with the Globalization and Localization subjects from
the TechEd 2005? It looks like you will be covering pretty much what we need. I've been keeping track of some presentations so far, but a DVD with the entire collection will be more than helpful. I think there was a DVD issued from the TechEd 2003 event, would it be a similar one this year? Thanks in advance,
Lizet
Lizet Pena de Sola
Friday, June 10, 2005 4:55:01 PM (GMT Standard Time, UTC+00:00)
Michele,
Our team decided to develop and deploy the globalization project we have with VS 2003. Unfortunately, despite of the several advantages that VS 2005 has, the IDE would become unresponsive constantly and there are some other bugs that made us change our minds. So it was a decision to wait to the final release of VS 2005 to deploy any of our products with it. I don't know if we were extremely cautious here though. However we decided to supply one .resX file per page of the application to the translation team, from the project tracking perspective is a lot easier to follow up a resource file per form/per language than a main global one per language, so you were right about that. With the main global resource file, it is hard for the programmer to look for the particular resource name and for the project manager to keep track of what part of the application already supports Globalization.
I look forward to have the DVD with the conferences at Tech Ed 2005.
Cheers,
Lizet
Lizet Pena de Sola
Saturday, June 11, 2005 6:54:38 PM (GMT Standard Time, UTC+00:00)
Lizet, et al,

I do not think a specific DVD for Tech Ed will be focused soley on localization, however if there is a Tech Ed DVD it would certainly include all the content from the localization presentations. What I can do is create a blog entry with reference to Michael, Achim, Simon and my talks. I also did a live webcast from my talk, unfortunately my VPC was not behaving and the IDE crashed a few times...but we still got through most of it.

Let me see if I can get everyone's links for you.
-Michele
Monday, June 13, 2005 2:32:40 PM (GMT Standard Time, UTC+00:00)
Thanks Michele,
I saw the presentation online and asked some questions to the panel. I did miss the rest of the conferences on Globalization, so if you could gather the links it would be great! I truly appreciate it.
I know the DVD will have all the webcasts from TechEd. Although I'm focusing on Globalization now, the rest of the IT team at the company can benefit from the DVD as well.
Lizet
Lizet Pena de Sola
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

    ON THIS PAGE
    SEARCH
    CATEGORIES
    ARCHIVES
    BLOGROLL

Designed by NUKEATION STUDIOS