Skip navigation

There’s nothing like a fresh Salesforce release to reassure SF consultants who, gainfully distracted by quotidian customer requests, have had their impetus to innovate temporarily quenched. Translation — I love working on a platform that innovates faster than I can.

Before Richard Vanhook jumps out of his skin (check out his excellent idea posted over a year ago), let me assure you that Salesforce has NOT added a much needed Apex API for Custom Labels / Translations. However, with Spring 12, it HAS finally enabled us to use Visualforce to dynamically render and use Custom Labels — and associated Translations — when the Label name is NOT known beforehand.

How does this make Custom Labels / Translation Workbench more useful? There are several thoughts that come to mind, but I’ll just describe one use case:

Rebranding the UI — At Skoodat, our trademark is design-oriented products, so we’ve done some heavy-duty overhauling of the standard SFDC UI, and have built a custom markup language to dynamically drive the content of our pages. Having the ability to dynamically insert text that automatically gets translated into other languages is a huge win, and the triumvirate of Salesforce’s Translation Workbench, built-in multi-language architecture, and Custom Labels, really makes the implementation of this fairly painless.

HOWEVER, for an ISV Partner interested in rendering pages dynamically based on custom metadata, this whole architecture is inaccessible, because there’s no way to access the value of a Label or Translation through Apex by name, i.e. there is no equivalent of loosely-typed System.Label.get('MyLabelName') … only the strongly-typed System.Label.MyLabelName .

So, how is this magic achieved? Well, with Spring 12, there will actually be 2 ways to achieve it:

  1. Dynamic Visualforce Bindings (which have now been extended to Global Variables)
  2. Dynamic Visualforce Components (which are finally Generally Available [i.e. not Pilot, not Beta] — and thus Packageable!!!

For this example, I first enabled Translation Workbench, and added one language: Spanish. I then created 2 Custom Labels: ‘Release’ and ‘WelcomeMessage’

Custom Labels

and then created an Apex controller called CustomLabelsController:


public class CustomLabelsController {

    public Component.Apex.OutputText output { public get; private set; }
    public String labelName { public get; private set; }

    public CustomLabelsController() {

        // Get the name of the Custom Label to display
        // from a Query String parameter
        Map params = ApexPages.currentPage().getParameters();
        labelName = params.get('label');

        // Instantiate a new Dynamic Visualforce Component,
        // and set its value attribute to a dynamic expression
        output = new Component.Apex.OutputText();
        output.expressions.value = '{!$Label.' + labelName + '}';
    }
}

This controller reads in a query string parameter called ‘label’ and assigns it to a page property (which we will retrieve from Visualforce using a Dynamic Binding), and then instantiates a new Dynamic OutputText component, setting the value property to the VF expression needed to retrieve a Custom Label.

I then created the following Page (called ‘CustomLabels’) which uses this controller:


<apex:page controller="CustomLabelsController">

    <apex:pageBlock title="Using Dynamic VF BINDINGS">
        <apex:outputText value="{!$Label[labelName]}"/>
    </apex:pageBlock>

    <apex:pageBlock title="Using Dynamic VF COMPONENTS">
        <apex:dynamicComponent componentValue="{!output}"/>
    </apex:pageBlock>

</apex:page>

In this page, I first use Dynamic VF Bindings to access the $Label Global Variable, which, as of Spring 12, can now be used with Dynamic Bindings to retrieve an arbitrary label name. I then display the Dynamic Component.

When I navigate to ‘/apex/CustomLabels?label=WelcomeMessage’, I am greeted in our language:

Where this becomes incredibly useful is when we start translating our Labels. I translated my labels into Spanish:

Spanish translation of Welcome Message

and then changed my user language to Spanish. Returning to my page, I was greeted by the following:

For  those of you who joined the Dynamic VF Components Pilot, this functionality technically has existed since Summer 11. In my mind, however, this is really a feature that would most appeal to ISV’s, so the inability to use it in Managed Packages sidelined its appeal until Spring 12.

Advertisements

3 Comments

  1. Thank you for a really helpful article!!
    I have 3 questions:
    1. Performance impact of doing this: output.expressions.value = ‘{!$Label.’ + labelName + ‘}’
    2. Any security considerations
    3. Is it possible for the Component.Apex.OutputText value to be a collection?
    I am trying to use this functionality to localize the pick-list values. If it was possible for the value to be a collection, the hypothetical code would look like this:

    List labels = [select PickListLabel__c from PickListCustomLabels__c];
    for (String labelName : labels) {
    output.expressions.value[0] = ‘{!$Label.’ + labelName + ‘}’;
    }

    • Hi Marina, glad you liked the article!

      1. Performance Impact: not that I know of, other than hitting your Script Statements governor limit in Apex as you construct your Dynamic Components.
      2. Security Considerations Yes – you should JSENCODE() both your label names, and the actual label value. Moreover, always have your generated content be escaped — that is, do NOT use escape=false. This would be a security risk.
      3. Converting the values into a JavaScript collection: Absolutely, you can use this syntax to assemble a JavaScript Array or Object, depending on which is more helpful for you. We use this approach at my company (Skuid) to dynamically retrieve Custom Labels (and their associated translations). You’ll basically need to have a dynamic apex:outputPanel with a bunch of dynamic child apex:outputText components, one for each Label you’d like to retrieve. If you want your Labels to be returned in a JavaScript object, each of the child apex:outputTexts should be formatted like a JavaScript key-value pair, e.g. component.expressions.value = '{!\'"\'+JSENCODE(\'' + labelname + '\')+\'":"\' + JSENCODE($Label.' + labelname + ') + \'",\'}';. Then wrap the final apex:outputText output in brackets to create a Javascript object.

  2. Thanks Zach!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: