Chapter 6. Web Part resources and localization – SharePoint 2010 Web Parts in Action

Chapter 6. Web Part resources and localization

 

This chapter covers

  • Adding resources for your Web Parts
  • Deployment methods for resources
  • Localizing Web Parts

 

Web Parts are interface focused and are the building blocks of many successful SharePoint sites. A good user interface design is user friendly. I’ve discussed how you can add controls and logic to a Web Part; now you’ll explore how you can add images, scripts, and style sheets to your solution. These attached items are resources. This chapter covers two types of resources:

  • Linking and embedding resources such as images, scripts, and style sheets
  • Localization resources containing culture-specific resources

Images and style sheets are important when building a good-looking interface. Use them to enhance the user experience and accessibility. There are several ways to add them to your solution, ranging from farm-deployed to assembly-embedded resources. Choosing a method depends on how you plan to use and access them, and I’ll guide you through the various scenarios. The techniques in this chapter aren’t applicable to just Web Parts—you can use them in user and delegate controls, pages, and other SharePoint projects and Features.

Localization of Web Parts is an important aspect when building reusable Web Parts. Localization means that you make the Web Part aware of which language the user is currently using in SharePoint and adapt your Web Part to that language, decimal numbers, and time format. The localization of a Web Part may be time consuming and often requires thorough testing, but if you’re aiming for a global market this step is a necessity.

6.1. Linking and embedding resources

When building Web Parts, the most common resources you should include are images, style sheets, and script files. In chapter 4, you briefly looked at how to add a CSS file to take advantage of the SharePoint themes in a Web Part. In this chapter, you’ll follow up that discussion and look at all your options for including style sheets and other resources in your Web Part.

Resources such as images and scripts can be included in a SharePoint solution in several ways. Let’s review all your options:

  • Deploying resources in the SharePoint root
  • Deploying resources to the Web Part resource storage
  • Embedding resources in the assemblies
  • Deploying resources into the SharePoint sites

Each of these scenarios has its advantages and disadvantages. Your decision will depend on usage and how you plan to deploy the solution.

6.1.1. Using the SharePoint root folders

Each SharePoint site collection has a virtual directory called _layouts that’s mapped to the {SharePoint Root}\TEMPLATE\Layouts folder. This folder looks the same for all site collections and web applications in the farm. The _layouts folder also contains a number of subfolders, one of which is the images folder. That folder is also a virtual directory, mapped to the {SharePoint Root}\TEMPLATE\Images folder. Any files deployed into these subfolders will be available for every site collection in the farm, even if the solution isn’t installed on the web application or deployed to the site collection. Figure 6.1 shows how a SharePoint web application looks in the Internet Information Services (IIS) Management Console. You can see the _layouts folder and the images folder beneath it.

Figure 6.1. The _layouts folder and other folders are mapped to the physical paths in IIS as virtual directories.

 

Note

The virtual directories in IIS are mapped to physical paths in the SharePoint root. Don’t modify these paths or in any other way tamper with the settings in IIS.

 

Using these SharePoint mapped folders is an easy way to add resources to a Web Part project. Visual Studio provides great integration for adding the folders and including files in them. To add a SharePoint mapped folder, right-click the project and select Add, or you can use the Project menu in the Visual Studio menu. You have three options to add the SharePoint mapped folders, as you can see in figure 6.2. You can directly add the Images and Layouts folders or select the third option that opens a dialog box in which you can select any of the folders in the SharePoint Root folder. The Images folder is used for images and the Layouts folder for other files such as scripts, style sheets, or Silverlight binaries.

Figure 6.2. Adding the SharePoint mapped folders

When you’re adding the SharePoint mapped folders, Visual Studio will create a subfolder in the project with the name of your project. You have the option to add your files into that folder or the root folder, or you can create a new one. A good convention is to use the folder that Visual Studio creates for you. This folder name should be unique, and it keeps you from accidentally overwriting files with the same name from another solution.

To create a Web Part that displays an image located in the SharePoint root Layouts folder (see figure 6.3), you need to create a new Web Part project. In the SharePoint Customization wizard, select to deploy it as a farm solution. This is because the image will eventually be deployed into the SharePoint Images mapped folder, which is mapped to a physical path on the server’s hard drive. This can only be achieved by using a farm solution because sandboxed solutions don’t allow you to add files to the physical drive of the server.

Figure 6.3. Web Parts that use the /_layouts/images folder to store images must be deployed as farm solutions because sandboxed solutions don’t allow files to be written to the file system.

When the project is created, add the Images mapped folder and then add the image to the subfolder with the project name. Add the image file by right-clicking the project and selecting Add > New or Add > Existing Item. Then add a Visual Web Part in which you type the following code:

<h3>An image in the /_layouts/images folder</h3>
<img src="/_layouts/Images/WebPartsInAction.Ch6.ImagesAndScripts/Annotation.png" />

The src attribute of the img element points to the file image that you added to the project. As you can see, the path to the image is a server-relative URL. Because you’re adding this image to the file system, it’s available in all site collections so you don’t have to care about any site-relative URL.

 

