CodeNet / Языки программирования / Java Script / DOM
CodeNet / Языки программирования / Java Script / XML
Создание многоязычных веб-приложений с помощью JSTemplater 1.0Alfa
Исходные тексты (ZIP)
Доброго времени суток уважаемые читатели !
В этой статье я бы хотел поговорить о многоязычных приложениях, а именно создание оных в контексте технологии JavaScript и XHTML, без использования при этом произвольных серверных технологий.
Каждый из нас, кто когда-то непосредственно сталкивался с разработкой многоязычных приложений, знает всю их многогранность и в некоторых случаях неоднозначность создания. Так например, иногда клиенту необходимо отправить, предположим, опросник, в котором бы клиент указал, что именно он хочет, как он этого хочет, и что может за это отдать.
Вот тут и появляется вопрос: "А если клиент иностранец ?", то есть уже из этого вопроса, появляется ещё один вопрос: "Как же рациональнее всего реализовать многоязычность ?". Конечно, можно изначально перевести документ на несколько языков, после же отправлять заказчику один из них. Да, это безусловно допустимо, и наиболее используемо в контексте современных веб-студий и прочих компаний так или иначе ведущих диалог с заказчиками.
Я же выбрал иной подход, который считаю немного более гибкий и практичный, при чём ничем не уступающий "ручному" разбиению на языки. Суть его заключается в введении системы шаблонирования, и преобразовании языковых единиц в переменные шаблона, которые в последствии будут заменены в теже языковые единицы, однако относящиеся к другому языку. Пример схожего механизма можно наблюдать повсеместно в системах, так или иначе использующих шаблонирование в интерфейсе или в целом во внутренней реализации системы. Так ярким примеров систем-шаблонизаторов могут служить такие системы как PatTemplaters, Smarty и прочее. В них результирующие данные формируются на основании некоторых входящих данных (переменных шаблона) которые "подставляются" в шаблон, после чего выполняются в контексте заданного набора алгоритмической логики шаблона, и возвращаются ввиде обработанного текста.
В нашем случае всё аналогично, однако парсер JSTemplater 1.0Afla создан в расчете на функционирование на стороне клиента, и в качестве входящих данных принимает не текст шаблона, а весь текущий HTML-документ, начиная тегом <body>, и закачивая местом вызова метода для рендеринга служебных конструкций, которые были обнаружены в HTML-документе.
Но говорим мы сейчас не о предмете парсера JSTemplater 1.0Alfa, а о том как его использовать на практике. Но ведь для этого вам необходимо как минимум скачать его, для этого перейдите по следующему адресу: http://e-code.tnt43.com/sources/jsTemplater.zip (ZIP-packed archive).
Для подключения парсера к вашему документу просто подключите JS-скрипт, находящийся в архиве к вашему документу в разделе <HEAD>. Далее необходимо указать идентификатор тега <body>, и установить его значение в "body". Это необходимо для получения доступа к узлам элементов XHTML-документа.
Так же принципиальныс условием, для того, чтобы документ был корректно обработан, является вызов функции JSTemplater.init() именно перед закрывающим тегом </body>, что является необходимым для того, чтобы парсер получил все узлы документа, а не только те, которые успели подгрузится в настоящее время.
Что ж, вот скелет минимального приложения:
Листинг 1.1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <meta name="generator" content="PSPad editor, www.pspad.com"> <title></title> <script type='text/javascript' src='jsTemplater.js'></script> </head> <body id='body'> <script type='text/javascript'> <!-- JSTemplater.init(); --> </script> </body> </html>
Итак, чтобы больше не останавливаться на описании технологии шаблонизатора, я приведу список из функций, которые мы будет в дальнейшем использовать, а так же их семантики:
Функция | Пояснение |
---|---|
JSTemplater.init() | Функция после вызова которой происходит начало обработки. Необходимо вызывать перед закрывающим тегом </body> |
JSTemplater.registerLib(src, type) | Происходит подключение внешней библиотеки к текущему документу. Библиотека - файл src, формата type (text/javascript, text/css). Добавление происходит в раздел <head> |
JSTemplater.assignVariable(name,value) | Объявить переменную шаблона с именем name и значением value |
JSTemplater.makeArray(name) | Создать массив name |
JSTemplater.append2Array(name, value) | Добавить скалярное значение value к массиву name |
JSTemplater.append2ArrayIndex(arr, name,value) | Добавить элемент value, скалярного типа, к массиву name, находящегося в массиве arr (двумерный массив) |
JSTemplater.loadLibs() | Загрузка зарегистрированных (см. JSTemplater.registerLib) библиотек. |
Что ж, а теперь давай-те непосредственно о многоязычности. Для того чтобы раскрыть тему статьи, я предлагаю рассмотреть реальную ситуацию с некоторой формой, предназначеной для заказчиков, с двумя условиями: она доступена на 3-х языках, она должена быть ориэнтирована на обработку на стороне клиентского интерфейса.
Сейчас, мы создадим небольшой опросник, который будет содержать в себе: 5 информационных полей (название поля, поле ввода), 3 кнопок для переключения между языками(рус., англ., франц.).
Она будет простейшей:
Листинг 1.2
<div class='langs'> <button onclick='setLang("ru");'>Хочу на русском !</button> <button onclick='setLang("en");'>I'm want it in English !</button> <button onclick='setLang("fr");'>Je veux en francais!</button> </div> <form action='http://somehost.somedomain/formProceed' method='post'> Введите ваше имя: <input type='text' name='first'/><br/> Откуда вы узнали о нашей компании? <br/> <input type='text' name='wayf'><br/> Как вы оцениваете качество предоставляемых нами услуг ?<br/> <select name='quality'> <option value='0'>Отлично</option> <option value='1'>Хорошо</option> <option value='2'>Удовлетворительно</option> <option value='3'>Посредственно</option> <option value='4'>Плохо</option> </select><br/> <input type='submit' name='send' value='Отправить нам информацию'/> </form>
Как видите, в нашем случае у нас много текстовых данных, которые можно по их семантике разбить на отдельные строковые константы, а некоторые после аналогичного приведения распределяются относительно массива значений (пример тому значения списка "quality").
Каждому изменяемому текстовому значению документа будет соответствоватьпеременная, которая обычно или ставится в значении имени элемента управления напротив неё с прибавлением постфикса "_l", либо просто семантически близкое к данному название.
Так, у нас будут следующие константы:
- lang {en, fr, ru} //массив с надписями к кнопочкам изменения языка
- yname //текст напротив элемента yname
- wayf //аналогично
- quality {0,1,2,3,4} //массив значений оценки качества
Ещё нужно учесть, что некоторые константы имеют одинаковое значение(я) относительно языка, а другие объявляются относительно выбранного сейчас языка. В нашем случае, мы будем использовать для этих целей оператор switch(){default:break;} и набор операторов case, которые будут попросту объявлять константы в зависимости от выбранного языка.
А как мы будет определять какой выбран язык ? Через QUERY_STRING.
Вот функции setLang(val:String):Void: и getLang():String, которые будут использоваться для установки/получения текущего параметра языка.
Листинг 1.3
function setLang(value){ document.location.href='?lang='+value; } function getLang(){ if(document.location.search){ lang=document.location.search.split('='); lang=lang[1]; }else{ lang='ru'; } return lang; }
Теперь же мы можем непосредственно задать языковые схемы:
Листинг 1.4
function definitions(){ JSTemplater.assignVariable("lang",getLang()); JSTemplater.makeArray("quality"); JSTemplater.makeArray("lang"); JSTemplater.append2ArrayIndex("lang","ru","Хочу на русском !"); JSTemplater.append2ArrayIndex("lang","en","I'm want it in English !"); JSTemplater.append2ArrayIndex("lang","fr","Je veux en francais!"); switch(getLang()){ case 'ru': //Русская языковая схема JSTemplater.assignVariable("yname","Введите ваше имя"); JSTemplater.assignVariable("wayf","Откуда вы узнали о нашей компании ?"); JSTemplater.append2Array("quality","Хорошо"); JSTemplater.append2Array("quality","Отлично"); JSTemplater.append2Array("quality","Посредственно"); JSTemplater.append2Array("quality","Плохо"); break; case 'en': //Английская языковая схема JSTemplater.assignVariable("yname","Enter your name"); JSTemplater.assignVariable("wayf","Where do you found us?"); JSTemplater.append2Array("quality","Good"); JSTemplater.append2Array("quality","Very good"); JSTemplater.append2Array("quality","Average"); JSTemplater.append2Array("quality","Bad"); break; case 'fr': //Французская языковая схема break; } }
В данном листинге продемонстрировано задание текстовых констант, на значение которых будут изменятся служебные конструкции в исходном коде шаблона, после обращения к функции init().
Как видите всё предельно просто. И для большей наглядности мы сейчас перейдём к исходному коду шаблона, который будет обрабатыватся:
Листинг 1.5
//.... <body id='body'> Значение текущего идентификатора языковой схемы: <strong>{^lang^}</strong> <div class='langs'> <button onclick='setLang("ru");return false;'>{^lang{ru}^}</button> <button onclick='setLang("en");return false;'>{^lang{en}^}</button> <button onclick='setLang("fr");return false;'>{^lang{fr}^}</button> </div> <form action='http://somehost.somedomain/formProceed' method='post'> {^yname^}: <input type='text' name='first'/><br/> {^wayf^} <br/> <input type='text' name='wayf'><br/> {^lang{quality_label}^}<br/> <select name='quality'> <option value='0'>{^quality{0}^}</option> <option value='1'>{^quality{1}^}</option> <option value='2'>{^quality{2}^}</option> <option value='3'>{^quality{3}^}</option> </select><br/> <input type='submit' name='send' value='Отправить нам информацию'/> </form> //...
Вот и всё на этом. Наше приложение полностью функционально, и вполне корретно работает, при этом расширение не составляет особых проблем.
Ну, для тех, кому лень почитать спецификацию конструкций JSTemplator (http://e-code.tnt43.com/specs/t0.005.pdf) версии 1.0, приведу синтаксис основных конструкций:
Маска | Название |
(open_bracket)+(.*)(close_bracket)+ | Обращение к переменной |
(open_bracket)+((.*)\{([0-9]*)\})(close_bracket)+ | Обращение к числовому индексу массива |
(open_bracket)+((.*)\{(.*)\})(close_bracket)+ | Обращение к литеральному индексу массива |
При этом open_bracket и close_bracket по умолчанию "{^" и "^}", и могут быть изменены с помощью специальной функции библиотеки JSTemplater.
Всё, считаю тему на этом исчерпаной, если будут вопросы прошу отправлять их мне на почту: LoRd1990@gmail.com