Эффективные стратегии локализации в .NET [закрыто]

121

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

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

smartcaveman
источник
2
Отличный вопрос! Я сталкиваюсь с подобной ситуацией и хотел бы, чтобы эксперты взвесили это.
У кого-нибудь есть хорошие стандарты для управления ресурсами? Локализованное значение может также включать изображения, а не только строки.
1
Это пользовательский интерфейс WPF / silverlight или Winforms? Из моего (ограниченного) опыта опыт локализации в WinForms намного проще, чем в WPF / Silverlight.
Пит Стенсонес
1
Если вы в конечном итоге сохраните свои локализованные строки в базе данных вместо файлов ресурсов, вы можете взглянуть на это обсуждение: stackoverflow.com/questions/2458615/…
1
@ Пит, @smartcaveman сказал, что он «разрабатывает пользовательский интерфейс для приложения .NET MVC», так что ...
BrunoSalvino

Ответы:

74

Вы разрабатываете приложение ASP.Net MVC? Другие ответы кажутся специфичными для настольных приложений. Позвольте мне захватить общие вещи:

Обнаружение локали

Очень важно, чтобы ваше приложение правильно определяло локаль пользователя. В настольном приложении CultureInfo.CurrentCulture содержит предпочтительный языковой стандарт форматирования (тот, который должен использоваться для форматирования чисел, дат, валют и т. Д.), Тогда как CultureInfo.CurrentUICulture содержит предпочтительный языковой стандарт пользовательского интерфейса (тот, который следует использовать для отображения локализованных сообщений). , Для веб-приложений вы должны установить обе культуры на автоматическое (для автоматического определения локали из заголовка AcceptLanguage), если вы не хотите реализовать какой-то причудливый рабочий процесс определения локали (т.е. хотите поддерживать изменение языка по требованию).

Внешние строки

Все строки должны исходить из ресурсов, то есть файлов Resx. В приложении Winforms это легко достижимо, если для свойства Localizable формы установить значение true. Вам также нужно будет (к сожалению) вручную выводить строки из ваших моделей. Это также относительно просто. В Asp.Net вам нужно было бы выводить все вручную ...

Макеты

Вам определенно нужно разрешить расширение строки. В мире Winforms это достижимо с помощью TableLayoutPanel, который следует использовать, чтобы убедиться, что макет будет корректироваться автоматически для размещения более длинного текста. В мире Интернета вам немного не повезло. Возможно, вам потребуется реализовать механизм локализации CSS - способ изменить (переопределить) определения CSS. Это позволило бы людям Localization изменять проблемы стиля по требованию. Убедитесь, что каждый элемент HTML на отображаемой странице имеет уникальный идентификатор - это позволит точно нацелить его.

Культурно-специфические проблемы

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

ToString () и Parse ()

Обязательно всегда передавайте CultureInfo при вызове ToString (), если это не поддерживается. Таким образом, вы комментируете свои намерения. Например: если вы используете какое-то число внутри себя и по какой-то причине необходимо преобразовать его в строковое использование:

int i = 42;
var s = i.ToString(CultureInfo.InvariantCulture);

Для номеров, которые будут отображаться для пользователя, используйте:

var s = i.ToString(CultureInfo.CurrentCulture); // formatting culture used

То же самое относится к Parse (), TryParse () и даже ParseExact () - некоторые неприятные ошибки могут быть внесены без правильного использования CultureInfo. Это потому, что какая-то бедная душа в Microsoft, полная благих намерений, решила, что было бы неплохо рассматривать CultureInfo.CurrentCulture как стандартную (она будет использоваться, если вы ничего не передадите) - в конце концов, когда кто-то использует ToString ( ) он / она хочет показать это пользователю, верно? Оказывается, это не всегда так - например, попытайтесь сохранить номер версии вашего приложения в базе данных, а затем преобразовать его в экземпляр класса Version. Удачи.

Даты и часовые пояса

Обязательно всегда храните и создайте экземпляр DateTime в UTC (используйте DateTime.UtcNow вместо DateTime.Now). Преобразуйте его в местное время в местном формате при отображении:

