Saturday, September 02, 2006

Localization in WebParts

Microsoft Sharepoint Portal Server doesn't have support of localization in multiple

Languages natively. The document at

http://www.microsoft.com/technet/prodtechnol/office/sps2003/maintain/spsinatl.mspx#E5F

 

Discusses this situation. It is clearly mentioned that

SharePoint Portal Server 2003 does not support a mixture of different localized portal servers on the server farm, nor does it support a mixture of different localized Windows Server 2003 servers. All servers running Windows Server 2003 in a farm topology must be in the same language, and all servers running SharePoint Portal Server 2003 in a server farm must be in the same language

 

Still, if you want to perform localization in webparts for whatever reasons, it is simple to do so.

We will create a simple MOSS 2007 webpart with localization support.

 

  • Create a simple class library project and reference to the sharepoint namespace.
  • Create a template of webpart
  • Now we will add a resource file to the project. Choose Add New file from the project menu
    And add a resource file for each of the languages. For example

Healthcare.resx

Healthcare.de.resx for German

Healthcare.fr.resx for French

 

Note that you cannot add App_GlobalResources to the project since it is only valid for the web sites

And not the class library projects.

 

  • Add the following reference to your webpart source file
    using System.Configuration;

using System.Globalization;

using System.Resources;

 

We will pick the language settings from the web.config file. Add the following tag to the

<appsettings> section of the web.config file of your sharepoint web site.

<add key=culture value="de-DE">

 

Add the following class variables to your webpart source file.

CultureInfo cult =  CultureInfo.CreateSpecificCulture(ConfigurationSettings.AppSettings["culture"]);

ResourceManager rm;

 

This will create a CultureInfo object based on the language settings in the web.config file.

 

In the constructor of your webpart add a line like this

rm = new ResourceManager("CustomWebParts.HealthCare", this.GetType().Assembly);

 

Where HealthCare is the name of your resource file ex HealthCare.resx and HealthCare.de.resx

And CustomWebParts is the namespace of your webpart.

 

Basically this line creates a resource manager for the specific resource file.

 

Now we will load all the strings which are used in the webpart source to the resource file.

This is fairly easy.

 

Now to load strings at any point in the webpart source we will use the GetString() method of

ResourceManager class. For Ex

 

protected override void CreateChildControls()

        {

            base.CreateChildControls();

            this.Title = rm.GetString("CarePlan", cult);

        }

 

This method sets the title of the webpart to the appropriate language based on the web.config file

 

The above localization is not specific to sharepoint instead it's an asp.net 2.0 feature.

I can mail the source code of the webpart to anyone if needed.

 

Send your suggestions and comments.

 

 

 

 

 

30 comments:

Anonymous said...

Hi Madhur,

I was wondering how to accomplish localization for page layouts.

So I have a page layout that has label controls on it that need to be translated based on the variation I am working with.

Any ideas?

Thanks,
Anabhra

Madhur said...

Hi

just enabling variation doesnt creates localized pages. You have to manually replace the translated page's label to the different language.

Anonymous said...

Well I am aware of that and that is why I am looking into creating resource files for the labels on the page. The question is where do these resource files go?

Do we create them in a folder called "App_GlobalResources" that I create or is there some other way to localize the labels?

thanks,
anabhra

Madhur said...

well anabhra I am not aware of how to use variations in MOSS 2007. See
http://www.sharepointblogs.com/vandest/archive/2006/06/07/8157.aspx

Anonymous said...

Hi Madur

Great post. I just have 2 questions for you, that I hope you can help me with:

1) Usually in ASP.NET 2.0 I detect the preferred languages of the client based on his browser settings, however, in MOSS these are ignored, as a site always has one specific language. Is it possible to programmatically detect the language of a MOSS site?

2) Those resource files - where do you put them, if your web part assembly is deployed in the GAC? Can you somehow use resources embedded into the web part assembly?

Unknown said...

Hi,

great blog!

I'm looking for answers about these questions:

1) Is it possible to programmatically detect the language of a MOSS site?

2) Could I use ressource file (.resx) and if yes, where should put it ?

Do you know where I could search to find information about these problems ?

Madhur said...

hi david

1) Did you try looking up this information in MOSS SDK?

2)It depends on .resx .. What project are they part of ? If its a webpart, they will go in bin directory as dlls.. if they are aspx pages, they will go to app_globalresources in the inetpub folder.....

