Як правильно локалізувати числа?


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, оку = 100.000.000, написана в Японії як 1.0000.0000 і chō. ..
здогадуйтесь

6
Чому ви повинні турбуватися з цього приводу? Ви не можете дотримуватися налаштувань ОС?
Ян Догген

3
@JanDoggen, оскільки це одна з цікавих проблем домену Software Engineering: "як правильно представити дані людям". Що мене має хвилювати при проектуванні системи - це питання цього питання. І я навіть не кажу про гроші, як сказав наш друг Стефан, а також дату та час. Просто необроблені цифри.
Мачадо

5
@JanDoggen, це стає набагато складніше при роботі з Інтернет-програмним забезпеченням. Користувач може перебувати в Індії, на комп’ютері з англійською мовою в США, але читає веб-сторінку на португальській мові. Ваш сервер може бути китайським. Ваш додаток повинен розуміти, що хоче користувач, незалежно від того, якою ОС він / вона користується або де ваш сервер. Тож ваші 1000,00 доларів становлять 67,545,00 рупій: американська валюта, перерахована за місцевим курсом, але відображається у португальському форматі.
нодерман

Відповіді:


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, як-от. . " - Це може бути не зрозуміло, але зауважте, що позиція ,у рядку формату значною мірою не має значення, і "#, 0,00" матиме такий же ефект. ,просто означає "використовувати роздільники номерів груп у спосіб, визначений локалом".
hvd

23

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

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

  • коли число записується у файл або надсилається по мережі, або інша форма, де це число потрібно в машиночитаній формі, переконайтеся, що воно не відформатоване відповідно до поточної культури, а відповідно до фіксованої настройки (наприклад, у середовищі .NET, використовуйте InvariantCulture).

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

На мій досвід, це одне з найбільших перешкод у правильній локалізації чисел: у спробі централізації форматування чи перетворення чисел люди починають створювати загальні, багаторазові функції для форматування, а потім починають використовувати їх у всьому місце. Однак, як тільки потрібні цифри також у машиночитаному рядковому форматі десь ще в програмі, потрібні два варіанти: локалізоване та нелокалізоване форматування. Це спричиняє високий ризик змішування двох форм перетворень (особливо, коли розробники та тестові машини мають свої параметри локалізації за замовчуванням, аналогічні встановленому "фіксованому" параметру, що використовується для форматування без інтерфейсу користувача, але частина користувацької бази не має).

Додаток: ця проблема може стати справді неприємною в ситуаціях, коли заздалегідь не зрозуміло, чи буде номер опрацьований машиною або людиною (або обома) пізніше. Наприклад, як частина виводу файлу журналу. У таких випадках, мабуть, найкраще дотримуватися "нейтрального" стандарту, коли не використовується роздільник, окрім точки, як десяткового роздільника.


2
І що ще гірше, для багатьох сучасних мов програмування очевидні / стандартні функції в стандартній бібліотеці "локалізовані". Отже, якщо розробник не знає або не піклується про локалізацію, отримана програма, швидше за все, буде нефункціональною, а не просто негарною для іноземних систем.
Пітер Грін

4
Я не погоджуюся з однаковою мірою поганою. Інструмент, який не відповідає локальним числовим умовам у його інтерфейсі, все ще стане корисним. Інструмент, який не може прочитати власні файли даних або не зможе поговорити з його сервером через невідповідність чисельних умов, набагато більше шансів бути непридатним.
Пітер Грін

5
Анекдот цього: Десятковий сепаратор для en-ZA змінився між Win 7 та Win 8. Раніше локально збережені значення почали не
десаріалізувати

1
@PeterGreen: інструмент, який не відповідає місцевим числовим умовам у його інтерфейсі, все ще може бути корисним або може бути абсолютно непридатним для певних випадків використання. Я б дуже обережно робив такі припущення. Причина, по якій стільки дияволів неправильно локалізують числа, саме в цьому - роблячи такі припущення.
Док Браун

1
@DocBrown У мене є найжахливіший спадковий код, на який потерпає локалізована ціла / плаваюча розбиття стандартної бібліотеки. Я думаю, що справедливо сказати, що програма, написана без піклування про локалізацію, коли підпрограми за замовчуванням для цих завдань не локалізовані, може бути непридатною для деяких ситуацій, але якщо підпрограми за замовчуванням локалізовані, програма завжди буде порушена в той момент, коли це виконується на комп’ютері, де глобальна локаль не є англійською.
Себастьян Редл

9

Правильна локалізація досить складна. Більшість програмних екосистем мають спроби вирішення локалізації, але, на мій досвід, вони всі більш-менш зламані. Тому я б запропонував:

  • Не намагайтеся автоматизувати локалізацію. Це не завжди спрацює. Вам важко помітити проблеми та розчарувати своїх користувачів.

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

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

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


18
Також майте на увазі, що велика кількість користувачів ненавидить конвенцію, яка вважається "правильною для їхньої локальності", вважайте це огидною спадковою практикою і не хочуть групування взагалі або іншого типу групування. Тому такі, ймовірно, повинні бути варіанти вимкнути його або вручну змінити його.
Р ..

2

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

Візьміть типову мітку типу "Ви вибрали n елементів". Це неправильне значення, якщо вибрано лише один елемент. Потворне, але прагматичне рішення - написати "Ви вибрали п. Елементів". Але якщо ви хочете зробити це правильно, вам потрібні два різні тексти залежно від російської. Якщо ви спробуєте зробити це в декількох локалях, це швидко стане справді складним, оскільки різні мови мають різну граматику. Деякі мови мають різні сполучення для одного, двох та декількох предметів тощо. З цієї причини люди, які знають, завжди скаржаться на те, що існуючі рамки локалізації є недостатніми.

Але ви повинні вибрати свої битви і вирішити, який рівень витонченості достатній. Для багатьох цілей стандартна бібліотека локалізації для форматування чисел і дат повинна бути достатньою.


Це вирішує 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

Я намагався змінити Бразилію, щоб перевірити відмінності, але, схоже, це не вмикає візуалізацію для цього: 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
Відсутній елемент: Для розробників: використовуйте існуючу бібліотеку для локалізації. Якщо ви можете, скористайтеся нативними тестерами та вкажіть тестові випадки локалізації / інтернаціоналізації, інакше довіряйте бібліотеці.
Гайд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.