DateTime now = DateTime.UtcNow;
var s = now.ToLocalTime().ToString(CultureInfo.CurrentCulture);

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

DateTime someDate; // i.e. from database
var formattedDate = String.Format("{0} {1}", 
             someDate.ToLocaleTime().ToString(CultureInfo.CurrentCulture),
             TimeZoneInfo.Local.DisplayName);

Сложные сообщения

Вы уже были предупреждены, чтобы не объединять строки. Вместо этого вы, вероятно, будете использовать String.Format (), как показано выше. Однако я должен заявить, что вы должны минимизировать использование составных сообщений. Это просто потому, что целевые грамматические правила довольно часто различаются, поэтому переводчикам может потребоваться не только переупорядочить предложение (это можно решить с помощью заполнителей и String.Format ()), но и перевести все предложение другим способом на основе что будет подставлено. Позвольте привести несколько примеров:

// Multiple plural forms
English: 4 viruses found.
Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów.

// Conjugation
English: Program encountered incorrect character | Application encountered incorrect character.
Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.

Другие проблемы конкатенации

Конкатенация не ограничивается строками. Старайтесь не расставлять элементы управления вместе, скажите:

Напомните мне еще раз в [текстовое поле с номером] дней.

Это должно быть изменено на что-то вроде: Напомнить мне снова через это количество дней: [текстовое поле].

Кодировка символов и шрифты

Всегда сохраняйте, переносите любой текст в Unicode (то есть в UTF-8). Не программируйте шрифты жестко - возможно, потребуется изменить их при локализации, и это отключит механизм возврата шрифтов по умолчанию (в случае Winforms). Не забудьте разрешить «странные» символы в большинстве полей (например, имя пользователя).

Контрольная работа

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

Павел Дида
источник
5
Что касается составных сообщений - я должен был сделать несколько множественных форм один раз. Я расширил его, String.Formatчтобы он мог поддерживать этот классный синтаксис: "There {0:was|were} {0} {0:virus|viruses} found."каждый язык может загружать свои собственные правила, поэтому вы можете сделать это "Znaleziono {0} {0:wirusy|wirusów}." . Источник находится на GitHub: github.com/scottrippey/SmartFormat/wiki
Скотт Риппи,
2
@ Scott Rippey Вы заметили, что польский пример гласит: «Znaleziono 4 wirusy. ИЛИ Znaleziono 5 wirusów». <- Польский, как и многие другие языки, имеет более двух форм множественного числа, и правила различения между ними также могут быть сложными. Здесь я должен оставить польский, поскольку я не говорю на нем, но на моем языке форма множественного числа для 101 вещи такая же, как и для 1. Вы можете взглянуть на то, как GNU GetText решает эту проблему: gnu.org/s/hello/manual/gettext/Plural-forms.html
gregopet
2
@gregopet Мой польский пример был придуман, потому что я не говорю на нем, но это именно то, что делает проект SmartFormat. Вот лучший пример: "{0} {0:plik|pliki|plików}". У форматера есть польское правило, которое определяет, какую из 3 форм использовать, и правильно определяет особые случаи. В настоящее время я работаю над добавлением дополнительных правил, поэтому gettextстатья окажется очень полезной, спасибо.
Скотт Риппи
Для псевдолокализации я создал бесплатный онлайн-инструмент псевдолокализации
JerSchneid
74

Некоторые основные вещи, которые вы должны принять во внимание:

Вывести все строковые ресурсы

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

Оставьте достаточно места для расширения строки

Строки в некоторых языках, как правило, на 30% длиннее (например, греческий), поэтому убедитесь, что вы проектируете свой пользовательский интерфейс таким образом, чтобы при необходимости строки могли расширяться. Вот довольно экстремальный пример для французского:

Хорошо -> Accepter (французский - расширение на 400%)

