Как поддерживать меняющееся состояние языка в expressJS

Я работаю над проектом, используя nodeJs, handlebars и expressJs framework. Я добавляю функциональность языка изменений с помощью модуля i18n-express. Этот модуль добавляет строку запроса в конце URL - адреса, когда мы собираемся изменить язык. Теперь проблема в том, что когда я перемещаю одну страницу на другую страницу, тогда строка запроса удаляется и теряет его состояние. Как я могу поддерживать состояние языка? если пользователь выбирает французский язык, тогда все страницы открыты на французском языке. Это то, чего я хочу.

Код:

var i18n =  require("i18n-express");

app.use(i18n({
  translationsPath: path.join(__dirname, 'lang'), // <--- use here. Specify translations files path.
  siteLangs: ["ar","en","cn","fr","ge","he","hu","it","ja","ko","es","ru"],
  cookieLangName : 'ulang',
  textsVarName: 'translation'  
}));

Ссылка на изменение языка

<a href="#!" id="{{icon}}" onclick=" return changeLanguage(this)"></a>

Функция Onclick для изменения языка

function changeLanguage(event){
   $('#languages img').attr('src','/images/flag-icons/'+event.id+'.png');
   var url = window.location.href;
   url = url.split("?")[0];
   url += '?clang='+event.id;
   window.location.href = url;
   localStorage.setItem("clang", '?clang='+event.id); //event.id returns locale name such as en, ar, sp, fr etc.
   //console.log(url);
}

Ответ 1

На клиентской стороне, если вы можете установить элемент в локальном хранилище, вы также можете получить тот же элемент и использовать его значение, чтобы также нажать его в очередь. Таким образом, вам в основном нужна дополнительная функция на вашем javascript клиента, которая будет получать элемент каждый раз, когда открывается страница.

    function getParameterByName(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, '\\$&');
        var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }

    function checkLanguageFromLocalStorage(){
        var clang = getParameterByName('clang');
        if (clang == null) {
            if (localStorage.getItem("clang") != null) {
                var clang = localStorage.getItem("clang");
                var url = window.location.href;
                url = url.split("?")[0];
                url += '?clang='+clang;
                window.location.href = url;
            }
        }
    }

    checkLanguageFromLocalStorage();

Ответ 2

Я рекомендую вам Lingua для ExpressJS

В основном, Lingua является промежуточным программным обеспечением для Express.js, и это помогает вам интернационализировать ваш webapp легко. Он определяет язык пользовательского агента и подталкивает ресурсы i18n к вашим представлениям.

$ npm install -s lingua

var express = require('express'),
    lingua  = require('lingua');

// Express app configuration code and lingua init.
app.configure(function() {

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// Lingua configuration
app.use(lingua(app, {
    defaultLocale: 'en',
    path: __dirname + '/i18n'
}));

app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(__dirname + '/public'));
app.use(app.router);

Языковые файлы

'./i18n/en.json' and './i18n/de-de.json').

// en.json
    {
        "title": "Hello World",
        "content": {
            "description": "A little description."
        }
    }

// de-de.json
    {
        "title": "Hallo Welt",
        "content": {
            "description": "Eine kleine Beschreibung."
        }
    }

И вы можете легко реализовать его на своих страницах с помощью:

<h1><%= lingua.title %></h1> <!-- out: <h1>Hello World</h1> -->
<p><%= lingua.content.description %></h1> <!-- out: <p>A little description.</p> -->

Ответ 3

Почему бы вам не передать cookie с языком вместо параметра запроса? i18n-express есть опция cookieLangName которую вы уже настроили на стороне сервера (cookieLangName: 'ulang'). Установка cookieLangName делает i18n-express языком чтения из файла cookie с именем, которое вы передаете. Все, что вам нужно, это установить этот файл cookie в сценарий клиентской стороны - внутри функции changeLanguage - и он сделает трюк:

function changeLanguage(event){
   $('#languages img').attr('src','/images/flag-icons/'+event.id+'.png');
   document.cookie = 'ulang=${event.id}; path=/';

   localStorage.setItem("ulang", 'ulang=${event.id}; path=/'); // you can still save it to localStorage and synchronize it when cookie is removed
}

Ответ 4

Требование, я понимаю, сводится к следующему:

Если конечный пользователь выбрал язык, выбор должен всегда быть прозрачным в URL-адресе, чтобы обеспечить надлежащее функционирование модуля трансляции. Выполнение этого требования не должно вызывать ненужную перезагрузку страницы. Тем не менее, объем этого вопроса игнорирует тот факт, что при холодном запуске, где clang=xx не существует, для загрузки правильного содержимого потребуется перенаправление вручную, поскольку предыдущий выбор пользователя известен только клиенту.

Вы почти там, на основе фрагмента, который вы опубликовали. Функция changeLanguage правильно загружает контент на выбранном языке. Если бы я делал обзор кода на нем, я бы попросил несколько изменений в следующем результате:

Патч HTML

<a href="#!" id="{{icon}}" onclick="return loadContentInSelectedLanguage(this.id)"></a>

Патч JS:

function processLanguageSelection(selectedLang) {

  highlightCurrentlySelectedLang(selectedLang);
  saveSelectedLangAcrossSession("clang", selectedLang);

  reloadContentInSelectedLang(selectedLang);
}

function highlightCurrentlySelectedLanguage(selectedLang) {
  $('#languages img').attr('src', '/images/flag-icons/' + selectedLang + '.png');
}

function saveSelectedLangAcrossSession(entryKey, selectedLang) {
  window.localStorage.setItem(entryKey, selectedLang);
}

function reloadContentInSelectedLang(selectedLang) {
  var search = window.location.search || "?";

  if (/clang=\w{2}/.test(search)) {
    search = search.replace(/clang=\w{2}/, "clang=" + selectedLang);
  } else {
    search += ("?" === search ? "clang=" : "&clang=") + selectedLang;
  }

  window.history.replaceState(null, "", search);
  window.location.reload();
}

Ты почти там, как я уже говорил. Итак, что осталось в конечном итоге? - Отсутствует чип: предыдущий пользовательский выбор должен применяться только при загрузке страницы. И любое необходимое перенаправление должно быть сделано как можно раньше, прежде чем браузер начнет обрабатывать тело документа. Естественно, это означает, что часть ваших сценариев с этой ответственностью должна быть первой, которая запускается внутри раздела <head>...</head>.

<head>
  <script>
    (function() {
      var previouslySelectedLanguage = window.localStorage.getItem("clang");

      if (/clang=\w{2}/.test(window.location.search)) {
        // correct content should have been loaded in this case
        // otherwise the server needs fixing, but that not
        // in the scope of this question.

        // determine selectedLang from window.location.search, then..
        highlightCurrentlySelectedLanguage(selectedLang);

        if (!previouslySelectedLanguage || "selectedLang" !== previouslySelectedLanguage) {
          saveSelectedLangAcrossSession("clang", selectedLang);
        }

        return;
      }

      if (previouslySelectedLanguage) {
        // redirect
        reloadContentInSelectedLang(previouslySelectedLanguage);
      }
    })();

  </script>
</head>

Пожалуйста, обратите внимание, что примеры, предлагаемые в этом ответе, не являются готовыми к производству. Соблюдайте должную осмотрительность, убедившись, что они надежны, эластичны и соответствуют другим стандартам, необходимым в вашей организации. Например, это регулярное выражение /clang=\w{2}/ делает смелое предположение, которое не всегда может быть истинным.