URL strings in SharePoint

SharePoint uses three forms of URL strings:

  • An absolute URL is a URL that starts with the protocol and server address, like this: http://server/[sites/][web site]/.
  • A server-relative URL starts from the top-level website, beginning with a forward slash, like this: /[sites/][web site]/.
  • The third form is the website-relative URL (also called just site-relative), which doesn’t start with a forward slash.

 

One of the advantages of having these resources residing in the file system and mapped through IIS virtual directories is that you can use IIS compression and caching techniques to improve the performance of your application. Another advantage is that you can share the resources between solutions. The disadvantage of using these shared-linked resources is that they’re available from any site or site collection in the farm. This can be problematic if the resource contains sensitive data. Keep in mind that if you don’t carefully name your folders and files they may collide with other solutions, which can lead to unwanted scenarios.

6.1.2. Using class resources

Another method of including resources in the solution involves using the special Web Part resource storage. This storage is another virtual directory mapped in IIS that’s specifically made to host resources for Web Parts and separate them from other Web Parts. It works similar to storing the resources in the SharePoint mapped folders except that SharePoint makes sure that each assembly and class gets its own separate folder. The resources are stored in the _WPRESOURCES IIS virtual directory; under that directory SharePoint creates one folder for each assembly and version. Just as with the mapped folders,, these files reside in the file system. This method has the same advantages and disadvantages, except that file conflicts are more unlikely to occur because each assembly and version automatically gets a new folder tree.

To add an image as a class resource in a Web Part, you need to add the image to your Web Part project item. Right-click on the Web Part, click Add > Existing Item, and select the image to include. When the file is added to the project, you have to select the item and edit its properties. Edit properties by right-clicking the item and selecting Properties or by pressing the F4 key. The Properties window contains information about how the project item should be handled during compilation and packaging of the solution. Specifically, you must change Deployment Type to make this item a class resource. By default, the Deployment Type property of the added image has the value NoDeployment, which means that this item won’t be included in the solution or deployed. You must change the value of Deployment Type to ClassResource. When you do, Visual Studio will change the value of the Deployment Location property. The deployment location is the path in the _WPRESOURCES folder and consists of two parts. The first part, called the root, is the ClassResourcePath, which is the automatically generated path created from the assembly name and version. The second part, called the path, is a configurable folder that by default is set to the name of your project and the name of the project item. This will generate a very long path by default, and I recommend that you expand the Deployment Location property and change the value of the Path part to something shorter or just leave it empty. Figure 6.4 shows the Properties window with the default values for a class resource item.

Figure 6.4. Using the Properties window of a project item in Visual Studio, you can configure how the item is going to be deployed and to which location.

 

_WPRESOURCES versus WPRESOURCES

There are two different WPRESOURCES directories: _WPRESOURCES and WPRESOURCES. _WPRESOURCES is used for solutions that are deployed as farm/full-trust solutions, and WPRESOURCES is used by solutions that are deployed to a web application (see chapter 7).

For farm solutions, the _WPRESOURCES directory is the same for all web applications across the farm, but WPRESOURCES exists on the web application level so those resources aren’t shared across web applications.

 

Once the image item in the project is changed to a class resource, Visual Studio automatically adds it to the package of the solution. It adds the item as a ClassResource element in the package manifest. To view the manifest, double-click on the package in the Solution Explorer and select the Manifest tab. The ClassResource element should look like this if you set the path in the Deployment Location property to Empty:

<ClassResources>
    <ClassResource Location="Annotation2.png" />
</ClassResources>

The root part of the Deployment Location property consists of the name of the assembly, the version, and the public key token. For example, it could look like this:

/_WPRESOURCES/WebPartsInAction.Ch6.ImagesAndScripts/1.0.0.0__b96bfa3ca5f92c49

Using the server-relative path in code may be problematic, especially if you change the version of the assembly. So you don’t have to hardcode this path, the SharePoint Web Part Manager provides a static method called GetServerRelativeClassResourcePath that automatically generates the path for you. To add an image as a class resource into a Visual Web Part, you must set the ImageUrl property in the code-behind to be able to use the method to get the class resource path like this:

<h3>An image using ClassResources</h3>
<asp:Image runat="server" id="WPImage" />

In the code behind the ImageUrl property set the OnInit method. It uses the static method of the SPWebPartManager object and appends the name of the image like this:

protected override void OnInit(EventArgs e) {
    WPImage.ImageUrl =
        SPWebPartManager.GetServerRelativeClassResourcePath(
            SPContext.Current.Web,
            typeof(WebPartWithImage))
        + "/Annotation2.png";
    base.OnInit(e);
}

GetServerRelativeClassResourcePath needs two parameters. First, it needs the current site, SPWeb, to get the relative path to the _WPRESOURCES folder. The second parameter is the type of the class—in this case, the Web Part—so that it can generate the folder names. You need to use the type of the Web Part because the Visual Web Part is dynamically compiled and therefore isn’t a part of the Web Part assembly.

