Technical Instructions

Technical documentation for Transifex Live.

Nina avatar
Written by Nina
Updated over a week ago

This article will explain how Transifex Live works behind the scenes. If you're a developer, we've also included some instructions on how to customize Transifex Live's behavior.


How a user's language is detected

The window.liveSettings.detectlang field of the JavaScript code can be used to get the user's preferred language. When this option is set to true, Transifex Live tries to guess the language in the order listed here:

  • Look for a ?lang=code URL parameter, e.g. www.transifex.com/?lang=de.

  • Match code.domain.xyz domain, e.g. de.transifex.com

  • Look for domain.xyz/code/ URL pattern, e.g., www.transifex.com/de/features.

  • Check the browser's language preference. When a visitor reaches a website page, Transifex checks if a specific language was preselected by checking localStorage. That way, the last user’s preference is identified. In case no preselection is found (the user has never visited this site before), then if the setting “Display translations based on browser locale” is enabled, Transifex checks the user’s language preferences on the browser he uses and serves the translations that correspond to this specific locale.

For more customization options, check out the Transifex Live JavaScript API documentation.


Hiding translation swapping on page load

Although translations are cached locally to the user's computer, when a user fetches translations from the Transifex CDN for the first time, they might see a page in the source language briefly before the translated language appears.

To avoid this, add a special txlive class to the <body> of your page (be sure that you still install the JavaScript code inside the head).

Like this:


<head>
...JavaScript integration code...
</head>
<body class="txlive">
...
</body>

The txlive class hides the underlying content; it's removed when the translation has been applied to the page.


Creating a custom language selector

Each website has its own way of presenting a language selector to the user. The snippets below are examples of creating a custom language selector using the JavaScript API.

  • <ul> element

    //This is called each time the languages list is retrieved
    //from Transifex Live. This may happen more than once, so we should
    //be able to handle this case.
    Transifex.live.onFetchLanguages(function(languages) {

    //set the language selector to the source language (default)
    $('#language-current').html(
    Transifex.live.getSourceLanguage().name
    );

    //empty our language list
    $('#language-selector').empty();

    //add translation languages to the list
    for (var i = 0; i < languages.length; ++i) {
    $('#language-selector').append(
    '<li data-code="' + languages[i].code +
    '" data-name="' + languages[i].name +
    '">' + languages[i].name + '</li>'
    );
    }

    //handle user selecting a language
    $('#language-selector').find('li').click(function(e) {
    e && e.preventDefault();
    var code = $(this).closest('[data-code]').data('code');
    var name = $(this).closest('[data-code]').data('name');

    //tell transifex live to translate the page
    //based on user selection
    Transifex.live.translateTo(code, true);
    });

    //called when Transifex Live successfully translates the
    //page to a language. In that case let's update the
    //selected language of the widget
    Transifex.live.onTranslatePage(function(language_code) {
    $('#language-current').html(
    Transifex.live.getLanguageName(language_code)
    );
    });
    });

  • <select> element

    /* 
    Custom picker example with <select> type language dropdown, e.g.
    <select id="language-select">

    <!-- This is populated by the snippet below -->
    <option value="en">English</option>
    <option value="fr">French</option>
    <option value="de">German</option>

    </select>
    */

    //This is called each time the languages list is retrieved
    //from Transifex Live. This may happen more than once, so we should
    //be able to handle this case.
    Transifex.live.onFetchLanguages(function(languages) {

    //empty our language <select> list
    $('#language-select').empty();

    //add translation languages to the list
    for (var i = 0; i < languages.length; ++i) {
    $('#language-select').append(
    '<option value="' + languages[i].code +
    '">' + languages[i].name + '</option>'
    );
    }

    //set the language selector to the source language (default)
    $('#language-select').val(
    Transifex.live.getSourceLanguage().code
    );

    //handle user selecting a language
    $('#language-select').change(function() {
    //tell transifex live to translate the page
    //based on user selection
    Transifex.live.translateTo($(this).val());
    });

    //called when Transifex Live successfully translates the
    //page to a language. In that case let's update the
    //selected language of the widget
    Transifex.live.onTranslatePage(function(language_code) {
    $('#language-select').val(language_code);
    });
    });

