wikimedia / jquery.i18n

🌐 jQuery based internationalization library
GNU General Public License v2.0
704 stars 144 forks source link

How can I translate strings dynamically? #274

Open TechOverflow opened 1 year ago

TechOverflow commented 1 year ago

I'm having trouble translating strings dynamically. It seems that this is because the translation is loaded after the rest of the code.

main.js (script linked in head)

function _T(key) {
    'use strict';
    var i18n = $.i18n();
    $.i18n().load('../assets/lang/ui_' + $.i18n().locale + '.json', $.i18n().locale).done(function() {
        console.log(key + ' : ' + $.i18n(key));
        return $.i18n(key);
    });
}

page.php

<script type="text/javascript">
    $(document).ready(function () {
        var formats = { portrait : _T('text-portrait'), landscape : _T('text-landscape'), square : _T('text-square') }
        $.each(formats, function (key, format) {
            console.log('appending '+key)
            $('#format').append($('<option>', { 
                value: key,
                text : format
            }))
        })
    })
</script>

console output:

[Log] appending portrait
[Log] appending landscape
[Log] appending square
[Log] text-portrait : Portrait
[Log] text-square : Square
[Log] text-landscape : Landscape

As you can see, the translation happens after the each loop. What is the correct way to preload the translation to ensure it being available when document is ready?

TechOverflow commented 1 year ago

Brain fart, the load() needs to be outside of the function. Hope this helps someone else.

var i18n = $.i18n();
$.i18n().load('../assets/lang/ui_' + $.i18n().locale + '.json', $.i18n().locale);

function _T(key) {
    console.log(key + ' : ' + $.i18n(key));
    return $.i18n(key);
}
TechOverflow commented 1 year ago

I am still sometimes experiencing that the json file isn't loaded in time for the translations to be done. Is there a way to ensure that the (very small) files are loaded before executing the rest of the script?

Abhinob-Bora commented 9 months ago

i think modify the _T function, you can make use of a deferred object (e.g., $.Deferred()) to handle the asynchronous loading of translations :

function _T(key) { 'use strict';

var deferred = $.Deferred(); // Create a deferred object

// Load translations asynchronously
$.i18n().load('../assets/lang/ui_' + $.i18n().locale + '.json', $.i18n().locale).done(function () {
    console.log(key + ' : ' + $.i18n(key));
    deferred.resolve($.i18n(key)); // Resolve the deferred object with the translation
});

return deferred.promise(); // Return the promise from the deferred object

}

Now, the _T function returns a promise. This allows you to use the .done() method when calling _T to handle the asynchronous nature of loading translations:

$(document).ready(function () { // Define the formats without directly calling _T var formats = { portrait: 'text-portrait', landscape: 'text-landscape', square: 'text-square' };

// Load translations asynchronously
var loadOperation = $.i18n().load('../assets/lang/ui_' + $.i18n().locale + '.json', $.i18n().locale);

// Execute after translations are loaded
$.when(loadOperation).done(function () {
    // Populate #format with translated options
    $.each(formats, function (key, translationKey) {
        console.log('appending ' + key);

        // Use _T with .done() to get the translated value
        _T(translationKey).done(function (translatedValue) {
            $('#format').append($('<option>', {
                value: key,
                text: translatedValue
            }));
        });
    });
});

});