Pull to refresh

Comments 18

Немного риторики — как дела с доменами, контекстами, множественными числами? (Хотя из кода вижу, что никак) Ну и конвертить PO онлайн — должно быть очень удобно для билда проектов.
Я же и прокомментировал в конце статьи, что жду от вас всех пожеланий и нужд. По поводу конвертации, я всё равно перед тем как залить на сервер запускаю POEdit, и он создает .mo файл. Но видел решения автоматической генерации перевода на сервере. Думаю, туда несложно добавить автоматическое создание JSON-файла. Просто относится ли это к этой библиотеке или нет? Если вы считаете, что да, то как вы видите это процесс? Спасибо.
Вы можете просто сделать эту фичу отдельный модулем. Кому будет нужно — тот подключит.
Всё верно, я так уже и планирую. Просто в каком виде? Это будет bash скрипт или php скрипт (второе больше по душе).
PHP, наверное, будет лучше тем, что более кроссплатформенно получится, чем баш.
т.е. господа минусующие хотят сказать, что баш скрипт проще будет запустить под Windows, чем PHP?
Скорее всего да. Bash поставить на Windows — раз плюнуть (и если вы более-менее серьезный разработчик, то он у вас уже есть), а разбираться с подключением PHP — это отдельный гемор если у вас серверная часть на другом языке.
Joshua I. Miller в свое время написал отличнейший порт GNU gettext-a, тут есть его копия — phpxref.pagelines.com/nav.html?dms/editor/js/Gettext.js.source.html. Там можете найти много интересного. У себя на проекте используем именно этот модуль.

С файлами локализации у нас работают документаторы, через POEdit. На выходе получаем .po файлы, которые вышеупомянутой библиотекой конвертируем в .json, во время билда. В клиент подтягиваем уже скомпиленый .json, который внедряется в код урезанной версией Gettext-а.

При этом сохранены все доступные методы GNU.
>Первым делом я искал, как же в JS прочитать PO-файлы. Можно парсить, но это лишняя нагрузка, поэтому я решил не насиловать JavaScript и отдавать ему уже готовый JSON.
Я бы всё-таки подумал о том, чтобы добавить парсер po->json в библиотеку. Во многих случаях вполне допустимо потратить сотню миллисекунд на парсинг po-файла, особенно если он происходит уже после DOM Ready.
Имхо, это тот случай, когда можно разгрузить сервер и отдать работу клиенту.
Обычно po-файлы меняются не так часто, но не у всех настроены всякие билд-скрипты, которые автоматически смогут перевести po во json при изменении перевода, и возможность прямой загрузки po может помочь некоторым будущим пользователям вашей библиотеки.
Для более менее серьезных проектов файл .po может быть немаленьким. И конвертация на клиенте может занять неприятное время. Но я согласен с вами, парсинг нужно добавить, но он должен происходить или во время билда, или на сервере при загрузке страницы. Дело в том, что хотелось бы какое-то универсальное решение. Я могу написать парсер на PHP, но что, если проект на Python или Ruby?
поэтому я и говорю — парсер на js на клиенте. Укажите в документации, что гораздо лучше иметь заранее созданный json на сервере, но дайте и возможность автоматического подключения po-файла. Не все из тех, что хочет переводы, имеют инфраструктуру на сервере, и им придётся вручную запускать создание json-а.
Но смотрите сами. Вы просили улучшения, я считаю, что количество пользователей эта функция увеличит. Но решать вам. Если вы считаете архитектурно неправильным парсить на клиенте, то так и быть. Вон, твиттер пытался сделать шаблонизацию на клиенте, а потом отказался и стал с сервера выдавать готовый html.
Небольшая подсказка — phantomjs. Его можно запустить из любой среды, скормить ему парсер на JS, и источник .po, на выходе получить .json. Весь код запуска сведется к одной строке.
Без поддержки числительных и контекста это несерьезно, в любом сколько-либо крупном проекте это требуется. Ну и интерфейс не-gettext совместимый уже сейчас.
Солидарен с комментатором выше по поводу кода: зачем дикой частоты интервал, там где всего один раз должен сработать коллбек после загрузки файла? Да и односимвольные переменные (как и underscore-префикс для всего подряд) не добавляют читаемости, оставьте эту работу минимизатору.