Worth considering when using class resources is that SharePoint configures IIS to set content expiration (caching) rules on the _WPRESOURCES folder but not on the WPRESOURCES folder. Chapter 9 will discuss this topic in more detail.

6.1.3. Embedded resources

The two previous methods add files to the file system and these files are accessible from any site collection on any web application in the farm. There are situations when you don’t want the resources to reside in the file system or be accessible from anywhere except when called from your Web Part. Then you should use the standard ASP.NET technique to embed the resources within the assembly. This is done by embedding the files into the assembly file. These files are then retrieved from the assembly using the WebResource.axd handler. This assembly resource handler is called using a set of query string parameters that contain encrypted information about which assembly to retrieve the resource from and the name of the resource. The handler will then load the resource stream from the assembly and send it back to the client. You can’t use this method for sandboxed Web Parts; the handler doesn’t have access to the assembly existing in the sandbox, so it can’t access and load the resources.

To add embedded resources to a project, you add the item or add an existing item to the project, just as with the class resource items. The Deployment Type property of the resource should be set to NoDeployment and the Build Action property to Embedded Resource so that the compiler knows that it should embed the item into the assembly. To make this embedded resource available for the ASP.NET assembly resource handler, you have to add a WebResource assembly attribute. You add the assembly attribute to the AssemblyInfo.cs file; find the AssemblyInfo.cs file by expanding the Properties node of the project in the Solution Explorer. The attribute should look like this:

[assembly: System.Web.UI.WebResource(
"WebPartsInAction.Ch6.ImagesAndScripts.WebPartWithImage.Annotation3.png",
"image/png")]

The first parameter in the attribute represents the resource name. By default, it has the name of the project along with the project item and the filename of the resource. In this case, WebPartsInAction.Ch6.ImagesAndScripts is the project name, WebPartWithImage is the name of the Web Part, and Annotation3.png is the filename. The second parameter is the content type of the resource. Because this image is a PNG, the content type is set to image/png.

The path to the image is a reference to the WebResource.axd with a set of encrypted parameters. This URL to the image must to be set in code and not in the user control. In a Visual Web Part, you add the Image control in the user control like this:

<h3>An image as embedded resource</h3>
<asp:Image runat="server" id="EmbedImage" />

The ImageUrl property of the Image control is set in the code-behind of the Visual Web Part user control using the ClientScript object of the current page. The ClientScript object has a method called GetWebResourceUrl, which takes two parameters. The first parameter is the type of the Web Part that’s used to resolve the current assembly. The second parameter is the exact name of the resource that was used in the WebResource assembly attribute. The following code is added to the OnInit method to make the Web Part show the embedded resource:

EmbedImage.ImageUrl = Page.ClientScript.GetWebResourceUrl(
   this.Parent.GetType(),
   "WebPartsInAction.Ch6.ImagesAndScripts.WebPartWithImage.Annotation3.png"
);

Because this is a Visual Web Part, you need to use this.Parent.GetType() to be able to resolve the assembly. If the type was retrieved using this.GetType(), it would’ve only returned the assembly of the dynamically created user control. When you’re using the GetWebResourceUrl method in a standard Web Part, you should use this.GetType().

6.1.4. Resources in SharePoint libraries

None of the previous methods I discussed for including resources are available for use in sandboxed solutions, so how do you add images and other resources to those solutions? Because sandboxed solutions are deployed into a site collection and they live in and have access to only that site collection, you could add the resources to the site collection. You could add the resources to the Site Assets library, the Style Library, or a custom library. This approach also allows users to edit the resources. The best way is to create a custom folder, instead of a list or a library, in the site collection. This strategy prohibits users from tampering with the data, unless they have access to SharePoint Designer.

To create a Web Part that shows an image that you can deploy as a sandboxed solution, you start as you normally would with an empty SharePoint project in which you’ll add a Web Part item. You add the resources to the solution in a new SharePoint project item of the type Module and assign it a unique name so that it won’t collide with other solutions. The Module item contains two files: elements.xml and a sample file called sample.txt. Remove the sample file and add the image to the Module item. The elements.xml file should look like listing 6.1 when you’ve added the image.

Listing 6.1. Adding resources using modules in a SharePoint feature
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Module
        Name="Resources">
        <File
            Path="Resources\Tick.png"
            Url="Resources/Tick.png" />
     </Module>
</Elements>

The element manifest of the Module item includes a Module element whose Name attribute contains the name of the folder you want to create. For each resource that should be included, a File element is added. This element has a Path attribute that specifies the source of the file. The Url attribute specifies the destination of the resource. Ordinarily you don’t have to add the File elements manually; Visual Studio will create a new File element each time you add a new item to the Module SharePoint item and remove the redundant elements when you remove a file.

In the Web Part, an image control is added that points to the image added by the module. Because the resources added to the solution are added to the site collection, you need to be sure to add the correct path to the resource. The Web Part class should look like listing 6.2.

