Как стать автором
Обновить

Комментарии 36

Почему amount_ofbananas0 соответствует 1 банан, а не 0 бананов? И что будет если передать 11 и 21?

Действительно, нумерация внутри словаря идет несколько странно. Однако, один раз все настроив, про это можно забыть.
Передавать можно любые цифры, конкретно 5 я взял для примера.

Вопрос про 11 и 21 был задан потому, что
0, 10, 20 и т.д.бананов
1 банан, 11 бананов, 21 банан
2,3,4 банана, 12,13,14 бананов, 22,23,24 банана
5 и далее как и ноль.

Language Plural Rules:
http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html

Есть ли возможность сразу загружать только один язык, а остальные подтягивать по мере необходимости?

Собственно в примере оно так и работает. Каждый раз, когда пользователь меняет язык, с помощью require подгружается нужный файл.
подгрузка синхронная, значит вебпак (или что вы используете) уже вкомпилировал json словарь в бандл. Для более-менее большого приложения не годится. Решается легко, но в статье — не боевой вариант.
Я у себя в проекте сделал на базе https://github.com/WebbyLab/itsquiz-wall, на мой взгляд очень неплохой вариант.

json не вкомпиливается, работает изоморфно.

Чтобы было совсем хорошо, надо добавить в языковые json хеш-суммы и ставить большой expire на веб-сервере
А существуют ведь наверняка библиотеки интернационализации для js, которые не заставляют самостоятельно объявлять ключи, а используют в качестве ключа саму фразу на языке «по умолчанию»? (что-то вроде PHP-шного gettext).

Мне такой подход кажется куда более удобным, особенно если имеется удобные инструменты для собственно процесса перевода.
https://slexaxton.github.io/Jed/ — что-то нашлось. Приделать удобный псевдоним в глобальное пространство (window.t, например) и какую-нибудь очень простую вещь, которая будет ловить все фразы, туда попадающие и выдавать по каким уже есть перевод, а по каким еще нет — и можно почти не терять времени на поддержку версий для разных языков.

Косяки этого способа:


  1. Вы всегда грузите два языка.
  2. Исправление опечатки в тексте приводит к созданию нового ключа с последующей необходимостью повторного перевода.
  3. Нужно что-то решать с плюральными формами.
  1. С другой стороны я гружу только один язык, а не язык + ключ на каждую фразу, когда работаю с языком по умолчанию. А в способе из статьи это точно всегда будет язык + ключи.
  2. Да, но по идее это должно отслеживаться какой-то автоматикой.
  3. В вышеприведенном Jed это решено и выглядит так:

i18n.translate("%d key doesnt exist").ifPlural( n, "%d keys dont exist" ).fetch();

  1. Ключи обычно куда меньше текстов.
  2. В идеальном мире — да :-)
  3. Выглядит как жуткий костыль по сравнению c this.text( 'resultMessage' )

Как вы будете действовать, когда потребуется число сделать жирным шрифтом, а бананы — серым?

Внутри словаря вы сами определяете, как будет выводиться строка, конкретно {{count}} отвечает за число. Таким образом, можно перед 18next.t('amount_of_bananas', {count: 5}) поставить 5 в спане, которая и будет выводиться.

Вы предлагаете зашивать разметку в локализацию?

Нет. Внутри компонента, перед вызовом функции локализации будет стоять span с нужным числом (например, 5). Дальше идет функция перевода, куда вы эту 5 передаёте. А уже внутри словаря вы уберете {{count}}, и вторая пятерка (внутри функции) выводиться не будет.

Давайте более предметно. Вот у вас несколько вариантов текста:


На вас ещё никто не подписан.

На вас подписан 1 пользователь

На вас подписаны 2 пользователя

На вас подписаны 5 пользователей

На вас подписаны 11 пользователей

На вас подписаны 12 пользователей

На вас подписаны 15 пользователей

На вас подписан 21 пользователь

На вас подписаны 22 пользователя

На вас подписаны 25 пользователей

