Wednesday, October 2, 2013

Localizing Content Search Webpart Display Templates in SharePoint 2013

In a previous post, I wrote about a way to parameterize the search query in Content Search Webparts. The method actually resolves some filter criteria in the query text before content is rendered in the CSWP: SharePoint 2013 Content Search Web Part (CSWP) in Variation Sites.

As part of the same task I wanted to localize some hardcoded content rendered in the CSWP. Even though it seemd CSWPs support localization because of the CustomStrings.js javascript reference added in the display template, I could hardly find a reference on how to use it, syntax, etc.

<script>
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
</script>

So here is the way. CustomStrings.js by default contains 2 entries and comment at the top asks to add custom localized strings to use in display templates.

// Add your custom localized strings and then include these string dictionaries in your display templates using the $includeLanguageScript function

$registerResourceDictionary("en-ca", {
    "sampleCustomStringId": "Sample custom string",   
    "rf_RefinementTitle_ManagedPropertyName": "Sample Refinement Title for ManagedPropertyName"
});

Therefore the Step 1 is to add localized strings to the CustomStrings.js files and to make sure they are deployed to the master page gallery of the site in the Language files folder. We have to deploy such a file for each culture we want to support.

$registerResourceDictionary("en-ca", {
    "sampleCustomStringId": "Sample custom string",
    "PostedOn": "Posted on",
    "ReadMore": "Read More",
    "rf_RefinementTitle_ManagedPropertyName": "Sample Refinement Title for ManagedPropertyName"
});

Then in the display template we have to make sure CustomStrings.js is referenced using the $includeLanguageScript function.

And lastly, in order to reference a key from the CustomStrings file, we can create variables like:
var readMoreText = $resource("ReadMore");
var postedOnText = $resource("PostedOn");

Defined variables can be used as:
<a href="_#= linkURL =#_" class="btn_more">_#=  readMoreText =#_</a>

Complete body section of the Item Template:
<body>
<!--
 Warning: Do not try to add HTML to this section. Only the contents of the first <div> inside the <body> tag will be used while executing Display Template code. Any HTML that you add to this section will NOT become part of your Display Template.
-->
<script>
    $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
</script>

<!--
    Use the div below to author your Display Template. Here are some things to keep in mind:
    * Surround any JavaScript logic as shown below using a "pound underscore" (#_ ... _#) token inside a comment.

    * Use the values assigned to your variables using an "underscore pound equals"
    (_#= ... =#_) token.
-->

<div id="TwoLines">
<!--#_
var monthname = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");

var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncode);
var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);

var line1 = $getItemValue(ctx, "Line 1");
var line2 = $getItemValue(ctx, "Line 2");
line1.overrideValueRenderer($contentLineText);
line2.overrideValueRenderer($contentLineText);

var containerId = encodedId + "container";
var pictureLinkId = encodedId + "pictureLink";
var pictureId = encodedId + "picture";
var dataContainerId = encodedId + "dataContainer";
var line1LinkId = encodedId + "line1Link";
var line1Id = encodedId + "line1";
var line2Id = encodedId + "line2";

var readMoreText = $resource("ReadMore");
var postedOnText = $resource("PostedOn");
_#-->
 <div id="_#= containerId =#_" data-displaytemplate="Item2Lines">
  <div class="NewsRight" id="_#= dataContainerId =#_">
   <div id="_#= line1Id =#_"> _#= postedOnText =#_
    <label>_#= monthname[new Date(line1).getMonth()] + " " + new Date(line1).getDate()+ ", "+new Date(line1).getFullYear() =#_</label>
   </div>
              
<!--#_
if(!line2.isEmpty)
{
_#-->
   <div class="Award_Itm_Link" id="_#= line2Id =#_" >
    <a href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_">_#= line2 =#_</a>
   </div>
<!--#_
}
_#-->
   <a href="_#= linkURL =#_" class="btn_more">_#= readMoreText =#_</a>   
  </div>
  <br class="clearfloat" />
 </div>
</div>
</body>

3 comments:

Unknown said...

Hi,

Nice to see the concept in detail. But I need one help in the same approach. I have used #includeLangaugeScript tag in my delegate (.ascx) control and getting the resources (key, value) perfectly fine. But I had a problem here that, if my page loads very first time $resource("key") is returning empty string and from the second request or refresh of the page am able to get the content. Can you pls help me on that.

Thanks in advance.
Raju

Anonymous said...

Very well documented.

Anonymous said...

HI, Is it possible to access the resource files in a content editor web part?