Introduction

LiveJS is an in-context JavaScript editor that lets your translators or copywriters edit your website texts and translations right on the webpage. All changes are shown in the browser and saved directly to Lokalise, not to your localization files or database running your web. In other words, once your translators are done with the texts on your web, you would need to take care of how the changes will reach your localization files or database.

Again, this editor does not download or fetch any translations from Lokalise, its only purpose is to allow in-context editing and sync back to Lokalise. There are some hints though on how to update translations locally below.


Prerequisities

  • Your site is prepared for localization with localization files containing key/value pairs, i.e. in any localization file format
  • The project is properly set up in Lokalise
  • Site visitors are served with local localization files (e.g. JSON, YML, PO) or translations from the database
  • Translators have accounts with Lokalise and are allowed to edit the target languages.


Getting started

 Assuming you want to give text editing access only to specific users, you need to decide at which point Lokalise LiveJS plugin is included and initialized. There are several options to do that, which you can combine: 

  • dedicated translation environment (e.g. development or staging servers)
  • certain GET parameter is supplied
  • certain URL is visited
  • already authenticated users with a certain session variable set


Step 1. Include Lokalise LiveJS script at the end of your HTML

You need to include following script in your HTML just before the closing </body> tag:

<script>
    window.LOKALISE_CONFIG = {
      projectId: "18302045592fa799a35d20.15846093",
      locale: "en"
    };
    (function () {
      var a = document.createElement("script");a.type = "text/javascript";a.async = !0;
      a.src = ["https://lokalise.co/live-js/script.min.js?", (new Date).getTime()].join("");
      document.body.appendChild(a)
    })();
</script>

As mentioned above, do not include and initialize it for all of your website's visitors.


Step 2. Adjust Lokalise LiveJS script parameters

projectId    

string (required)
The project ID (it must be already set up in Lokalise). You can find the project ID in Project settings.

locale

string (required)
Current locale that is being edited. It must match the language code in Lokalise.

plainKey

boolean (default false)
Enable to convert plain key names into editable HTML elements. The key names must be wrapped (see plainKeyLeftWrapper and plainKeyRightWrapper parameters). 

The default wrappers are {.  and .}. If enabled, you can skip adding special data attributes to HTML elements. 

plainKeyLeftWrapper

string (default "{.")
Unique key name prefix used to expose plain keys in a HTML code.

plainKeyRightWrapper

string (default ".}")
Unique key name suffix used to expose plain keys in a HTML code.

disableAdvancedHtml

boolean (default false)
Enable to edit only content-editable sections (Bold, Italic, Headings, Paragraphs, Links and Lists will be still available in dynamic toolbar).

onSave  

function (optional, default: null)
Callback function, which can be used to update your local database or files directly or by pulling strings from Lokalise. 

Function arguments are:

updatedTranslations
array of translation objects (see below)
Successfully updated translations.

skippedTranslations
array of translation objects (see below)
Translations which were not updated, including errorMessage, with a reason.

dismissedTranslations
array of translation objects (see below)
Translations which were cancelled by a translator.

errorMessage
string
Error message (if any).


Translation object:

  • key (string) Lokalise translation key
  • translation (string) HTML\text
  • locale (string) Lokalise locale of translation
  • success (boolean) (optional) Flag indicating that translation was updated
  • skipped (boolean) (optional) Flag indicating that translation was skipped
  • errorMessage (null | string) (optional) Reason why translation was skipped

Usage example:

window.LOKALISE_CONFIG = {
    projectId: '98305045592fb799a15d20.15846093',
    locale: 'en',
    usePanelOffset: true,
    onSave: function (updatedTranslations, skippedTranslations, dismissedTranslations, errorMessage) {
        for (var i = 0; i < updatedTranslations.length; i++) {
            $.ajax({
                type: 'POST',
                url: '/ajax/translations/update',
                data: {
                    'key': updatedTranslations[i].key,
                    'translation': updatedTranslations[i].translation,
                    'locale': updatedTranslations[i].locale
                },
                success: function (response) {
                    console.info('Translation updated', response);
                }
            });
        }
    }
};

Step 3. Expose key names in HTML

The plugin needs to know which phrase on your website corresponds to which key, thus making it possible to save the changes to Lokalise once a translator finishes the editing. 

Depending on the plainKey parameter you have set when initializing the snippet, you ether need to wrap the translated text in any HTML element with the data-lokalise attribute and set the data-key attribute or just expose a wrapped key name.

Example for plainKey: false

<span data-lokalise data-key="index.hero.title">Translation platform for developers</span>

Example for plainKey: true

{.index.hero.title.}


In case you are wrapping into HTML (if plainKey is false) It is a good idea to make an automatic wrapper for your template engine. Here is the example for the Twig template engine:

$lokalise = new Twig_SimpleFilter('lokalise', function ($key) {
    return '<span data-lokalise data-key="' . $key . '">' . __($key) . '</span>';
}, ['is_safe' => ['html']]);

$twig->addFilter($lokalise);

As you can see, this Twig filter is using __() function which simply returns the value of the key from a local .json file:

global $locales;
$locales = json_decode(file_get_contents('locale/en.json'), true);

