Kl10 tch – paver.js + t.js

53
JavaScript Укладка изображений в галереях и интернационализация приложений Денис Ольшин http://vk.com/denull

Transcript of Kl10 tch – paver.js + t.js

JavaScriptУкладка изображений в галереях

и интернационализация приложений

Денис Ольшинhttp://vk.com/denull

О чем пойдет речь

Задача: делаем Single page application.Или расширение для Хрома.Или приложение на PhoneGap.Или приложение для социальной сети.Или свою социальную сеть.Или вообще любой современный сайт.

О чем пойдет речь

Общие задачи решают фреймворки. Рассмотрим две частные (на самом деле не связанные, зато интересные) задачи:

1. Как вывести много картинок.2. Как выводить много текста.

Часть 1. Укладка изображений

(layout то есть, но раз уж вторая часть про локализацию…)

В этой части будет много картинок.

Цель?

● Выводим картинки или текст, HTML?● Много (лента), мало (альбом) или очень

мало (запись с аттачами)?● Можно сжимать и обрезать?● Можно менять местами?● Можно таскать, редактировать,

анимировать?

Тривиальный случай: квадратики!

Фиксируем соотношение сторон — соответственно, можем легко посчитать число строк и столбцов.

Используется: повсеместно.

Квадратики+Если на некоторых фотохочется сделать акцент —делаем их в 4 раза больше.

Требуется чтобы число столбцов было четным (бонус: укладка на одном CSS).

Используется: Facebook

А если не квадрат?Вариант А: сжимать+ всё на месте– дырки– всё мелкое

Вариант Б: обрезать+ аккуратные поля– потери– иногда потери критические (портреты?)

Сделаем поинтереснее

Пусть можно сжимать, но очень не хочется обрезать И оставлять пустые «дырки».

Bin Packing Problem: NP-полнота, нужен перебор всех комбинаций.

(Почти) идеальное решениеФиксированная высота строки, ничего не обрезано, везде равные поля.

Используется: поиск Google, Яндекс, iOS-приложение ВК (в альбомах).

Как эта магия работает?

Сколько бы картинок ни было в строке, их можно сделать равной высоты, а суммарную ширину — равной ширине строки.«Набиваем» их, пока высота > minRowHeight

...и когда эта магия не работает?

● В небольших альбомах висячая последняя строка портит вид.

● У широооких фоток (ландшафты, панорамы) преимущество перед высокими (портреты).

● Строки немного плавают по высоте.

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

Используется: ВК(в постах)

А если столбики, а не строки?Если порядок не особоважен, можно простозаполнять столбики.

Чит: ещё можно выбирать ширину столбиков как-нибудь по-хитрому.Используется: tumblr, Pinterest, Lightbox

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

Столбики+

Фиксируем числостолбцов (немного)и перебираем разныеварианты. Можно делать акценты.

Используется: 500px

Экзотика: золотое сечениеПользуемся тем, что из двух ландшафтов четко формируется один портрет (и наоборот).

– У портретов илиу ландшафтов перевес.– Квадратам места нет.– Висячий хвост в конце.

Как всё это применить?Например, Masonry:Или Packery.Или Isotope.Все упаковывают,никто не масштабирует: не для картинок.http://masonry.desandro.com/http://packery.metafizzy.co/

Как всё это применить?Или вот Freewall:плагин jQuery.

Поддерживает4 укладки, перетаскивание и анимации.http://vnjs.net/www/project/freewall/

(Почти) идеальное решение+Внутрь строк прячем стопки! Наполняем почти как строки — пока можем.

Теперь широкие фотки складываются в стопки, а не забивают всю строку.

+ Можно гибко настраивать размеры строк и стопок.+ Альтернативный режим: подгонять все фото под искомую площадь. Бонус: можно делать акценты (задать искомую площадь побольше).– Те же проблемы с последней строкой.– Строки по-прежнему могут плавать.

Где используется?

А нигде.Но есть в виде библиотеки!

Paver.JShttps://github.com/deNULL/Paver.js

ИспользованиеPaver(dataSource, width, opts).render(el);

dataSource – массив, у элементов поляwidth, height.

width – ширина контейнера.opts – настройки.el – контейнер, куда всё отрисовать.

Для рендеринга в opts передаем функцию:renderTile: function(tile, path) { … return html;},

path содержит тройку индексов row, stack и tile – номер строчки, стопки и картинки в стопке.

Использование

И о настройках

ДемкаТут можно подергать за рычажки:http://denull.github.io/Paver.JS/

Конец первой части.

Есть вопросы?

Следующая часть начнетсяпосле перерыва.

Часть 2. Об интернационализации

(и локализации тоже)

● язык = ru, en● локаль = ru_RU, en_US, en_GB● перевод = отображение ключей на строки● интернационализация = i18n = подготовка● локализация = l10n = процесс перевода

А нужны ли эти заморочки?

Нужны.● Задел на будущее.● Избавление от «Найдено 21 фотографий».● Возможность править тексты без правки

шаблонов.

Начнем с простогоВсе строки кладем в виде полей куда-нибудь в lang { … }, а потом достаем по lang[‘key’].

Сразу же хочется научиться делать подстановки (интерполировать) — пишем функцию:function T(key, substitute) { … }

А что там с числами?

Всё страшно.

В каждом языке своикатегории. До шестиштук. ШЕСТИ, КАРЛ.

http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html

Половой вопрос

Тут чуть проще: только два случая (если не придираться).

Придется спрашивать ещё одно поле при регистрации, зато никаких уродливых«Загрузил(а)».

Число, род… и падеж, конечно

Тут всё совсем плохо. Даже для одного языка фамилии склоняются по неоднозначно определенным правилам:Чаплин → Чаплином или Чаплиным?Повезло тем, у кого в языке падежей нет.

Решение: Petrovich.js

Работа с датами

Тут всё чуть иначе: формат зависит от локали, а не от языка.Но от языка зависят фразы типа «3 часа назад», которые хорошо бы тоже уметь выводить с умом.

Решение: moment.js, разумеется.

Работа с числами

Всё аналогично датам, только заморочек с выводом относительного времени нет.

Решение: Numeral.js или сами фреймворки

А как же .toLocaleString()?В ванильном JS есть:Date.prototype.toLocaleString()Number.prototype.toLocaleString()

Есть давно, но настроить можно только с Chrome 24, FF 29, IE 11, Opera 15, а в Safari до сих пор нельзя.

А неплохо бы ещё...

...вспомнить о типографских правилах.● кроме «-» есть, как минимум, «—» и «–»● кавычки бывают “тоже” «разные»● автозамены: (c) , (r) , (tm) , ...● и вообще много всего

Решения: Типограф, mdash.ru, грамотность.

Итого:

Для i18n + l10n:● l10n.js● LocalePlanet● L20n от Mozilla

● Moment.js – даты● Numeral.js – числа● Petrovich.js – имена● Типограф – правила

Ближе всего к тому, что надо: FormatJS.io и i18next.com (но все равно не идеально)

+

У всех свои форматы :(

i18next:{ en: { translation: { girlsAndBoys: '$t(girls, {"count": __girls__}) and __count__ boy', girlsAndBoys_plural: '$t(girls, {"count": __girls__}) and __count__ boys' }, girls: '__count__ girl', girls_plural: '__count__ girls' } } };

FormatJS:‘You have {itemCount, plural, =0 {no items} one {1 item} other {{itemCount} items}}.’

Это хотя бы стандарт Message ICUНо он совсем адовый

Хочется всего и сразу

Но без излишеств (встроенного во фреймворки не хватает, тащить кучу библиотек ради базовых вещей грустно). К тому же, вещи реально тесно связанные.

Склонять имена вообще все боятся.

Мое решение?

Да, ещё один велосипед. С блекджеком и своим форматом шаблонов.

T.jshttps://github.com/deNULL/T.js

Это почти как шаблонизатор, но нетphotos: 'фотографий',liked: 'оценил',user_liked: '{user} {>liked} {photos} {>photos}',

Делаем: T(‘user_liked’, {user: ’Олег’, photos: 5}) и получаем: ‘Олег оценил 5 фотографий’.

Подставили входные данные + другие ключи.

Структура языковых данныхT.define({ ru: { key1: ‘str1’, key2: ‘str2’, key3: { subkey: { subsubkey: ‘wow’ } },}})

Можно вызывать сколько угодно раз. Вложенность любая. Достаем через точку:T(‘key3.subkey.subsubkey’)

А что с числами?

Чтобы не было ‘Олег оценил 1 фотографий’:photos: { $plural: { one: ‘фотографию’, few: ‘фотографии’, other: ‘фотографий’}}

Категории зависят от языка, есть поддержка ru/en. Можно добавить свою функцию определения категории.

А если не Олег, а Анна?liked: { $gender: { m: ‘оценил’, f: ‘оценила’}}Аналогично, но надо передавать пол как параметр в подставляемый шаблон:user_liked: ‘… {>user.name user.gender} …’

T(‘user_liked’, { user: { name: ‘Анна’, gender: ‘f’});

А добавить «... Ильи» в конце?user_liked: ‘… {$name.gen whom.name}’

= вызов функции $name с первым параметром whom.name, вторым — ‘gen’ (родительный падеж).Есть внутренние функции $name, $surname, $patronym для русского, их можно доопределить или переопределить.

Что за «вызов функции»?

Функция = шаблон. Подставить шаблон = вызвать функцию. Если имя функции или шаблона начинается с $, то при подстановке > не нужен ({>$some} = {$some}).То, что после точек (func.p1.p2) интерпретируется как дополнительные параметры.

Бонус: трансформации

Пишем:user: ‘пользователь’

Получаем:T(‘user’) => ‘пользователь’T(‘User’) => ‘Пользователь’T(‘USER’) => ‘ПОЛЬЗОВАТЕЛЬ’

Непривычно, но может быть удобно.

И внезапно — инлайн-переводT.inlineTranslation(true);

TA-DA! Все строки кликабельны и открывают окошко с текстом перевода.Сохранение изменений (и проверка прав) на сервере — лежит на вас.T.showAllKeys();

Показать вообще все ключики списком.

Такая вот красота

Это всё без дополнительных зависимостей.Можно и вырезать, если юзер не переводчик.

К слову

T(‘user!’) — Локально отключить инлайн.Инлайн-перевод генерит HTML — в шаблонизаторы надо подставлять результат в сыром виде (Angular: $sce + ng-bind-html).

Во входных данных эскейпятся < и > – а в самих переводах нет, будьте внимательны.

Чего пока нет

● форматирование дат ({$date …})● форматирование чисел ({$num …})

Под некоторым сомнением: применение типографских правил.

Конец второй части.

Есть вопросы?

Денис Ольшинhttp://vk.com/denull