(Промахнулся веткой комментариев, хотел на первом уровне написать)
Отличный метод…

    ready: function(cb) {
        var _t = this, i = setInterval(function() {
            if (_t._r) {
                cb();
                clearInterval(i);
            }
        }, 10);
    },


Да еще и несоблюдение JS стандартов.
Я понимаю, что вы гуру и вам достаточно написать саркастическое словосочетание. Но знаете что, отвергая, предлагай. Не все мы пишем идеальный код. На вашем месте я бы лучше поделился опытом и объяснил, что в этой функции не так.
Писал с iPad, ночью, по-этому так «сухо». Сейчас попробую все разжевать.

Во-первых, не i18n (internationalization), а всего лишь i10n (localization). Не путайте.

Во-вторых, на GitHub у вас написанно:
Super-simple gettext translation in pure JS
и, хочу я сказать, что Gettext тут не при чем.

В-третьих, у инструментов, перечисленных вверху поста, нет зависимостей. Библиотека/фреймворк, под которую написан плагин/дополнение не может быть зависимостью, а только ноборот.

Код вашей библиотеки с моими комментариями
// Неправильное определение переменной: нет ключевого
// слова "var" - несоблюдение строгих стандартов JS.
pojs = {
    // Непонятное имя свойства
    _l: null,
    // Непонятное имя свойства
    _r: false,
    // Непонятное имя свойства
    _p: {},
    // Непонятное имя параметра
    init: function(l) {
        this._l = l;
        this._load();
    },
    _: function(key, args) {
        // Избыточное выражение.
        // Проще:
        //  this._p[key] || key
        //
        // Неправильное форматирование кода. Не только здесь, повсеместно.
        // Рекомендую к прочтению JS Style Guide: https://github.com/BR0kEN-/javascript
        //
        // В данном случае лучше так:
        //  var t = this._p[key] || key,
        //      a;
        var t = this._p.hasOwnProperty(key) ? this._p[key] : key, a;
        // Неправильная проверка. "args" может быть строкой и удовлетворять условие.
        // Пример:
        //  var args = 'string';
        //
        //  if (args) {
        //    for (var arg in args) {
        //      // args[arg] = s
        //      // args[arg] = t
        //      // args[arg] = r
        //      // args[arg] = i
        //      // args[arg] = n
        //      // args[arg] = g
        //    }
        //  }
        if (args) {
            for (a in args) {
                t = t.replace(/%s/, args[a]);
            }
        }
        return t;
    },
    // Неправильный подход. Необходимо использовать
    // событие "load" для XMLHttp объекта.
    //
    // Отсутствие проверки на тип.
    // Пример:
    //  pojs.ready('fucking code');
    //  Uncaught TypeError: string is not a function
    ready: function(cb) {
        var _t = this, i = setInterval(function() {
            if (_t._r) {
                cb();
                clearInterval(i);
            }
        }, 10);
    },
    _load: function() {
        // "'localStorage' in window" и "window['localStorage'] !== null" - одно и то же.
        var _t = this, x, lsa = 'localStorage' in window && window['localStorage'] !== null, cache = null;
        if (_t._l) {
            if (lsa) {
                cache = localStorage.getItem('pojs_' + _t._l);
                if (cache) {
                    _t._p = JSON.parse(cache);
                    _t._r = true;
                    return;
                }
            }

            x = new XMLHttpRequest();
            x.onreadystatechange = function() {
                // Избыточная вложенность и неправильное обращение к объекту.
                //
                // Выражение записывается так:
                // if (this.readyState === 4 && this.status === 200) {
                //   // actions
                // }
                //
                // Или же еще проще:
                // if (this.response) {
                //   // actions
                // }
                //
                // Помимо этого, в IE8, данный код обрастет ошибками:
                //  - отсутствие объекта XMLHttpRequest;
                //  - отсутствие объекта console.
                if (x.readyState === 4) {
                    if (x.status === 200) {
                        // Выше, почему-то, есть проверка на существование
                        // localStorage, а тут подразумевается что объект
                        // будет во что бы то ни стало?
                        localStorage.setItem('pojs_' + _t._l, x.responseText);
                        _t._p = JSON.parse(x.responseText);
                    } else {
                        console.error('Can not load JSON from ' + _t._l);
                    }
                    _t._r = true;
                }
            };
            x.open('GET', this._l, true);
            x.send();
        } else {
            _t._r = true;
        }
    }
};

P.S. Создал pull request на GitHub.
Sign up to leave a comment.

Articles