How to switch languages with the i18next plugin?

26,052

Solution 1

The function to change the language is i18next.changeLanguage. You only need to call it, there's no need to call init again or to "change the init options" as the options are attributes inside i18next and they are managed through the API (the functions).

i18next.init({
    lng: 'en',
    fallbackLng: ['en', 'de', 'fr', 'it'],
});

// catch the event and make changes accordingly
i18next.on('languageChanged', (lng) => {
    // E.g. set the moment locale with the current language
    moment.locale(lng);

    // then re-render your app
    app.render();
});

In the view with the language selector:

const LangView = Backbone.View.extend({
    events: {
        'change .language-selector': 'onLangChange',
    },

    onLangChange(e) {
        // only change the language
        i18next.changeLanguage(e.currentTarget.value);
    }
});

Proof of concept

const app = {};

app.translations = {
    "fr": {
        "translation": {
            "label": "Choisir une langue",
            "fr": "Français",
            "en": "Anglais"
        }
    },
    "en": {
        "translation": {
            "label": "Choose a language",
            "fr": "French",
            "en": "English"
        }
    }
};

i18next.init({
    lng: 'en',
    fallbackLng: ['en', 'fr'],
    resources: app.translations,
});

// catch the event and make changes accordingly
i18next.on('languageChanged', (lng) => {

    // then re-render your app
    app.view.render();
});

const LangView = Backbone.View.extend({
    template: _.template($('#selector').html()),
    langTemplate: _.template('<option value="<%= value %>"><%= name %></option>'),
    events: {
        'change .language-selector': 'onLangChange',
    },

    render() {
        this.$el.html(this.template({
            label: i18next.t('label')
        }));
      
        // cache the jQuery object of the select
        this.$selector = this.$('.language-selector');
      
        // then dynamically populate it
        this.populateSelector();

        return this;
    },

    populateSelector() {
        // for each languages in i18next, add an option to the select
        _.each(i18next.languages, this.addLanguage, this);
    },

    addLanguage(lang) {
        // adding the option with the translated names
        this.$selector.append(this.langTemplate({
            value: lang,
            name: i18next.t(lang),
        }));
    },

    onLangChange(e) {
        // change the language
        i18next.changeLanguage(e.currentTarget.value);
    }
});

app.view = new LangView();

$('#app').html(app.view.render().el);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/i18next/4.1.1/i18next.min.js"></script>

    <div id="app"></div>
    <script type="text/template" id="selector">
        <label>
            <%=label %>
          </label>
        <select class="form-control language-selector"></select>
    </script>

Regarding translating the language names, take a look at Language of language names in the language selector?

Solution 2

$(document).ready(function () {
    i18n.init({
        "lng": 'en',
        "resStore": resources,
        "fallbackLng" : 'en'
    }, function (t) {
        $(document).i18n();
    });

   'change .language-selector': function(e){
        e.preventDefault();
        i18n.init({
        lng: $(e.target).val()}, (err, t) => {
            console.log(arguments);
            $(document).i18n();
        });
   }
}

I dunno backbone.js. Working solution in normal JavaScript is here

Share:
26,052
harsh
Author by

harsh

Updated on January 29, 2022

Comments

  • harsh
    harsh over 2 years

    I am using Backbone.js in my application and the i18next plugin for my language switch function on my application. When I pass a value to the lng option in the init function call, then it translates my page correctly.

    Now I want to do this dynamically via a language selector. I have a <select> of four languages and I want to pass the value of the selected language to the lng option of the init function.

    Here is my code:

    HTML

    <div class="col-xs-6>
        <select class="form-control language-selector">
            <option value="de">Deutsch</option>
            <option value="en">English</option>
            <option value="fr">Français</option>
            <option value="it">Italiano</option>
        </select>
    </div>
    

    JavaScript

    i18next.init({
            debug: true,
            languages: ['de','en','fr','it'],
            lng: 'de',  
            fallbackLng: false,
            load: 'current',
            resources: resBundle
        }, function(err, t){
    
    });
    
    'change .language-selector': function(e){
        e.preventDefault();
        i18next.setLng($(e.target).val(), (err, t) => {
            console.log(arguments);
            this.render();
        });
    }
    
    • rule
      rule over 7 years
      have you tried to print your i18n model after changin the language to see if is not a problem with your setLng? if the model is really getting the language changed?
    • harsh
      harsh over 7 years
      @rule: I get an error "i18next.setLng" is not a function.
    • Sunil B N
      Sunil B N over 7 years
      check if i18next is initialized .. do console in callback function of init.
    • harsh
      harsh over 7 years
      @SunilBN: Yes, when I load the application then i18next. init() function is initialized but when I change the language via select then it gives me error i18next.setLng is not a function.
  • harsh
    harsh over 7 years
    unfortunately this solution is not working for me. I think, I need to just pass the value of "lng" when it gets changed. But I don't know how can I do this? And also update the init options when "lng" get changed.
  • Emile Bergeron
    Emile Bergeron over 7 years
    setLng is deprecated and your jsfiddle example doesn't even use it. Also, favor stack snippet over off-site resources.
  • Emile Bergeron
    Emile Bergeron over 7 years
    @harsh yes, I corrected that. I have a service module named i18n in my app which is i18next in the background and forgot to change the name back.
  • harsh
    harsh over 7 years
    I dont use moment.locale in my view. What is the alternative of that.?
  • Emile Bergeron
    Emile Bergeron over 7 years
    @harsh that is just an example of stuff to handle there, you can completely ignore moment.
  • harsh
    harsh over 7 years
    Ok, but still I get an error."cannot read property 'render' of undefined" I defined .on method after the .init method, and both are in initialize function. I am confused that why this.render(); is not working in my i18next.on method.
  • harsh
    harsh over 7 years
    Of-course I understand what I am doing..;) and I already found out what the problem was. I am calling another API in initialization and it needs also the lang parameter. That's why it wasn't working. I need to figure out that. But as per this question your solution is working good. Thank you for that.