Как правильно локализовать номера?

38

Какие предостережения я должен знать при локализации чисел в моем приложении?

Пример: в бразильском португальском (pt-BR) мы разделяем тысячи точками и десятичными запятыми. В американском английском (en-US) это наоборот. В pt-BR мы представляем цифры, разделенные тысячами, так же, как en-US. Но читая сегодня об индийском английском (en-IN), я наткнулся на этот драгоценный камень:

Индийская система нумерации является предпочтительной для группировки цифр. Когда они написаны словами или произнесены, числа меньше 100 000/100 000 выражаются так же, как и в стандартном английском. Номера, включая и превышающие 100 000/100 000, выражены в подмножестве индийской системы нумерации.

https://en.wikipedia.org/wiki/Indian_English#Numbering_system

Что значит:

1000000 units in pt-BR are formatted 1.000.000
1000000 units in en-US are formatted 1,000,000
1000000 units in en-IN are formatted 10,00,000

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

Какие еще предостережения следует знать при локализации номеров в моем приложении? Особенно, если я показываю номера для нелатинских наборов символов?

Мачадо
источник
3
Становится еще интереснее при работе с деньгами! :-)
Стефан Бийзиттер,
4
Не говоря уже о марсианской системе нумерации, которая имеет основание 6 (два раза по 3 пальца) ;-) Но у японцев также есть странность: человек = 10.000, записанный как 1.0000, oku = 100.000.000, написанный в Японии, как 1.0000.0000 и chō. .. угадайте
qwerty_so
6
Почему вы должны беспокоиться об этом? Вы не можете следовать настройкам ОС?
Ян Догген
3
@JanDoggen, потому что это одна из интересных проблем в области разработки программного обеспечения, «как правильно представлять данные людям». То, о чем я должен беспокоиться при разработке системы, является предметом этого вопроса. И я даже не говорю о деньгах, как сказал наш друг Стефан, ни о дате и времени. Просто необработанные цифры.
Мачадо
5
@ JanDoggen, это становится намного сложнее при работе с онлайн-программным обеспечением. Пользователь может находиться в Индии, на компьютере с английским языком в США, но читать веб-страницу на бразильском португальском языке. Ваш сервер может быть китайским. Ваше приложение должно понимать, чего хочет пользователь, независимо от того, какую ОС он / она использует или где находится ваш сервер. Таким образом, ваши 1000,00 долларов станут 67,545,00 рупий: валюта США, конвертированная по местному обменному курсу, но отображаемая в португальском формате.
noderman

Ответы:

87

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

Например, экосистема C # имеет пространство имен System.Globalization , которое позволяет вам указать, что Cultureвы хотите:

Console.WriteLine(myMoneyValue.ToString("C", "en-US"));

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

Роберт Харви
источник
2
Мне известны System.Globalization и другие фреймворки, которые справляются с такими сложностями для меня. Я не знаю, какие проблемы они решают. Например, несколько приложений, которые я вижу, используют специальную маскировку для ToString, например .ToString ("#, ## 0.00", locale), но эта маска сама по себе недопустима, если я показываю это число индейцу. Итак, кроме «не используйте специальные маски», что еще я должен знать?
Мачадо
7
Ничего из того, что я знаю. Если вы используете фреймворк правильно, он должен просто работать. Есть определенные, конкретные случаи проблем интернационализации, но мы не делаем полный перечень их. Смотрите этот пример .
Роберт Харви
5
Это единственный правильный ответ: установите свой языковой стандарт, затем протолкните свои значения через слой i18n, прежде чем показывать его пользователю, и позвольте авторам платформы разобраться с этим. Это верно для чисел, значений валют, переведенных строк, дат, всего.
2
Идеальный ответ. «Не изобретай велосипед» - это то, что всегда следует принимать во внимание при решении общих проблем, подобных этой. Жаль, что я не могу проголосовать больше, чем один раз.
BgrWorker
3
@Machado "Например, несколько приложений, которые я вижу, используют специальную маскировку для ToString, например .ToString (" #, ## 0.00 ", locale), но эта маска сама по себе недопустима, если я показываю этот номер индейцу «. - Это может быть непонятно, но обратите внимание, что позиция ,в строке формата в основном не имеет значения, и «#, 0,00» будет иметь такой же эффект. ,просто означает «использовать разделители числовых групп в порядке, указанном в локали».
HVd
23

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

  • когда это для пользовательского интерфейса, должно применяться локализованное форматирование

  • когда число будет записано в файл, или отправлено по сети, или в другой форме, где число необходимо в машиночитаемой форме, убедитесь, что оно не отформатировано в соответствии с текущей культурой, но в соответствии с фиксированной настройкой (например, в среде .NET используйте InvariantCulture).

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

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

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

