Я создаю веб-сайт чаш Грааля мультиязыков, и я должен получить порядковый суффикс числа для нескольких языков как английский, французский, испанский, немецкий и итальянский язык.
Я полагаю, что эта проблема довольно характерна для владельцев веб-сайта мультиязыков. Я нашел эту статью, которая предоставляет решение, но это является английским только.
Например:
/**
*@value number
*@locale Current locale
*@returns ordinal suffix for the given number
**/
public static String getOrdinalFor(int value, Locale locale)
даст следующие результаты:
assert getOrdinalFor(1, Locale.ENGLISH) == "st"
assert getOrdinalFor(1, Locale.FRENCH) == "er"
assert getOrdinalFor(2, Locale.ENGLISH) == "nd"
assert getOrdinalFor(3, Locale.ENGLISH) == "rd"
assert getOrdinalFor(4, Locale.ENGLISH) == "th"
assert getOrdinalFor(4, Locale.FRENCH) == "ème"
Вы знаете библиотеку (в Java или Groovy), который может помочь этому? Или Вы знаете алгоритм, который реализует его?
Я думаю, что во многих языках такой подход невозможен, так как они просто не имеют понятия о порядковых номерах, которые могут состоять из числа с некоторыми буквами в качестве продолжения. Для "1-го", т.е. на немецком языке, можно написать только "1" или "erster"/"erste"/"erstes" в зависимости от рода того, что ты нумеруешь.
Не знаю ни одной библиотеки, но лучшим алгоритмом может быть получение всех возможных чисел/локалей/ординалов в Карте
.
private static Map<Integer, Map<Locale, String>> ordinals = new HashMap<Integer, Map<Locale, String>>();
static {
Map<Locale, String> ordinal1 = new HashMap<Locale, String>();
ordinal1.put(Locale.ENGLISH, "st");
ordinal1.put(Locale.FRENCH, "er");
ordinals.put(1, ordinal1);
Map<Locale, String> ordinal2 = new HashMap<Locale, String>();
ordinal2.put(Locale.ENGLISH, "nd");
ordinals.put(2, ordinal2);
Map<Locale, String> ordinal3 = new HashMap<Locale, String>();
ordinal3.put(Locale.ENGLISH, "rd");
ordinals.put(3, ordinal3);
Map<Locale, String> ordinal4 = new HashMap<Locale, String>();
ordinal4.put(Locale.ENGLISH, "th");
ordinal4.put(Locale.FRENCH, "ème");
ordinals.put(4, ordinal4);
}
getOrdinalFor()
может выглядеть следующим образом (в сторону от очевидной обработки ошибок во время выполнения):
public static String getOrdinalFor(int value, Locale locale) {
return ordinals.get(value).get(locale);
}
Для других номеров, которые не покрыты картой, вы можете рассмотреть возможность обратного отсчета номера до тех пор, пока в карте не будет найдено совпадение (так что запрос ординала для e. g. 5
или выше вернет порядковый номер для 4
(первое последующее совпадение при обратном отсчете):
public static String getOrdinalFor(int value, Locale locale) {
Map<Locale, String> ordinal = null;
for (int i = value; i > 0 && (ordinal == null || !ordinal.containsKey(locale)); i--) {
ordinal = ordinals.get(i);
}
return ordinal != null ? ordinal.get(locale) : null; // Or other default?
}
Если вы не можете применить правило для каждого языка, то обычно пытаются обойти сложные лингвистические проблемы. Вы должны учитывать не только номер и его порядковый номер, но и контекст, в котором он появляется, и даже то, как положение в предложении может повлиять на перевод.
Вместо того, чтобы пытаться написать "1-е место" , такой ресурс гораздо проще перевести:
#easyToTranslate_en.properties
label.position=Position: {0,number,integer}
В зависимости от того, что вы пытаетесь сделать, вы можете пойти на компромисс с решением, подобным этому:
#compromise_en.properties
label.position.first=1st place
label.position.second=2nd place
label.position.third=3rd place
label.position.default=Position: {0,number,integer}
Это потребует, чтобы код, прочитанный ресурсом, выполнял тест на регистр, чтобы выбрать, какой ресурс загрузить.