📝 Note: Please note that if you decide to implement a custom language selector, you need to disable the default language picker we offer by following the steps below:

  1. Open the settings in the Transifex Live preview.

  2. Select "Do not place a picker" in the "Language picker position" field.

  3. You must publish at least one translation language to see the language picker.


Handling change when the user switches languages

There might be cases where you want to catch the event on the backend side when a user switches a language and react accordingly.

Here is an example of how you can achieve this:

<script type="text/javascript">
window.liveSettings = {
api_key: "<your key>",
picker: "bottom-left"
};
</script>
<!-- Settings example ^^ -->
<script type="text/javascript" src="//cdn.transifex.com/live.js"></script>
<!-- live.js link ^^ -->
<script>
Transifex.live.onFetchLanguages(function (languages) {
Transifex.live.onTranslatePage(function (language_code) {
console.log(language_code);
});
});
</script>
<!-- Code to handle language change ^^ -->


Customizing your website per language

There might be cases where a web page must be customized based on the selected language. In that case, there are two options.

The first one is to use CSS. Transifex Live alters the <html lang> attribute so that special CSS directives can be used.

For example:

html[lang="ar"] .foo { … }
html[lang="de"] .foo { … }

The second option is to use the Transifex Live JavaScript API and capture the event:

Transifex.live.onTranslatePage(function(lang) {
if (lang === ‘ar') {
//do stuff
}
});


Handling dynamic content

Transifex Live automatically handles static content by default, i.e., HTML initially loaded from the first HTTP request. However, many websites have dynamic content that must be translated, such as popups or content loaded from AJAX calls.

Dynamic content is handled automatically when the "Enable translation of dynamically injected content" check is enabled in the Live Settings (enabled by default); however, the developer can also handle it manually.

This solution involves using Transifex Live JavaScript API to manually mark content for translation by specifying the HTML DOM node/nodes to be translated.

Here is an example of how to translate a dynamic portion of a page:

...
//start adding dynamic content after Transifex Live
//has loaded, and translations have been fetched
Transifex.live.onReady(function() {
...
//Add dynamic parts of the page
$('#foo').append(
'<h1>Section</h1><p>This is a paragraph</p>'
);
Transifex.live.translateNode($('#foo').get(0));
...
});

Another technique is to use the Transifex.live.translateText call inside a JavaScript template engine. The following example shows how this can be done using underscore.js.

//after the inclusion of live.js library
<script type="text/javascript">
//create an alias
window._t = Transifex.live.translateText;
</script>
...
...
<script type="text/template" id="template">
<div>
<h1><%= _t("This is a title") %></h1>
<p><%= _t("This is a paragraph") %></p>
<p><%= _t("Hello {name}", params) %></p>
</div>
</script>
...
...
<script type="text/javascript">
...
$('#foo').html(
_.template($(#template).html())({
params: {
name: 'John'
}
});
);
</script>


How the parser works

The Transifex Live JavaScript parser works in the background for you. As you and your users browse through pages of your live website (or pages in a staging environment), Live automatically detects translatable content in the background and stores it for your review.

This is how your content is segmented:

Block tags

Block tags include DIV, P, H1, TABLE, UL, OL, etc.

When the content of a block tag is a combination of plain text and inline elements such as SPAN, all the content is considered a single segment.

HTML:
<div>
<p>This is a paragraph</p>
<p>This is a paragraph with <span>inline element</span></p>
<div>

Segments:
"This is a paragraph"
"This is a paragraph with <span>inline element</span>"

Plain text

When the content of a block tag is NOT a combination of plain text and a tag, only the plain text content is extracted.

HTML:
<div>
<p>
<span>My span text</span>
<span>Another span text</span>
</p>
</div>

Segments:
"My span text"
"Another span text"

📝 CSS Data Binding On The Angular or React Framework

