Я работаю над проектом с использованием nodeJs, handlebars и expressJs framework. Я добавляю функцию изменения языка с помощью модуля i18n-экспресс. Этот модуль добавляет строку запроса в конец 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.info(url);
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


На стороне клиента, если вы можете установить элемент в локальном хранилище, вы также можете получить тот же элемент и использовать его значение, чтобы отправить его в строку запроса. Таким образом, вам в основном нужна дополнительная функция на вашем клиентском 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();
Я пробовал это, но он загружает страницу два раза. есть идеи по этому поводу?
Основываясь на этом ответе ссылка, вы можете добавить дополнительную проверку в свой элемент управления, чтобы узнать, установлен ли clang уже в строке запроса, чтобы не обновлять страницу, если она уже настроена. Я изменил ответ этой проверкой.
Рекомендую Lingua для ExpressJS
По сути, Lingua - это промежуточное ПО для Express.js, которое помогает легко интернационализировать ваше веб-приложение. Он определяет язык пользовательского агента и передает ресурсы 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> -->
Вдруг на этой странице нет @types для программирования TypeScript.
Почему бы вам не передать 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
}
Насколько я понимаю, требование сводится к следующему:
Если конечный пользователь выбрал язык, выбор всегда должен быть прозрачным в 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's 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}/ делает смелое предположение, которое не всегда может быть правдой.
Можете ли вы создать минимальный пример проблемы «двойного обновления», с которой вы столкнулись (из решения ниже), в коды?