Pull to refresh

Comments 27

Было бы неплохо примерчик работающий увидеть. На стороне сервера нужно все равно подстраивать вмето текста название этих ключей, а потом в js вручную создавать хеш значений. Я правильно понимаю как использовать эту библиотеку? Если это так, то я, как разработчик RoR, никакого смысла в этом не вижу. Это просто самописная js библиотека наподобие гема i18n (только вот i18n работает и будет работать как надо без багов). Где нужно было применить вот эту библиотеку, на каком проекте? Очень хотелось бы знать
> На стороне сервера нужно все равно подстраивать вмето текста название этих ключей, а потом в js вручную создавать хеш значений
Я не понимаю до конца, что вы здесь имеете в виду.
А применить можно в любом веб-приложении, где необходима локализация.
Я имел ввиду, что генерить код на стороне сервера нужно будет наподобие этого:
  <a href='...'>this_is_cancel_link</a>
где this_is_cancel_link — это ключ, который потом можно будет перевести с помощью вашей библиотеки и готового словаря.
Совершенно необязательно. Реализация связывания элементов с хэшем ложится на стороннего программиста, который использует эту библиотеку.
Да, можно использовать и приведённый вами пример; можно указывать ключ в атрибутах; можно вообще не указывать ключ, а совершать «накладывание» JavaScript-объекта с ключами на HTML-структуру.
Суть библиотеки не в замене ключей на их значения, а в изменении текущего значения элемента на новое при изменении словаря. Причём словарь может быть загружен или выгружен в произвольный момент времени.
Хочется пример большой страницы, где реально много всего, мне кажется что если у вас нагруженная структура то можно легкой сойти с ума делаю подобное, тем более ведь не каждый элемент вы создаете динамически.
Специально для вас:
clip2net.unet.by/page/m341/61867
Просто откройте при включенном интернете.
Сваял по-быстрому, поэтому возможны ошибки. Да и на английский не обижайтесь )
Не пробовали выдернуть innerHTML из document.body, а потом вставить назад со всеми заменами?
/*саркастично*/
Правильно — пересоздайте все элементы на странице и потеряйте обработчики событий на них.
А почему бы этого не сделать до создания обработчиков?
Извиняюсь, прочитал внимательнее: у вас другая цель и предложенный мною вариант — не вариант.
Я делал динамическую смену языка следующим образом:

— на клиенте шаблонизатор
— данные для рендеринга шаблонов кешируются на клиенте
— языковые файлы в отдельном хеше
— языковые фразы вставляются через шаблонизатор
— следовательно сменить хеш на другой язык и прорендерить страницу заново не составляет труда
— без обращения к серверу — так как данные для страницы закешированы

Понятно что все это делалось не ради динамической смены языка — она просто как бонус получилась сама собой.
Еще раз для вас:
Суть библиотеки не в замене ключей на их значения, а в изменении текущего значения элемента на новое при изменении словаря. Причём словарь может быть загружен или выгружен в произвольный момент времени.
Я вас не критикую — просто написал к слову свой опыт работы с похожими вещами…
> Хотя на самом деле я считаю, что линейку IE до восьмой версии включительно нужно давно похоронить.

Я это уже пол года как практикую — и искренне сочувствую тем кто по каким либо причинам вынужден поддерживать IE версии ниже 9
Любой проект, который делается для широких масс вынужден поддерживать IE7-8
Хочется Вам тоже посочувствовать… и вот почему:

Пожалуйста, попробуйте следующий сценарий:

IE — меню Сервис (нажать кнопку Alt, если не видно меню) — Свойства обозревателя — Дополнительно — поставьте галку «Не сохранять незашифрованные страницы на диск»
Перезапускаем браузер и пытаемся скачать любой файл с HTTPS-сайта

На IE9 и IE10 (Preview) у Вас это вряд ли выйдет.
На IE8 работает в большинстве сценариев (хотя если после перезапуска браузера сразу вбить прямую ссылку на файл на HTTPS-ресурсе — то тоже не скачает)

P.S. если сразу не сработает — то для большего эффекта попробуйте добавить сайт в надежные узлы.