CSS styles may also be used for data binding on the Angular or React framework. The DOM model is used to decipher the Angular or React framework. This entails that the text inside the Inline Element is directly controlled by the Angular/React framework instead of being modified through HTML (e.g., in the case of jQuery).

Because of this, when a block tag combines plain text and inline elements, such as SPAN, that use a data-binding-based CSS style on the Angular/React framework, the text attribute needs to be evaluated separately. This results in the creation of multiple segments.

HTML:
<div>
<p>This is a paragraph</p>
<p>This is a paragraph with <span class="AngularReact">an inline element</span></p>
<div>

Segments:
"This is a paragraph"
"This is a paragraph with"
"an inline element"

Page title

HTML:
<title>My title</title>

Segments:
"My title"

Anchor titles

HTML:
<a title="My title">..</a>

Segments:
"My title"

Image titles and alt text

HTML:
<img title="My title" alt="My alt text"/>

Segments:
"My title"
"My alt text"

Input values and placeholders

Input values are only detected for inputs with the type button, reset, and submit.

Textarea placeholders

HTML:
<textarea placeholder="My placeholder text">

Segments:
"My placeholder text"

Meta keywords and descriptions

HTML:
<meta name="keywords" content="tag1, tag2, tag3">
<meta name="description" content="My page description">
<meta name="title" content="My page title" >
<meta property="og:title" content="Localization Platform for Translating Digital Content | Transifex">
<meta property="og:description" content="Integrate with Transifex to manage the creation of multilingual websites and app content. Order translations, see translation progress, and tools like TM.">

Segments:
"tag1, tag2, tag3"
"My page description"
"My page title"
"Localization Platform for Translating Digital Content | Transifex"
"Integrate with Transifex to manage the creation of multilingual websites and app content. Order translations, see translation progress, and tools like TM."

Input elements of type 'image'

HTML:
<input type="image" alt="Submit">

Segments:
"Submit"

SVG elements

SVG tags may contain some nested TEXT tags, which are parsed and their strings extracted, but there is no MARKING in the UI for these elements. However, when you mouse over these elements, the options for the strings are shown (ignore string, follow link, etc.).

Elements that are ignored: script, style, link, iframe, noscript, canvas, audio, video, code.

Social widgets such as Facebook and Twitter that have tags with class names facebook_container and twitter_container are also ignored.


How to detect elements that are not detected by default by the Live JS parser

Live.js, by default, skips certain tags like style, code, etc. To detect such a tag, change the live JS snippet by adding the enable_tags option.

e.g.

window.liveSettings={
...
enable_tags: ['code'],
...
};