David B. said...

Thanks Madhur,

it's because i'm programming a userControl (.ascx) and I want change the language of my label if I'm in the french side or in the english side. I think I solved my problem. I have installed the language pack of WSS AND the language pack of MOSS (this pack is not available right now, I contacted Microsoft).

1- I created a variation (en & fr)
2- I installed my .ascx in a smartpart.
3- I put my .resx in the same folder of my .ascx but in the App_LocalResources and all worked fine! Now, if I switch in EN or in FR, the language of the label change. I found that MOSS changes the thread.culture so it's easy to catch in my .ascx (Thread.CurrentThread.CurrentCulture.Name)

Just one question: I would like to
"force" MOSS to switch in EN or in FR with a button. I tried to put this code on the button_click event:

Thread.CurrentThread.CurrentCulture = New CultureInfo("fr-CA")

but nothing happened.

Do you have any ideas to solve this problem ?

Thanks,
David

Madhur said...

Hi David

Did you try refreshing the page after execution of this code, infact refresh or reload it programmatically.
Thread.CurrentThread.CurrentCulture = New CultureInfo("fr-CA")

Also, try changing the UICulture of the thread to "fr-CA"

David B. said...

I didn't try to refresh manualy the page because when the button_click is called, the page reload automatically.

I tried it, in a simple .aspx page:

Try
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-CA")
Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-CA")
'Session("currentTread") = "en-CA"
Page.Response.Redirect(Page.Request.Url.ToString(), True)
Catch ex As Exception
et6.Text &= " ," & ex.Message
End Try

and I received a {System.Threading.ThreadAbortException}

David B. said...

Ok, I change the 'true' parameter to 'false' and the page reload work fine but the thread.culture don't change :(

Maybe it chooses the culture of my browser and don't pay attention to my changes...

Michael Hanes said...

Hi,

This post should fill in a few gaps:

http://michhes.blogspot.com/2007/05/localizing-web-parts-custom-controls.html

Anonymous said...

first let me thank Madhur for great post. somehow what he described did not work entirely for me (may be I am using WSS 3.0 SDK?) so this is what I did. ( I hope it help someone out!)
protected override void CreateChildControls()
{
cult = CultureInfo.CreateSpecificCulture("de-DE"); // **** I created Resource.de.DE.resx- Make sure this file in same level as your project name and create label_name as name and provided some value in german. ****//

System.Threading.Thread.CurrentThread.CurrentCulture = cult;
System.Threading.Thread.CurrentThread.CurrentUICulture = cult; // not sure i have to do it but I am doing it anyway.

rm = new ResourceManager("[**Namespace**].[**Resource**]", this.GetType().Assembly);
//specify your namespace and resourcefile name, take square bracket and stars out offcourse!.

lbl = new Label();
lbl.Text = Resource.label_name; //label_name is the "Name" in the resx file
Controls.Add(lbl);

}
BTW I am using Visual studio WSS 3.0 SDK it moves project dll file to GAC but it did not copy DLL under each culture. So you have to do it manually.
Go to \bin\debug under project and there should be folder "de-DE" (automatically created) move the dll under it to GAC C:\windows\Assembly and reset your IIS.

This should take care of localization. Happy coding :)

Indrajeet Kumpavat said...

Hi Madhur,

It is great article to localize webparts.

I have a query:

1. How can we do localize the whole site? if the site have objects like
- WebPart (for this Thanks to you)
- SharePoint designer workflows
- Workflow task forms
- List and document libraries
- Navigation bars

And can the locale be change as per browser default language settings?

Thanks in advance.
Indrajeet.
http://blogindrajeet.blogspot.com

Anonymous said...

I try to reproduce your example but I have a problem.
I don't know where to upload the resource files ??

Can you tell me where I can put them ?
At the moment I add the resource files, I put the DLL in the GAC but it doesn't works, ...

Anonymous said...

I try to reproduce your example but I have a problem.
I don't know where to upload the resource files ??

Can you tell me where I can put them ?
At the moment I add the resource files, I put the DLL in the GAC but it doesn't works, ...

Madhur said...

Hi

You can put your resources in the DLL itself as a resource. You have to change the compile action to embedded resource for the resource files in VS 2005.

Thanks,
Madhur

Anonymous said...

Hello Madhur,