Подобных багов несложно с десяток найти в разных версиях IE.

Если уж отказываться от IE — то от всех версий.

Если поддерживать IE — то хотя бы с 8 версии и выше (хотя бы потому, что 60-70% юзеров до сих пор сидят на Windows XP, для которого нет 9 версии IE — и только попробуйте им сказать «пользуйтесь другим браузером» — сразу в ответ получите «Я же Вас не прошу вместо Вашего (сисадминского) свитера носить нормальный костюм»).

Удачи!
Как клиентский программист, я с вами согласен, что IE можно поддерживать с восьмой версии, но не ниже. Потому что в плане рендеринга страниц восьмая версия, конечно, отстаёт от девятой, но имеет результат гораздно более близкий к ожидаемому. Эта проблема относится к верстальщикам. Огорчает IE и программистов, потому что в своё время IE8 был очень большим продвижением, но всё равно его функционала не хватает для нормальной разработки: постоянно приходится что-то дописывать.

И мне всё равно, что этот комментарий заминусуют. Но поймите же вы, что, идя на уступки в виде поддержки старых браузеров, вы замедляете развитие интернетов!
С одной стороны — да, замедляю.

С другой стороны:
— допустим, у пользователя куплена лицензионная Windows XP. Ради Internet Explorer 9.0 покупать Windows 7 — зачем? Абонента все устраивает… он привык работать на ней… мало того — КПД сотрудика может упасть, пока он будет обучаться Windows 7
— допустим, пользователю ставят Mozilla Firefox, Google Chrome или Opera вторым браузером (единственным браузером не всегда получится — есть куча бизнес-сайтов, использующих ActiveX). В конце концов это закончится тем, что пользователь перестанет пользоваться вторым браузером, потому что он либо запутается в закладках, либо его достанут постоянные обновления браузера, которые «всегда не вовремя», либо еще какая беда случится — я не раз наблюдал такое собственными глазами

К сожалению (по крайней мере, в компании, где я работаю) таких пользователей больше 50 000…

Поэтому я немного переформулирую исходную фразу:
«версии поддерживаемых сайт браузеров зависят не только от желания разработчиков сайта, от задания заказчика и от тенденций развития технологий, но и от результатов анализа, кто же будет посещать этот сайт»

Например, сайт Microsoft на многих страницах до сих пор хорошо рендерится в IE6 (хотя уже и плохо в IE 5.5 на Windows 2000). Причина такой совместимости — вынужденная необходимость из-за большой посещаемости сайта Microsoft с браузера IE6 на Windows XP.

И выражаю большую благодарность всем тем, кто дочитал мое мнение до конца ;-)
Я вас понимаю бизнес и все такое… Но я вольная птица и могу себе позволить использовать канвас без костылей. И по статистике моего проекта я теряю 2.5% пользователей. Но мог бы и 10% потерять — для меня это не так критично.
У вас ужасный стиль кода. Написанные в uppercase идентификаторы обычно считаются константами, а у вас — нет. Это запутывает. Также, у вас дурацкие имена методов. Например params() — это setParams() или что?

Также, меня бесят конструкции вида:

if(!(strName instanceof Array))
strName=[strName];

Если по ошибке мы передадим неправильный параметр, функция, вместо того чтобы выругаться и упасть, продолжит работать как ни в чем не бывало. Это затрудняет обнаружение ошибок.

По поводу статьи, идея понятна, вместо того, чтобы вставить переведенный текст и забыть, мы храним ссылки на все DOM-элементы. В общем, мне идея не нравится, так как это серьезное изменение архитектуры и усложнение ради вещи, которую юзер делает в лучшем случае 1 раз в жизни. лучше наверно, как кто-то предложил в комментах, просто заново перегенерировать все виджеты на странице с учетом нового языка, если архитектура это позволяет.

Подход, типа «ИЕ не нужен» на мой взгляд, характеризует разработчика с отрицатеьной стороны. В ИЕ (включая 7 и иногда 6) можно делать почти все, что нужно в современном веб-приложении (а что нельзя. делается через флеш) — было бы желание.
Толсто, друг мой.

