Локализовать строки в Javascript

В настоящее время я использую файлы .resx для управления ресурсами на стороне сервера для .NET.

приложение, с которым я работаю, также позволяет разработчикам встраивать JavaScript в различные обработчики событий для проверки на стороне клиента и т. д. Как мне лучше всего локализовать сообщения и строки JavaScript?

В идеале я хотел бы хранить строки в файлах .resx, чтобы сохранить их вместе с остальными локализованными ресурсами.

Я открыт для предложений.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
41
0
47 240
12

Ответы 12

Я бы использовал обозначение объекта / массива:

var phrases = {};
phrases['fatalError'] ='On no!';

Затем вы можете просто поменять местами файл JS или использовать вызов Ajax для переопределения списка фраз.

Обратите внимание, что это неверно. phrases будет массивом, но вы просто устанавливаете одно из его свойств для строки (например, phrases.fatalError = 'Oh no'; эквивалентно вашей второй строке). Вместо этого используйте объектные литералы для чистоты.

millenomi 19.09.2008 22:03

Расширение ответа diodeus.myopenid.com: пусть ваш код выпишет файл, содержащий массив JS со всеми необходимыми строками, а затем загрузите соответствующий файл / скрипт перед другим кодом JS.

Базовый объект JavaScript представляет собой ассоциативный массив, поэтому его можно легко использовать для хранения пар ключ / значение. Итак, используя JSON, вы можете создать объект для каждой строки, которая будет локализована следующим образом:

var localizedStrings = {
    confirmMessage:{
        'en/US':'Are you sure?',
        'fr/FR':'Est-ce que vous êtes certain?',
        ...
    },

    ...
}

Тогда вы можете получить локальную версию каждой строки следующим образом:

var locale='en/US';
var confirm=localizedStrings['confirmMessage'][locale];

Проблема с этим подходом в том, что вы загружаете все строки для всех языков. Однако вполне вероятно, что сервер будет знать либо через подсказки браузера, либо через настройки пользователя, какой язык нужен. Было бы лучше отправить файл на одном языке.

AnthonyWJones 19.09.2008 22:03

Поскольку я пишу объектно-ориентированный JS, каждый объект определяет английские строки по умолчанию, которые он использует в прототипе. Если мне нужен другой язык, я просто загружаю другой файл и изменяю строки прототипа. Таким образом, мне не нужно загружать сразу все строки для одного языка (они загружаются динамически). Недостатком является то, что вам может потребоваться повторить некоторые строки для разных объектов.

Juan Mendes 12.08.2011 20:40

просто инвертирование порядка 'localizedStrings [culture] [key]' решает проблему загрузки нескольких культур ... это также может позволить использовать 'нейтральную' культуру в качестве прототипа для всех остальных (обеспечивая плавный откат, когда культура не не определяю конкретный ключ)

Andrew Theken 04.02.2012 16:38

Я использую Т4 для генерации в точности кода, предложенного выше.

Jochen van Wylick 24.11.2012 10:35

Вдохновленный SproutCore Вы можете установить свойства струны:

'Hello'.fr = 'Bonjour';
'Hello'.es = 'Hola';

а затем просто укажите правильную локализацию в зависимости от вашей локали:

var locale = 'en';
alert( message[locale] );

С помощью вспомогательной сборки (вместо файла resx) вы можете перечислить все строки на сервере, на котором вы знаете язык, таким образом создавая объект Javascript только со строками для правильного языка.

У нас работает что-то вроде этого (код VB.NET):

Dim rm As New ResourceManager([resource name], [your assembly])
Dim rs As ResourceSet = 
    rm.GetResourceSet(Thread.CurrentThread.CurrentCulture, True, True)
For Each kvp As DictionaryEntry In rs
    [Write out kvp.Key and kvp.Value]
Next

Однако, к сожалению, мы еще не нашли способ сделать это для файлов .resx.