Listing 6.2. Adding an image to a Web Part using the server-relative URL
public class SandboxedWebPartWithImage : WebPart {
    protected override void CreateChildControls() {
        this.Controls.Add(
            new Image {
                ImageUrl = SPContext.Current.Site.ServerRelativeUrl +
                    "/Resources/Tick.png"
         });
    }
}

The Image control is created with an ImageUrl property that’s a concatenation of the relative URL to the site collection and the path to the image. Using the site collection–relative URL ensures that the path to the image is correct on subsites.

The SharePoint API has a utility class called SPUtility, which contains numerous utility and helper methods. When creating site collection- or site-relative URLs, you can use the tilde syntax in combination with the GetServerRelativeUrlFromPrefixedUrl method of the SPUtility class. The tilde syntax means that, instead of concatenating the URL as in listing 6.2, you can write the URL like this:

~sitecollection/Resources/Tick.png

This URL can then be processed by the GetServerRelativeUrlFromPrefixedUrl method, which creates the correct URL to be used by the client. This helper method can be used as shown next to translate the previous URL into a relative URL. The URL is stored in a string that you can use to set the image link property of the image control:

string url = SPUtility.GetServerRelativeUrlFromPrefixedUrl
    ("~sitecollection/Resources/Tick.png");

Unfortunately this helper method doesn’t work in Sandboxed mode and you won’t notice this fact until you test the Web Part. To make your solution work in Sandboxed mode, you have to build the URL manually by concatenating the strings.

6.1.5. URL Expression Builder in SharePoint 2010 Server

The publishing features in SharePoint 2010 Server edition have an Expression Builder class called SPUrlExpressionBuilder, defined in the Microsoft.SharePoint.Publishing assembly. This class is registered in the web.config (in the expressionBuilders section) with the SPUrl prefix. You can use this expression in ASPX pages or ASCX controls—for instance, in a Visual Web Part—to easily create server-relative or site-relative URLs like this:

<asp:Image
    runat="server"
    ID="img"
    ImageUrl="<%$SPUrl:~SiteCollection/Style Library/Images/image.png%>"/>

When the page containing this image is rendered, it’ll make a server-relative URL from the expression in the ImageUrl. To create a website-relative URL, you use the ~Site prefix instead of ~SiteCollection.

6.2. Localization resources in Web Parts

You’re living and working in a global world where you interact with people from all over the world. Not only is the language different from country to country, but you also treat dates and numbers differently. It would be great if everyone spoke the same language and used the same date and currency formatting—but that’s not the reality.

SharePoint 2010 supports various cultures and languages. You can’t expect everyone to be fluent in a single language. People feel more confident in using their native language when collaborating or having high-level discussions. If you develop solutions that might be used in organizations that use multiple languages, or if you’re building solutions that will be sold on a global market, you need to make sure that the solution is culture aware and supports multiple languages. The procedure of translating the user interface is called localization.

 

Cultures in .NET

The term culture is used in .NET and defines a set of properties for a culture such as language, sublanguage, country, calendar, sorting conventions, date and time formats, and so forth. All cultures have a name that consists of a two-letter language code and a two-letter region code—for example, en-US for English and the United States.

One specific culture is the “invariant culture,” which is culture insensitive; it’s associated with the English language but not with any country or region.

 

You install SharePoint using the English version and then apply language packs to support more languages. All sites are created with a default language, which means that all texts and labels will use that language. In previous versions of SharePoint, a site created in one language remained in that language and you couldn’t switch to other languages. SharePoint 2010 lets you enable users to switch to the language of their choice, as long as the necessary language pack is applied.

Let’s look at all the options you have when localizing your Web Part solutions and making them available for a global market. The user interface that you’re building with the Web Part should be localized as well as the features, Web Part properties, and the editing interface. You have to make several choices, depending on what part of the solution you’re localizing and if you’re deploying a farm or a sandboxed solution.

6.2.1. Localization methods

There are several methods and techniques available to localize SharePoint items. I recommend that you use resource (.resx) files (a Microsoft .NET framework native feature). You could create your own mechanisms for localizing Web Parts, but using the resource files approach is the only one that will work. To make a solution fully localizable, the Web Part interface and optional Editor Parts need to be localized as well as the Web Parts control description files (.webpart) and the SharePoint Feature that installs it.

You can choose among several methods of including resource files into a Visual Studio solution and SharePoint project, but none of them covers all possible aspects. The resource files in a SharePoint solution package are deployed into different locations, and use of the resources depends on the location. Table 6.1 shows the various locations that you can use to deploy resource files.

Table 6.1. Resources can be included in a solution via numerous methods.

Location

Usage

{SharePoint Root}/Resources Resources in this location are accessible from all web applications and can be used by Web Parts, Features, and Web Parts control description files.
{Feature}/Resources Resources in this location are only accessible and usable by the Feature.
{wwwroot}/App_GlobalResources Resources in this location are accessible from only that web application and can be used in Web Parts and user control files.
Satellite assemblies The default resources are embedded into the assembly and the other cultures have separate culture-specific assemblies.