function __($key)
{
    global $locales;

    if ($locales[$key]) {
        return $locales[$key];
    }

    return $key;
}

Use the filter in .twig files:

<div class="col-md-12">
    <h1 class="hero-text>
        {{ "index.hero.title" | lokalise }}
    </h1>
    <p class="sub-text">
        {{ "index.hero.subtitle" | lokalise }}
    </p>
</div>


Translating placeholders, default values of input elements and aria labels

Some translations cannot be wrapped in a separate HTML tag, like placeholders, default values of input elements or aria labels. In order to translate them, add data-type-placeholder, data-type-input or data-type-aria-label attributes to the element respectively. 

<input type="email" placeholder="john.doe@mail.com" data-lokalise data-key="form.email.placeholder" data-type-placeholder>
<input type="text" value="lokalise" data-lokalise data-key="default.selector" data-type-input>
<button aria-label="Close" data-lokalise data-type-aria-label data-key="aria.close.button">X</button>


The setup for dynamic websites using events (Angular JS, React, Vue etc.)

lokalise-update-elements
Dispatch this event in case new editable elements were loaded to the webpage. The Lokalise LiveJS script will search for them if the editing mode is enabled. In case the configurable option syncTranslations is enabled, it will also sync these translations with the latest ones from Lokalise.

document.dispatchEvent(new Event("lokalise-update-elements"));


lokalise-update-locale
Dispatch this event in order to update the locale of translations.

document.dispatchEvent(new CustomEvent("lokalise-update-locale", {"detail": "en_US"}));


lokalise-on-save
By listening to this event you achieve the same result as with the configurable callback function onSave. Please note that the event detail is a Translation object.

document.addEventListener("lokalise-on-save", function(event) {
    console.log(event.detail.updatedTranslations);
    console.log(event.detail.skippedTranslations);
    console.log(event.detail.dismissedTranslations);
    console.log(event.detail.errorMessage);
});


lokalise-on-save-error
Listen for errors while saving translations. The event detail is a string with an error message.

document.addEventListener("lokalise-on-save-error", function(event) {
    console.log(event.detail);
});


lokalise-on-dismiss
Listen for dismissed translations, which were cancelled by a translator.

document.addEventListener("lokalise-on-dismiss", function(event) {
    console.log(event.detail);
});


lokalise-keys-parsed
Listen for plain keys to be replaced with editable elements. Event can be dispatched multiple times, when initialising and new HTML elements were added to the webpage (requires lokalise-update-elements event).

document.addEventListener("lokalise-keys-parsed", function() {
    console.log("Plain keys were parsed");
});

lokalise-keys-synced
Listen for keys to synchronise with Lokalise current translations. Event can be dispatched multiple times, when initialising and new HTML elements were added to the webpage. Keys can be synced only if user is authenticated.

document.addEventListener("lokalise-keys-synced", function() {
    console.log("Plain keys were synced");
});


lokalise-initialized
Listen for script to initialise. Event is dispatched when LiveJs has fully set up itself and parsed plain keys into editable elements.

This state does not require user authorisation or keys synchronisation.

document.addEventListener("lokalise-initialized", function() {
    console.log("LiveJs initialized");
});


lokalise-check-auth-state
Dispatch this event in case to retrieve current state of users authentication. LiveJs will dispatch lokalise-on-auth-state-change as an answer.

document.dispatchEvent(new Event("lokalise-check-auth-state"));


lokalise-on-auth-state-change
Listen to this event to retrieve basic information about authentication. Event detail is an object:

// event.detail:
{
    authenticated: true, // bool
    user: {
        name: "John Doe",
        email: "john.doe@mail.com"
    } // empty object if user is not logged in
}
document.addEventListener("lokalise-on-auth-state-change", function(event) {
    console.log(event.detail);
});

Updating localization files (local translations)

Once a translator is done editing a translation (and hits ⌘/Ctrl-S to save), Lokalise LiveJS will automatically update the respective translation in Lokalise. In order to make changes visible to all visitors, you now need to update the local translation files. Depending on your initial localization setup, there are several options. These include:

Instantly update your localization files (local translations)

Use the callback function and update your local translation files (or your database) instantly after every translation is saved. With this option you need to implement the update on your back-end side.

window.LOKALISE_CONFIG = {
    projectId: '98305045592fb799a15d20.15846093',
    locale: 'en',
    onSave: function (updatedTranslations, skippedTranslations, dismissedTranslations, errorMessage) {
        for (var i = 0; i < updatedTranslations.length; i++) {
            $.ajax({
                type: 'POST',
                url: '/ajax/translations/update',
                data: {
                    'key': updatedTranslations[i].key,
                    'translation': updatedTranslations[i].translation,
                    'locale': updatedTranslations[i].locale
                },
                success: function (response) {
                    console.info('Translation updated', response);
                }
            });
        }
    }
};


Use Lokalise API or CLI to generate translations at the build time

Some localization file formats, e.g. .po or .yaml, are not that easy to update. In this case, use the Lokalise exporter to get the files from Lokalise. You may still use the callback function to send a request to Lokalise API, however the common practice is to provide your admins or translators with a explicit method to update the translations. That could be a button in the admin panel in your back end or a specific URL (e.g. your domain/translations/fetch).

Did this answer your question?