Thanks to share this info with us. However I've got a slight problem with the resources files. It works fine to add the first .resx like for instance "words.resx". As soon as I add another resource file like "words.de.resx" the wrapper class isn't created by Visual Studio. As soon as there is a "." in the name, VS doesn't make its work....How to circumvent that?

Because the result is that whatever culture I define, it always returns the english value..

Any idea?

Thanks

Anonymous said...

Hello Madhur,

Sorry, it's me again! You can cancel my previous comment since I had actually the same problem than the german guy for whom the resource file wasn't copied to the GAC. By copying it manually, it works.

Thanks

Anonymous said...

Hi Madhur,

i need to maintain 2 common resource files 1 for english & another for french which will be used by all webparts in my site.

pls let me know where to place the resource file and how to access that file from c#.net Webpart code.

Unknown said...

Hi Madhur,

i am working in moss2007.
i need to accomplish localization in all the webparts in my home page.
i need to have seperate resource file for english & french and all the webparts need to access only these 2 resource file(common file) from my c#.net code.

pls give ur comments.

Madhur said...

hi thiru

There will be two files
Resource.fr.resx
Resource.en-US.resx

You can use the sample code given in the blog article.

Unknown said...

hi Madhur,

Below is my code but i am getting error.

ResourceManager rm;

rm = new ResourceManager("AccessibilityToolBar.1033", this.GetType().Assembly);



// AccessibilityToolBar - > namespace & 1033 is resource file which is 1033.en-US.resx

// I have placed 1033.en-US.resx in App_GlobalResources folder



CultureInfo cult = CultureInfo.CreateSpecificCulture(Thread.CurrentThread.CurrentCulture.ToString());

// Thread.CurrentThread.CurrentCulture.ToString() -> “en-US”

string strTit = rm.GetString("Title",cult); // This line throws the below error

Error

Error description : System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure " AccessibilityToolBar.1033.resources" was correctly embedded or linked into assembly "AccessibilityToolBar" at compile time, or that all the satellite assemblies required are loadable and fully signed.

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)

at AccessibilityToolBar.AccessibilityToolBar.RenderControl(HtmlTextWriter writer)::mscorlib



-----------------
1033.en-US.resx entry

Name = Title;

Value = FontSize;


-----------------

Pls give ur comments

Unknown said...

hi madhur,

below is my code in DLL .cs file but i am getting below mentioned error.

ResourceManager rm;

rm = new ResourceManager("AccessibilityToolBar.1033", this.GetType().Assembly);



// AccessibilityToolBar - > namespace & 1033 is resource file which is 1033.en-US.resx

// I have placed 1033.en-US.resx in App_GlobalResources folder



CultureInfo cult = CultureInfo.CreateSpecificCulture(Thread.CurrentThread.CurrentCulture.ToString());

// Thread.CurrentThread.CurrentCulture.ToString() -> “en-US”

string strTit = rm.GetString("Title",cult); // This line throws the below error



Error

Error description : System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure " AccessibilityToolBar.1033.resources" was correctly embedded or linked into assembly "AccessibilityToolBar" at compile time, or that all the satellite assemblies required are loadable and fully signed.

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)

at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)

at AccessibilityToolBar.AccessibilityToolBar.RenderControl(HtmlTextWriter writer)::mscorlib

---------------


1033.en-US.resx entry


Name = Title;

Value = FontSize;

---------------

Pls give ur comments

Unknown said...

hi madhur,

thanks for your immediate response.

Unknown said...

Hi Madhur,

Thanks for ur reply.

Currently the resource file for webpart will be interms of DLL, so in future if v wish to change or update any values then we need to rebuild that once again & then need to do IISRESET for web applications.

Is there any other option to update resource file without going for rebuild & IISRESET?.

Pls correct me if i am wrong.

Thanks in advance.

Madhur said...

Thiru,
It is not necessary to put that as a resource. You can have it outside the assembly as simply .resx and refer it as file and update it whenever as required. Obviously if you are updating the source code, then you need rebuild.

Unknown said...

Hi Madhur,

Outside assembly means?
can i place the file in "App_GlobalResources" folder?

kindly let me know the location wr i can place the .resx files.

Unknown said...

Hi madhur,

Gr8 post. I was wondering if you can mail me the source code for more clarifications.
My id is kedarnath.waikar@gmail.com

Unknown said...

Hi,

I have this solution and im trying to add localization to it would you be able to help.

heres the files

http://plastic-surgery.knowledge-council.com/Demo.zip

Cheers

Ste