I am wandering if I use xml configuration files(like castle.windsors component xmls) to store my localization strings and messages instead of resources file for the sake of flexibility. I may need to change messages frequently and getting frequent builds freaks me out. As the size of document I can say that I will have a couple of thousands strings stored in multiple xml files according to the languages. Is it a good practice to do this that way?
You could implement this Globalisation system provided by MVP RIck Strahl should suit your needs nicely and provide a lovely interface at the same time - also uses a DB as backing storage rather than XML files which should be easier to generally keep track of with regard to backing up and such forth.
On NuGet here
https://nuget.org/packages/Westwind.Globalization
Here's the project page and a summary direct from it (See the Data Driven Localization Resource Provider section).
http://www.west-wind.com/westwindwebtoolkit/
Related
tl;dr Does strongly typed resource code generation work with normal (non-embedded) resources in App_LocalResources?
If not then why, and does the alternative of using embedded resources in satellite assemblies work with implicit localization?
The rest of this post just explains where I currently am in solving these questions, feel free to ignore it if you know the answers.
When using implicit localization (meta:resourceKey="Foo" syntax), I understand that one would need to write their own resource provider if one wants to embed the resources in satellite assemblies. The reason would be that ASP.NET always uses the default provider for these, and that this provider expects resx files in App_LocalResources that can be retrieved at runtime. Also see this question, which has no answer at the time of this writing.
If that assumption is correct, then it doesn't seem possible to use strongly typed generated classes (using ResXFileCodeGenerator) without writing such a provider (which we'd like to avoid doing), as enabling code generation requires the use of embedded resources.
Because the use of generated types appears to work perfectly fine for global resources, I want to question that second assumption:
If I can generate strongly typed classes for global resources (in App_GlobalResources using GlobalResourceProxyGenerator) without embedding them in a satellite assembly (Build Action set to Content as opposed to Embedded), then why can't I do the same for local resources? Why can't the generated code find and use the resx files in App_LocalResources?
Note that the exception thrown when attempting to do this is a System.Resources.MissingManifestResourceException containing the following message:
Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure
"PROJECT.App_LocalResources.PAGE.aspx.resources" was
correctly embedded or linked into assembly "PROJECT" at
compile time, or that all the satellite assemblies required are
loadable and fully signed.
I know that this message is misleading, as it clearly looks up satellite assemblies instead of trying the resx files (or whatever they're compiled to by the runtime, App_LocalResources.dll I guess).
If there is a good reason why this is not allowed (and we are thus forced to use embedded resources in satellite assemblies), is there a good implementation of a resource provider that can look up resources in satellite assemblies when doing implicit localization? Surely somebody has tried to do this before, and it doesn't sound like the application developer's job to tackle this kind of plumbing problem.
As a sub-question to the previous one, I also assume that when using embedded resources in satellite assemblies, one wouldn't put the resx files in the App_* directories, as these are special directories used by the runtime. Indeed, the resx files aren't even deployed, so the directories would be empty. Is that correct, and are there what would pass as best practices regarding this?
I suppose another way of formulating the question is: Can I make ResXFileCodeGenerator behave like GlobalResourceProxyGenerator when it comes to generating code that can load assemblies compiled by the runtime, as opposed to satellite assemblies compiled at build time?
Embedded resources can co-exist with ASP.NET Resource provider resources that live in the App_LocalResources/App_GlobalResources folder. But all the intrinsic WebForms localization features only work with the resources that are fed by the ASP.NET Resource Provider, which means the resources by default come out of the App_ folders only - not from embedded resources.
Embedded strongly typed resources do not use the ASP.NET Resource Provider - they use a stock .NET Resource Manager and when you use them you lose some of the optimizations that the ASP.NET ResourceProvider system uses vis a vis caching and loading of resources. It's more efficient in the ASP.NET scenario.
As you correctly point out it's possible to do this by creating a custom resource provider that reads embedded resources (or resources from another source such as a database), but you have to create this resource provider and hook it up. I wrote about this in an article some time ago (using a SQL database provider): http://www.west-wind.com/presentations/wwDbResourceProvider/
I wouldn't recommend mixing App_ folder resources from the Resource Provider with strongly typed resources because you'll end up with two different sets of resources loaded using different mechanisms. It works and can be done but it's just not very inconsistent. Pick one approach or the other. For Web Forms the resource provider model works better simply because it's the only way you'll be able to use implicit resources.
Note that ASP.NET MVC doesn't use the ASP.NET Resource Provider typically (although it could) and rather relies on strongly typed resources embedded into the code. If your WebForms code is mainly script based then using embedded resources might work well, but if you need to bind control properties the Resource Provider is the only way to go.
We're building an ASP.NET MVC application that is yet not localizable with a lot of Data Annotations DisplayAttribute with hard-coded strings and hard-coded message strings all over the code.
Now we have a requirement that the application must be localizable, but still, we need to allow the users to customize the field displays and the texts.
So far, I'm considering using RESX files with a custom IResourceProvider. Rick Strahl has written a good article about that. In this approach, the application is developed with standard RESX files, but in runtime, when the application need the strings, the custom provider will query the DB looking for customizations and will use them when found.
Even though it seems a good solution, it doesn't seem natural. I wonder if there's some better alternative.
Is there any standard for this?
What's not natural with using static values as defaults and checking database for localized ones? For me it's nice approach, because if someone will mess recources in db and, for example, remove one of them somehow, you'll always have a default text to display.
You can always do it in different way, by using only the db-based texts to not bother about changing defaults in your code and translations in database because it's easy to miss something when resources are in few places. When I was checking code of nopCommerce maybe 2 years ago, I've seen that when they do localization with resources from database only. I'm not sure how it's done now, but you can download source code and check it.
In WinForms app I developed a year ago I was using XML files for different languages because our customer wanted to be able to allow non-technical natives to create new language files. And I created localization tool built-in into app, but for websites it's best to use database, as you already have access to this and can easily manipulate data.
You can read more about this topic in this blog post.
At my office, we have had a long-standing debate about Localization/Globalization and how to handle it. One side pushes for the Resource (.resx) file route built in to ASP.NET, one side pushes for a database driven solution. A third group believes in rolling a custom solution.
Of course, each method has its own unique benefits and disadvantages - and we've discussed it over and over, without ever coming to a real consensus.
So, I pose it to the community: in your experience, which method provides the best mix of the following as the application grows:
Maintainability
Extensibility
Performance / Scalability
In addition to just advice, we'd also be interested in any open source projects which might help to simplify the question, as well. Thanks!
Rick Strahl (An MS MVP) has a great tool kit for managing localization via the DB - offer the ability to update and modify on demand through a controlled environment and does much of the heavy lifting for you. Histoolkit offer the following features:
Data Driven Localization Resource Provider
Database driven Localization lets you store resources in a SQL Server database.
Interactive Web based Resource Adminstration provides a live Web based adminstration for that can edit and update resources while the app is running
Resource Editing Control associates icons with each localizable control and allows jumping directly to the administration form with the current resource id and locale selected.
Resx Import and Export lets you import existing Resx resources, interactively edit them with the data driven provider, then export them back out as Resx resources.
Localization Utilities like a JavaScript Resource Handler, functions to embed localized script values and much more.
He also summarises the issues very well here (Ive pasted some good bits here - not my own work!)
To Resx or not to Resx
The default resource storage mechanism in .NET
uses Resx based resources. Resx refers to the file extension of XML
files that serve as the raw input for resources that are native to
.NET. Although XML is the input storage format that you see in Visual
Studio and the .Resx files, the final resource format is a binary
format (.Resources) that gets compiled into .NET assemblies by the
compiler. These compiled resources can be stored either alongside with
code in binary assemblies or on their own in resource satellite
assemblies whose sole purpose is to provide resources. Typically in
.NET the Invariant culture resources are embedded into the base
assembly with any other cultures housed in satellite assemblies stored
in culture specific sub-directories.
If you’re using Visual Studio
the resource compilation process is pretty much automatic – when you
add a .Resx file to a project VS.NET automatically compiles the
resources and embeds them into assemblies and creates the satellite
assemblies along with the required directory structure for each of the
supported locales. ASP.NET 2.0 expands on this base process by further
automating the resource servicing model and automatically compiling
Resx resources that are found App_GlobalResources and
App_LocalResources and making them available to the application with a
Resource Provider that’s specific to ASP.NET. The resource provider
makes resource access easier and more consistent from within ASP.NET
apps.
The .NET framework itself uses .Resx resources to serve
localized content so it seems only natural that the tools the
framework provides make resource creation tools available to serve
this same model.
Resx works well enough, but it’s not very flexible
when it comes to actually editing resources. The tool support in
Visual Studio is really quite inadequate to support localization
because VS doesn’t provide an easy way to cross reference resources
across multiple locales. And although ASP.NET’s design editor can help
with generating resources initially for all controls on a page – via
the Generate Local Resources Tool – it only works with data in the
default Invariant Culture Resx file.
Resx Resources are also static
– they are after all compiled into an assembly. If you want to make
changes to resources you will need to recompile to see those changes.
ASP.NET 2.0 introduces Global and Local Resources which can be stored
on the server and can be updated dynamically – the ASP.NET compiler
can actually compile them at runtime. However, if you use a
precompiled Web deployment model the resources still end up being
static and cannot be changed at runtime. So once you’re done with
compilation the resources are fixed.
Changing resources at runtime
may not seem like a big deal, but it can be quite handy during the
resource localization process. Wouldn’t it be nice if you could edit
resources at runtime, make a change and then actually see that change
in the UI immediately?
Using Database Resources
This brings me to storing resources in a
database. Databases are by nature more dynamic and you can make
changes to data in a database without having to recompile an
application. In addition, database data is more easily shared among
multiple developers and localizers so it’s easier to make changes to
resources in a team environment.
When you think about resource
editing it’s basically a data entry task – you need to look up
individual resource values, see all the different language variations
and then add and edit the values for each of the different locales.
While all of this could be done with the XML in the Resx files
directly it’s actually much easier to build a front end to a database
than XML files scattered all over the place. A database also gives you
much more flexibility to display the resource data in different views
and makes it easy to do things like batch updates and renames of keys
and values.
The good news is that the resource schemes in .NET are
not fixed and you can extend them. .NET and ASP.NET 2.0 allow you
create custom resource managers (core .NET runtime) and resource
providers (ASP.NET 2.0) to serve resources from anywhere including out
of a database.
As you perhaps know, default method (which is actually industry best practice) for Localizing .Net Applications is using resource files (.resx in this case). If you want to use database, you would have to write your own ResourceManager.
From this, the answer should be obvious: use standard and do not reinvent the wheel.
You might be wondering why Localization via resource files became industry-wide standard. Well, there are many reasons (too many to mention here), most of them regard to Localization process. The key one is, it is painfully hard to update (i.e. fix or install) translations for database driven Localization. Just think of what you need to install it - some SQL script. You know what will happen if you send out this for translation? Or even mistakenly update it? These kind of files are not very safe to work with (and they tend to be very large), so either you would need to create some kind of generator (with resource-like file as an input, which totally bits the purpose...) or you would need to be very careful (and pray that a translator won't break the file).
That is to say, database-driven Localization is sometimes the only sensible way of doing things - this is when you need to implement so-called dynamic Localization, that is allow users to translate things or add their contents in multiple languages.
For static Localization (typical scenario) use resource files.
Localizing user interface should not be stored in database, it is preferable to use the standard resx method because this will give you the flexibility to customize the user interface of front end for each client/deployment, without the need to change the back end or store much data about each client customization in database.
Regarding data (bi-lingual data or multi-lingual data) store them in database and use whatever technique suitable for the context (table per language, or duplicate columns for each language).
using resx is the best approach for some static values that needs not to be manipulated via UI of the app but if your values needs to be updated DB driven would be the best for it. For me its still a case to case basis. But one of the blogs I have seen in the internet made the resx files updateable via user interface.. http://sandblogaspnet.blogspot.com/2009/11/updating-resource-file.html.. hope this would help you.
As all the above are true, I want to add some additional insights.
I tend to use .resx based localisation, when working on "static" projects/websites like Dashboards or other small websites, which are focused on a specific usergroup.
When working on larger and more "dynamic" projects like shops, service-offerings, etc. (esp. when content is localized - not only labels) I like to use database localisation.
When you are developing on larger projects each language is maintained by another person, who is not necessarily in your project (especially in community-projects). Thus maintenance of different languages becomes a real hassle.
On the other side providing users some good/easy UI to update their language is time-consuming as well. So try to find a good path for your project.
Problem scenario:
Implement ASP.Net localization in a SaaS based application.
Additional complexity: The tenant should be able to edit the localized content. Thus, if the hosted application has 10 tenants with each supporting 5 languages, we could end up with 50 units of translation content.
Please suggest on what would be an ideal approach given the above scenario.
Listed below, are approaches used in the past (for my other applications) and why they are not relevant now:
Option 1:
ASP.Net resource files
Problem:
Only one language file is created per localizable resource (.aspx page). Hence, it is not possible to have one Home.aspx.resx file for each of the tenant translations.
Though the resx keys can be modified to contain the TenantId (lblFirstName_44) and stored in the same resx file, but then this would be difficult to maintain and we could end up with large files.
Option 2:
Storing multilingual content in dedicated database tables (Labels, Messages, MenuItems)
Problem:
This has worked well in the past (in scenarios where the end user requires dynamic update of localizable content). The earlier solution relied heavily on cached data, in case of a multi-tenant solution the data would require extensive caching per page – per tenant. The caching could also be done per content type (Labels, Messages, MenuItems)
An alternate approach could be to implement a custom resource provider (by building on .Net’s existing provider)
Option 3:
Third party open source solutions like FairlyLocal
Problem:
Although very simple to implement, suffers from the same drawback as .resx files – not designed for allowing the end user to modify the content and to maintain multiple versions (tenant-wise) of same file.
Note: In case of not finding another solution, we would probably go with Option 2
I'd go for the second option. Especially since your resource entries are subject to modifications, resex files are not an option as you have said.
. You can easily find a good resource provider such as westwind one or write a custom provider.
The first option (storing translatable texts into resource files) is out. This would result in totally unmanageable mess.
The second option (using Database) is the most promising, just write your own Resource Provider, implement DB logic and you are done. In case of multi-tenancy, you would also need to provide valid context (based on URL?) and fall-back mechanism (so if the resource key is not found for this tenant, it would use default string) but these are minor annoyances.
As for third-party solutions I haven't heard of one that could be used in your context. You would probably have to implement almost the same amount of code as in case of DB solution (to support multi-tenancy) but you would end up with having a dependency on some vendor - this seems less flexible to me (just think how you would fix bugs...).
The only option that sounds scalable and maintainable is to store localized text in database. Resource type could be a bit complicated to map (such as images) but still a better solution than either of the other two.
It makes me wonder, how come Microsoft did not think of a solution to this challenge specially with their Azure initiative.
We use resx files to localize our web applications. We usually create local resx files (that map to a specific page) when only one page uses a certain phrase, and a global resx file when more than one page needs the phrase.
But the good thing about global resx files is that they are a class, and you can call the phrases like you call properties of a class:
Resource.UI.iNotFound
So I was thinking - why have local resx files at all? why not use one global resx file for the whole application, and that way avoid runtime errors from calling non-existent phrases?
I'm sure there's a good answer for that, I just don't know what it is....
I kept on looking for guidelines, and found this in MSDN:
Choosing Between Global and Local Resource Files
You can use any combination of global
and local resource files in the Web
application. Generally, you add
resources to a global resource file
when you want to share the resources
between pages. Resources in global
resource files are also strongly typed
for when you want to access the files
programmatically.
However, global resource files can
become large, if you store all
localized resources in them. Global
resource files can also be more
difficult to manage, if more than one
developer is working on different
pages but in a single resource file.
Local resource files make it easier to
manage resources for a single ASP.NET
Web page. But you cannot share
resources between pages. Additionally,
you might create lots of local
resource files, if you have many pages
that must be localized into many
languages. If sites are large with
many folders and languages, local
resources can quickly expand the
number of assemblies in the
application domain.
When you make a change to a default resource file,
either local or global, ASP.NET
recompiles the resources and restarts
the ASP.NET application. This can
affect the overall performance of your
site. If you add satellite resource
files, it does not cause a
recompilation of resources, but the
ASP.NET application will restart.
So it seems that it's really up to the programming team to weigh the pros and cons of each method and choose what's good for them.
Joe90 - I have to say that in my experience, I can't agree that managing lots of local resource files scattered throughout your whole project is easier than managing one, global resource file. There is nothing to stop repetition of the same translations again and again and they are very difficult to track down. Access to the Global resource file is very easy to co-ordinate within a team and multiple users can see at a glance whether their required translation has already been done.
I started off with exactly the same policy as Lea - i.e. start with a local resource file and then move this to a global resource file if it was referenced more than once. This soon became loads of hassle to manage and I've since moved to using global resource files every time now.
There don't seem to be any clear guidelines by Microsoft as to what the best practice is, or even, how the two methods are implemented so that we can hazard a guess!
I'm guessing the comparison/payoff is that local resource files only require a recompile of the file they relate to, whereas changing a global resource file seems to require a recompile of the whole web site - with an inherent loss of session state etc. so requires taking the site offline during the update to be safe.
I have a development team of at least 10 developers on a single product and we are using one global resx for each site.
The problem with merging this big resx file should in my opinion not be a problem.
If you have 10 developers who themselves set the language on the site, how do you get a uniform way to express themselves on the site? Developers often tend to be good at code and not the grammatical expression. (I am a developer myself.)
A language expert should edit resx file and lock it for the developers!
A Global Resource file is the best method for translation. The key is use a naming convention, like page name abbreviations for the first few letters of a string name so that you can locate resources per web page basis easily. Trying to reuse many phrases across multiple pages will cause more confusion for the translators.
You can define resuable phrases as much or as little as you want, like Yes, No, BTN_OK, BTN_Cancel, QTN_AreYouSure, etc by using a lack of page naming convention (no page name abbreviations for the first few letters). The majority of your lines of RESX will be specific to each page and you should not focus on trying to reuse as much as possible. Changing one phrase across the entire file can be carefully done in minutes using text find/replace when needed.