/webroot/js/i18n.js
[return to app]1
/**
2 * Phonetic-Typing System - multilingual forms allow users to easily type characters in other alphabets by
pressing the phonetically-equivalent English keys
3 * This file MUST be saved as a UTF-8 text file; saving in Latin or another character set will permanently destroy
the character maps.
4 * @author Eric David Benari
5 * @link http://www.Vork.us
6 */
7
8 /**
9 * Activates the i18n system
10 * @param str ids Optional, a string or an array of strings containing the id(s) of form inputs/textareas to
enable use of i18n - if omitted all textareas and text-inputs will be i18n activated
11 */
12 /* public */ var i18n = function(ids) {
13 i18n.initialized = true;
14 if (typeof ids != 'undefined') {
15 if (typeof ids != 'object') {
16 ids = [ids];
17 }
18 var thisid;
19 for (var i in ids) {
20 thisid = document.getElementById(ids[i]);
21 if (thisid) {
22 thisid.onkeypress = i18n.keyPressed;
23 }
24 }
25 } else {
26 var textareas = document.body.getElementsByTagName('textarea');
27 for (var i = 0; i < textareas.length; i++) {
28 textareas[i].onkeypress = i18n.keyPressed;
29 }
30 var inputs = document.body.getElementsByTagName('input');
31 for (var i = 0; i < inputs.length; i++) {
32 if (inputs[i].type == 'text') {
33 inputs[i].onkeypress = i18n.keyPressed;
34 }
35 }
36 }
37 if (typeof i18n.langs == 'undefined') {
38 i18n.setLanguages();
39 }
40 }
41
42 /**
43 * Name of the current language
44 * @var string
45 */
46 /* protected */ i18n.languageName = 'english';
47
48 /**
49 * Current language
50 * @var mixed English is a string, other languages are an object
51 */
52 /* protected */ i18n.language = 'english';
53
54 /**
55 * Language mappings
56 * @var object
57 */
58 /* protected */ i18n.languages = {
59 'russian': {'a':'а', 'b':'б', 'c':'Ñ', 'd':'д', 'e':'е', 'f':'Ñ', 'g':'г', 'h':'Ñ',
'i':'и', 'j':'ж',
60 'k':'к', 'l':'л', 'm':'м', 'n':'н', 'o':'о', 'p':'п', 'q':'Ñ', 'r':'Ñ', 's':'Ñ',
't':'Ñ', 'u':'Ñ', 'v':'в',
61 'w':'Ñ', 'x':'Ñ
', 'y':'Ñ', 'z':'з',
62 '[':'Ñ', ']':'Ñ', "'":'Ñ', '`':'Ñ', '=':'й', '-':'Ñ', '\\':'Ñ',
63 'A':'Ð', 'B':'Ð', 'C':'Ц', 'D':'Ð', 'E':'Ð', 'F':'Ф', 'G':'Ð', 'H':'Ч', 'I':'Ð',
'J':'Ð',
64 'K':'Ð', 'L':'Ð', 'M':'Ð', 'N':'Ð', 'O':'Ð', 'P':'Ð', 'Q':'Ð', 'R':'Ð ', 'S':'С',
'T':'Т',
65 'U':'У', 'V':'Ð', 'W':'Ю', 'X':'Ð¥', 'Y':'Я', 'Z':'Ð',
66 '{':'Ш', '}':'Щ', '"':'Ь', '~':'Ъ', '+':'Ð', '_':'Ы', '|':'Ð'},
67 'hebrew': {'a':'×', 'A':'×¢', 'b':'×', 'B':'×', 'c':'×', 'C':'×', 'd':'×', 'D':'×',
'e':'×', 'E':'×¢',
68 'f':'פ', 'F':'×£', 'g':'×', 'G':'×', 'h':'×', 'H':'×', 'i':'×', 'I':'×', 'j':'×',
'J':'×', 'k':'×§', 'K':'×§',
69 'l':'×', 'L':'×', 'm':'×', 'M':'×', 'n':'× ', 'N':'×', 'o':'×', 'O':'×', 'p':'פ',
'P':'×£', 'q':'×', 'Q':'×',
70 'r':'ר', 'R':'ר', 's':'ס', 'S':'ש', 't':'ת', 'T':'×', 'u':'×', 'U':'×', 'v':'×',
'V':'×', 'w':'×', 'W':'×',
71 'x':'צ', 'X':'×¥', 'y':'×', 'Y':'×', 'z':'×', 'Z':'×'},
72 'arabic': {'a':'ا', 'A':'ع', 'b':'ب', 'B':'ب', 'c':'Ù', 'C':'Ù', 'd':'د', 'D':'ض',
73 'e':'Ø¥', 'E':'Ø£', 'f':'Ù', 'F':'Ù', 'g':'غ', 'G':'غ', 'h':'Ø', 'H':'Ù', 'i':'Ù',
'I':'Ø¥',
74 'j':'ج', 'J':'ظ', 'k':'Ù', 'K':'Ù', 'l':'Ù', 'L':'Ù', 'm':'Ù
', 'M':'Ù
', 'n':'Ù',
'N':'Ù', 'o':'Ù', 'O':'ؤ',
75 'p':'Ù¾', 'P':'Ù¾', 'q':'Ù', 'Q':'Ù', 'r':'ر', 'R':'ر', 's':'س', 'S':'ص', 't':'ت',
'T':'Ø·', 'u':'Ù', 'U':'ؤ',
76 'v':'Ù', 'V':'ؤ', 'w':'Ù', 'W':'ؤ', 'x':'Ø®', 'X':'Ø®', 'y':'Ù', 'Y':'ئ', 'z':'ذ',
'Z':'ز',
77 '1':'Ù¡', '2':'Ù¢', '3':'Ù£', '4':'Ù¤', '5':'Ù¥', '6':'Ù¦', '7':'Ù§', '8':'Ù¨', '9':'Ù©',
'0':'Ù ',
78 "'":'Ø¡', '`':'Ø©', '[':'Ø«', '{':'Ú', ']':'Ø´', '}':'Ú'},
79 'greek': {'a':'α', 'A':'Î', 'b':'β', 'B':'Î', 'c':'Ï', 'C':'Ï', 'd':'δ', 'D':'Î',
80 'e':'ε', 'E':'Î', 'f':'Ï', 'F':'Φ', 'g':'θ', 'G':'Î', 'h':'Ï', 'H':'Χ', 'i':'ι',
'I':'Î', 'j':'θ', 'J':'Î',
81 'k':'κ', 'K':'Î', 'l':'λ', 'L':'Î', 'm':'μ', 'M':'Î', 'n':'ν', 'N':'Î', 'o':'ο',
'O':'Î', 'p':'Ï', 'P':'Î ',
82 'q':'Ï', 'Q':'Ψ', 'r':'Ï', 'R':'Ρ', 's':'Ï', 'S':'Σ', 't':'Ï', 'T':'Τ', 'u':'η',
'U':'Î', 'v':'Ï
', 'V':'Î¥',
83 'w':'Ï', 'W':'Ω', 'x':'ξ', 'X':'Î', 'y':'γ', 'Y':'Î', 'z':'ζ', 'Z':'Î'}
84 }
85
86 /**
87 * Converts keystrokes pressed to the selected language
88 * @param object evt
89 */
90 /* protected */ i18n.keyPressed = function(evt) {
91 if (typeof evt != 'undefined') {
92 var charCode = evt.which;
93 var chr = String.fromCharCode(charCode);
94 if (i18n.language == 'default' || typeof i18n.language[chr] == 'undefined') {
95 return true;
96 }
97 var loc = this.selectionStart;
98 if (loc == this.value.length) {
99 this.value += i18n.language[chr];
100 } else {
101 this.value = this.value.substring(0, loc) + i18n.language[chr] +
this.value.substring(this.selectionEnd, this.value.length);
102 loc++;
103 this.setSelectionRange(loc, loc);
104 }
105 evt.preventDefault();
106 } else { //IE
107 evt = window.event;
108 var charCode = evt.keyCode;
109 var chr = String.fromCharCode(charCode);
110 if (i18n.language == 'default' || typeof i18n.language[chr] == 'undefined') {
111 return true;
112 }
113 var bookmark = document.selection.createRange().getBookmark();
114 var selection = this.createTextRange();
115 selection.moveToBookmark(bookmark);
116 var before = this.createTextRange();
117 before.collapse(true);
118 before.setEndPoint("EndToStart", selection);
119 var loc = before.text.length;
120 if (loc == this.value.length) {
121 this.value += i18n.language[chr];
122 } else {
123 var end = (loc + selection.text.length);
124 this.value = this.value.substring(0, loc) + i18n.language[chr] + this.value.substring(end,
this.value.length);
125 loc++;
126 before.collapse(true)
127 before.moveStart('character', loc);
128 before.moveEnd('character', 0);
129 before.select();
130 }
131 return false;
132 }
133 }
134
135 /**
136 * Builds the keyboard display for the selected language
137 */
138 /* protected */ i18n.getKeyboardLayout = function() {
139 var specialUpper = {'`': '~', '-':'_', '=':'+', '[': '{', ']': '}', '\\':'|', ';':':', "'": '"'}
140 var qwerty = [
141 ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'],
142 ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'"],
143 ['z', 'x', 'c', 'v', 'b', 'n', 'm', ', ', '.', '/']
144 ];
145 var margin = 13;
146 if (typeof i18n.language['`'] != 'undefined') {
147 if (typeof i18n.language['1'] != 'undefined') {
148 qwerty.unshift(['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=']);
149 } else {
150 qwerty[0].unshift('`');
151 qwerty[0][qwerty[0].length] = '-';
152 qwerty[0][qwerty[0].length] = '=';
153 }
154 margin = 48;
155 }
156 var keyboard = '<div class="keyboardcontainer">';
157 for (var row in qwerty) {
158 keyboard += '<div class="keyboard keyboardrow' + row + '">';
159 for (var chr in qwerty[row]) {
160 if (typeof i18n.language[qwerty[row][chr]] != 'undefined') {
161 var upper = qwerty[row][chr].toUpperCase();
162 if (upper == qwerty[row][chr] && typeof specialUpper[upper] != 'undefined') {
163 upper = specialUpper[upper];
164 }
165 if (upper != qwerty[row][chr] && typeof i18n.language[upper] != 'undefined') {
166 keyboard += '<div class="key"><div>' + i18n.language[upper] + '<br />' +
i18n.language[qwerty[row][chr]] + '</div>' + upper + '<br />' + qwerty[row][chr] + '</div>';
167 } else {
168 keyboard += '<div class="key"><div><br />' + i18n.language[qwerty[row][chr]] + '</div><br />'
+ qwerty[row][chr] + '</div>';
169 }
170 }
171 }
172 keyboard += '</div>';
173 }
174 keyboard += '</div>';
175 if (typeof i18n.css == 'undefined') {
176 i18n.css = '.keyboardcontainer {margin-top: 5px;}\n '
177 + '.keyboard {clear: left;}\n '
178 + '.keyboardrow1 {margin-left: ' + margin + 'px;}\n '
179 + '.keyboardrow2 {margin-left: ' + (margin + 20) + 'px;}\n '
180 + '.keyboardrow3 {margin-left: ' + (margin + 40) + 'px;}\n '
181 + '.keyboard .key {float: left; width: 28px; height: 30px; border: 1px solid; margin: 2px; padding:
3px; font-weight: bold;}\n '
182 + '.keyboard .key div {float: right; font-weight: normal;}\n';
183 var css = document.createElement('style');
184 css.setAttribute('type', 'text/css');
185 if (typeof css.styleSheet == 'undefined') {
186 css.appendChild(document.createTextNode(i18n.css));
187 } else {
188 css.styleSheet.cssText = i18n.css;
189 }
190 document.getElementsByTagName('head')[0].appendChild(css);
191 }
192 return keyboard;
193 }
194
195 /**
196 * Internal array of existing keyboard displays
197 * @var array
198 */
199 /* protected */ i18n.keyboards = []
200
201 /**
202 * Toggles the display of a keyboard
203 * @param str id
204 */
205 /* public */ i18n.toggleKeyboard = function(id) {
206 var keyboard = document.getElementById(id);
207 if (!keyboard) {
208 return;
209 }
210 i18n.keyboards[i18n.keyboards.length] = id;
211 var link = document.getElementById('keyboardlink_' + id);
212 if (keyboard.innerHTML == '' && i18n.languageName != 'english') {
213 keyboard.innerHTML = i18n.getKeyboardLayout();
214 link.style.border='1px inset';
215 } else {
216 keyboard.innerHTML = '';
217 link.style.border='0px';
218 }
219 }
220
221 /**
222 * Changes the keyboard layout to the currently selected language
223 */
224 /* protected */ i18n.updateKeyboard = function() {
225 var keyboardLayout = i18n.getKeyboardLayout();
226 var keyboard;
227 for (var i in i18n.keyboards) {
228 keyboard = document.getElementById(i18n.keyboards[i]);
229 if (keyboard.innerHTML != '') {
230 keyboard.innerHTML = keyboardLayout;
231 }
232 }
233 }
234
235 /**
236 * Change the current language
237 * @param str lang
238 */
239 /* public */ i18n.setLanguage = function(lang) {
240 var prevButton; var currentButton;
241 for (var x = 1; x <= i18n.languageLinkCount; x++) {
242 prevButton = document.getElementById('languagelink_' + i18n.languageName + '_' + x);
243 currentButton = document.getElementById('languagelink_' + lang + '_' + x);
244 if (prevButton) {
245 prevButton.style.border='0px';
246 }
247 if (currentButton) {
248 currentButton.style.border='1px inset';
249 }
250 }
251 i18n.language = (typeof i18n.languages[lang] != 'undefined' ? i18n.languages[lang] : 'english');
252 i18n.languageName = lang
253 i18n.updateKeyboard();
254 }
255
256 /**
257 * Limits the array of languages available (default is all languages) and if to include the default language
(English.)
258 * FYI: Setting to just a single language and hiding English will restrict form entry to that language.
259 * @param mixed langs Can be a string or an array containing multiple strings
260 * @param Boolean hideEnglish
261 */
262 /* public */ i18n.setLanguages = function(langs, hideEnglish) {
263 if (typeof i18n.initialized == 'undefined') {
264 i18n();
265 }
266 i18n.hideEnglish = (typeof hideEnglish == 'undefined' ? false : hideEnglish);
267 if (typeof langs != 'undefined') {
268 i18n.langs = (typeof langs == 'object' ? langs : [langs]);
269 } else {
270 i18n.langs = [];
271 var x = 0;
272 for (var key in i18n.languages) {
273 i18n.langs[x++] = key;
274 }
275 }
276 if (i18n.hideEnglish) {
277 i18n.setLanguage(i18n.langs[0]);
278 }
279 }
280
281 /**
282 * Internal counter of language-link button-arrays that are displayed
283 * @var int
284 */
285 /* private */ i18n.languageLinkCount = 0;
286
287 /**
288 * Gets a link buttoms to change languages - buttons are returned in the order the languages are defined in
i18n.setLanguages()
289 * @return str
290 */
291 /* public */ i18n.getLanguageLinks = function() {
292 i18n.languageLinkCount++;
293 var selected = ' style="border: 1px inset;"';
294 var languageLinks = '';
295 if (!i18n.hideEnglish) {
296 languageLinks += '<a href="javascript: i18n.setLanguage(\'english\'); void(0);" title="English"
id="languagelink_english_' + i18n.languageLinkCount + '"';
297 if (i18n.languageName == 'english') {
298 languageLinks += selected;
299 }
300 languageLinks += '>EN</a>';
301 }
302 if (typeof i18n.langs != 'undefined' && (i18n.langs.length == 1 && languageLinks == '') || i18n.langs.length
== 0) { //no buttons if only one language
303 return '';
304 }
305 for (var i in i18n.langs) {
306 if (typeof i18n.languages[i18n.langs[i]] != 'undefined') {
307 languageLinks += ' ' + '<a href="javascript: i18n.setLanguage(\'' + i18n.langs[i] + '\'); void(0);"
title="Phonetic ' + i18n.langs[i].substring(0, 1).toUpperCase() + i18n.langs[i].substring(1) + '"
id="languagelink_' + i18n.langs[i] + '_' + i18n.languageLinkCount + '"';
308 if (i18n.languageName == i18n.langs[i]) {
309 languageLinks += selected;
310 }
311 languageLinks += '>' + i18n.langs[i].substring(0, 2).toUpperCase() + '</a>';
312 }
313 }
314 return languageLinks;
315 }
316
317 /**
318 * Gets a link to toggle keyboard display
319 * @param str id Determines which keyboard to open (created by i18n.getKeyboard)
320 * @param str label Optional, the word "keyboard" will be used if omitted
321 * @return str
322 */
323 /* protected */ i18n.getKeyboardLink = function(id, label) {
324 if (typeof label == 'undefined') {
325 label = 'keyboard';
326 }
327 return '<a href="javascript: i18n.toggleKeyboard(\'' + id + '\'); void(0);" id="keyboardlink_' + id + '">' +
label + '</a>';
328 }
329
330 /**
331 * Gets a keyboard link to display the language key-mapping
332 * @param str id Optional, keyboard will replace the contents of the element for the ID supplied; if id is omitted
then keyboard will display inline
333 * @param str label Optional, the word "keyboard" will be used if omitted
334 * @return str
335 */
336 /* public */ i18n.getKeyboard = function(id, label) {
337 if (typeof id == 'undefined') {
338 id = 'keyboard_' + Math.floor(Math.random() * 1000);
339 return i18n.getKeyboardLink(id, label) + '<div id="' + id + '"></div>';
340 } else {
341 return i18n.getKeyboardLink(id, label);
342 }
343 }