Introduction
The .NET framework provides support for localization. Localization deals with customizing data and resources for specific culture or locale or language. Supporting localization is important for an application if the application is required to be customizable based on the respective culture.
Here I am going to talk about two ways of implementing and accessing resources that you can use and access from the current running assembly. The resource files should be added and administered from outside the scope of the running assembly and should not form a part of the assembly.
This approach is helpful because the resource file is generated outside the building process of an application. It provides flexibility in terms of externally creating the language-specific resource, and adding it to the executing assembly without compiling the current project.
The Approach
The two approaches are:
- Creating a satellite assembly for culture specific resource file and using it in the executing assembly
- Creating a file based resource manager which enables accessing and reading a resource file from a location outside the assembly manifest
Let us now see these two approaches in detail.
-
Creating a satellite assembly for culture specific resource file and using it in the executing assembly
The .NET framework uses the hub and spoke model for packaging and deploying resources. The hub is the main assembly that contains the executable code, and the resource for a single culture. This culture, called as neutral or default is the fallback culture for the application. Each spoke connects to a satellite assembly that contains the resource for a single culture, but does not contain any executable code.
Steps for creating a satellite assembly to include the resource file in your application:
- Create a default resource file at the root level of the application.
Let�s say, MyApplication is the application name and MyResource.resx is the default resource. MyResource.resx is called a default resource because this is the resource file that .NET runtime will look for, if there are no language-specific resource files available.
To create the above mentioned resource file using Visual Studio .NET, highlight a project and add a new item of type "assembly resource". Name the assembly resource as MyResource.resx. This will create a resource file with .resx extension.
- Create satellite assembly outside the project manifest.
I will explain how to create a satellite assembly for UK English culture (culture name:en-GB), in the following steps:
- Create a resource file and name this resource file as MyResource.en-GB.resx.
Run resource generator utility on this resource file by using the Visual Studio .NET command prompt. The command for generating a .resources file is:
Resgen MyResource.en-GB.resx
This will create a binary version of the above resource file named, MyResource.en-GB.resources.
- Run the AL (Assembly Linker) utility to generate a satellite assembly from the resource file generated in the previous step (Step a). The command for generating a satellite assembly looks like as below:
Al.exe
/t:lib
/embed: MyResource.en-GB.resources,
MyApplication.MyResource.en-GB.resources
/culture:en-GB
/out:MyApplication.resources.dll
The explanation of the above command line is as below:
/t:lib: indicates that you intend to create a .dll.
/embed:MyResource.en-GB.resources,MyApplication. MyResource.en-GB.resources: Embeds and renames the resource to a name that matches the naming structure of Visual Studio IDE.
/culture:en-GB: Indicates the intended culture
/out:MyApplication.resources.dll: Indicates the name of the output DLL. The resultant DLL (MyApplication.resources.dll) should have the same naming convention to locate it.
- Place the created satellite assembly in the en-GB folder inside the bin directory of your application directory.
The directory structure should look like as below:
\MyApplication\bin\en-GB\MyApplication.resources.dll
Note that you may need to create the en-GB folder inside the bin directory. You can create as many satellite assemblies as you like and place them in the bin folder of your application, under respective culture-specific directories.
Now that we have created a satellite assembly and copied it in the bin folder of the project root directory, we are ready to use this assembly to read the resource text from the resource file.
Following namespaces will be required for the code snippet written below:
using System.Reflection;
using System.Resources;
using System.Globalization;
To read from the resource file, we need to create an instance of the ResourceManager
with the default resource name and current executing assembly, as shown below:
ResourceManager resmgr = new ResourceManager("MyApplication.MyResource ",
Assembly.GetExecutingAssembly());
Note that MyApplication is the name of the application and MyResource is the base name of the resource file.
To read a value from resource file, GetString
method of the ResourceManager
is used, as shown below:
string msg = resmgr.GetString(messageId,ci);
Where,
messageId
is the name of the key for the intended value in the resource file.
ci
is the CultureInfo
indicating the intended culture specific resource.
Let's assume we need to read the UK specific (en-GB) resource file for which we have created a satellite assembly and placed it in the appropriate directory. The CultureInfo
can be instantiated as below:
CultureInfo ci = new CultureInfo("en-GB");
If the runtime fails to load or locate this culture specific resource, it will read the intended resource text from the default resource (MyResource.resx) as discussed in Step 1 above.
-
Creating a file based resource manager which enables accessing and reading from a resource file from a location outside the assembly manifest
This approach is helpful when we need to keep the resource files at a separate location, isolated from the project manifest, and still want access to the culture specific resources from the current assembly.
Steps to include resource file in your application from outside the project manifest:
- Create a default resource file using Visual Studio .NET IDE.
Let�s say, MyResource.resx is the default resource name. MyResource.resx is called a default resource because it is this resource file that .NET runtime will look for, if there are no language-specific resource files available.
To create above mentioned resource file using Visual Studio .NET, highlight a project, and add a new item of type �assembly resource�. Name the assembly resource as MyResource.resx. This will create a resource file with .resx extension.
Similarly, create the resource file for intended culture. Let�s say, you need to create a resource file for UK English culture (culture Name: en-GB). Create this resource using Visual Studio .NET IDE and name it as MyResource.en-GB.resx.
In the same way you can create other culture specific resource files with same naming convention.
- Create .resources file from .resx file created in Step 1 above.
Run RESGEN utility on this resource file by using Visual Studio .NET command prompt. The command for creating .resources file is as below:
Resgen MyResource.resx
This will create a binary format of the resource file named MyResource.resources
Similarly, create .resources for all culture-specific .resx files.
For e.g. Resgen MyResource.en-GB.resx
will result in MyResource.en-GB.resources file.
Important: It is very important to follow correct naming convention for creating resource files, as it forms the base for the runtime to locate the correct resource file. These resource files have a specific naming structure as:
<resource file basename>.<culture>.resources
- Keep all .resources files at the same location, e.g. C:\Program Files\ResourceSet
The path for MyResource.resources will be:
"C:\Program Files\ResourceSet\MyResource.resources"
Similarly the path for MyResource.en-GB.resources will also be:
"C:\Program Files\ResourceSet\MyResource.en-GB.resources"
Following namespaces will be required for the code snippet written below:
using System.Resources;
using System.Globalization;
To read the key values from the resource files created in the above step, we need to use CreateFileBasedResourceManager
method of the ResourceManager
, as shown below:
ResourceManager resourceMgr =
ResourceManager.CreateFileBasedResourceManager(resourceName,
resourcePath,null);
Where,
resourceName
is the base name of resource file. In this case, it is MyResource
resourcePath
is the path of the resource repository from where culture specific resource files are to be picked. In this case, it is C:\Program Files\ResourceSet
null
indicates that the default runtime ResourceSet
is used.
To read a value from resource file, we will use GetString
method of the ResourceManager
as below:
string msg = resourceMgr.GetString(messageId,ci);
Where,
messageId
is the name of the key for the intended value in the resource file
ci
is the CultureInfo
indicating the intended culture specific resource.
Let us assume we need to read the UK specific (en-GB) resource file for which we have created a resource file named MyResource.en-GB.resources. The CultureInfo
can be instantiated as below:
CultureInfo ci = new CultureInfo("en-GB");
If the runtime fails to load or locate this culture specific resource, it will read the intended resource text from the default resource (MyResource.resources) as discussed in Step 1 and 2 above.