Комментарии 20
В принципе проблема давно решена (gnu.gettext.GettextResource API), но если вам хочется изобретать велосипед, то да — кто ж вам запретит…
Я в упор не вижу решения там проблемы склонения существительных. Я так понял, что эта фиговина предназначена для интернационализации? В Struts есть fmt для этого. Я решаю совсем другую проблему.
Gettext — это библиотека для интернационализации, она отлично работает с Java и поддерживает работу с числительными. А какую другую проблему решаете вы?
Ну подходит вам решение или нет — это другой вопрос. А решение там следующее: в ngettext передаётся три аргумента, но реально используется два. Первая — число и вторая — ключ. В .po файле указывается сколько вариантов теста может быть в языке (в арабском, например, шесть), как они выбираются и, собственно, эти варианты. Третий аргумент функции ngettext используется только для английского языка.
Да — по сути всё упирается в примерно те же формулы, что и у вас (русский язык-то для всех один), но оно работает для всех языков, а не только для русского.
Да — по сути всё упирается в примерно те же формулы, что и у вас (русский язык-то для всех один), но оно работает для всех языков, а не только для русского.
В английском языке все просто: 1 year, 2 years ,… N years
А также criterion —> criteria, stigma —> stigmata, ox —> oxen, все по тому же шаблону ;)
Или что выбрать — appendices или appendixes? Или опять s просто добавить? :)
Это уже проблема согласования с числительными неизвестных слов. Она во всех языках с трудом решается. Речь идёт про бесконечные строки типа
if ($mailnum==1)
print $t['mail received'];
else
printf $mailnum+$t['mails received'];
Объяснить американцам что вариантов может быть больше двух и выбираться они могут загадочным способом и даже текст может меняться не только после числительного, но и до — довольно сложно…
if ($mailnum==1)
print $t['mail received'];
else
printf $mailnum+$t['mails received'];
Объяснить американцам что вариантов может быть больше двух и выбираться они могут загадочным способом и даже текст может меняться не только после числительного, но и до — довольно сложно…
Это в любом случае решается обычным ChoiceFormat. И, таки да, для красного словца :)
Приведённый код, по моему вкусу, не так уж и хорош.
Предлагаю вам заглянуть сюда и ознакомится с достаточно универсальными формулами для целой кучи языков. При многоязыковой разработке эти формулы сильно сэкономят время. Не знаю как в Java, но в PHP эти формулы в чистом виде не применимы из-за несколько другой интерпретации оператора ?:, но в умелых руках всё работает.
Предлагаю вам заглянуть сюда и ознакомится с достаточно универсальными формулами для целой кучи языков. При многоязыковой разработке эти формулы сильно сэкономят время. Не знаю как в Java, но в PHP эти формулы в чистом виде не применимы из-за несколько другой интерпретации оператора ?:, но в умелых руках всё работает.
Я все жду, что кто-нибудь внятно напишет, как это хозяйство к готовому Java-коду прикрутить с минимумом переделок. Особенно интересует, как этот gettext использовать в JSP.
Видите ли, из-за частного решения, пусть даже красивого и правильного, не разносят всю систему.
Видите ли, из-за частного решения, пусть даже красивого и правильного, не разносят всю систему.
Вообще я не о геттексте говорил, а об универсальных формулах для числительных.
Но про геттекст тоже отвечу для Си ибо Яву уже не помню. Главный принцип gettext — минимум телодвижений. Если забыть о числительных, то для перевода на gettext программы с английскими строками требуются следующие действия:
1 Дописать инициализацию локали в начале программы.
2 Обернуть все строки «text» в _(«text»)
3 Запустить poedit и поковыряться в настройках
4 Перевести с английского на нужный.
Для строк с параметрами и с числительными придётся немного переписать код, но, как правило, эти участки после переписывания упростятся.
Не знаю как это реализовано в Яве, но не думаю, что есть большие отличия.
Но про геттекст тоже отвечу для Си ибо Яву уже не помню. Главный принцип gettext — минимум телодвижений. Если забыть о числительных, то для перевода на gettext программы с английскими строками требуются следующие действия:
1 Дописать инициализацию локали в начале программы.
2 Обернуть все строки «text» в _(«text»)
3 Запустить poedit и поковыряться в настройках
4 Перевести с английского на нужный.
Для строк с параметрами и с числительными придётся немного переписать код, но, как правило, эти участки после переписывания упростятся.
Не знаю как это реализовано в Яве, но не думаю, что есть большие отличия.
В Яве это реализовано на «ура». Есть класс Format и куча его наследников для разных нужд, есть класс Locale, ResourceBundle и т.п. Т.е. в Java с l10n и i18n все в порядке, за исключением проблемы множественного числа в русском языке, потому что с помощью ChoiceFormat его не опишешь. В английском, немецком, французском — запросто.
Я не спорю с тем, что библиотека gettext — штука интересная и задачу выполняет, но во-первых, в Java все (почти все, как оказалось) уже придумано до нас, описано в книгах и т.п., во-вторых, наша система изначально делалать с интернационализацией и локализацией, т.е. проблема выдирания строк изначально не стояла.
Я не спорю с тем, что библиотека gettext — штука интересная и задачу выполняет, но во-первых, в Java все (почти все, как оказалось) уже придумано до нас, описано в книгах и т.п., во-вторых, наша система изначально делалать с интернационализацией и локализацией, т.е. проблема выдирания строк изначально не стояла.
Решил добавить кратенький пример взятый из своего кода. Поддержка языков кроме русского пока отсутствует, но мы уже готовы к ней. Думаю, что этот код может отказаться полезным. (В пхп можно использовать русские юникодовые строки для геттекста, сем успешно и пользуюсь).
function plural ($n){ return plural_russian($n); } function plural_russian($n){ return $n%10==1 && $n%100!=11 ? 0 : ($n%10>=2 && $n%10<=4 && ($n%100<10 or $n%100>=20) ? 1 : 2); } $strings= array( 0 => "через %d месяц", 1 => "через %d месяца", 2 => "через %d месяцев", 3 => "через %d месяцев форма 3", 4 => "через %d месяцев форма 4", 5 => "через %d месяцев форма 5", ); return sprintf($strings[plural($mn)], $mn);
Для русского языка нужно добавить еще одно условие. Для числительного 1 и заканчивающихся на 1 (21, 31 и т.д.) нужна первая форма. Как-то так:
private Integer plurals(Long n){
if (n==0) return 0;
n = Math.abs(n) % 100;
Long n1 = n % 10;
if (n == 11) return 1;
if (n > 11 && n < 20) return 5;
if (n1 > 1 && n1 < 5) return 2;
if (n1 == 1) return 1;
return 5;
}
private Integer plurals(Long n){
if (n==0) return 0;
n = Math.abs(n) % 100;
Long n1 = n % 10;
if (n == 11) return 1;
if (n > 11 && n < 20) return 5;
if (n1 > 1 && n1 < 5) return 2;
if (n1 == 1) return 1;
return 5;
}
Да, я согласен с автором о сложности русского языка. Но когда точно известны ограничения, например только от 1 до 59 минут или от 1 часа до 24, то силы MessageFormat вполне достаточно. Всё зависит от ситуации
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Склонение существительных с числительными