Sunday, March 17, 2013

Localize SharePoint Solution



For a SharePoint solution, there are three types of files need to be localized.
1. The feature XML files.
2. The .NET source code.
3. The ASP.NET pages.
 
1. The feature XML files.

For this type of files, the localization mechanism is to deploy *.resx file to SharePoint global resource folder C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Resources (SP 2007) or C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources (SP 2010).
*.resx file is an XML file and has no project specific information such as class name or namespace. To refer the text resource in *.resx file deployed to above global resource folder, use syntax such as: "$Resources:FileName, Text-Key;"
 
<!-- List Email Settings -->
<CustomAction Id="My Settings"
GroupId="Communications"
Location="Microsoft.SharePoint.ListEdit"
Sequence="1000"
Title="$Resources:MyFileName, Welcome"
RequireSiteAdministrator ="False"
>
</CustomAction>
Or use "DefaultResourceFile"
 

<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Title="$Resources:Welcome" DefaultResourceFile="MyResourceTest1" Description="My Event Receiver Feature $Resources:MyTest1" Id="4c98083d-8016-4c91-a1f7-b9be7fee3a11" Scope="Web">
<Properties>
<Property Key="GloballyAvailable" Value="true" />
</Properties>
<ElementManifests>
<ElementManifest Location="EventReceiver1\Elements.xml" />
</ElementManifests>
</Feature>


In a SharePoint solution, *.resx file are deployed to SharePoint global resource folder in manifest file using "<RootFile>".
In the background, at run time SharePoint builds the resx files in this folder and uses a namespace "Resources".
A second way to deploy *.resx file is to deploy it to feature folder under sub folder "Resources" and with file name as "Resrouce.resx", "Resrouce.ja-jp.resx". I think this is a better way to deploy the resource file. First, you don't need to worry about name conflicts. Second, you can refer the resource in the file without mentioning the file name. The syntax get shorter as "$Resources:Text-Key;"
To deploy resource file to feature folder, use the same mechanism as deploy feature files in manifest file.

There are two ways to deploy resource files to feature folder.

The first method is to use "ElementFile" element of feature.xml file

In feature xml file

<ElementManifests>
<ElementManifest Location="Elements.xml" />
<ElementFile Location="Resources\Resources.resx" />
<ElementFile Location="Resources\Resources.ja-jp.resx" />
</ElementManifests>

In ddf file

;Feature files must goto FeatureName folder without FEATURES\
TEMPLATE\FEATURES\MyNewFeature\feature.xml MyNewFeature\Feature.xml
TEMPLATE\FEATURES\MyNewFeature\Elements.xml MyNewFeature\Elements.xml
TEMPLATE\FEATURES\MyNewFeature\Resources\Resources.resx MyNewFeature\Resources\Resources.resx
TEMPLATE\FEATURES\MyNewFeature\Resources\Resources.ja-jp.resx MyNewFeature\Resources\Resources.ja-jp.resx
In solution manifest file

<FeatureManifests>
<FeatureManifest Location="MyNewFeature\Feature.xml"/>
</FeatureManifests>

The second method is to use TemplateFile element of manifest to deploy resource file as template files

In feature.xml file
<ElementManifests>
<ElementManifest Location="Elements.xml" />
</ElementManifests>


In ddf file
;Feature files must goto FeatureName folder without FEATURES\
TEMPLATE\FEATURES\MyNewFeature\feature.xml MyNewFeature\Feature.xml
TEMPLATE\FEATURES\MyNewFeature\Elements.xml MyNewFeature\Elements.xml
TEMPLATE\FEATURES\MyNewFeature\Resources\Resources.resx FEATURES\MyNewFeature\Resources\Resources.resx
TEMPLATE\FEATURES\MyNewFeature\Resources\Resources.ja-jp.resx FEATURES\MyNewFeature\Resources\Resources.ja-jp.resx

In solution manifest file
<FeatureManifests>
<FeatureManifest Location="MyNewFeature\Feature.xml"/>
</FeatureManifests>

<TemplateFiles>
<TemplateFile Location="Features\MyNewFeature\Resources\Resources.resx"/>
<TemplateFile Location="Features\MyNewFeature\Resources\Resources.ja-jp.resx"/>
</TemplateFiles>



2. The .NET source code.

When you add *.resx file and localized version of *.resx file to your project in Visual Studio, VS will build resource dll files. In source code, these resources can be accessed using strong type.

For example:
The text resources are in file "constant.resx" and a localized version is in "constant.ja-jp.resx", when VS builds the project, it outputs a file "*.resources.dll" in bin "ja-jp" folder. These files needs to be deployed with the main dll file of the project to the targeted environment.

To access the text resource in the file, in the code it will be "string welcome = Constant.Welcome".

It doesn't matter if the resources file are in a sub folder such as "Resources" or what namespace you use in the code behind file in the VS project.

It is a convention to put resource file in the "Resources" sub folder in the VS project, and VS will assign a namespace such as "MyProject.SharePoint.Resources" to the code behind file. When you access the resource in code, the code will be like "string welcome = Resources.Constant.Welcome". However this is not required. You can put the file under "Resources" and still use the same namespace as the other files such as "MyProject.SharePoint " and using code like "string welcome=Constant.Welcome".

Localized resource dll files are deployed as the main dll file in solution manifest file.

3. The ASP.NET pages.

It is tricky to access resource in ASP.NET pages in SharePoint. By default, SharePoint accesses resource from IIS virtual directory such as "C:\inetpub\wwwroot\wss\VirtualDirectories\80\App_GlobalResources".

For example: <%$Resources:wss,emailsettings_pagetitle%>

WSS is the name of the file "wss.resx".
 
When deploying custom application pages, a resource file needs to deployed to "App_GlobalResources". If this done, at runtime resources are built into a namespace "Resources" and can be referred as
<%$Resources:filename,text-key%>

However SharePoint 2007 didn't provide a mechanism to do so. The "< ApplicationResourceFile>" element of manifest file deploys resource file to "Resources" folder under the virtual directory which is a bug according to http://stackoverflow.com/questions/296003/deploy-a-resource-file-to-app-globalresource-folder-on-activation.
 
In the time frame SharePoint 2010, it provides a new mechanism which is " App_GlobalResourceFile" element of manifest file to deploy resource file to "App_GlobalResources" folder. See http://blog.mastykarz.nl/provisioning-appglobalresources-sharepoint-2010/

If you are developing SharePoint 2007 and 2010 compatible solutions, you have to stick to the SharePoint 2007 mechanism. Mikhail Dikov provides a workaround at http://www.mikhaildikov.com/2007/03/sharepoint-resources-types-use-and_2163.html

However, there is a much easier workaround that no one referred. It is actually every easy to use "<%= />" syntax in ASP.NET page to get the resource from dll as strong type.

For example: "<%= Constant.Welcome %>"

or you can just initialize the ASP.NET controls in your code behind file and assign text using strong type.
Note: The locale fallback to default mechanism only works when the using strong types in code but not in XML file according to http://www.fkollmann.de/v2/post/SharePoint-2010-resource-files-have-to-be-complete.aspx
The localized resource file must have all the text localized from the default resource file.

More Resources:

No comments:

Post a Comment