Переменные верхнего регистра у меня обозначают замыкания, недоступные извне.

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

По поводу хранения ссылок: их можно и не хранить, но тогда при большом количестве элементов при траверсе HTML при обновлении словаря будут страшные тормоза на странице.

А еще у меня совсем не виджеты, а полноценные приложения. И да, архитектура намного сложнее, чем вы можете представить.

Пожалуйста, это ваше собственное желание — писать по IE. Кстати, да, вот вам баянчик.

И давайте не будем мыслить узко. Эта штука может не только языки менять, а текст как вам угодно в принципе. Например, кто-то независимо дописывает тексты в БД, и как только происходит сохранение, то изменения отражаются на клиенте почти моментально (например, с использованием лонг-поллинга или веб-сокетов).
1. Соглашусь с предыдущим комментарием, код оформлен ужастно: проблемы с отступами, отсуствие пробелов, мешанина с именованием. Именуйте по общепринятыми правилам (КОНСТАНТЫ, Классы, остальныеНазвания) и прогоняйте ваш код через какой нибуть jsbeautifier.org перед публикацией.
2.
arrParams instanceof Array

Так массивы не проверяют. В ES5 есть функция Array.isArray, для старых браузеров делается простая замена:
if (typeof Array.isArray != 'function')
  Array.isArray = function(value){
      return Object.prototype.toString.call(value) === '[object Array]';
  }

3.
Объясните, для чего вы делаете так:
hash_rebuild=function hash_rebuild(){
...
LANG_HASH[prop].replace(/%(\d+)/g,function rep(a,b){return params[b]||"";})
...
get:function get(strProp){

Во всех этих случаях задавать имя функции не нужно. Хотя для первых функции не ясно зачем нужно делать из них переменные?

4. Вы первый на моей памяти человек который default запихнул в начало switch… Даже не знал что так будет работать :)
switch(typeof data){
    default:
        return;
    case "string":
        LANG_PROPS_TO_UPDATE[data]=1;
    break;
    case "object":
        lang_mixer(LANG_PROPS_TO_UPDATE,data);
}


5. Свойство textContent относительно новое свойство в DOM, и предназначено для других целей нежели используете вы. Самый близкий аналог это innerText, который поддерживают все кроме Firefox (то есть работает в IE/Opera/Chrome/Safari). Для текстовых узлов, атрибутов (AttributeNode) и комментариев поменять из значение можно через свойство nodeValue. Либо же свойство data, но оно работает не для всех типов.
Поэтому если использовать nodeValue — то минус один «хак», который решает вами же созданную проблему, и только для IE8 (defineProperty работает только там) и только для текстовых узлов.
То есть замените «textContent» на «nodeValue» и проблема будет решена.

6. Самый грязный хак из вашего примера это:
if("v"=="\v"){
  .. какие то хаки для каких то браузеров
}

Я намеренно не указал на IE, так как проверка не адресная: условие «v» == "\v" не определяет наличие или отсутствие фич у браузера. Здесь нужно проверять каждую фичу по отдельности.

7. indexOf входит в состав ES5 и относительно молодой метод, а это значит что реализация метода отсутсвует не только в IE8, но и в других браузерах (в версиях отличных от последних). Поэтому хорошо будет позаботиться о всех, и делается это так:
// для старых браузер не имеющих реализации indexOf для массивов
if (typeof Array.prototype.indexOf != 'function')
    Array.prototype.indexOf = function(value, offset){
        offset = parseInt(offset);
        for (var i = offset > 0 ? offset : 0, l = this.length; i < l; i++)
            if (this[i] === value)
                return i;
        return -1;
    };


8. Да, compareDocumentPosition не поддерживается в IE до 9 версии. Но там есть неплохая альтернатива с sourceIndex.
Вы использовали «магическую» константу, что затрудняет понимание кода, а это всего лишь DOCUMENT_POSITION_CONTAINS. Если используете compareDocumentPosition, то используйте и соответствующие константы (либо указывайте это в комментариях). Итого, вы проверяете находится ли узел внутри document.body или нет. Для этого есть более простое решение:
if (document.body.contains(node))
  alert('node находится внутри document.body');

Этот метод поддерживает даже IE6! А вот Firefox до недавнего времени его не имел, поэтому нужно сделать фикс для старых firefox
if (typeof Node.prototype.contains != 'function')
    Node.prototype.contains = function(node){
        return !!(this.compareDocumentPosition(node) & this.POSITION_CONTAINED_BY)
    }

Можете так же почитать статью John Resig по этой теме, там так же есть реализация кроссбраузерного comparePosition.

9. Что касается самого метода.
Во-первых, добавление у вас N^2/2. Когда узлов будет много вставка будет тормозить.
Во-вторых, при каждом обновлении словаря перетрясается DOM, дергается compareDocumentPosition и все обновляется. Причем не важно используется ли новое значение узлом или нет (не увидел проверок).
А потом вы проверяете сколько времени уже затратили:
  if((LANG_UPDATE_LAST%10)&&(new Date()-date>50))
     return;

Хотели проверять время каждый десятый раз? Так вот проверяется оно 9 раз из 10… а вызов new Date операция дорогая.
Если переписать lang_set можно значительно ускорить:
function lang_set(node, langKey, params){
  var propName = params[0];
  var newValue = langKey in LANG_HASH
    ? LANG_HASH[langKey].replace(/%(\d+)/g, function(a, b){return params[b]||""})
    : "#" + prop + (params.length > 1 ? "(" + params.slice(1) + ")" : "");
  if (node[propName] != newValue)
    node[propName] = newValue;
};

Самая медленная операция — это запись в DOM. Потом чтение из DOM. А вот javascript вычисления значительно дешевле. У вас тут в лучшем случае (коих предполагаю будет большинство) будет только чтение из DOM (node[propName]) и вычисление нового значения — без обязательной записи в DOM.

Вообще код еще пилить и пилить ;)
1-2. За совет спасибо.

3. Почитайте, что такое strict mode. Если мне вдруг придётся сделать рекурсивную функцию, то с помощью arguments.callee я не смогу обратиться к текущей анонимной функции. Во-вторых, при отладке я сразу же буду видеть по именам в стеке вызовов, где произошла ошибка. Это, кстати, для меня и есть главная причина писать имена. В-третьих, гляньте пример:
(function init() {
    var f = function f() {
            alert(f);
        },
        z = f;
    f = 1;
    alert(f);
    z();
})();
В таком случае внутри функции f переменная f не будет замыканием.

6-7. В заголовке написано — именно для IE8.

9. Признаю фейл с оператором %. И, да, я потерял проверку, когда переписывал эту функцию.

За пункты 5, 8 и 9 ставлю плюс.

Отдельная благодарность будет в статье.
3. Почитайте, что такое strict mode. Если мне вдруг придётся сделать рекурсивную функцию, то с помощью arguments.callee я не смогу обратиться к текущей анонимной функции.

Что-то я не увидел у в коде strict режима. Как в прочем не увидел у вас рекурсивных функций. И что мешает объявить функции, как функции, а не как выражение?
(function(){
  function factorial(n){
    if (n <= 1) return 1;
    return n * factorial(n - 1);
  }

  function factorial5(){
    return factorial(5);
  }

  ...
})()

Во-вторых, при отладке я сразу же буду видеть по именам в стеке вызовов, где произошла ошибка. Это, кстати, для меня и есть главная причина писать имена.

В большинстве случаев, вы и так увидите имена функций, современные браузеры неплохо разрешают имена.

Я бы сказал, что слишком сложно. Может, быть, я не прав.
Я считаю, что чем проще структура, API, тем больше вероятность для фреймворка стать популярным.
В своей реализации я задействовал всего 6 методов для полноценной работы с переводами, в т.ч. с подставляемыми параметрами.
В JSGettext я даже рабочего примера не нашёл, да и как сваять его — тоже. Да и цели, по-моему, несколько различаются.
Вот это всё, что могу сказать.
Sign up to leave a comment.

Articles