Что вы напишете в коде и что будет в словаре?

Может кому пригодится. Мы использовали очень долго babelfish. Мне не нравилось что он не дает компилировать сообщения (и таким образом довольно много места в бандле занимает). Я стал искать, чтобы во первых можно было компилировать, во вторых чтобы можно было использовать icu message format. Смотрел на format.js, там была какая то беда со сборкой (сейчас не знаю), хотя они и используют message format из icu. В конце концов, взял то что они использовали внутри messageformat.js. Надеюсь это кому то сэкономит время.

После одного недавнего проекта осталось несколько мыслей по поводу перевода.
1 Тексты это косвенные данные проекта. Не следует их засовывать в код через require. Это приведет к тому, что из-за изменения текстов придется пересобирать проект.
Гораздо проще засунуть их в Глобал.
2. Не надо привязывать Тексты жёстко к компонентам.
Например, з я сделал так, добавил в компонент свойство text. Компонент знает только об схеме этого свойства, т.е о доступных ключах.
Так же сделал простой декоратор @ text который из Глобал объекта тянет нужный ключ в компонент.
использовал react-intl, все отлично и быстро делается

vintage вот пример для вашего комментария выше.

translates = {
  "message_subscribed_count" : "На вас {count, plural, =0 { ещё никто не подписан} one { подписан <b>#</b> пользователь} few { подписаны <b>#</b> пользователя} other { подписаны <b>#</b> пользователей}}."
}

<FormattedHTMLMessage id="message_subscribed_count" values={{count: COUNT}}/>

Заставляете переводчиков понимать теги и экранировать символы? А среда перевода понимает этот волшебный синтаксис или и его нужно знать бедным переводчикам?

в админке есть просто конструктор, а переменную он просто не трогает. К примеру у него сначала есть конструкция «На вас $MESSAGE$» и дальше идет определение конструкций (=0, one, few, other), и потом уже MESSAGE собирается в {count, plural, ...}.

Если у вас есть более приятное решение, поделитесь. Ну и насколько я знаю, то переводчики пользуются вордом, а потом бедный контент менеджер сидит и все это забивает. Переводчики не лезут в админку. Но даже если вдруг, то им не составит труда запомнить некоторые правила
    var lang = { 'ru' : {
      'result' : [
        'На вас ещё никто не подписан.' ,
        'На вас подписан 1 пользователь' ,
        'На вас подписаны 2 пользователя' ,
        'На вас подписаны 5 пользователей'
       ]
    } }

    document.body.innerHTML += text( 'result' , 0 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 1 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 2 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 5 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 10 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 11 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 12 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 15 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 20 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 21 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 22 ) + '<br/>'
    document.body.innerHTML += text( 'result' , 25 ) + '<br/>'

http://liveweave.com/c90hNl


Для коллаборативного перевода уже давно есть специализированные сервисы так то.

Отличный пример.
Только как по мне, тяжело расширять такие переводы.

Для того же примера: будем выводить не 'вас', а '$username$ ', и пусть username = nick1, и все поломается

Не сломается, там же будет плейсхолдер {username}.

Извините, я не очень понял, а в чем преимущество такого решения, в связи с вашими комментариями про теги? Как вы будете действовать, когда потребуется число сделать жирным шрифтом, а надпись «пользователей» — серым?

Обычно требуется статичный текст приглушить, а вариативный выделить.

Ну так как вы будете делать это в вашем варианте с result?

Я же уже привёл пример. Динамически добавляемые данные оборачиваются тегом.

В вашем примере только один тег <br/>, ни цвета ни болда там нет. У вас функция подстановки перевода сама магические спаны добавляет?

Вы не умеете пользоваться css? Да, сама.

Ясно. А если надо 2 связанных параметра передать в сообщение и каждый выделить по-своему («Вы набрали 18 очков из 20 возможных»), у вас будет другая функция text2()?

Зачем? Эту вполне можно расширить и на этот случай. Это пример, а не готовое решение, если это не очевидно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории