LiveJS — web in-context editor

Live WYSIWYG editor for your website.

Andrew avatar
Written by Andrew
Updated over a week ago

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 the database running your website. In other words, once your translators are done with the texts on your website, 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 to Lokalise. However, there are some tips and tricks on how to update translations locally below.


  • 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 provided 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 provide text editing access only to specific users, you need to decide at which point the Lokalise LiveJS plugin is included and initialized. There are several options for doing this, which can also be combined: 

  • a dedicated translation environment (e.g. development or staging servers)

  • a certain GET parameter is supplied

  • a 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:

    window.LOKALISE_CONFIG = {
      projectId: "18302045592fa799a35d20.15846093",
      locale: "en"
    (function () {
      var a = document.createElement("script");a.type = "text/javascript";a.async = !0;
      a.src = ["", (new Date).getTime()].join("");

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

Step 2. Adjust Lokalise LiveJS script parameters


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


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


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. 


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


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


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


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

The function arguments are:

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

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

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

Error message (if any).



This parameter is usually set to true. It means that the LiveJS panel will slide from the bottom of the page, slightly pushing the page's content to the top. However, if for some reason the bottom of your site is not visible (it might be hidden with some banner or overlay), set this parameter to false.

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

    projectId: '98305045592fb799a15d20.15846093',
    locale: 'en',
    usePanelOffset: true,
    onSave: function (updatedTranslations, skippedTranslations, dismissedTranslations, errorMessage) {
        for (var i = 0; i < updatedTranslations.length; i++) {
                type: 'POST',
                url: '/ajax/translations/update',
                data: {
                    'key': updatedTranslations[i].key,
                    'translation': updatedTranslations[i].translation,
                    'locale': updatedTranslations[i].locale
                success: function (response) {
          '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 the translator finishes editing. 

Depending on the plainKey parameter you have set when initializing the snippet, you either 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


If you are wrapping in HTML (if a plainKey is false), it is a good idea to make an automatic wrapper for your template engine. Here is an 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']]);


As you can see, this Twig filter is using the __() 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 }}
    <p class="sub-text">
        {{ "index.hero.subtitle" | lokalise }}

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 respectively, to the element.

<input type="email" placeholder="" data-lokalise data-key="" 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.)

Dispatch this event in the case that new editable elements were loaded to the webpage. The Lokalise LiveJS script will search for them if editing mode is enabled. In the case that 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"));

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

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

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) {

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

document.addEventListener("lokalise-on-save-error", function(event) {

Listen for dismissed translations, which were cancelled by a translator.

document.addEventListener("lokalise-on-dismiss", function(event) {

Listen for plain keys to be replaced with editable elements. The event can be dispatched multiple times, when initializing 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");

Listen for keys to synchronize with Lokalise current translations. The event can be dispatched multiple times, when initializing and new HTML elements were added to the webpage. Keys can be synced only if the user is authenticated.

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

Listen for script to initialize. The event is dispatched when LiveJS has fully set itself up and parsed plain keys into editable elements.

This state does not require user authorization or key synchronization.

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

Dispatch this event in the case of retrieving the current state of user authentications. LiveJs will dispatch lokalise-on-auth-state-change as an answer.

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

Listen to this event to retrieve basic information about authentication. The event detail is an object:

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

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. For this option you need to implement the update on your back-end.

    projectId: '98305045592fb799a15d20.15846093',
    locale: 'en',
    onSave: function (updatedTranslations, skippedTranslations, dismissedTranslations, errorMessage) {
        for (var i = 0; i < updatedTranslations.length; i++) {
                type: 'POST',
                url: '/ajax/translations/update',
                data: {
                    'key': updatedTranslations[i].key,
                    'translation': updatedTranslations[i].translation,
                    'locale': updatedTranslations[i].locale
                success: function (response) {
          '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 so 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 the Lokalise API, however the common practice is to provide your admins or translators with an explicit method of updating the translations. This could be a button on the admin panel in your back-end or a specific URL (e.g. your domain/translations/fetch).

Did this answer your question?