JSGettext отлично справляется с этой задачей - динамическая загрузка файлов GNU Gettext .po с использованием практически любого языка в серверной части. Google для "Динамической локализации Javascript с помощью Gettext и PHP", чтобы найти пошаговое руководство для JSGettext с PHP (я бы опубликовал ссылку, но этот глупый сайт не позволяет мне, вздох ...)

Редактировать: это должен быть ссылкой

MSDN способ сделать это, в основном:

You create a separate script file for each supported language and culture. In each script file, you include an object in JSON format that contains the localized resources values for that language and culture.

Я не могу сказать вам лучшего решения вашего вопроса, но ИМХО, это худший способ сделать это. По крайней мере, теперь вы знаете, как этого НЕ делать.

Просто потому что это РС, это плохо? Неудачная попытка показаться смешной! Это наиболее распространенный способ. Если это наихудший способ, нужно хотя бы объяснить почему!

Juan Mendes 12.08.2011 20:43

@Juan Попытка быть смешным? Я предполагаю, что способ локализации своих строк в js - это в точности способ MSDN, также известный как «CPP - копирование и вставка программирования», и я не мог терпеть, когда кто-то его критиковал. «Самый распространенный способ» - это нарушить принцип DRY в соответствии с вашим утверждением, но вы, вероятно, не воспринимаете это как запах кода.

BrunoSalvino 12.08.2011 23:14

Как это нарушение DRY? Даже если ваш аргумент верен, ответ все равно слабый, поскольку он ничего не объясняет.

Juan Mendes 13.08.2011 03:00

ИМХО, это одно из самых СУХИХ решений. Строки находятся только в одном файле, в одном месте, и на этот файл ссылается везде, где требуется отображать строки.

Andrew Dunkman 04.02.2012 02:34

Пользовательский интерфейс jQuery также использует «способ MSDN», над которым вы насмехаетесь. Мне нравится, что все, что делает Microsoft, для некоторых людей «неправильно».

Josh Earl 16.03.2012 03:54

Проблема в том, что они защищают повторение логики (дословно) для каждого отдельного языка, который вы хотите поддерживать. Они также предлагают смешивать ваши строковые ресурсы с вашим кодом. Тоже не лучшая идея. Упомянутый выше Jquery.i18n этого не делает. Они отделяют данные (строковые ресурсы) от кода и аналогичным образом хранят 1 копию вашей логики, опять же отдельно от данных.

Julian 08.01.2013 10:25

Я считаю, что они рекомендуют вам включить сценарий, отдельный файл для каждого языка .. с одним экспортом (который представляет собой объект с парами ключ / значение) для конкретного языка .. и включить его отдельно от вашего кода / логики .. именно это и использует jQuery.i18n.

Tracker1 30.09.2013 23:00

Ребята, ребята, расслабьтесь, способ, предложенный в MSDN, не так хорош, потому что, если вы действительно используете файл .resx, вам нужно будет повторить его в JS. пока способ DRYies: stackoverflow.com/a/14782225/1930376

João Antunes 27.09.2017 12:46

Я сделал следующее, чтобы локализовать JavaScript для мобильного приложения с HTML5:

1. Создал набор файлов ресурсов для каждого языка, назвав их как «en.js» для английского языка. Каждый из них содержал разные строки приложения, как показано ниже:


        var localString = {
        appName: "your app name",
        message1: "blah blah"
      };

2. С помощью Lazyload загрузил соответствующий файл ресурсов в зависимости от языка локали приложения: https://github.com/rgrove/lazyload

3. передайте языковой код через строку запроса (поскольку я запускаю html-файл с Android с помощью PhoneGap)

4.Затем я написал следующий код для динамической загрузки нужного файла ресурсов:


