Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

How one can access custom labels in javascript linked as separate static resource?

For example, some user action on the page should trigger confirmation dialog with custom message. And this message should be translated. Anything else on the page can be translated just fine with custom labels. The problem is that accessing custom labels requires VF context and {!xxx} syntax which of course doesn't work in separate resource.

So, is there a way to access custom labels from javascript? (Or any appropriate way to translate script messages)

share|improve this question
add comment

2 Answers 2

up vote 15 down vote accepted

This is a great question, and Custom Labels and the $Label global are the right place to start! Instead of evaluating Visualforce inside your JavaScript, you can do a little bit of JavaScript inside your Visualforce.

How do I get evaluated Visualforce variables into dumb static JavaScript?

  1. Load your Custom Labels into the platform using the normal interface,

  2. Create what I like to call a "Visualforce bridging component" that loads before your script, like so:

    <script>
        window.$Label = window.$Label || {};
        $Label.MyError = '{!JSENCODE($Label.MyError)}';
        $Label.MyPrompt = '{!JSENCODE($Label.MyPrompt)}';
        $Label.MyMessage = '{!JSENCODE($Label.MyMessage)}';
    </script>
    
  3. Now in your javascript (in a static resource) use the variables just as if they were VF without {!}

    <script src="{!URLFOR($Resource.ScriptZip, '/my.js')}">
        //NOTE: this example code is for clarity,
        //really he lives in the static resource
        function errorHandler() {
            console.log($Label.MyError);
            alert($Label.MyMessage);
        }
    </script>
    

vf-js-bridging-component

This is in the spirit of the platform: there is no need to interpret any variation on the token names and you can pluck the values straight out in your JavaScript without inventing anything :-)

share|improve this answer
1  
Nice approach. Is there any way of dumping some/all of the labels in the window.$Label object without a line of code per label? –  Keith C Apr 15 at 23:14
    
Not easily @KeithC - it might be a candidate for your continuous integration system to auto-generate a Visualforce Component from all the CustomLabels using the Metadata API. But if you maintain such a component by hand, at least it forms a 'single source of truth' for all your devs to request/consume the tokens. –  user320 Apr 15 at 23:21
    
So, it seems that VF does not generate any global variable with custom labels, and if I want to have one I should make it myself, right? I think also, it is good idea to create separate namespaces for different labels group in the published global variable. For example $Label.*myComponent* = { 'message1': '{!$Label.myComponent_message1}'} –  Vasily Liaskovsky Apr 16 at 12:09
    
Interesting idea @VasilyLiaskovsky. Definitely you might make life easier for your front-end guys by providing a grouping later in the application code. Personally I try not to create namespaces in the bridging component itself as it introduces an artificial mapping or 'third layer' that needs to be interpreted by a human. (For clarity, the JavaScript bridging component is intended to exactly match the Visualforce global variable it represents. Otherwise the bridging component becomes 'smart' and no longer has single responsibility.) –  user320 Apr 16 at 13:02
add comment

I think it is impossible to generate translations directly in static resource javascript. But it is possible to send a translation to the script via pass-through attributes. Like with a component we can pass some attributes to the script object and access it with javascript:

Visualforce page:

<apex:page>
    <script id="myScript" data-testme="{!$Label.MyTest1}" src="{!URLFOR($Resource.Scripts,'mytest.js')}"/>
    <input type="button" value="Test!" onclick="testMe();" />
</apex:page>

Here is a javascript that was packed to the static resource Scripts in the mytest.js file:

function testMe(){
    var scriptElement = document.getElementById('myScript');
    var label = scriptElement.getAttribute("data-testme");
    alert(label);
}

So if you click on the button a javascript function is executing and a popup will be show with a translation passed:

enter image description here

share|improve this answer
    
Idea is very good, especially using data-XXX attributes, but this approach has one serious drawback. Linking script to a component with multiple instances on a page will end up with one of: 1) multiple rendered elements with same id (when rendering script tag directly) or 2) mangling of id attribute (when using apex:includeScript). So, there could be a problem retrieving actual data. –  Vasily Liaskovsky Apr 16 at 12:04
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.