Click here to Skip to main content
Click here to Skip to main content

.NET - Localization using Resource file

By , 15 Nov 2003
 

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:

  1. Creating a satellite assembly for culture specific resource file and using it in the executing assembly
  2. 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.

  1. 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:

    1. 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.

    2. 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:

      1. 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.

      2. 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.

      3. 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.

  2. 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:

    1. 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.

    2. 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
    3. 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Prakash Kumar Singh
Web Developer
United Kingdom United Kingdom
Member
Hi!!
I am working for Wipro Technologies, Bangalore,India.I am basically into design and development of enterprise software application,primarily on .Net technologies.
 
I am also Microsoft Certified Solutions Developer(MCSD)for .Net
 
I have been hung on this site for quite some time now, and found it extremely useful for anyone who is seeking basic to advance level info about .Net(C# in particular),XML,MFC & so on.
 


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMy Vote of 5memberbharatRajM165878 Apr '13 - 1:16 
Very Nice article.
 
Thanks.
QuestionAwesome perfectmembersofygrafe3 Dec '12 - 15:11 
Wow this helped a lot and so easy to understand. Thanks!
GeneralMy vote of 5memberMember 81358325 Jun '12 - 23:25 
superb article, the way it explains using example is great.....
QuestionExactly what I was looking for!memberNaerling17 May '12 - 8:16 
Two questions though. It seems step A.2 is done automatically in .NET 4.0. Can you confirm this?
Also, is it possible for users (maybe admins) to add or alter resource files (or the dll's that are generated as MyApplication\bin\en-GB\MyApplication.resources.dll)?
Thanks and have my five.
It's an OO world.
public class Naerling : Lazy<Person>{
    public void DoWork(){ throw new NotImplementedException(); }
}

GeneralMy vote of 5memberlukeer25 Jan '12 - 2:36 
For me, it was /embed's second parameter that I found explained here for the first time
GeneralMy vote of 5memberDiMann22 Sep '11 - 1:13 
Very substantial and laconic article.
GeneralMy vote of 5memberAdam Roderick J6 Jul '11 - 23:33 
Good article useful.
GeneralBaseName for Resource File is a propertymemberkvanpal14 Jun '11 - 11:09 
The BaseName given in the description has not worked for me in .Net 3.5
After looking around I found a property BaseName in the resource itself.
 
ResourceManager resMgr = new System.Resources.ResourceManager(Properties.MyResource.ResourceManager.BaseName, Assembly.GetExecutingAssembly());
 
Kishore Vanapalli
GeneralMy vote of 5memberBaesky10 Apr '11 - 19:08 
easy to understand, nice article!
QuestionAssembly Linker ErrormemberRichik Sinha Roy17 Sep '09 - 0:26 
My Application name is Test App 2, and the resource file is Resource.nl-NL. Its full directory structure is C:\Users\admin\Documents\Visual Studio 2005\Projects\Test App 2\Test App 2\Prope
rties\Resource Set\Resource.nl-NL.resources.
 
Resgen works perfectly. However, on using the Assembly Linker tool with the following command,
 
al /t:lib /embed:"Resource.nl-NL.resources, Test_App_2.Resour
ce.nl-NL.resources" /culture:"nl-NL" /out:"Test_App_2.resource.dll"
 
However, i get the following error.
 
ALINK: error AL1022: Error reading embedded resource
'c:\Users\admin\Documents\Visual Studio 2005\Projects\Test App 2\Test
App 2\Properties\Resource Set\Resource.nl-NL.resources,
Test_App_2.Resource.nl-NL.resources' -- The system cannot find the file
specified.
 
My application namespace is Test_App_2, as i found out from the project in Visual Studios.
 
I would really appreciate if you could help me.
 
Thanks a ton.
AnswerRe: Assembly Linker ErrorgroupSkyhawk11 Jan '13 - 3:29 
That is so stupid, yet painful problem. To resolve this, you just need to remove space after comma, i.e. change:
/embed:"Resource.nl-NL.resources,[SPACE]Test_App_2.Resour
ce.nl-NL.resources"
to
/embed:"Resource.nl-NL.resources,Test_App_2.Resour
ce.nl-NL.resources"

GeneralLocalization of data read from databasememberManjuHanzan8 Apr '09 - 0:37 
Hi,
I am developing a business application iwth silverlight. I have tried localization from your article. Its fine.
but my requirment is not just in displaying labels and texblocks.
I want all details reading from database also to be in local language( or the language user chooses)
i want multi language support for my silverlight application
 

Pls help.
 
Manju
GeneralI suggest to use Microsoft's default approachmemberdjdane8 Mar '09 - 14:54 
I tried both approaches, IMO al.exe cannot do the job correctly (or these internet-based instructions were wrong on how to link .resources file with appropriate assembly when producing dll file), correct me (or them) if I'm wrong.
Under http://msdn.microsoft.com/en-us/library/y99d1cd3(VS.71).aspx#[^], it is clearly stated how to manually add resource files to the project and edit them. More importantly, it is explained how to properly link resources with main assembly( new ResourceManager("...",typeof(Form1).Assembly); ), so you don't have to worry about faulty batch files when doing approaches 1 or 2.
Approach No.1 ( Assembly.GetExecutingAssembly() ) - has anybody made it at all?
Approach No.2 doesn't even have default (fallback) resource, so you have to worry about that also when shipping your app!
 
I suggest to let Visual Studio to do the job for you, it works out of the box, no pain.
GeneralRe: I suggest to use Microsoft's default approachmemberYaroslav Trofimov15 Apr '09 - 2:05 
What can i do if application is not has any form?
GeneralError when publishing my website with satellite assembliesmemberSydBarrett24 Feb '09 - 9:46 
I made all the steps for building resource files with resgen.exe and al­.exe and when I execute it locally in debug with VS2008 (3.5 framework target), everything is fine. My messages are translated without any problems. But when I publish my wcf services and asp.net application on a windows 2003 server with IIS 6.0, I get this error after a certain amount of time of inactivty, when I try to reload the same page. Anybody has an idea about this issue? I fetch my resource value with the "ResourceManager" object, with the GetString() method.
 
Thanks
 
below is the error :
 
========================================================================================
 
Server Error in '/' Application.
Could not load file or assembly 'ADP.PayConnexion.Business.Messages, Version=1.0.0.0, Culture=en, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly 'ADP.PayConnexion.Business.Messages, Version=1.0.0.0, Culture=en, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
 
Source Error:
 
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
 
Assembly Load Trace: The following information can be helpful to determine why the assembly 'ADP.PayConnexion.Business.Messages, Version=1.0.0.0, Culture=en, PublicKeyToken=null' could not be loaded.
 
=== Pre-bind state information ===
LOG: User = NT AUTHORITY\NETWORK SERVICE
LOG: DisplayName = ADP.PayConnexion.Business.Messages, Version=1.0.0.0, Culture=en, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///D:/ADP/PayConnexion_2008/UI/Web/
LOG: Initial PrivatePath = D:\ADP\PayConnexion_2008\UI\Web\bin
Calling assembly : ADP.PayConnexion.UI.Web, Version=1.0.0.0, Culture=en, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: D:\ADP\PayConnexion_2008\UI\Web\web.config
LOG: Using host configuration file: \\?\c:\windows\microsoft.net\framework\v2.0.50727\aspnet.config
LOG: Using machine configuration file from c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: The same bind was seen before, and was failed with hr = 0x80070002.
GeneralBest Localization Plug-in for Visual Studio.memberAlexander Nesterenko24 Sep '08 - 2:03 
Extract strings from code to resx and translate their automatically. Try RGreatEx[^] free.
GeneralLinking dll not workingmemberRupesh R. Tarwade6 Jul '08 - 19:30 
I tried linking satellite assembly using the first way, but it doesn't work Confused | :confused: . The second way is pretty straight forward and it works fine. I am using VS2005. I am able to make the dll using Al.exe. Is this approach working for anyone else??
 
Cheers!!

Questionerror CS0234: when compilingmembervalmir19692 Jul '08 - 4:11 
Hi. I follow the B solution steps, but I put the resource files on another project inside the same solution. The system works fine, but I got the following error when I compile the resources project:
 
C:\Projetos\vs2k5\MDI\Idiomas\MDI.Designer.cs(38,25): error CS0234: The type or namespace name 'ComponentModel' does not exist in the namespace 'System' (are you missing an assembly reference?)
C:\Projetos\vs2k5\MDI\Idiomas\MDI.Designer.cs(53,25): error CS0234: The type or namespace name 'ComponentModel' does not exist in the namespace 'System' (are you missing an assembly reference?)
C:\Projetos\vs2k5\MDI\Idiomas\MDI.Designer.cs(22,21): error CS0234: The type or namespace name 'CodeDom' does not exist in the namespace 'System' (are you missing an assembly reference?)
 
Thats the code:
 

[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
 
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
 
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]

 
Using VC2005
 
Thanks
 
Valmir Cinquini
Notepad MVP

GeneralLinker wouldn't work under VS2005 until I removed the rename valuememberkmillen8 May '08 - 10:37 
I kept getting AL1047 linker errors until I changed the linkder line to:
 

Al.exe /t:lib /embed:MyResource.en-GB.resources /culture:en-GB /out:MyApplication.resources.dll
GeneralApproach A not workingmemberanni317 Apr '08 - 0:13 
Hello,
 
I've created a satellite assembly using approach A but it's not working.
I have no error but the strings that are to be read from the resource are coming up empty.
I don't know what I am doing wrong.
GeneralIssue using Satellite Assembly [modified]memberRuchi.Shivnani8 Apr '08 - 20:25 
Hello Prakash,
I have tried both the options you have mentioned here in article. Second works fine but is not recommended by Microsoft.
The error I get while using Satellite assembly:
"Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "Resource.resources" was correctly embedded or linked into assembly "App_Web_prvhcn9b" at compile time, or that all the satellite assemblies required are loadable and fully signed."
 
I am very frustated now and not able to proceed in my work as I have already spent my 1 week now on solving this issue. Please help in this matter urgently.
 
Regards,
Ruchi Shivnani
 
modified on Wednesday, April 9, 2008 2:57 AM

GeneralIssue using Satellite AssemblymemberRuchi.Shivnani7 May '08 - 21:06 
Hello,
Can anyone help on this issue.
 
Ruchi
GeneralRe: Issue using Satellite Assemblymemberyoyoyo00923 Sep '08 - 20:55 
I'v got the same issue. Can anybody help?
GeneralRe: Issue using Satellite AssemblymemberYaroslav Trofimov15 Apr '09 - 2:11 
A have the same problem and the same exception. In my case it is nesessary to set the correct name of the resource file.The name should be . when you create the ResourceManager.
GeneralRe: Issue using Satellite AssemblymemberLenin.N.C16 Jun '10 - 23:08 
Friends i am also having the same problem can anyone help me. Blush | :O
 
- Lenin

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 16 Nov 2003
Article Copyright 2003 by Prakash Kumar Singh
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid