ermouth: (ang)
[personal profile] ermouth
Я впервые сделал локализованное (двуязычное) приложение со всем обвесом на платформе CloudWall + jQuery.my. Типа, майлстоун. Покажу черех месяцок вместе с проектом, который сейчас на приложении делается.

К проблеме я присматривался давно, и всё никак не находилось полностью подходящего решения. Я несколько раз попробовал поприкручивать сторонние, плюнул слюной и нагородил своё.

Причин появления велосипедика несколько.

1. «Статическая» локализация это нэ

jQuery.my app, в общем случае, это набор вложенных друг в друга приложений, каждое из которых «сидит» на своём поддереве данных, модифицируя его в зависимости от действий юзера или других событий. Как правило, верхние уровни приложения мало что знают о подробностях работы глубоких уровней, и наоборот. Они могут даже вообще не знать о существовании друг друга.

Более того, при доставке пользователю система может менять код приложения – например, обрезать или подменять ветви, ответственные за недоступный данному конкретному юзеру функционал. Так как приложения – JSON-документы, такие штуки делаются особенно легко и это супер-удобная вообще-то фича платформы.

Естественно, словари локализации должны по умолчанию отрезаться/подменяться вместе с самими компонентами.

2. Полная локализация во время инициализации – это нэ

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

3. Тридцать лет и три года

Ну и русский язык же. То-есть, мы можем записать для инглиша "User is {1} year old", например. А в русском, по-хорошему, нам нужно склонять. 15 лет, 21 год, 33 года, вот это всё. Строковым шаблончиком не отделаться никак.

То-есть, у нас должны быть где-то строки, где-то шаблоны (такие, например), а где-то – вовсе функции. Которым надо что-то передавать и не давать повалить/изуродовать приложение, если они поломались.

4. Компоновка

Вообще говоря, локаль должна иметь возможность влиять на компоновку и пропорции интерфейса. То-есть, кнопки «Сохр.» и «Закр.» вместо Save и Close – это хороший пример, когда CSS и локаль живут отдельными независимыми жизнями и между ними бетонная стена. Так быть не должно.

----

В результате, по итогам нескольких итераций в течение двух недель, у меня образовалась идиома из двух строчек кода и очень компактный формат для исходных строк/шаблонов/функций. То-есть, раз получилась идиома и формат более-менее приколотился, надо это всё вносить в платформу.

Это вторая фича, которая войдёт в jQuery.my 1.3 как новая. А первая – поддержка ARIA-кодов, да.

Date: 2016-06-09 09:27 am (UTC)
From: [identity profile] tonsky.livejournal.com
Расскажи, как со склонениями поступил?

Date: 2016-06-09 10:13 am (UTC)
From: [identity profile] ermouth.livejournal.com
Старый грязный хак.

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

В случае с примером, нам надо чтобы внутри приложения this.Lang.USER_AGE.assign(age) работал правильно вне зависимости от того, USER_AGE у нас строка шаблона или функция.

Это несложно сделать – надо просто обходить словарь при старте/переключении локали, и если какая-то ветка – функция, то:

а) переопределять у неё toString(), чтобы она при взятии в выражении без скобок вызывала себя со скобками
б) приделывать к ней метод assign , который будет вызывать её саму с переданными в assign параметрами.

Ну и ещё несколько похожих штришков.

Итого у тебя словарь выглядит так:

Lang:{
en:{ USER_AGE:"User is {1} year old" },
ru: { USER_AGE:function(age){ /* returns phrase */}}
}
Edited Date: 2016-06-09 10:15 am (UTC)

Date: 2016-06-09 11:36 am (UTC)
From: [identity profile] tonsky.livejournal.com
Ага, спасибо. Локализация это функция. Логично, в принципе

Date: 2016-06-10 01:21 am (UTC)
From: [identity profile] ermouth.livejournal.com
> Локализация это функция

Я есчо неверно первый раз пример в комменте написал.

Так что, скорее, «некоторые ветки словаря могут быть функциями, если их не реализовать просто шаблоном, но эти функции ведут себя в некотором смысле как строки».

Date: 2016-06-10 08:36 am (UTC)
From: [identity profile] tonsky.livejournal.com
Я понял, ага, и вот эти грязные js-ные хаки с приделыванием к ф-ии методов строки. Все в конечном счете сводится к тому, что общий знаменатель — функция, а значит словари i18n не могут быть статическими, должны задаваться в коде

Date: 2016-06-10 09:04 am (UTC)
From: [identity profile] ermouth.livejournal.com
> словари i18n не могут быть статическими

Не очень понимаю, что значит «статическими», но прокомментирую, как понял.

$.my-приложение в транспортном формате – это json, в котором некоторые ветки – строковые представления функций (или регэкспов).

"function (x) { return \"a\"+x;}" – типа такого.

Так как у нас функции без сайд-эффектов, это прекрасно работает.

С учётом того, что функции вызываются в контексте самого приложения – то-есть почти всегда видят js-дерево через this – функции и с сайд-эффектами могут быть, но эти сайд-эффекты распространяются только в контексте экземпляра приложения.

То-есть у нас нет какого-то специального куска кода, внутри которого эти функции надо описывать.

Так весь $.my работает, и именно поэтому любое приложение можно вложить в любое другое с практически нулевым усилием на монтаж. Даже в само себя можно вложить.

В случае с локализацией я просто к этим функциям без сайд-эффектов (которые поэтому не обязаны быть «динамическими») прикручиваю во время переключения всякие хаки, вот и всё.

Date: 2016-06-10 10:39 am (UTC)
From: [identity profile] tonsky.livejournal.com
Да это понятно, в языках, где есть eval и можно гарантировать некую изолированность функций (или следить, что они не приходят от third-party), все круто. В других языках, если словари хочется подгрузить из файла, там код уже не запихнешь.

Date: 2016-06-11 12:32 am (UTC)
From: [identity profile] ermouth.livejournal.com
> В других языках <...> там код уже не запихнешь

Ты же couchbase администрил, как же это «не запихнёшь»? Берёшь себе Spidermonkey – и запихиваешь. Или Lua вот есть.

Date: 2016-06-09 11:21 am (UTC)
From: [identity profile] archaicos.livejournal.com
У меня лет десять назад, если не больше, была мысля домашнюю страничку сделать многоязычной с помощью некоей тулзы (в идеале специального редактора), которая бы позволяла делать общий каркас и переключать содержимое, в частности во время добавления нового языка видеть уже существующий текст на другом, некий гибрид WYSIWYG и The Norton Commander. Сейчас если такого нет, то должно делаться очень легко (понятно, с поправкой на «компутерные мозги», когда контент генерируется, а не берётся готовый статический).

Profile

ermouth: (Default)
ermouth

November 2021

S M T W T F S
 123456
78910111213
14151617181920
21 222324252627
282930    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 2nd, 2026 09:19 am
Powered by Dreamwidth Studios