SharePoint 2007 Deployment: Using Resources in Features

This series of posts about SharePoint deployment would not be complete if I didn’t write one about using resources in Features to allow localization. After all, SharePoint’s out-of-the-box features use resources all the time. Check the first post SharePoint 2007 Deployment: Overview for an introduction and the series index.

Why should I use Resources?

In my opinion, you should always use resource files for your features. Why?

  • First, because it’s easy to do even if you only have one language.
  • Second, because if you do, all the objects you are provisioning in SharePoint will be localized and will be displayed in the correct language of the website (provided you have deployed the resource file for that language).

Examples of things that should be placed in resource files:

  • Title and Description of you feature, so that they will be displayed in the language of the website;
  • Site column display name and description;
  • Content type name and description;
  • List template name and description;
  • List instance title and description;
  • Custom action title and description.

How do I use it?

There are three steps to use resources in a feature:

  1. Build the resource (.resx) files;
  2. Place the resource files in the correct folder;
  3. Use the resource strings in the feature manifest and element manifests.

Note: The next sections show how to use feature-specific resources. I’ll briefly discuss shared resources in the end of the post.

Building the resource (.resx) files

The best way to build the resource files is using Visual Studio 2008, but you can do it manually on any text editor since they’re just XML text files.

<?xml version="1.0" encoding="utf-8"?>
<root>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>
      System.Resources.ResXResourceReader, 
      System.Windows.Forms, 
      Version=2.0.0.0, 
      Culture=neutral, 
      PublicKeyToken=b77a5c561934e089
    </value>
  </resheader>
  <resheader name="writer">
    <value>
      System.Resources.ResXResourceWriter, 
      System.Windows.Forms, 
      Version=2.0.0.0, 
      Culture=neutral, 
      PublicKeyToken=b77a5c561934e089
    </value>
  </resheader>
  <data name="MyFeatureName" xml:space="preserve">
    <value>My Feature Name</value>
  </data>
  <data name="MyFieldDisplayName" xml:space="preserve">
    <value>My Field Display Name</value>
  </data>
  <data name="MyFieldChoice1" xml:space="preserve">
    <value>My Choice 1</value>
  </data>
  <data name="MyFieldChoice2" xml:space="preserve">
    <value>My Choice 2</value>
  </data>
</root>

See above an example of a resource (.resx) file. The <data> elements are the ones that hold the localized strings:

  • The name attribute is the key used to retrieve the localized string;
  • The <value> child element is the localized string itself.

Each language must have its own resource file which follows a specific naming convention:

  • The main resource file must be called Resources.resx. This is the culture neutral resource file (or fall back resource file) which will be used by SharePoint whenever there is no resource file for a specific culture.
  • All culture specific resource files must be named Resources.[culture].resx. Some examples:
    • Resources.en-US.resx (english – United States)
    • Resources.pt-PT.resx (portuguese – Portugal)
    • Resources.fr-FR.resx (french – France)
    • Resources.pt-BR.resx (portuguese – Brazil)

Placing the resource files in the correct folder

These files must be placed in a Resources folder inside your feature’s folder. So, if your feature’s folder is C:\…\12\TEMPLATE\FEATURES\MyFeature, the resource files need to be placed in the folder C:\…\12\TEMPLATE\FEATURES\MyFeature\Resources.

Resources and the Feature Manifest

After you have created the resource files and placed the in the correct folder, you can now used them in your feature manifest (feature.xml).

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="5DFD12AF-D0AA-4c63-8FB8-C49DB1191083"
         Title="$Resources:MyFeatureName"
         Scope="Site"
         Version="1.0.0.0">
  <ElementManifests>
    <ElementManifest Location="SiteColumns.xml"/>
    <ElementFile Location="Resources\Resources.resx" />
    <ElementFile Location="Resources\Resources.pt-PT.resx" />
    <ElementFile Location="Resources\Resources.es-ES.resx" />
  </ElementManifests>
</Feature>

The sample above, shows a feature manifest that uses resources to specify the feature title. As you can see, the value of the Title attribute is $Resources:MyFeatureName. This tells SharePoint that it should check the resource file for the current website’s culture and retrieve the string that has the key MyFeatureName.

Notice the use of <ElementFile> elements to reference the resource files in the feature. This is required if you are deploying this feature through a solution package (.wsp).