Deploying resource files into the {SharePoint Root}/Resources folder is a good approach to use when localizing your Web Parts. This technique covers all scenarios (except for the case when you’re localizing the user control in Visual Web Parts). For Web Parts, the combination of using this folder and {wwwroot}/App_GlobalResources is the best alternative. Even though you could use the Feature’s local resources, having more files to work with will probably cause you trouble. For sandboxed Web Parts the only options you have are Feature local resources and culture-specific assemblies. You can’t deploy resource files as root or application global resources.

A resource file is an XML file with the extension of .resx and contains key/value pairs. There’s one resource file for each culture, and there should be one resource file that’s culture invariant as fallback. The filename of the resource file must be appended with the culture. For example, if the invariant culture resource file is named Resources.resx, then the English (US) resource file must be named Resources.en-US.resx and the Swedish resource file must be named Resources.se-SV.resx. A standard convention is to have the invariant resource file containing the same content as the English (US) resource file. You should also carefully name your resource files so they don’t overwrite other resource files (or aren’t overwritten).

Because resource files aren’t tied to your assembly or code, you can easily localize other SharePoint solutions or have other, for instance a translation agency, localizing yours. To localize an existing solution, make a copy of the resource file, change the culture, and then edit the .resx file. It’s smart to create a SharePoint solution package of the resource files so that you can install it as a language pack and deploy it to the farm.

Visual Studio provides an editor for resource files that simplifies editing. Just double-click on an .resx file in the Solution Explorer and the Resource editor will open, as shown in figure 6.5.

Figure 6.5. The Resource editor in Visual Studio allows you to add resource items and values.

The Resource editor allows you to edit the name and value of each resource item as well as add a comment. Using comments can be valuable when translating the resource files to other cultures to provide details about the context of the resource item.

6.2.2. Localizing code

The first thing you’ll localize are the controls you’re creating for the user interface. This step is probably the hardest part of localization because all strings or resources in the source code of the Web Part have to be replaced with calls to utility methods. Fortunately the SPUtility class has a method called GetLocalizedString that you can use to localize strings. To use this method in a Web Part, you have to deploy the resource files for localization to the {SharePoint Root}\Resources folder or the App_GlobalResources folder in the web application.

To localize a control in a Web Part, you have to add a resource file to the solution. Do so by adding a new item to the Web Part. Right-click the Web Part item in the Solution Explorer and select Add > New Item. In the Add New Item dialog box, select the SharePoint 2010 category and then select the Global Resource File item and click Add. Always assign unique names to the resource files so that they don’t overwrite resources from other solutions. When you click Add, Visual Studio asks which culture to use for the resource file. The first resource file you add should have the Invariant Language culture. When Visual Studio adds the file to the solution, it’ll create a file using the filename specified, and if any other culture than the invariant is selected, it’ll append the culture to the filename automatically. For example, if you name your resource file MyAppGlobalResources and select the English (United States) culture, Visual Studio will name the file MyAppGlobalResources.en-US.resx. You should always add one invariant culture to serve as the fallback when no culture-specific resource file is found.

When the resource file is added to the solution, it will have a deployment type of RootFile, which means that it’ll be deployed to the SharePoint Root Resources folder. To switch deployment to the App_GlobalResources folder in the web application, edit the properties of the file and change Deployment Type to AppGlobalResource. As long as you’re working with a Web Part and not user controls or Visual Web Parts, you can deploy it as a Root File, as you’ll learn in the next section.

Listing 6.3 shows how to add a localized Label control to a Web Part. This example localizes the Text property using the SharePoint utility methods. The text displayed depends on which culture is used in the interface and which installed resources exist in the solution.

Listing 6.3. Adding a localized Label control to a Web Part
protected override void CreateChildControls() {
    Label label = new Label();
    label.Text = SPUtility.GetLocalizedString(
        "$Resources:Title",
        "MyAppGlobalResources",
        (uint)CultureInfo.CurrentUICulture.LCID);
    this.Controls.Add(label);
}

The SPUtility.GetLocalizedString method is used to localize the Text property. The helper utility method takes a first argument, which represents the resource key. Resources are expressed using a resource expression, which has the following format:

$Resources:[file,]key

file is an optional parameter and isn’t used in this example. The file is instead used as the second argument to this method. Finally, the current locale identifier of the user interface is passed. You can easily turn this into your own helper method to make your code look cleaner by creating a new method that only takes the resource key as an input parameter.

 

Tip

You can also use the ASP.NET HttpContext.GetGlobalResourceObject method to retrieve resources from the App_GlobalResources folder.

 

6.2.3. Localizing Visual Web Part user controls

User controls in Visual Web Parts don’t have access to resources other than those deployed into the App_GlobalResources folder. This means that if you’re building Web Parts based on Visual Web Parts, you have to use two kinds of resources:

  • Resources deployed to {SharePoint Root}/Resources (for Features and .webpart files)
  • Resources deployed to {wwwroot}/App_GlobalResources (for Web Parts)