var lang = getQueryString("language");
localization(lang);
function localization(languageCode) {
    try {
        var defaultLang = "en";
        var resourcesFolder = "values/";
        if (!languageCode || languageCode.length == 0)
            languageCode = defaultLang;
        // var LOCALIZATION = null;
        LazyLoad.js(resourcesFolder + languageCode + ".js", function() {
            if ( typeof LOCALIZATION == 'undefined') {
                LazyLoad.js(resourcesFolder + defaultLang + ".js", function() {
                    for(var propertyName in LOCALIZATION) {
                        $("#" + propertyName).html(LOCALIZATION[propertyName]);
                    }
                });
            } else {
                for(var propertyName in LOCALIZATION) {
                    $("#" + propertyName).html(LOCALIZATION[propertyName]);
                }
            }
        });
    } catch (e) {
        errorEvent(e);
    }
}
function getQueryString(name)
{
  name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
  var regexS = "[\?&]" + name + "=([^]*)";
  var regex = new RegExp(regexS);
  var results = regex.exec(window.location.href);
  if (results == null)
    return "";
  else
    return decodeURIComponent(results[1].replace(/\+/g, " "));
}

5. Из файла html я ссылаюсь на строки следующим образом:


    span id = "appName"

Можете ли вы объяснить, что именно делает этот блок кода: if (typeof LOCALIZATION == 'undefined') {LazyLoad.js (resourcesFolder + defaultLang + ".js", function () {for (var propertyName in LOCALIZATION) {$ ( "#" + propertyName) .html (LOCALIZATION [propertyName]);}}); } else {для (var propertyName в LOCALIZATION) {$ ("#" + propertyName) .html (LOCALIZATION [propertyName]); }}

shailbenq 23.10.2012 05:09

Есть библиотека для локализации приложений JavaScript: https://github.com/wikimedia/jquery.i18n

Он может выполнять замену параметров, поддерживает пол (умная обработка), число (умная обработка множественного числа, включая языки, которые имеют более одной формы множественного числа) и пользовательские правила грамматики, которые необходимы некоторым языкам.

Строки хранятся в файлах JSON.

Единственное требование - jQuery.

После того, как я много погуглил и не был удовлетворен большинством представленных решений, я только что нашел удивительное / универсальное решение, которое использует Шаблоны T4. Полный текст сообщения Йохен ван Вайлик вы можете прочитать здесь:

Использование T4 для локализации ресурсов JavaScript на основе файлов .resx

Основные преимущества:

  1. Имея только 1 место для управления ресурсами (а именно .resx файлы)
  2. Поддержка нескольких культур
  3. Используйте IntelliSense - разрешите завершение кода

Недостатки:

The shortcomings of this solution are of course that the size of the .js file might become quite large. However, since it's cached by the browser, we don't consider this a problem for our application. However - this caching can also result in the browser not finding the resource called from code.


Как это работает?

По сути, он определил шаблон T4, который указывает на ваши файлы .resx. С помощью некоторого кода C# он просматривает каждую строку ресурса и добавляет ее в свойства чистого значения ключа JavaScript, которые затем выводятся в одном файле JavaScript с именем Resources.js (вы можете настроить имена, если хотите).


Шаблон Т4 [измените соответственно, чтобы указать на расположение ваших файлов .resx]

<#@ template language = "C#" debug = "false" hostspecific = "true"#>
<#@ assembly name = "System.Windows.Forms" #>
<#@ import namespace = "System.Resources" #>
<#@ import namespace = "System.Collections" #>
<#@ import namespace = "System.IO" #>
<#@ output extension = ".js"#>
<#
 var path = Path.GetDirectoryName(Host.TemplateFile) + "/../App_GlobalResources/";
 var resourceNames = new string[1]
 {
  "Common"
 };

#>
/**
* Resources
* ---------
* This file is auto-generated by a tool
* 2012 Jochen van Wylick
**/
var Resources = {
 <# foreach (var name in resourceNames) { #>
 <#=name #>: {},
 <# } #>
};
<# foreach (var name in resourceNames) {
 var nlFile = Host.ResolvePath(path + name + ".nl.resx" );
 var enFile = Host.ResolvePath(path + name + ".resx" );
 ResXResourceSet nlResxSet = new ResXResourceSet(nlFile);
 ResXResourceSet enResxSet = new ResXResourceSet(enFile);