Я бы порекомендовал сделать какой-нибудь псевдоперевод в качестве отправной точки ( http://en.wikipedia.org/wiki/Pseudolocalization ). Или вы можете перевести свои ресурсы с помощью Google Translate или Bing. Это даст вам хорошее представление о том, как будут выглядеть реальные переводы.

Остерегайтесь текста в изображениях

Если вы используете какие-либо изображения в вашем приложении - убедитесь, что они не содержат текста - это, очевидно, не может быть переведено.

Никогда не кодируйте пути к папкам Windows

Очевидно, но я видел это в прошлом. Например, C:\Program Filesпереводится на некоторые международные версии Windows, например, C:\Programmeна немецкую ОС.

Избегайте использования конкретных региональных условий

Например, если вы спрашиваете кого-то об их «средней школе» в форме, это не имеет большого значения в Западной Европе.

Избегайте создания строк с помощью конкатенации строк

Например, это выглядит безобидно:

strWelcome = ReadExternalString("Welcome"); 
strMessage = strWelcome + ", " + UserName;

Но порядок слов на японском, например, будет другим, так что в конечном итоге это может не иметь никакого смысла.

Настройки времени / даты

Всегда проверяйте, чтобы получить формат времени / даты из ОС.

Джимми Коллинз
источник
@Jimmy C, как ты собираешься строить строки для логически независимой логической последовательности?
smartcaveman
14
@Smart сделайте что-нибудь в вашем ресурсе, например "{0}, {1}", затем, когда вы его локализуете, используйте string.format и передайте приветствие и имя пользователя. Кроме того, это дает вам преимущество «Текущая скорость {0} равна {1} {2}», и вы можете передавать «Engine», «50» и «MPH», а когда вы переводите предложение, вы можете перемещать { 0} и т. Д., Где они имеют смысл на этом языке
taylonr
4
Хороший список JimmyC. «Никогда не кодируйте пути к папкам Windows» напомнило мне «Всегда использовать Path.Combine» вместо конкатенации строк для путей Windows.
@ Джимми-С Отличный ответ!
1
Environment.GetFolderPath может использоваться для получения допустимых путей к общим путям, таким как Мои документы, без зависимости от английского имени для этих папок.
Crippledsmurf
24

Особые соображения для азиатских языков

В дополнение ко всем отличным ответам, которые уже здесь, есть некоторые предупреждения для азиатских языков:

Остерегайтесь различной длины текста

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

Тем не менее, японский текст обычно имеет тенденцию быть намного длиннее, даже длиннее, чем эквивалентный английский текст с точки зрения количества символов.

Остерегайтесь базовой компоновки и «скользящего» взгляда

Азиатские символы обычно располагаются на базовой линии , которые не включают в себя спуски (то есть нижнюю часть y, g, q, j и т. Д.) При форматировании элемента экрана - обычно кнопок - с текстом внутри, и если это текст - только азиатские языки (т.е. нет западных алфавитов), тогда текст будет выглядеть так, как будто он смещен вверх.

Форматирование чисел и локализованных числовых единиц

Относитесь к форматированию чисел по-разному. Разные азиатские страны имеют разные способы форматирования чисел. То же самое с валютами. Например, в Восточной Азии 10000 (Ван) является общей единицей. В Индии 100 000 (лакхов) распространено.

Местные валюты

Валюты некоторых стран имеют много нулей и не имеют десятичной точки (например, Япония, Индонезия, Италия), в то время как другие имеют до двух цифр после десятичной точки.

Остерегайтесь разных порядков слов

Порядок слов не всегда может быть одинаковым. Лучше всего использовать {0}, {1} и т. Д. В форматировании строки вместо жестко заданного порядка слов, если ваша строка состоит из комбинации различных фрагментов данных.

Использовать сортировку по локали

Сортировка различается в зависимости от языка и локали - вы всегда должны полагаться на сортировку, специфичную для локали O / S.

Будьте очень осторожны с символами полной ширины / полуширины

Остерегайтесь различий между символами «полная ширина» и «половина ширины». Кронштейны, знаки пунктуации и т. Д. Могут иметь версии "полной ширины", которые отличаются от стандартных ASCII. Если вы выполняете поиск или разбиение строк на основе этих букв, вам необходимо сначала преобразовать все символы полной ширины в эквиваленты полуширины.

Точка не точка ... запятая не запятая ...

Остерегайтесь вводимых данных - например, на китайском языке точка не является точкой "." Запятая - это полная ширина, а не ",". Не пытайтесь искать западную пунктуацию, если пользователь, вводящий данные, может случайно включить IME на азиатском языке.

Телефонные номера

Не думайте , что - нибудь в номер телефона форматирования. Не всегда есть код города и т. Д., И он может быть отформатирован по-разному. Обычно есть строка формата для каждой страны.

Не думайте, что у людей будет только один номер мобильного телефона или один номер факса и т. Д. В Азии это не так.

Адреса - плотнее, чем вы думаете

Для адресов не принимайте ничего . Там не всегда может быть почтовый индекс. Почтовые индексы не всегда могут быть числами. Страна может не иметь провинций / штатов. Страна может быть просто большим городом (например, Сингапур). Для некоторых азиатских стран наименьшей единицей дома может быть «Комната X, Единица Y, Секция Z, Этаж A, Блок B, Группа C, Поместье D». В общем, будьте очень либеральными в отношении количества полей и количества символов, разрешенных в адресах.

Приветствия

Приветствия не ограничивается только мистер, миссис и т.д. Несмотря на то, что вы , вероятно , безопасны в использовании «M» и «F» для секса - мы не что странно еще ...


источник
1
Последний абзац заставил меня улыбнуться.
BoltClock
О, мы (i18n парни) еще даже не начали ... Мы могли только поцарапать поверхность :) Если бы мы обсуждали конкретные вопросы, такие как поддержка GB18030, наш пост был бы слишком длинным для SO, чтобы справиться с ним :) Спасибо В любом случае, я пропустил несколько вещей.
Павел Дида
Что касается последнего, я считаю, что Великобритания теперь официально принимает «Другое» как секс. Думайте, трансгендеры.
Барт Фридрихс
11