The Visual Web Part user controls can take advantage of the ASP.NET resource syntax, which means that you don’t have to use the SPUtility class to localize. The ASP.NET resource handler is only aware of App_GlobalResources, so when using this syntax you can’t use resources in Root Resources or Feature local resources. Listing 6.4 shows the same example as listing 6.3 but using a Visual Web Part.

Listing 6.4. Using the ASP.NET resource syntax in a user control
<asp:Label
    ID="label"
    runat="server"
    Text="<%$Resources:MyAppGlobalResources,Title %>" />

The Text property of the Label control uses inline scripts to localize the property. The same syntax you used for the SPUtility class is employed here, except that you must specify the name of the file. You can use the SPUtility class in the code-behind of the Visual Web Part if you prefer that syntax.

6.2.4. Localizing the Feature

The solution won’t be completely localized until you localize the Feature that includes your Web Parts. Even though this Feature isn’t seen by most end users, I recommend that you do this. For a Feature containing Web Parts, only the title and description of the Feature is of interest for localization.

To localize a feature, you can use Feature local resource files or resources in the {SharePoint Root}/Resources folder. Unless you have specific needs, I suggest that you place your resources in the Root Resources folder.

 

Restrict features to specific cultures

There’s one situation when you need to use the local resources for a Feature: when you’re restricting a Feature to a specific culture.

For example, say you don’t want a Feature to install if the corresponding resources aren’t available. You can then set the RequiresResources property of the Feature to true. Doing so will prohibit the Feature from showing up in the administration interface if no local resource files match the currently used culture.

 

To localize the Feature, start by adding a root resource file or by adding new resource items to existing root resource files. Then you have to set the Feature to use these resource files. Do so by opening the Feature in the Feature designer; then in the properties window, set Default Resource File to the name of your resource file. To access the properties window while in the Feature Designer, you can either press F4 or select View > Properties Window. You should only enter the name of the file without the extension and culture postfix. Then change the Title and Description settings to use the resource items using the resource expression syntax, as shown in figure 6.6. Because you’ve specified the default resource file you want to use, you don’t have to supply the filename.

Figure 6.6. The Feature can be localized using Feature local resource files.

 

Note

If you don’t specify a default resource file, the default will be core.resx, which resides in the {SharePoint Root}/Resource folder.

 

Not only the title and description can be localized in a Feature—you can also localize other parts, such as the elements manifest. The elements manifest of a Web Part normally contains the name of the group in the Web Part Gallery that the Web Part will be deployed to. This group name can be localized. The localized name of the group will be used when the Web Part feature is activated and the gallery is populated using the default language setting of the site, not the user’s settings.

To localize the group name of the Web Part, add the name to either the Feature local resources or the root resources. The resource expression is added to the Value attribute of the Property element like this:

<Property Name="Group" Value="$Resources:RootResources,GroupName;" />

This sample uses a resource file called RootResources and a resource item called GroupName. You can also localize the name of the Web Part file in the gallery and other items in the element manifests.

6.2.5. Localizing the Web Parts control description file

The Web Parts control description file (.webpart) contains the default property values for a Web Part and should be localized. The procedure is the same here as when localizing Features, but you can only use resources stored in the {SharePoint Root}/Resources folder. This also means that you can’t localize the .webpart file for Sandboxed solutions. Figure 6.7 shows a Web Part that has been localized into French and has been installed in a site collection that has French as the default language.

Figure 6.7. The Web Part Gallery uses the default language settings of the site for the groups and Web Parts added to the site collection.

Just as with the group name in the element manifest, the resource used for the properties is the default language of the top-level site of the site collection when deployed. Remember to always have a fallback invariant culture resource file or set the Requires Resources property of the feature to true to avoid invalid translations. It’s especially important to localize the Title and Description property values, which appear in the Web Part Gallery.

To localize the property values in the Web Parts control description file, you add resources to a root resources file and then use resource expressions in the property elements. Listing 6.5 shows how a .webpart file can be localized.

Listing 6.5. Localizing a Web Parts control description file

The default .webpart file that’s created contains the import error message , which is already localized using the core resource file. The Title and Description are localized using the RootResources file deployed into {SharePoint Root}/Resources.

6.2.6. Localizing Web Part properties

You just saw how to localize property values, but you also have to localize property names. As you’ll recall from chapter 5, you created custom properties and added attributes with the name, description, and category for each property. They’re hardcoded values that can’t be localized out of the box. To be able to localize these property names, you must extend the Web Part framework with custom attributes. Figure 6.8 shows a Web Part property that is localized.

Figure 6.8. A correctly localized Web Part property contains a localized title, description, and category.

To localize property names, you create three custom attributes, one for each standard attribute: name, description, and category. They all derive from the corresponding default .NET attribute (see chapter 5) so that the properties are correctly handled by SharePoint and the Web Part infrastructure and that they behave like the default attributes. The three attributes that you’ll create are:

  • LocalizedWebDisplayNameAttribute—Localized version of WebDisplayName
  • LocalizedWebDescriptionAttribute—Localized version of WebDescription
  • LocalizedWebCategoryAttribute—Localized version of SPWebCategoryName