#>

<# foreach (DictionaryEntry item in nlResxSet) { #>
Resources.<#=name#>.<#=item.Key.ToString()#> = {
 'nl-NL': '<#= ("" + item.Value).Replace("\r\n", string.Empty).Replace("'","\'")#>',
 'en-GB': '<#= ("" + enResxSet.GetString(item.Key.ToString())).Replace("\r\n", string.Empty).Replace("'","\'")#>'
 };
<# } #>
<# } #>

На стороне формы / просмотра

Чтобы получить правильный перевод, добавьте это в свой мастер, если вы используете WebForms:

<script type = "text/javascript">

    var locale = '<%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>';

</script>

<script type = "text/javascript" src = "/Scripts/Resources.js"></script>

Если вы используете ASP.NET MVC (как и я), вы можете сделать это:

<script type = "text/javascript">

    // Setting Locale that will be used by JavaScript translations
    var locale = $("meta[name='accept-language']").attr("content");

</script>

<script type = "text/javascript" src = "/Scripts/Resources.js"></script>

Помощник MetaAcceptLanguage, который я получил из этой замечательной публикации Скотта Хансельмана:

Глобализация, интернационализация и локализация в ASP.NET MVC 3, JavaScript и jQuery - Часть 1

public static IHtmlString MetaAcceptLanguage<T>(this HtmlHelper<T> html)
{
     var acceptLanguage =
         HttpUtility.HtmlAttributeEncode(
                     Thread.CurrentThread.CurrentUICulture.ToString());

      return new HtmlString(
      String.Format("<meta name=\"{0}\" content=\"{1}\">", "accept-language",
                    acceptLanguage));
 }

Используй это

var msg = Resources.Common.Greeting[locale];
alert(msg);

Мы используем MVC и просто создали действие контроллера для возврата локализованной строки. Мы поддерживаем культуру пользователя в сеансе и устанавливаем культуру потока перед любым вызовом для получения языковой строки, AJAX или иным образом. Это означает, что мы всегда возвращаем локализованную строку.

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

Global.asax.cs

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
    {
        // Set the current thread's culture
        var culture = (CultureInfo)Session["CultureInfo"];
        if (culture != null)
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;
        }
    }
}

Действие контроллера

public string GetString(string key)
{
    return Language.ResourceManager.GetString(key);
}

Javascript

/*
    Retrieve a localized language string given a lookup key.
    Example use:
      var str = language.getString('MyString');
*/
var language = new function () {
    this.getString = function (key) {
        var retVal = '';
        $.ajax({
            url: rootUrl + 'Language/GetString?key=' + key,
            async: false,
            success: function (results) {
                retVal = results;
            }
        });
        return retVal;
    }
};

Что ж, я думаю, вы можете это рассмотреть. Англо-испанский пример:

Напишите 2 сценария Js, например:

en-GB.js
lang = {
    date_message: 'The start date is incorrect',
    ...
};
es-ES.js
lang = {
    date_message: 'Fecha de inicio incorrecta',
    ...
};

Сторона сервера - код позади:

Protected Overrides Sub InitializeCulture()
    Dim sLang As String 
    sLang = "es-ES" 

    Me.Culture = sLang
    Me.UICulture = sLang
    Page.ClientScript.RegisterClientScriptInclude(sLang & ".js", "../Scripts/" & sLang & ".js")

    MyBase.InitializeCulture()
End Sub

Вы знаете, где sLang может быть "en-GB", в зависимости от выбора текущего пользователя ...

Javascript вызывает:

alert (lang.date_message);

И это работает, я думаю, очень просто.

Другие вопросы по теме