Important: because we are using feature-specific resource files (resource files that are only used for this specific feature), you cannot use the DefaultResourceFile attribute on the <Feature> element. If you do, SharePoint will not look for resource files in the local Resources folder for this feature.

Resources and the Element Manifest

Besides using localized strings to specify the feature title and description, you can (and should) use localized strings for most feature elements.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Field Type="Choice"
         DisplayName="$Resources:MyFieldDisplayName"
         Required="FALSE"
         Format="Dropdown"
         FillInChoice="FALSE"
         ID="{485b2176-4cfc-4923-8085-c003b85dab36}"
         StaticName="MyField"
         Name="MyField">
    <Default>$Resources:MyFieldChoice1</Default>
    <CHOICES>
      <CHOICE>$Resources:MyFieldChoice1</CHOICE>
      <CHOICE>$Resources:MyFieldChoice2</CHOICE>
    </CHOICES>
  </Field>
 </Elements>

The sample above specifies a choice field, and uses localized strings for:

  • Field display name
  • Each of the field’s choices
  • The field’s default choice

The theory is exactly the same as it was used for the feature manifest: you use the expression $Resources:[key] whenever you want SharePoint to retrieve a localized string from the resource file of the current website’s culture.

Shared Resource Files

The method shown in the previous sections assumed that each feature has its own resource files. However, that is not always the case and SharePoint itself uses shared resource files. That is, resource files that can be shared by multiple features.

There are only two differences when using shared resource files:

  • The folder where the resource files are placed;
  • The way you reference the localized string in you feature manifest and element manifests.

Other than that, the file format and contents can be exactly the same.

Folder for Shared Resources

Shared resource files must be placed in the folder C:\…\12\Resources instead of the local Resources folder inside the feature folder.

Referencing Shared Resources

Because the shared resources files can have any name you want, you must reference the localized strings in a more specific way, so as to tell SharePoint which resource file holds a particular string.

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="5DFD12AF-D0AA-4c63-8FB8-C49DB1191083"
         Title="$Resources:MyResources,MyFeatureName"
         Scope="Site"
         Version="1.0.0.0">
  <ElementManifests>
    <ElementManifest Location="SiteColumns.xml"/>
  </ElementManifests>
</Feature>

As you can see in the above sample, instead of $Resources:MyFeatureName I’m referencing the localized string with $Resources:MyResources,MyFeatureName. This tells SharePoint to look for:

  • A localized string whose key is MyFeatureName
  • In a resource file named MyResources.[Culture].resx
  • In the C:\…\12\Resources folder

If all your strings are in the same shared resource file, then you can specify that file as the default resource file and reference the strings as shown in the first sample.

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="5DFD12AF-D0AA-4c63-8FB8-C49DB1191083"
         Title="$Resources:MyFeatureName"
         DefaultResourceFile="MyResources"
         Scope="Site"
         Version="1.0.0.0">
  <ElementManifests>
    <ElementManifest Location="SiteColumns.xml"/>
  </ElementManifests>
</Feature>

The sample above does exactly the same as the previous one. The only difference is that it specifies MyResources.[culture].resx as the default resource file and, because of that, you don’t need to specify it on all references to the localized strings.

Additional Notes

So, how does SharePoint choose which resource file to use when loading the localized strings?

  1. Looks for the resource file of the exact culture of the website. If you have a website based on a portuguese (pt-PT) site template, it will look for the Resources.pt-PT.resx. If it’s there, it loads all the strings from it.
  2. If it’s not there, it looks for any resource files of the same culture, even if it has a different location. So if your website’s language is pt-PT (Portuguese – Portugal) and you don’t have a Resources.pt-PT.resx file, but you have a Resources.pt-BR.resx (Portuguese – Brazil) file, then SharePoint will use it.
  3. If there is no resource file for the website’s culture, SharePoint will use the fall back resource file (Resources.resx).

Samples

You can download samples for:

These samples include:

  • The solution manifest file (manifest.xml).
  • The solution cab structure file (solution.ddf).
  • The feature manifest file (Feature.xml).
  • The element manifest file (SiteColumns.xml).
  • The resource files (.resx)
  • A batch file (build.bat) that creates the solution package

Warning: Do not install both solutions in the same farm, since some of the IDs are the same and the feature has the same name on both solutions. If you want to use it as is, test each solution separately, removing one before installing the other.

Notice: These samples are given for illustrative purposes only. Feel free to modify and use them as templates for your solutions and features.