The implementation of these attributes will be similar—the only differences are the names of the attribute classes and the classes they derive from. You can find full implementations of these classes for you to use in your projects in the source code for the book. Listing 6.6 shows the implementation of the LocalizedWebDisplayNameAttribute.

Listing 6.6. Implementation of the localized Web Part property display name

The localized display name is an attribute that can be used only on properties, and listing 6.6 allows it to be used just once on each property . This attribute inherits from the WebDisplayNameAttribute . The constructor takes the name of the resource item and the resource file to be used. Resource files can either be root resource files or stored in App_GlobalResources. The overridden DisplayName property is used to translate the resource item. First it checks if it has already been translated , and if not, it uses the SPUtility.GetLocalizedString to translate the item. Finally, it returns the DisplayName of the base class, which has now been translated.

When you’ve created all three attributes, you can add them to the properties of the Web Parts. Listing 6.7 shows how a property can be localized using these three attributes.

Listing 6.7. Using the localized Web Part property attributes
[Personalizable]
[WebBrowsable(true)]
[LocalizedWebDisplayName("CustomProperty", "RootResources")]
[LocalizedWebDescription("CustomPropertyDesc", "RootResources")]
[LocalizedWebCategory("CustomCategory", "RootResources")]
public string CustomProperty {
    get;
    set;
}

Instead of using the standard attributes, the display name, description, and category attributes have been replaced with the localized versions of these attributes. SharePoint will still identify these attributes because they inherit from the standard classes that SharePoint searches for.

6.2.7. Localizing using satellite assemblies

A common method for localization is to use satellite assemblies containing the resources. Satellite assemblies are culture-specific assemblies that contain the resources of only one culture. These assemblies are registered together with the main assembly for the solution, and the resources are available through automatically generated classes. Using satellite assemblies isn’t easy, and you must do some configuration. Another downside is that you can only access the resources from within your Web Part code and you can’t reuse the resources in manifests or .webpart files.

The easiest way to create satellite assemblies is to right-click the project and select Properties. In the Project Properties editor, select the Resources tab and choose to create a default resource file. The default resource file will be the invariant fallback resource file and its resources will be embedded in the main assembly. The resource file will be added to the project under the Properties node, as you can see in figure 6.9, and called Resources.resx. To add more cultures, just copy the default resources file and append the filename with the culture code.

Figure 6.9. Embedded resources in the project will be compiled to culture-specific satellite assemblies.

Each new resource file will result in a separate assembly. They’ll all have the same name but they’ll be located in separate subfolders in the build output folder. These built assemblies aren’t included in the SharePoint solution package by default. Consequently, they aren’t deployed to SharePoint. To include them in the WSP file, you have to open and edit the package. In the Package editor, switch to the Advanced tab, where you can add additional assemblies. To add one of the resource assemblies you’ve created, click the Add button and select Add Existing Assembly.

In the Edit Existing Assembly dialog box, set the Source Path field to one of the satellite assemblies. You can find them in your project folder under the bin\<configuration>\<culture>\ folder. All the satellite assemblies have the same name, so you have to edit the Location field of the assembly and prefix it with the culture, as shown in figure 6.10. For each assembly, repeat this procedure. Because you had to select the assemblies from one of the solution configuration folders (such as Release or Debug), you have to change the assembly references when switching between configurations.

Figure 6.10. The Package designer lets you add existing assemblies, which you’ll find necessary when deploying satellite assemblies.

 

Tip

You can avoid changing the references for the satellite assemblies by using a post-build script that copies the satellite assemblies into a custom folder. Then you reference the assemblies in this custom folder instead of the standard build output folders.

 

The resources can be used by any application that references the main assembly if you change the Access Modifier setting of the invariant resources to public (via the Project Properties window in the Resources tab). By default, the resources are available only for internal use. To use these resources in your code, you use the automatically generated resource classes:

Controls.Add(new Label {
    Text = Properties.Resources.Title
});

I don’t recommend that you make satellite assemblies your main approach to localizing your Web Parts—there are just too many issues, such as:

  • Resources are only available from code.
  • The Solution Package needs editing between release and debug builds. When you add the satellite assemblies to the package, they’re tied to one output directory, which is different between release and debug builds.
  • Compilation is necessary to build the satellite assemblies. RESX files can be edited without compilation

6.2.8. Localizing style sheets, scripts, and images

So far you’ve only looked at localizing text resources, but there are often situations when Web Parts need resources such as CSS files, JavaScript files, and images. These files might require localization—especially texts in JavaScript files or images containing text. Fortunately SharePoint has good support for this.

The {SharePoint Root}/Template/Layouts folder provides support for culture-specific folders. Most of the default JavaScript files of SharePoint reside in the culture-specific folders in the Layouts folder. When you add a new language pack for SharePoint, a new folder for the language pack is created in the Layouts folder. The name of the folder represents the locale identifier (LCID) instead of the short form of the culture name that’s used with the resource files.

Each culture-specific folder within the Layouts folder has two subfolders by default: one used for images and one used for style sheets, as you can see in figure 6.11. Scripts and other files are stored in the folder.

Figure 6.11. The Layouts folder mapped to the _layouts virtual directory contains one culture-specific folder for each installed language.

In chapter 4 you saw how to make a style sheet SharePoint theme aware. You added the CSS files into the Layouts/1033/Styles folder. A similar procedure is used to localize other file types. Start with adding the SharePoint Layouts mapped folder. You can safely remove the default folder created with the name of your project. Create one new folder for each culture that’s going to be supported using the LCID number. Scripts are added directly to the culture folder. To use localized scripts in your Web Parts, use the ScriptLink control. Do not hardcode or add the script manually. The ScriptLink control ensures that your JavaScript is included just once in the resulting page. With the ScriptLink control, you specify the name of the script and (optionally) if it’s localized. In a user control, it can look like this:

<SharePoint:ScriptLink
    runat="server"
    Name="CustomScript.js"
    Localizable="true" />

This code makes sure that SharePoint loads the script file with the name CustomScript.js. Because Localizable is set to true (which is the default value), it will create a reference to the file in the correct culture folder in the Layouts folder. If Localizable is set to false, it will look for the script file directly in the Layouts folder.

Style sheets use a similar control called CssRegistration. If you specify the name of the CSS file, it automatically assumes that the style sheet is in the Styles folder under the culture-specific folder. If the EnableCssTheming property is set to true, the file must be in the Styles/Themable folder:

<SharePoint:CssRegistration
    runat="server"
    Name="ThemedLookAndFeel.css"
    EnableCssTheming="true" />

If you need to reference culture specific images or other files in code, you can concatenate the path to the files by using the LCID value. In C#, you should use the current UI culture to get the LCID:

int lcid = CultureInfo.CurrentUICulture.LCID;

In JavaScript you can access the LCID using one of two methods. The first one is available as soon as the Document Object Model (DOM) has loaded:

var lcid =_spPageContextInfo.currentLanguage;

The other one requires that the SharePoint JavaScript files and the SP.* objects be loaded:

var lcid = SP.Res.lcid;

If you need to reference the images, scripts, or other files in the manifest files or files that can use resource expressions, you can use the core resource file to get the current LCID. The core resource files contain a resource item that always returns the current UI LCID, like this:

$Resources:core,Language;

Finally you always have the option to have values other than text in your resource files. You can use paths to files and scripts that are language dependent in the resource files.

6.2.9. Other localization considerations

You’ve learned how to localize text, images, scripts, and style sheets in SharePoint. To create applications that can be used by many different languages and cultures, you also need to make sure that you handle input data in the correct way. Another important thing is to thoroughly test your Web Part using different languages. The lengths of text may vary, which may affect your overall design.

One common mistake that I’ve seen in several products, including Microsoft’s, is the simple case that the decimal separator is treated differently in different cultures. For example, the Swedish write decimals using a comma whereas a dot is used in the United States. Another common mistake is that dates are formatted differently. The Microsoft .NET Framework contains all the functions that you need to avoid these common mistakes.

In listing 6.8, you have a Web Part that takes a decimal value as input and then prints the value. Although this example is simple, it shows you how to avoid two basic mistakes: parsing the input incorrectly and printing it incorrectly.

Listing 6.8. Using correct parsing of culture-specific input
TextBox tb = new TextBox();
Button btn = new Button();
btn.Text = "Click me";
Label lbl = new Label();

this.Controls.Add(tb);
this.Controls.Add(btn);
this.Controls.Add(lbl);

btn.Click += new EventHandler((s, e) => {
    decimal d = Decimal.Parse(tb.Text, CultureInfo.CurrentUICulture);
    lbl.Text = d.ToString(CultureInfo.CurrentUICulture);
});

When a user clicks the button, the Web Part converts the value from the text box into a decimal variable. As an argument to the Parse method, the current UI culture is passed, ensuring that the decimal parsing is done using the correct culture information. The value is printed using the Label control, and the decimal value is converted to a string using the ToString method with the current UI culture as an argument.

Visual Studio includes a feature called Code Analysis that helps you avoid these mistakes (I recommend that you always enable this feature). The code analysis can be run manually by selecting Build > Run Code Analysis. You can also enable this feature to run every time you compile your project by opening the Project Properties window, selecting the Code Analysis tab, and selecting the Enable Code Analysis On Build check box, as shown in figure 6.12.

Figure 6.12. Using Visual Studio Code Analysis helps you avoid common mistakes such as forgotten culture-specific conversions.

6.3. Summary

Localization of the Web Part can be tricky and time consuming, but the work will be worth it in the end. I recommend that you consider localizing your Web Part project when you start a new project—it’s always harder to implement localization when you’re done with the project. Even if you choose not to localize the interface, at least enable Code Analysis in Visual Studio and follow the design rules.

Now that you can attach items and scripts to your Web Part solutions, you’ll use this knowledge in upcoming chapters, especially when you’re building advanced Web Parts that uses the scripting capabilities of a web browser. Adding images and styling to your Web Parts is an easy trick to enhance the overall user experience.