Док Браун
источник
2
И что еще хуже, во многих современных языках программирования очевидные / стандартные функции в стандартной библиотеке «локализованы». Поэтому, если разработчик не знает или не заботится о локализации, получающееся в результате приложение, скорее всего, будет нефункциональным, а не просто уродливым на сторонних системах.
Питер Грин
4
Я не согласен с тем же плохим. Инструмент, который не следует локальным числовым соглашениям в своем пользовательском интерфейсе, все еще будет пригоден для использования. Инструмент, который не может прочитать свои собственные файлы данных или не может связаться со своим сервером из-за несоответствия числового соглашения, с большей вероятностью окажется непригодным для использования.
Питер Грин
5
Анекдот этого: десятичный разделитель для en-ZA изменен между Win 7 и Win 8. Ранее локально сохраненные значения начали не десериализоваться
Caleth
1
@PeterGreen: инструмент, который не следует местным числовым соглашениям в своем пользовательском интерфейсе, все еще может быть пригодным для использования или может быть полностью непригодным для определенных случаев использования. Я был бы очень осторожен с такими предположениями. Причина, по которой столь многие разработчики ошибаются в локализации чисел, заключается именно в том, что они делают подобные предположения.
Док Браун
1
@DocBrown У меня есть самый ужасный устаревший код для поддержки, который страдает от стандартных процедур синтаксического анализа целых чисел / чисел с плавающей точкой в ​​стандартной библиотеке. Я думаю, будет справедливым сказать, что программа, написанная без заботы о локализации, когда подпрограммы по умолчанию для этих заданий не локализованы, может быть непригодна для некоторых ситуаций, но если подпрограммы по умолчанию локализованы, программа всегда будет повреждена в тот момент, когда она выполняется на компьютере, где глобальный язык не является английским.
Себастьян Редл
9

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

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

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

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

  • Сделайте простой выбор форматирования настраиваемым для каждого пользователя: форматы для даты и времени, десятичные разделители, предпочтительная валюта,…. Это особенно полезно для путешественников, эмигрантов или других людей, которым необходимо смешать несколько языков или культур независимо от языка.

Амон
источник
18
Также имейте в виду, что большое количество пользователей ненавидят соглашение, которое считается «правильным для их языка», считают его отвратительной устаревшей практикой и не хотят никакой группировки вообще или другого рода группировки. Таким образом, вероятно, должны быть варианты его отключения или ручного переопределения.
R ..
2

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

Возьмите типичный ярлык типа «Вы выбрали n предметов». Это читается неправильно, если выбран только один элемент. Уродливое, но прагматичное решение - написать «Вы выбрали n элементов». Но если вы хотите сделать это правильно, вам нужно два разных текста в зависимости от n. Если вы попытаетесь сделать это в нескольких локалях, это быстро станет действительно сложным, поскольку разные языки имеют разную грамматику. Некоторые языки имеют разные спряжения для одного, двух и нескольких предметов и так далее. По этой причине знающие люди всегда будут жаловаться на то, что существующие рамки локализации недостаточны.

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

JacquesB
источник
Это решается ICU (MessageFormat). Недостатком является то, что принятие ICU на многих языках все еще слабо. Тем не менее, разработчик все еще должен правильно составить сообщение. Это действительно больше, чем просто инженерный аспект. userguide.icu-project.org/formatparse/messages
noderman
Это также решается более широко доступным функции ngettext в GNU gettext, но класс MessageFormat, по-видимому, также решает некоторые дополнительные проблемы, которых не имеет ngettext.
HVd
2

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

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

http://site.icu-project.org

http://cldr.unicode.org

Обновить

Инструмент опроса CLDR предоставляет доступ ко всем шаблонам. Это покажет вам, как форматировать число на определенном языке и регионе. Например, португальский (Португалия):

http://st.unicode.org/cldr-apps/v#/pt_PT/Number_Formatting_Patterns/

И если вы действительно хотите проверить все данные (и, возможно, использовать их), вы можете загрузить CLDR в формате JSON с GitHub:

https://github.com/unicode-cldr/cldr-json#cldr-json

Более подробная информация о загрузках здесь:

http://cldr.unicode.org/index/downloads

noderman
источник
Спасибо за вклад, но сейчас я больше всего интересуюсь цифрами. :)
Мачадо
Конечно. Я только что отредактировал ответ, добавив ссылку на инструмент опроса, где вы можете сузить область поиска.
noderman
Я попытался изменить Бразилию, чтобы проверить различия, но, похоже, он не позволяет визуализацию для этого: st.unicode.org/cldr-apps/v#/pt_BR/Number_Formatting_Patterns В остальном инструмент кажется довольно хорошим.
Мачадо
Это потому, что Бразилия является корневым языком. Инструмент опроса фактически используется для внесения изменений в данные CLDR, поэтому корни требуют специальных учетных записей. Вы можете перейти на GitHub и получить всю информацию напрямую: github.com/unicode-cldr/cldr-numbers-modern/tree/master/main В частности, Бразилия находится здесь: github.com/unicode-cldr/cldr-numbers-modern/ blob / master / main / pt /…
noderman
0

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

Пока это то, что мы должны знать при локализации номеров:

Для людей :

  • Разделители тысяч не всегда разделяются тысячами. См. Индийский случай в вопросе;
  • Тысячи и десятичные знаки изменяют культуру к культуре. Например, в немецком языке тысячи разделяются пробелами, а в английском это комманы, а в португальском - точки;
  • У нас нет информации, если есть существенная разница между языками слева направо и справа налево;
  • Предоставьте конкретный набор поддерживаемых локализаций и сделайте его понятным для ваших пользователей;
  • Позвольте вашим пользователям изменить локализацию по умолчанию на одну из поддерживаемых локализаций, и они будут счастливы и отправят вам благодарные пирожные, потому что вы великодушный бог. :);

Для компьютеров :

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

Для разработчиков :

  • (как предложено @hyde ниже): использовать существующую библиотеку для локализации;
  • Если вы можете, используйте встроенные тестеры и укажите тестовые примеры локализации / интернационализации, в противном случае доверяйте библиотеке;
  • Помните, что локализация - это проблема, в основном решаемая. У каждого основного языка есть библиотека, родная или внешняя, которая может локализовать числа, даты и время;
Мачадо
источник
1
Отсутствующий элемент: для разработчиков: используйте существующую библиотеку для локализации. Если вы можете, используйте встроенные тестеры и укажите тестовые примеры локализации / интернационализации, в противном случае доверяйте библиотеке.
Hyde