How to handle iframes

  1. Make sure the parent page has the live JS snippet.

  2. Ensure the page loaded within the iframe also has the live JS snippet. Browsers do not allow JavaScript to process child frames, so the following code in the parent page will not work:

    window.liveSettings={
    ...
    enable_tags: ['iframe'],
    ...
    };

  3. Use JavaScript in the parent page to pass the currently selected language as a URL parameter to the embedded page. Some sample code to make this happen:

    Transifex.live.onReady(function() {
    const lang_code = Transifex.live.getSelectedLanguageCode();
    window.document.querySelectorAll("iframe").forEach(function(frame) {
    var url = new URL(frame.src);
    if (url.host === window.location.host || host === 'ADD IFRAME HOST HERE') {
    url.searchParams.set('lang', lang_code);
    frame.src = url.href;
    }
    })
    });

    Transifex.live.onTranslatePage(function(lang_code) {
    window.document.querySelectorAll("iframe").forEach(function(frame) {
    var url = new URL(frame.src);
    if (url.host === window.location.host || host === 'ADD IFRAME HOST HERE') {
    url.searchParams.set('lang', lang_code);
    frame.src = url.href;
    }
    });
    }

  4. By default, Live doesn't parse or interact with iFrames. This can be accomplished by :

    • The pages inside the iFrame have the JavaScript snippet installed.

    • Some additional code is added to pass language changes down to the iFrames.

    Here is some sample code on how to achieve the desired behavior.

    <script>
    // When a page loads, make sure live is ready
    Transifex.live.onReady(function() {
    const webpageHost = 'ADD ADDITIONAL IFRAME HOST HERE';
    // Get the selected language
    const lang_code = Transifex.live.getSelectedLanguageCode();
    // Apply to all iframes
    window.document.querySelectorAll("iframe").forEach(function(frame) {
    var url = frame.src.split("?");
    var urlHost = url[0];
    var urlParams = url[1];
    var params = new URLSearchParams(urlParams || '');
    var host = new URL(urlHost).host;
    if (host === window.location.host || host === webpageHost) {
    params.set('lang', lang_code)
    var iframeUrl = url[0] + "?" + params.toString();
    frame.src = iframeUrl;
    }
    })
    });
    </script>


    ```
    **On language change**
    ```
    <script>
    // When language changes
    Transifex.live.onTranslatePage(function(lang_code) {
    const webpageHost = 'ADD ADDITIONAL IFRAME HOST HERE';
    // Apply to all iframes
    window.document.querySelectorAll("iframe").forEach(function(frame) {
    var url = frame.src.split("?");
    var urlHost = url[0];
    var urlParams = url[1];
    var params = new URLSearchParams(urlParams || '');
    var host = new URL(urlHost).host;
    if (host === window.location.host || host === webpageHost) {
    params.set('lang', lang_code)
    var iframeUrl = url[0] + "?" + params.toString();
    frame.src = iframeUrl;
    }
    })
    });
    </script>


How to handle non-translatable content

You can manually define a block or node as non-translatable by adding a notranslate class.

For example:

<div class="notranslate">This content will not be translated</div>


Marking attributes for collection and translation

Apart from the attributes automatically detected for translations, you can define custom attributes for translation using the tx-attrs="attr1, attr2,..." attribute.

Before:

HTML:
<span title="My title" data-content="My data content">

Segments: Nothing detected

After:

HTML:
<span title="My title" data-content="My data"
tx-attrs="title, data-content">

Segments:
"My title"
"My data"


How to tag strings in the source language

You can automatically tag source strings using the tx-tags="tag1, tag2,..." attribute.

These tags propagate to child elements as well.

For example:

<div tx-tags="marketing">...</div>

Tags will appear in Transifex's Web Editor in all languages, and you can filter strings using the tags.

⚠️Tag Updates: There is no “automatic” way to check for metadata changes and push new versions of a string; also, there is no easy way to determine when a string is new or not. If you need to perform an update, you must delete & re-approve the strings that have changed tags or change the tags through the editor.


How to handle inline-block variables

To define variables or placeholders within a block that shouldn't be translated, use class="notranslate" in the variable nodes or encapsulate them inside var tags.

For example:

HTML:
Hi, you are visitor <span class="notranslate">142</span>
Hi, you are visitor <var>341</var>

Segments:
"Hi, you are visitor {{0}}"


How to handle URLs as translatable content

When images <img> or links <a> appear within a segment, their URLs are handled by default as non-translatable content (i.e., variables).


Translating images

To translate an image, you should treat its URL (src attribute) as translatable text. To do so, use the special directive tx-content="translate_urls" to enable this functionality for a node and its children.

Before:

  • Only the alt attribute gets translated if there's no surrounding text.

  • If there is surrounding text, then the whole string gets translated.

HTML:
<div>
<img src="/uploads/smiley.jpg" alt="Smiley face" width="42" height="42">
</div>

Segments:
"Smiley face"


HTML:
<div>
Smile, you're on camera <img src="/uploads/smiley.jpg" alt="Smiley face" width="42" height="42">
</div>

Segments:
"Smile, you're on camera <img src="{{0}}" alt="Smiley face" width="42" height="42">"

After:

  • The alt and src attributes get translated if there's no surrounding text.

  • If there is surrounding text, then the whole string gets translated.

HTML:
<div tx-content="translate_urls">
<img src="/uploads/smiley.jpg" alt="Smiley face" width="42" height="42">
</div>

Segments:
"Smiley face"
"/uploads/smiley.jpg"


HTML:
<div tx-content="translate_urls">
Smile, you're on camera <img src="/uploads/smiley.jpg" alt="Smiley face" width="42" height="42">
</div>

Segments:
"Smile, you're on camera <img src="/uploads/smiley.jpg" alt="Smiley face" width="42" height="42">"


Translating links

To translate a link, you should treat each URL (href attribute) as translatable text. To do so, use the special directive tx-content="translate_urls" to enable this functionality for a node and its children.

Before:

  • If there's no surrounding text, only the display text gets translated.

  • If there is surrounding text, then the whole string gets translated.

HTML:
<div>
<a href="/features/">features</a>
</div>

Segments:
"features"


HTML:
<div>
Click to go to the <a href="/features/">features</a> page
</div>

Segments:
"Click to go to the <a href="{{0}}">features</a> page"

After:

  • The display text and href attribute get translated if there's no surrounding text.

  • If there is surrounding text, then the whole string gets translated.

HTML:
<div tx-content="translate_urls">
<a href="/features/">features</a>
</div>

Segments:
"features"
"/features/"


HTML:
<div tx-content="translate_urls">
Click to go to the <a href="/features/">features</a> page
</div>

Segments:
"Click to go to the <a href="/features/">features</a> page"

💡Tip: To treat ALL URLs as translatable content within a page, add the tx-content="translate_urls" to the opening BODY tag.


How to define custom variables

If you want to use your own custom patterns and are looking for a way to ignore such text handling this as a variable, then you can add custom rules on how variables are handled within a string segment.

E.g.

window.liveSettings = {
...
variables_parser: function(text, fn) {
// Example of replacing the value of an s-href attribute with a variable.
// Input: Hello <a s-href="doc:example">Click here</a>
// Output: Hello <a s-href="{{0}}">Click here</a>
// We use a regular expression to match the attribute
text = text.replace(/s-href="([^"]*)"/g, function(a, b) {
// Group a contains: s-href="doc:example"
// Group b contains: doc:example
// fn function registers the content of "doc:example" as variable
// in Live and returns a variable expression to replace it: {{0}}
return a.replace(b, fn(b));
});
return text;
},
...
}


