Мультиязычность и Ф7

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

У меня есть предложение: сделать таким образом: в template писать как-то так {{=меню}}, далее консольная команда собирает все значения для перевода и делает такой файл: en.js, который содержит массив
[‘меню’] = ‘menu’
На мой взгляд это позволит быстро и просто делать переводы.

Когда то использовал самописные библиотеки, хранил в объекте.
На чистом JS можно взглянуть на вот эту библиотеку https://www.npmjs.com/package/i18n

Сейчас планирую использовать vue-i18n

В принципе всё есть что надо, кэш, склонения, динамическая подгруздка локалей

1 Like

Штука с виду интересная, но:

  1. Нужно как-то обрабатывать шаблон этой JS-библиотеки в Template7, т.е. скомбинировать их.
  2. Не нашел там категорий, это нужно, например, когда одно слово на русском языке может иметь два разных слова на английском (в зависимости от контекста).

Множественные склонения должны быть, есть ещё l10n библиотеки

https://www.w3.org/International/questions/qa-i18n.ru.html

Да, конечно, вот та штука для Vue выглядит круто.

Я в Vue использую свою функцию, простая в реализации и рендерит с Template7, если необходимо. Без Vue, ее можно сделать через Template7 helper:

const locales = {
  'en-US': {
    home: {
      hello_text: 'Hello {{username}}!',
      // ...
    },
    // ...
  },
  'ru-RU': {
    home: {
      hello_text: 'Привет, {{username}}!',
      // ...
    },
    // ...
  },
};

const templatesCache = {};

Object.keys(locales).forEach((key) => {
  templatesCache[key] = {};
});

let language = 'en-US';

function $t(key, data) {
  let key;
  let data;
  
  if (!data) data = {};
  let localeString;
  localeString = locales[language];
  key.split('.').forEach((part) => {
    if (localeString && localeString[part]) {
      localeString = localeString[part];
    } else {
      errored = true;
    }
  });
  if (errored) return '';

  // Check if need to parse value as Template7
  if (localeString.indexOf('{{') >= 0 && localeString.indexOf('}}') >= 0) {
    if (!templatesCache[language][key]) {
      templatesCache[language][key] = Template7.compile(localeString);
    }
    localeString = templatesCache[language][key](data);
  }
  return localeString;
}

И потом:

$t('home.hello_text', { username: 'John' })

И если без Vue, то нужно где-то глобально хранить language

1 Like

Вот как раз этот вариант не удобен, приходится же держать все эти константы в голове. Было бы круто так:

$t(‘Привет, дорогой {username}’, { username: ‘John’ })

Это же очень удобно.

Зачем же в голове, как правило они выносятся в отдельные файлы с локалями.

А основываясь на чём $t(‘Привет, дорогой {username}’, { username: ‘John’ }) это может быть переведено на другой язык?))

Допустим, базовый язык - русский, делаем перевод на английский и немецкий.

  1. Везде пишем $t(‘Привет, дорогой {username}’, { username: ‘John’ }) Никаких констант не нужно ни в файле ни в голове держать.
  2. В любой момент времени вызываем консольную команду, она делает файлы:
    en.js и de.js
    В этих файлах массив:
    m['Привет, дорогой {username}'] = ''; //Пусто

Пустоты мы заполняем переводом, получится:
m['Привет, дорогой {username}'] = 'Hi, dear {username}';

  1. Переключаем в F7 язык на английский, теперь если соответствующий элемент массива в en.js не пустой, значит есть перевод и происходит автозамена, ну а если поле пустое, то замены нет.

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

Сначала был собственный механизм, типа:

Template7.registerHelper('locale', function (text) {
  return window.locale[text];
});

Где-то при инициализации приложения:

    if (navigator.language) {
      var twoLetterISO = navigator.language.substring(0, 2).toLowerCase();
      if (twoLetterISO == 'en' || twoLetterISO == 'ja' || twoLetterISO == 'ru' || twoLetterISO == 'ar') {
        defaultSettings.language = twoLetterISO;
      }
      initLocale(callback);
    }

И далее:

function initLocale(callback) {
        var xhr = new XMLHttpRequest(),
          url = 'assets/i18n/' + defaultSettings.language + '.json';
        xhr.onload = function () {
          window.locale = JSON.parse(xhr.response);
          if (callback) {
            callback();
          }
        };
        xhr.onerror = function (e) {
          console.warn('Locale file load error.');
          var platformCategory = 'platform-ios';
          AnalyticsManager.trackEvent(platformCategory, "locale-file-load-error", url, 0);
        };
        xhr.open('GET', url, true);
        xhr.send(null);
      }

Потом заменил на i18next:

import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';

Template7.registerHelper('t', (i18n_key) => { return i18next.t(i18n_key) })

Где-то в шаблонах:

{{t ‘CANCEL_BUTTON’}}