Некоторые основные шаги - убедиться, что любая строка, отображаемая на экране, не является литералом в вашем коде. Если вы делаете Winforms, каждая форма будет иметь ресурс пользовательского интерфейса. Для диалогов, отчетов и т. Д. Убедитесь, что вы используете файлы ресурсов проекта.

Таким образом, вместо «Загрузка не удалась» в вашем коде, у вас может быть что-то вроде Resources.UploadFailed

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

РЕДАКТИРОВАТЬ Я забыл упомянуть, когда вы делаете свой пользовательский интерфейс, убедитесь, что вы не просто втиснуть вещи там. В зависимости от языков, на которых вы локализуетесь, недвижимость может быть проблемой. Я работал над проектом, в котором немецкий и португальский языки были двумя крупнейшими нарушителями роста струн. Если бы мы не были осторожны, струны, которые были хороши на английском, французский и итальянский взорвались бы на немецком

taylonr
источник
1
Из моего опыта L10n, русский язык - худший вариант развития событий. Однако в Winforms с соответствующим пользователем TableLayoutPanels можно изящно обрабатывать рост строки.
Павел Дида
Да, мой опыт был ограничен 7 языками: английский, немецкий, португальский, итальянский, французский, испанский и японский. Но я вижу русских как плохих, так как они имеют много суффиксов и префиксов
taylonr
9

Я предлагаю вам запустить FXCop или Visual Studio Code Analysis (они почти одинаковые) на ваших сборках.

Они хороши в обнаружении кода .NET, который не использует правильные ориентированные на культуру перегрузки, как этот: CA1305: Укажите IFormatProvider .

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

Саймон Мурье
источник
Это значение по умолчанию, или мне нужно указать некоторые настройки для поиска правил, специфичных для глобализации?
smartcaveman
@smartcaveman - это по умолчанию (хм .. на самом деле, некоторые люди думают, что в этих инструментах есть много правил по умолчанию :-)
Саймон Мурье,
7

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

Джереми
источник
Для быстрого и простого способа псевдолокализации я создал бесплатный онлайн-инструмент на pseudolocalize.com
JerSchneid,
6

В дополнение ко всем другим полезным подсказкам, вот некоторые, которые отсутствуют:

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

Если вы задаете пользователю вопрос, который требует ответа одной буквой, не ожидайте, что пользователь нажмет клавишу «Y», чтобы сказать «Да».

В хранимых процессах очень хорошо осведомлены, что даты в базе данных SQL представлены в формате США.

Размещение текстовых строк в БД позволяет позже добавлять дополнительные языки без повторного развертывания.

При отправке письменных текстовых файлов для перевода всегда включайте описание контекста, чтобы убедиться, что переводчик выбрал правильное слово. Например, без контекста, вы можете перевести «pitch:» во что-то, связанное со звуком, или место, где вы играете в футбол.

Адресные метки всегда нуждаются в конвертации. Провинция в Канаде, штат в Америке, округ в Великобритании

Брайан Лиминг
источник
5

Вам необходимо учитывать:

  1. Маршрутизация для мультиязычности

  2. Переместить всю строку жесткого кода в файл ресурсов

Пример для свойства:

Модель:

[Display(Name = <Resource for display name>.<field for this property>)]
[Required(ErrorMessage = <Resource for error message>.<field for this validate message>)]
public string TestProperty { get; set; }

Посмотреть:

@Html.LabelFor(m=>m.TestProperty)
@Html.EditorFor(m => m.TestProperty)
@Html.ValidationMessageFor(m => m.TestProperty)

источник
5

Вот что-то не упомянутое в остальных ответах.

В зависимости от сложности вашего приложения и его локализации я бы настоятельно рекомендовал реализовать альтернативный поставщик ресурсов и хранить локализованные ресурсы в базе данных. При использовании схемы локализации ASP.NET по умолчанию все ресурсы хранятся в файлах RESX, которые:

  1. Есть боль в заднице для редактирования в Visual Studio
  2. Ограничьте распространение и управление локализованными ресурсами после компиляции / отправки / запуска приложения.

В качестве возможного варианта использования рассмотрите возможность предоставления языковых пакетов для вашего приложения и возможности импорта и экспорта языков через пользовательский интерфейс. Файлы RESX здесь не помогут.

В таких сценариях очень полезен альтернативный поставщик ресурсов. Более подробную информацию о том, как ее реализовать, можно найти здесь . Конечно, это редкий случай, чаще встречающийся в корпоративных приложениях, но все же действующий.

Славо
источник
1
Спасибо, что нашли время, чтобы просмотреть ответы на эти замечательные ответы и все же внести что-то новое и полезное.
smartcaveman
+1; Я создал обширное веб-приложение в Asp.NET, и мы закончили переводом через базу данных. Часто добавлялись новые функции, но поскольку наши переводчики не были экспертами в конкретной используемой терминологии, мы смогли быстро обратиться к рассерженным электронным письмам клиентов типа «Почему вы используете слово Y для X, что явно неверно?».
Грегопет
3

Самое главное это управление контентом на разных языках. Я сам разработал несколько веб-сайтов, и управление контентом на разных языках является самой большой проблемой.

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

Позже вы можете использовать переводчик для преобразования английского значения на любой язык.


источник
2

Резюме вещей, которые следует учитывать при интернационализации:

  • Вся информация должна быть интернационализирована. Учтите, что графика может содержать информацию, которую мы хотим интернационализировать.

  • Размер полей или строк зависит от языка, потому что это может вызвать у нас проблемы.

  • Порядок слов зависит от языка, которым мы являемся, поэтому порядок на одном языке будет одинаковым на другом.

  • Мы должны принять во внимание, что формат даты будет меняться с одного языка на другой


источник
1

Сделайте тест Турции :

Интернационализация программного обеспечения является сложной в наилучших обстоятельствах , но меня всегда удивляло, как часто в обсуждении проблем интернационализации возникала одна конкретная страна: Турция ...

Если вам небезразлична локализация или интернационализация, вынудите ваш код работать под турецкой локалью как можно скорее . Это сильный аргумент в пользу того, что ваш код работает в большинстве - но не во всех - культурах и локалях ...

Если ваш сайт / программа хорошо работает с турецким клиентом, вы можете быть уверены, что он будет работать на большинстве других платформ.

Карра
источник