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.
Related
I've got a few web projects that have alot of common code.
The common code even loads the website, in the sense that there is some MAIN.aspx page which all the websites load, and it uses the configuration file to determine what to show in a pre-designed place holders.
I'm trying to split all the projects (or at least new projects) into one common project with all the controls, common pages and common logic, and one project for every specific project.
The problem is that the main page will be located in the common project.
I found two solutions to the problem, but I don't like them:
Copy everything on build - I think that usually at one point or another, the copy function fails, and then the application won't update. Most developers on my team won't be able to debug that.
Use virtual directories to the common page - That might cause the project to load with different binaries, and also might cause it to use a different configuration file.
Is there a way to use some sort of reference for the aspx page itself, and then create some constant loader which will load the common code?
Is there some other design pattern that can help me solve that particular problem?
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.
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.
What are the suggested methods for using javascript files with MOSS 2007 ? in the 12 Hive somewhere or directly in the site's virtual directory in a scripts directory ? Or possibly as a embedded resource in a webpart ?
Personally, it all depends on what purpose the JavaScript files are going to serve. If they're going to be shared amongst multiple components then I would suggest placing them in the 12-hive. If however, they're going to be isolated to a single component - a web part for instance - then embedding them as a resource will work as well.
This article has a discussion about best practices for the deployment of web part resources which you may find useful, in concludes:
In this post, you have seen how to
both link to and embed Web Part
resources. Each has its own
advantages and disadvantages, mostly
boiling down to whether you need to
maintain the resource separately from
the Web Part. In both cases, the
resource file can be cached, so there
is little performance difference from
each option. Feel free to use one of
these two approaches for your next web
part.
I suggest you deploy these scripts in the 12-hive.
Having them in the 12-hive ensures fast access, which is important for scripts. You risk page rendering lag otherwise. More admin overhead as you must deploy them on all frontend webservers in your farm.
Having them in the content DB makes them more centrally manageble at the const of performance.
Mine where added to Sharepoint Designer in a folder I called "scripts" I think that puts it in the database.
We use a seperate scripts directory.
We use a similiar approach to images.
This allows us to share images and Javascript easily between our webparts, and custom applications which are available though Sharepoint.
This should also mean they're only downloaded once, and cached.
I am seeking some web architecture advice: I would like to know how to share common files, e.g. stylesheets, amongst web applicaitons that span virtual directories and many developers as opposed to having redundant files within each project? What are some recommendations?
It's somewhat hard to say, without knowing more about your web application.
Firstly, are you sure that you actually want to do this? One of your "many developers" could change the stylesheet, expecting it to only affect one application, and have it affect others. Things may end up even more messy with you having to create per-application stylesheets that override things in the shared one, etc. I'd consider these sorts of potential side-effects before going ahead with this.
But if you do actually want to do it, just host the stylesheet somewhere and have all the applications reference that location in their <link> or #import statements for it. There's no restriction that forces you to use a stylesheet from the same "site". If you want it to look nice, set up its own subdomain or something, like http://shared.whatever.com/css/styles.css.
Most source control solutions offer a method of sharing files between seperate projects. SourceGear Vault for instance.
This will allow you to manage your files (be they css, dll, or even images) in a single location and then any project that needs a set of files can link to those common files. The source control will pull them into the project but any time you edit them, it will update them in the common location.
You could create another virtual directory that contained the common/shared files and have the other web apps access them from there.