This FAQ is not the only solution for simple localization, but i know this way works. I didn't test other configurations (i followed the microsoft recommanded steps)
1. How it works
The aim is to separate the display content from the application. Doing this will allow you to create or modify the culture content without compiling again your application project. Consequently without using .NET framework. The main principles are: - The localization files (.resx extension) are separated and sorted in a special folder that only contains localization files. The sort order is very important, as you will see later. - The Web application will detect the language selected by the clientÆs browser (Internet Explorer) - Only the default language is compiled with the application. This case is apart from the rest. - There is ONE resx file for each WebForm.
(Pasted from MSDN site) The hub and spoke model for packaging and deploying resources uses a fallback process to locate appropriate resources. If an application user requests a ResourceSet that is unavailable, the common language runtime searches the hierarchy of cultures looking for an appropriate fallback resource that most closely matches the user's request, and raises an exception only as a last resort. At each level of the hierarchy, if an appropriate resource is found, the runtime uses it. If the resource is not found, the search continues at the next level. The resource fallback process is described in the following steps.
- The runtime first checks the Global Assembly Cache for an assembly matching the requested culture for your application. The global assembly cache can store resource assemblies that are shared by many applications. This frees you from having to include specific sets of resources in the directory structure of every application you create. If the runtime finds a reference to the assembly, it searches the assembly for the requested resource. If it finds the entry in the assembly, it uses the requested resource. If it does not find the entry, it continues the search. - The runtime next checks the directory of the currently executing assembly for a directory matching the requested culture. If it finds the directory, it searches that directory for a valid satellite assembly for the requested culture. The runtime then searches the satellite assembly for the requested resource. If it finds the resource in the assembly, it uses it. If it does not find the resource, it continues the search.
- The runtime next searches the global assembly cache again, this time for the parent assembly of the requested resource. If the parent assembly exists in the global assembly cache, the runtime searches the assembly for the requested resource. The parent is defined as the appropriate fallback culture. Consider parents as best-fit candidates; providing any resource is preferable to throwing an exception. This process also allows you to reuse resources. You need to include a particular resource at the parent level only if the child culture does not need to localize the requested resource. For example, if you supply satellites for en (neutral English), en-GB (English as spoken in the UK), and en-US (English as spoken in the US), the en satellite would contain the common terminology, and the en-GB and en-US satellites could provide overrides for only those terms that differ.
- The runtime next checks the directory of the currently executing assembly to see if it contains a parent directory. If a parent directory exists, the runtime searches the directory for a valid satellite assembly for the parent culture. If it finds the assembly, the runtime searches the assembly for the requested resource. If it finds the resource, it uses it. If it does not find the resource, it continues the search.
- The runtime next searches parent assemblies, as in the previous step, through many potential levels. Each culture has only one parent, but a parent might have its own parent.
- If the culture that was originally specified and all parents have been searched and the resource is still not found, the resource for the default (neutral) culture is used. Note The default resource is the only resource that is compiled with the main assembly. It is the absolute fallback (final parent). Therefore, it is strongly suggested that you always include a default set of resources in your main assembly. This helps to ensure that exceptions are not thrown. By including a default resource file you provide a fallback for all resources, and ensure that at least one resource is always present for the user, even if it is not culturally specific.
- Finally, if the runtime does not find a resource for a default (neutral) culture, an exception is thrown indicating that the resource could not be found.
As an example of how the search for a requested resource is conducted, suppose the user requests a resource localized for Mexican Spanish. In accordance with the resource naming conventions described above, the runtime first searches the global assembly cache for the assembly matching the requested culture, "es-MX". Not finding it, the runtime then searches the directory of the currently executing assembly for an "es-MX" directory. Failing that, the runtime searches the global assembly cache again for a parent assembly reflecting the appropriate fallback culture ù in this case, "es" (Spanish). If the parent assembly is not found, the runtime searches all potential levels of parent assemblies for the "es-MX" culture until a corresponding resource is found. If a resource is not found, the runtime uses the resource for the default culture.
4. Organize your files
The naming convention of the files is very strict. If you do not follow the given recommendation, this may not work at all.
The default language files must be named this way: WebFormName.resx
The specific language files must be named this way: ApplicationName.WebFormName.language.resx
So in our example, if we have 2 WebForms called WebForm_A and WebForm_B this will make:
The last step but not the least: Do not forget to delete all generated .resx files that are created at the WebForm creation (and also when changinf WebForm desing content, the .resx is created again) (they are sometimes hidden by .NET Framework, to show them click ôShow all filesö and expend the menu of your WebForm). Delete the resx file, or you could have a conflict with your files. (Error oncompile)
5. Inside the ASP.NET Code
Here is the code to implement the detection of the language into your ASP pages. It has 2 parts: the Global.asax and the WebForm
5.1 The resx file
LetÆs say you have 2 labels in your form. In your resx file you will define the content of the label:
5.2 The Global.asax
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) Application("RM4WebForm1") = New System.Resources.ResourceManager(GetType (WebForm1)) 'ResourceManager for WebForm1 Application("RM4WebForm2") = New System.Resources.ResourceManager(GetType (WebForm2)) 'ResourceManager for WebForm2 End Sub
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) ' Fires at the beginning of each request ' For each request initialize the culture values with ' the user language as specified by the browser. ' DO NOT PUT this code in Session_Start or it won't work Try Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Request.UserLanguages(0)) Catch ex As Exception Thread.CurrentThread.CurrentCulture = New CultureInfo("en") End Try Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture End Sub
Request.UserLanguages(0) Retrieves the Language defined by the user. Thread.CurrentThread.CurrentCulture Sets the current culture for the session
5.3 The WebForm
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
' Get the ResourceManager from the Application object. rm = Application("RM4WebForm1")
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load InitializeComponent() Label1.Text = rm.GetString("Label1") Label2.Text = rm.GetString("Label2") End Sub
Explanations: You retrieve the content of the resx file with the function GetString("whatever")
6. Compile your resources into DLL without rebuilding your application
The aim of this documentation is to allow the modification of your resx files without touching your application. This is the hardest part. If the .dll files are not generated correctly nothing will work, and the default language will always loaded even if you asked for ôEnglishö for example.
Two tools will help you to process this: resgen.exe (stand for Resources generator) and al.exe (stands for Assembly linker)
First check that you named your files EXACTLY as described above. Then you will have 2 steps: - Transform your .resx file to a .resources file - Link all .resources files into a single .dll (one dll by language)
For those 2 tools, you will have to use the Open Visual Studio .NET Command Prompt.
Transform each .resx file into a .resources file this way: >resgen.exe [the resx file] For example: For the file named MyApp.WebForm_A.en.resx your command will be: >resgen MyApp.WebForm_A.en.resx And the result will be the creation of a file: MyApp.WebForm_A.en.resources
This part is a bit more complicated. You must select all .resources files contained into your language folder. In our example, the dll generation for English (en) will be:
Options: /t: tells that you want a dll /embed: repeat this option X times (one by file) /culture: this option specifies the language to associate with the dll /out: the name of the dll
The name of the dll will always be: Application_Name.resources.dll
6.3 Place the files
The negated dll must be placed this way : Go in the BIN directory of you application. You can see a folder for each language (if there is not the folder for your language create it, always following the naming conventions) Put your generated dll for English in the folder ôenö. Put your generated dll for English-US in the folder ôen-usö. Put your generated dll for French in the folder ôfrö and so on.
7. Tools that may help you
If you get an error, like: ½ Could not find any resources appropriate for the specified culture (or the neutral culture) in the given assembly. + a tool called ildasm.exe may help you. To use this tool: Always in the Open Visual Studio .NET Command Prompt.
Enter: + ildasm.exe your_dll_file.dll
This tool helps you in viewing the content of a dll. I recommend you to launch this tool for the .NET framework generated dll and one for your own, generated dll, so that you can compare the too versions. The most common problems are for ô.mresource publicö field in the manifest. If the field is not the same, itÆs because you didnÆt name correctly the .resx files (not good).