How to fine-tune translatable content

For even finer control over how strings are detected, use the tx-content HTML attribute, which can contain the following values:

  • exclude to mark a node and its children to be excluded from string detection.

  • include to mark a node and its children within an exclude block to be included in string detection.

  • block to mark a node and its children to be detected as a single string.

  • notranslate_urls to mark a node and its children to handle URLs as variables (default).

  • translate_urls to mark a node and its children that URLs should be translated.

Include/exclude examples

Before:

HTML:
<div>
<p>First text</p>
<p>Second text</p>
<p>Third text</p>
</div>

Segments:
"First text"
"Second text"
"Third text"

After:

HTML:
<div tx-content="exclude">
<p>First text</p>
<p tx-content="include">Second text</p>
<p>Third text</p>
</div>

Segments:
"Second text"

Block example

Before:

HTML:
<div>
<h1>A header</h1>
<p>A paragraph</p>
</div>

Segments:
"A header"
"A paragraph"

After:

HTML:
<div tx-content="block">
<h1>A header</h1>
<p>A paragraph</p>
</div>

Segments:
"<h1>A header</h1> <p>A paragraph</p>"

⚠️Warning: Strings that match the following regular expression are ignored by Live:

^( |\s|\d|[-\/:-?~@#!"^_`\.,\[\]])*$


Localizing numbers and currencies

Transifex Live supports localized formatting of numbers and currencies. For example, when a number is presented to a German visitor, it will be formatted with a comma as the decimal marker and points as thousand markers; the same number, when presented to an English visitor, will use the reverse notation.

Furthermore, Live also handles the formatting of prices concerning the currency position defined for each language.

To activate this feature, mark the HTML tags you want to localize by including a tx-content attribute in your markup.

For example.

Before:

<div>
<p>1.000.000.000,45</p>
<p>125.4km</p>
</div>

After:

<div>
<p tx-content="number">1.000.000.000,45</p>
<p tx-content="number">125.4km</p>
</div>

The above example will work only if the number format matches the selected source language. For example, if you have English as a source language, then a number like 1.123.456,50 will not be localized except if you explicitly define the format by adding a tx-format attribute.

Markup example with explicit format definition.

<div>
<p tx-content="number">1.123.456,45</p> <-- Will not work with en locale
<p tx-content="number" tx-format=",.">1.123.456,45</p> <-- Will work because of explicit format
</div>

All the above will also work for nodes holding currency values.

<div>
<p tx-content="currency">5.123,50€</p>
</div>

The above currency value will be presented as € 5,123.50 to a US visitor and € 5 123,50 to a French one.


The file format used by Transifex Live

The file format for a resource can be found by:

  1. Clicking on the specific resource.

  2. Select the three vertical dots near the top right and click Settings.

  3. Looking at the greyed-out value under "Resource file/format type".

Screenshot-2021-05-31-122527.png#asset:9104

For this file format, a list of translation checks can be set up to trigger either warning or error messages to translators throughout the translation process and ensure that these rules won’t be violated or missed. This list for Transifex Live projects is under "Transifex Format (.json) checks".

Screenshot-2021-05-31-124017.png#asset:9105

💡Tip: The value for older Transifex Live projects will be "TX" instead of "WEB".


Allow multiple instances of the same source string.

When you have the same string appearing multiple times on your website, Transifex identifies it as a single instance. This means that you only need to approve and translate the string once instead of every time it appears on your site. Additionally, this feature helps you keep track of the number of times a particular string appears on your website and where these occurrences are located. To learn more about tracking text occurrences, please refer to this guide.

Sometimes, it is not ideal to address all instances of the same string in only one instance, as they might require different translations based on the context in which they are being used. In such cases, Transifex Live provides the option to save the same string occurrences in different instance groups. This allows for more accurate and context-specific translations.

This can be implemented in your project by just adding to your strings the attribute tx-string-group, and assigning it the name of the instance that you want to link to your string. The syntax would be the following:

Syntax

For a single element:

<element tx-string-group="group-name"> Text </element>


Example 1. List not using the tx-string-group attribute.

Let's say you have an unordered list with the same string multiple times:

<ul> 
<li>How are you</li>
<li>How are you</li>
<li>How are you</li>
<li>How are you</li>
<li>How are you</li>
</ul>

In the above list, the string appears five times, and Transifex will create a single instance with five occurrences.

Example 2. List using the tx-string-group attribute.

In this case, the list is using the tx-string-group attribute in some strings:

<ul> 
<li tx-string-group="mygroup">How are you</li>
<li >How are you</li>
<li tx-string-group="mygroup">How are you</li>
<li >How are you</li>
<li tx-string-group="othergroup">How are you</li>
</ul>

For this list, Transifex will create three instances of this string:

  • The first instance will have two occurrences (the first and third <li> elements).

  • The second instance will have two occurrences (the second and fourth <li> elements).

  • The third instance will have one occurrence (the fifth <li> element only).

Example 3. Parent element using the tx-string-group attribute.

The tx-string-group can also be propagated from a parent element, which means that if you add this attribute to an element with child elements in it, in case of having a string appearing multiple times in the child elements, all the occurrences inside the parent element will be assigned to the same instance.

In this case, the parent element will have the tx-string-group attribute:

<ul tx-string-group="othergroup"> 
<li >How are you</li>
<li >How are you</li>
<li tx-string-group="anothergroup">How are you</li>
</ul>

For this list, Transifex will create two instances of this string:

  • One for the two first <li> tags inherited from the parent <ul> element.

  • One for the third <li> tag that has his own tx-string-group attribute.


💡Tip

Looking for more help? Get support from our Transifex Community Forum!

Find answers or post to get help from Transifex Support and our Community.

Did this answer your question?