/ Published in: JavaScript
Expand |
Embed | Plain Text
Copy this code and paste it in your HTML
Read from top to Bottom see for **** especially.... /* ignore the spelling mistakes */ Make an application multi lingual by using google API.... This process can even be implemented by an web service, but i have made use of google API Please follow the steps and make changes accordingly PHP(make use of div's and apply to the id's), ASP(Apply to all labesl)...and the rest of the languages follow up the same procedure accoringly...... *****************Add these 2 scripts tags into u r header and make it common for the pages so that it includes in each and everything*** <!--<script type="text/javascript" src="Translate/googlelanguage.js"></script> <script type="text/javascript" src="Translate/translate.js"></script>--> ****************Better to add these 2 into head section of u r html or asp or jsp pages******************************************** <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Untitled Document</title> </head> <body> ************Add this thing into the body section where ever u wish to or u wanna Place the option for selection******************* <!-- <div><font size="+1">Select Language</font></div> <div id="mlt_languagelist"> </div>--> -->Steps: 1) As the page is loaded the the 2nd div gets activated and gets processed through the api and data is fetched from the tranlate.js script....check in the line number 166 the function getLangs() gets called and executed.just go through the function and understand the parameters passed u will know better whats happening. 2) G to line number 85 there u will come to know how the langues get changed based upon u r request. 3) if(GL_curLang == "orig") { refresh(); return; } find th this block and add few more langues based upon ICANN standards for language notations in google.soon after the above block by dumping more conditions to the above block u can select the langues aby your choice Add: else if(GL_curLang == "es") { //spanish refresh(); return; } else if(GL_curLang == "ja") { //japanese refresh(); return; } 4) So add according to u r choice all this has to be followed aftr line number 888 for the 3 point. 6) And now get to start of the page translate.js and point towards line 52, there you gonna find a an array assigned toa variable with various elements within the array, present with other elements within it for the converion usuage. for all required labels in asp or the div or span's which u find the page, assign them which are to be changed upon request. 7) rename those elements name by u r own names which u want, use those div's which are present in all front end pages .for each and every text item or asp with label tags, assign these id's one for all those text items(i.e the div's of each and every text item)..and u r almost done 8)save all changes and start using this applicationits gonna work i am sure.....if there is anything lemme know.post it on the comments section i will reply back. 5)By this way the combo box is set with languages which you require to make the application multi lingual 6)this particual api support 64 recognised languages , check the info in google for this particual api. ********************************************************************************************************************************* </body> </html> *******************Save it as translate.js*************************** /* Multi-Language Translation Script: * * Automatically translates a webpage (containing text in more than one language) into any single language * requested by the user. Particularly useful for sites involving a lot of user-generated content (which * might have originally been written in different languages) - e.g. blogs, forums, or other community sites. * Harnesses the Google AJAX Language API to perform translation and language detection. * * Version: 0.2.5 [2010-01-22] * Author: Patrick Hathway, OdinLab, University of Reading. * For Documentation and Updates: See http://code.google.com/p/multi-language-translation/ * Licence: MIT License - see http://opensource.org/licenses/mit-license.php for full terms. Also check * the script Documentation for more information, and for details of one important consideration. * * Some minor configuration is required for this script to work on your website. Follow the instructions * below, or see the Documentation for full details and examples... */ /* 1. Specify the 'Base Language' for your website: */ var GL_baseLang = "en"; /* 2. Specify the IDs for all major regions (i.e. HTML elements) in your site that should have their * contents translated. Note that an ID can only be used to identify a single element on a page (for * elements which appear multiple times, use Class Names instead - see below). The script will translate * each element separately; any elements that cannot be found on a page will be ignored: */ var GL_classIds = [ ["navigation"], ["navigation", "", true], ["quick-id", "", true], ["c-quote", "", true], ["c-need-quote", "", true], ["c-index", "", true], ["c-about", "", true], ["c-exper", "", true], ["c-solution", "", true], ["c-product", "", true], ["c-contact", "", true], ["c-indian-add", "", true], ["c-work", "", true], ["c-contact", "", true], ["c-contactinf", "", true], ["c-usa-add", "", true], ["c-warning", "", true], ["right_sidebar", "fr", true], ["footer"] ]; /* 3. Specify the Class Names of all major regions (i.e. HTML elements) in your site that should have their * their contents translated. Multiple elements may appear on a page with the same class name; the script * will locate each occurrance (if present) and translate them separately: */ var GL_classNames = [ ["entry_baselang"], ["entry_french", "fr"], ["index-class", "", true], ["about-class", "", true], ["association-class", "", true], ["building-class", "", true], ["career-class", "", true], ["college-class", "", true], ["construction-class", "", true], ["contact-class", "", true], ["entry_baselang", "", true], ["education-class", "", true], ["entry", "", true], ["expertise-class", "", true], ["description", "", true], ["list-custom_website", "", true], ["list-beautiful_graphic", "", true], ["list-using_nature", "", true], ["list-css_xhtml", "", true], ["description", "", true], ["list-branding_your", "", true], ["list-green_branding", "", true], ["list-who_are", "", true], ["list-long_term", "", true], ["list-the_importance", "", true], ["list-flow", "", true], ["list-click_through", "", true], ["list-scale", "", true], ["description", "", true], ["list-google_rank", "", true], ["list-ppc", "", true], ["list-custom_icon", "", true], ["list-why_use", "", true], ["list-web_standard", "", true], ["list-promoting_your", "", true], ["list-business_cards", "", true], ["fashin-class", "", true], ["right", "", true], ["web_portfolio", "", true], ["interior-class", "", true], ["manufacture-class", "", true], ["news-class", "", true], ["medical-class", "", true], ["opening-class", "", true], ["ourclass-class", "", true], ["portfolio-class", "", true], ["ecommerce-class", "", true], ["mobile-class", "", true], ["webdesign-class", "", true], ["product-class", "", true], ["professional-class", "", true], ["real-class", "", true], ["realestate-class", "", true], ["request-class", "", true], ["form_entry", "", true], ["request-id", "", true], ["requestquote-class", "", true], ["consumer-class", "", true], ["software-class", "", true], ["solutions-class", "", true], ["list-why_use", "", true], ["list-west_coast", "", true], ["list-custom_icon", "", true], ["list-crisp_graphics", "", true], ["list-scalable_across", "", true], ["testimonials-class", "", true], ["testimonials", "", true], ["tourism-class", "", true], ["trade-class", "", true], ["transport-class", "", true], ["levonsys-class", "", true], ["working-levonsys-class", "", true], ["quick", "", true], ["entry_french", "", true], ["quotes", "de", true] ]; /* 4. Specify the default language for new visitors (leave blank to auto-detect using browser/system settings) */ var GL_curLang = ""; /* The rest of the Script should not be modified; unless you want to alter the functionality! * ------------------------------------------------------------------------------------------ */ // Global variables: var GL_srcContent; // array containing all content on the page to be translated, split up into chunks var GL_transContent = []; // array containing all chunks which have been translated var GL_chunksTotal = 0; // total number of chunks to translate var GL_curChunk; // ID of current chunk being translated var GL_errors; // array containing details of all errors that occur (if applicable) var GL_errSrcTxt; // array containing all source text that causes errors (if applicable) var GL_miniTransItems = []; // array containing element IDs/class names which contain minor items to translate google.load("language", "1"); // load v1 of google ajax language api // run when page loads function initialise() { addTransMsgs(); // append elements (which will display translation status messages) to page buildChunkedContent(); // create a local 'cache' of chunked content to be translated getLangCookie(); // find out the current site language (if known) getLangs(); // display listbox containing all languages the site can be translated into // if the original languages should be shown, end function. if(GL_curLang == "orig") { return; } // otherwise, start the translation startTranslation(); } // display listbox containing all languages the site can be translated into (so that one can be selected by user) function getLangs() { // create listbox within script so that it won't appear if JavaScript is disabled document.getElementById("mlt_languagelist").innerHTML = '<select id="mlt_language" onchange="changeLang()" style="width:150px; height:20px;"></select>'; // + '<div id="mlt_langattr"></div>' var langItems = document.getElementById("mlt_language").options; // add option to top of listbox allowing user to view the site in its original (i.e. un-translated) languages langItems.add(new Option("Original Languages", "orig", true)); // loop through list of currently available languages and add each to listbox for(var lang in google.language.Languages) { // find out the 2 character Google language code var langCode = google.language.Languages[lang]; // convert language string to title case var langString = lang.substr(0,1) + lang.substr(1).toLowerCase(); // improve formatting of 'chinese_simplified' and 'chinese_traditional' language strings langString = langString.split("_").join(" - "); // check that Google can translate content into the current language if ((google.language.isTranslatable(langCode)) && (langCode != "")) { // if so, add to listbox and translate, so native speakers of that language can find it if(langCode=="ar") { langItems.add(new Option(langString, langCode)); miniTranslate(langItems[(langItems.length-1)],langCode); } } } document.getElementById("mlt_language").value = GL_curLang; // change listbox to display current site language google.language.getBranding("mlt_langattr"); // display Google attribution below listbox (as required by TOS) } // start the translation function startTranslation() { // reset global variables GL_curChunk = 0; GL_errors = []; GL_errSrcTxt = []; // check if all content has already been translated into current language since page loaded. if(chkLangTrans()) { return; // if so, don't need to translate content again } // sanity check - can google actually translate into the current site language? if (!(google.language.isTranslatable(GL_curLang)) || (GL_curLang == "")) { return; // if not, end translation } // Otherwise, send content to google to be translated: // show the 'Translating...' block document.getElementById("mlt_translatemsg").innerHTML = 'Translating... <span id="mlt_perc">0%</span>'; miniTranslate(document.getElementById("mlt_translatemsg")); // translate block into site language document.getElementById("mlt_translatemsg").style.display='block'; // find out the ID of the destination language var curLangNo = document.getElementById("mlt_language").selectedIndex; var k = 0; // create sub-array to hold all translations for current language GL_transContent[GL_transContent.length] = new Array(3); GL_transContent[(GL_transContent.length-1)][0] = []; // this array will contain all translated chunks GL_transContent[(GL_transContent.length-1)][1] = GL_curLang; // store current language GL_transContent[(GL_transContent.length-1)][2] = false; // mark translation of language as incomplete // loop through all the chunks to be translated, send to google... for(var i = 0; i < GL_srcContent.length; i++) { // find out the source language for the current element to be translated var srcLang = GL_srcContent[i][GL_srcContent[i].length - 1]; for(var j = 0; j < (GL_srcContent[i].length - 1); j++) { /* AJAX is used to return translated chunks, so they MAY be returned in any order. To solve, include current chunk id, destination language + separators at start of each string. This is a bit of a 'hack', so try to find a better solution! */ var srcText = curLangNo + "<br />" + k + "<br />" + GL_srcContent[i][j]; // send current chunk to google translate; when translated, call function translateChunk google.language.translate(srcText, srcLang, GL_curLang, translateChunk); k++; } } setTimeout("checkTransStatus()", 1000); // run function to check translation status after 1 second } // check if page content has already been translated into current language since page loaded. function chkLangTrans() { // loop through the list of languages the page has been translated into for(var i = 0; i < GL_transContent.length; i++) { // check if a translation for current language exists, and if so, whether it is complete. if((GL_transContent[i][1] == GL_curLang) && (GL_transContent[i][2] == true)){ /* if so, don't need to send content to google again, just assemble the pre-translated content. This will *dramatically* reduce the translation time for this language! */ endTranslation(i); return true; } } return false; // otherwise, all relevant page content must be submitted to google for translation. } // This runs after each chunk has been translated... function translateChunk(result) { // handle translation errors gracefully by storing error details but allowing translation to continue if (result.error) { GL_errors[GL_errors.length] = result.error.message; } else { /* Translated chunks may be returned in any order, so we need a method to assemble the chunks in the correct order: * Start of each chunk has a destination language id and a chunk id followed by separators. * Separator is a <br /> HTML tag, as these always appear to retain position after translation... * The destination language id is used to ensure the translated text is now in the correct language. * Each chunk is stored in the position of the 'GL_transContent' array corresponding to the current chunk id. * The ids + separators should not be shown, and are discarded from the chunk when it's stored in array. */ // split into array based on separator, so we know the id & destination language of translated chunk var transChunk = result.translation.split("<br />"); // [find out length of substring to chop off from start of chunk] var chunkSubStr = 12 + transChunk[0].length + transChunk[1].length; // remove whitespace from chunk id & destination language (a problem with some translations) transChunk[0] = transChunk[0].replace(/^\s+|\s+$/g,""); transChunk[1] = transChunk[1].replace(/^\s+|\s+$/g,""); /* If the translated chunk has a different destination language to the current site language, discard translation & end function. This may happen if user changes language whilst translation is in progress */ if(transChunk[0] != document.getElementById("mlt_language").selectedIndex) { return; } // store translated chunk in current language array, along with detected source language (if known) GL_transContent[(GL_transContent.length-1)][0][transChunk[1]] = new Array(3); GL_transContent[(GL_transContent.length-1)][0][transChunk[1]][0] = result.translation.substr(chunkSubStr); GL_transContent[(GL_transContent.length-1)][0][transChunk[1]][1] = result.detectedSourceLanguage; } GL_curChunk++; // increment current chunk ID every time function is called // calculate and display percentage of translation completed, based on number of chunks remaining var perc = (GL_curChunk / GL_chunksTotal)*100; document.getElementById("mlt_perc").innerHTML = Math.round(perc) + "%"; // when all chunks have been translated, run the 'endTranslation' function... if(GL_curChunk >= GL_chunksTotal) { endTranslation((GL_transContent.length-1)); // [final array element holds current language content!] } } /* runs once a second whilst translation is in progress, updating contents of all elements that have already been completely translated. Also shows 'timeout' messages if translation not completed within 30 seconds... */ function checkTransStatus() { // 'static' member variables to keep track of how many times function has run, as well as current language: if((typeof checkTransStatus.chkStatusCount == 'undefined') || (checkTransStatus.curTransLang != GL_curLang)) { // reset variables if not defined yet, or if site language has changed since last function call checkTransStatus.chkStatusCount = 0; checkTransStatus.curTransLang = GL_curLang; } // if translation is now complete, end function. if(GL_curChunk >= GL_chunksTotal) { return; } checkTransStatus.chkStatusCount++; // increment Translation Status counter // Store the list of languages in case they are replaced during translation var langList = document.getElementById("mlt_languagelist").innerHTML; var curElement; var curTransChunk = 0; var curClass = 0; var curTransLang = GL_transContent.length-1; // loop through all element IDs (as specified at script top), searching for ones with completed translations for(var i = 0; i < GL_classIds.length; i++) { curElement = document.getElementById(GL_classIds[i][0]); // find out current element // if current element ID exists on the page, replace contents with translated chunks if(curElement != null) { // assemble and display translated chunks for current element curTransChunk = unpackTransChunks(curTransLang,curTransChunk,curClass,curElement,false); curClass++; // move to next element ID } } // Get all elements on the page, so that ones with the specified class names can be located var allElements = document.getElementsByTagName("*"); // loop through all element class names (as specified at script top), searching for completed translations for(var i = 0; i < GL_classNames.length; i++) { // loop through all elements, so that any with the current class name can be identified for(var j = 0; j < allElements.length; j++) { if(allElements[j].className == GL_classNames[i][0]) { // assemble and display translated chunks for current element curTransChunk = unpackTransChunks(curTransLang,curTransChunk,curClass,allElements[j],false); curClass++; // move to next element Class Name } } } // if listbox containing all languages has been removed as a result of translation, display it again if(document.getElementById("mlt_languagelist").innerHTML == "") { document.getElementById("mlt_languagelist").innerHTML = langList; document.getElementById("mlt_language").value = GL_curLang; // change listbox to show current language } /* if translation still isn't complete after 30 seconds, update translation message. Note: there is no need to halt the current translation completely, but we will allow user to restart it if desired! */ if(checkTransStatus.chkStatusCount == 30) { // calculate and display percentage of translation completed, based on number of chunks remaining var perc = Math.round((GL_curChunk / GL_chunksTotal)*100) + "%"; // update translation status message document.getElementById("mlt_translatemsg").innerHTML = 'Translating (Slowly!)... ' + '<span id="mlt_perc">' + perc + '</span> - <a href="javascript:refresh()">Retry</a>'; miniTranslate(document.getElementById("mlt_translatemsg")); // translate block into site language } setTimeout("checkTransStatus()", 1000); // check translation status again after another second } // runs after all translations have been completed; displaying the results on screen in place of previous content function endTranslation(curTransLang) { var curElement; var curTransChunk = 0; var curClass = 0; // loop through all element IDs (as specified at script top), replacing current contents with translations for(var i = 0; i < GL_classIds.length; i++) { curElement = document.getElementById(GL_classIds[i][0]); // find out current element // if current element ID exists on the page, replace contents with translated chunks if(curElement != null) { // assemble and display translated chunks for current element curTransChunk = unpackTransChunks(curTransLang,curTransChunk,curClass,curElement,true,GL_classIds[i]); curClass++; // move to next element ID } } // Get all elements on the page, so that ones with the specified class names can be located var allElements = document.getElementsByTagName("*"); // loop through all element class names (as specified at script top), so contents can be replaced by translations for(var i = 0; i < GL_classNames.length; i++) { // loop through all elements, so that any with the current class name can be identified for(var j = 0; j < allElements.length; j++) { if(allElements[j].className == GL_classNames[i][0]) { // assemble and display translated chunks for current element curTransChunk = unpackTransChunks(curTransLang,curTransChunk,curClass,allElements[j],true,GL_classNames[i]); curClass++; // move to next element Class Name } } } // Perform translations of all content added by the script (e.g. language strings and error messages) transAddedText(); // Re-create listbox containing all languages, in case it has been removed as a result of translation getLangs(); // translate the 'Original Languages' listbox item to equivalent in current site language miniTranslate(document.getElementById("mlt_language").options[0],GL_curLang,"Original Languages"); // if any errors occured during translation, display warning message at top of screen and end function if(GL_errors.length != 0) { document.getElementById("mlt_translatemsg").innerHTML = GL_errors.length + ' Problems(s) Occurred During Translation: ' + '<a href="javascript:refresh()">Retry</a> - <a href="javascript:showErrDetails()">Details</a> - ' + '<a href="javascript:hideTransMsg()">Hide</a>'; miniTranslate(document.getElementById("mlt_translatemsg")); // translate warning message into current site language return; } // mark translation of page into current language as complete, so that translation can be quicker next time. GL_transContent[curTransLang][2] = true; hideTransMsg(); // otherwise, hide 'Translating...' message } // assemble and display translated chunks for current element on page function unpackTransChunks(curTransLang,curTransChunk,curClassNum,curElement,transComplete,curClass) { // 'static' member variable to keep track of how many times function has run if(typeof unpackTransChunks.curLinkId == 'undefined') { // reset curLinkId variable if not defined yet - it's used to identify the correct 'show source text' link unpackTransChunks.curLinkId = 0; } unpackTransChunks.curLinkId++; var j = unpackTransChunks.curLinkId; // increment current link id, j is an alias var curContent = ""; // reset translated contents of current element var initTransChunk = curTransChunk; // store initial chunk id of current element // loop through all translated chunks, assembling all translated content for current element for(var i = 0; i < (GL_srcContent[curClassNum].length - 1); i++) { // if current chunk does not exist, translation is not complete or errors occurred if((GL_transContent[curTransLang][0][curTransChunk] == null) && (transComplete == false)) { break; // stop looping through chunks if full translation has not yet been completed } else if((GL_transContent[curTransLang][0][curTransChunk] == null) && (transComplete == true)) { // if full translation IS complete, show warning message and a link to show source text (in red) curContent += '<div style="color: red;" id="mlt_srctxt' + j + '">[<span class="mlt_transerrtxt">' + '<em style="text-transform: uppercase;">THIS SECTION COULD NOT BE TRANSLATED</em> - '+ '<a id="mlt_srctxtlnk' + j + '" href="javascript:showSrcTxt(' + j + ',' + curClassNum + ',' + (i+1) + ')">View Source Text [+]</a></span><span id="mlt_srctxtbracket' + j + '">]</span></div>'; GL_errSrcTxt[GL_errSrcTxt.length] = GL_srcContent[curClassNum][i]; // store affected source text unpackTransChunks.curLinkId++; j = unpackTransChunks.curLinkId; // increment current link id } else { // otherwise append current translated chunk to translated content string curContent += GL_transContent[curTransLang][0][curTransChunk][0]; } curTransChunk++; // move to next chunk } // if translation is complete, replace contents of current element with translated text if(transComplete == true) { curElement.innerHTML = curContent; // append a language string to bottom of current element if desired getLangString(curTransLang,curElement,curClass,initTransChunk,(GL_srcContent[curClassNum].length - 1),j,curClassNum); // otherwise, check if all translated chunks for current element were assembled } else if((i == (GL_srcContent[curClassNum].length - 1)) && (GL_transContent[curTransLang][0][initTransChunk][2] != true)) { // if so (and current element translation is not yet marked as complete), replace contents with translation curElement.innerHTML = curContent; GL_transContent[curTransLang][0][initTransChunk][2] = true; // mark current element translation as complete } return curTransChunk; // return current chunk id to calling function } // If required, find and append a string containing the Source Language to the bottom of the specified element function getLangString(curTransLang,curElement,curClass,curTransChunk,transChunksLen,j,curClassNum) { var detectedLang = ""; // if the current element does not need a language string appended, end function if(curClass[2] != true) { return; } // if source language for current element has already been manually specified, set this as detected language if(curClass[1] != "") { detectedLang = curClass[1]; } // otherwise find out language based on the detected source languages for translated chunks in current element else { detectedLang = findDetectedLang(curTransLang,curTransChunk,transChunksLen); } // if detected language is same as site language, there is no need to display language string, so end function if(detectedLang == GL_curLang){ return; } var srcLangString = getFmtLangStr(detectedLang); // retrieve name of detected language as a formatted string // append language string to current element... // curElement.innerHTML += '<div style="color: green;" id="mlt_srctxt' + j + '"></div>'; } // convert a google language code into a formatted string containing the language name function getFmtLangStr(lang) { // loop through list of supported languages and retrieve names for(var l in google.language.Languages) { if(google.language.Languages[l] == lang) { // convert language string into title case var lang = l.substr(0,1) + l.substr(1).toLowerCase(); // improve formatting of 'chinese_simplified' and 'chinese_traditional' language strings lang = lang.split("_").join(" - "); break; // stop loop (don't need to continue searching for languages) } } // if language cannot be found in list of supported languages, set language to 'unknown' if(typeof lang == "undefined") { lang = "An Unknown Language"; } return lang; // return formatted language string } // find out the most common detected language for all translated chunks in current element, to appear in language string function findDetectedLang(curTransLang,curTransChunk,transChunksLen) { var chunkLangs = []; langCounter = 0; // loop through all translated chunks in current element for(var i = 0; i < transChunksLen; i++) { // bugfix: set detected language to 'undefined' if an error occurred during translation... if(GL_transContent[curTransLang][0][curTransChunk] == null) { GL_transContent[curTransLang][0][curTransChunk] = new Array(3); GL_transContent[curTransLang][0][curTransChunk][1] = "undefined"; } // loop through array of detected languages to see if current chunk has an existing detected language for(var j = 0; j < chunkLangs.length; j++) { if(chunkLangs[j][0] == GL_transContent[curTransLang][0][curTransChunk][1]) { // if so, increment counter containing the total number of chunks with that language chunkLangs[j][1]++; break; // halt loop } } // if current chunk has a language not yet detected, add it to end of detected languages array if(j == chunkLangs.length) { chunkLangs[j] = new Array(2); chunkLangs[j][0] = GL_transContent[curTransLang][0][curTransChunk][1]; // name of detected language chunkLangs[j][1] = 1; // total number of chunks with that language } curTransChunk++; // move to next chunk } /* once array has been created containing all detected languages in current element, loop through it to find the most common detected language - language string should contain this */ for(i = 0; i < chunkLangs.length; i++) { if(chunkLangs[i][1] > langCounter) { /* if current language was detected more times than all previous languages, store language and number of times detected - so that next language can be compared against this total */ var detectedLang = chunkLangs[i][0]; langCounter = chunkLangs[i][1]; } } return detectedLang; // return the most common detected language } // Auto-translate all text added previously by the script (including language strings and error messages) function transAddedText() { var allElements = document.getElementsByTagName("*"); // get all elements on page, so relevant ones can be translated var foundElements = []; // loop through all elements to find any of class 'mlt_langstring' or 'mlt_transerrtxt' for(var i=0; i<allElements.length; i++) { if((allElements[i].className == "mlt_langstring") || (allElements[i].className == "mlt_transerrtxt")) { foundElements[foundElements.length] = allElements[i]; } } // translate all located elements (runs separately from above code to prevent infinite loop as items are translated) for(i = 0; i < foundElements.length; i++) { miniTranslate(foundElements[i]); // translate current element } } /* this function runs before any translation takes place, and creates a local 'cache' of all content to be translated (in chunks) - meaning the content can be submitted to Google more rapidly, and the resulting translations can then be sorted reliably */ function buildChunkedContent() { var curElement; GL_srcContent = []; var j = 0; /* loop through all applicable element IDs (as specified at script top), converting the contents of each into chunks, and storing each chunk in an array */ for(var i = 0; i < GL_classIds.length; i++) { curElement = document.getElementById(GL_classIds[i][0]); // find out current element // check that element actually exists on the page - if not, ignore it if(curElement != null) { GL_srcContent[j] = createChunks(curElement); // separate the content of current element into chunks GL_chunksTotal += GL_srcContent[j].length; // store a running total of the number of chunks created // if a Source Language is not specified for current element, store Base Language in array instead if(GL_classIds[i].length == 1) { GL_srcContent[j][GL_srcContent[j].length] = GL_baseLang; } else { // otherwise store the specified language (or a blank string if this is to be auto-detected) GL_srcContent[j][GL_srcContent[j].length] = GL_classIds[i][1]; } j++; } } // get all elements on page, so that the ones specified can be located var allElements = document.getElementsByTagName("*"); // loop through all applicable element IDs (as specified at script top), converting into chunks and storing in array for(var i = 0; i < GL_classNames.length; i++) { // find all elements which have the current class name for(var k = 0; k < allElements.length; k++) { if(allElements[k].className == GL_classNames[i][0]) { // separate the content of current element into chunks GL_srcContent[j] = createChunks(allElements[k]); // store a running total of the number of chunks created GL_chunksTotal += GL_srcContent[j].length; // if a Source Language is not specified for current element, store Base Language in array if(GL_classNames[i].length == 1) { GL_srcContent[j][GL_srcContent[j].length] = GL_baseLang; } else { // otherwise store specified language (or a blank string if auto-detected) GL_srcContent[j][GL_srcContent[j].length] = GL_classNames[i][1]; } j++; } } } } /* Web browsers (and Google) limit the amount of text translated per request, so split contents of current element into chunks. The aim is to achieve this whilst maintaining the translation integrity */ function createChunks(srcContent) { var chars = 1000; // number of characters to allow per chunk. /* We do NOT want the content inside any HTML tag to be split between chunks (as this could cause rendering problems), so create 2 arrays storing tags and textual content of current div separately */ var tags = srcContent.innerHTML.match(/<.*?>/g); var text = srcContent.innerHTML.split(/<.*?>/g); if(tags == null) { tags = new Array();} // handle content containing no tags var curchar = 0; var tagnum = 0; var textnum = 0; var contTotal = tags.length + text.length; // create an array containing content to be chunked, with tags + text separately re-assembled (in order) var content = new Array(contTotal); // loop through content of current div for(var i=0; i < contTotal; i++) { // if current position in content is the start of a tag char, add appropriate tag to content array if(srcContent.innerHTML.substr(curchar,1) == "<") { content[i] = tags[tagnum]; curchar += tags[tagnum].length; tagnum++; // if it is a text string, add the corresponding text to the curent element in content array } else { content[i] = text[textnum]; curchar += text[textnum].length; textnum++; } } // Create the chunks - don't split either tags or words (to ensure as high translation quality as possible) var chunks = []; var curChunk = 0; chunks[0]=""; for (i = 0; i < contTotal; i++) { // if next content item (tag or textual) won't exceed length of current chunk, add it to chunk if((chunks[curChunk].length + content[i].length) < chars) { chunks[curChunk] += content[i]; } else { // otherwise, proceed to next chunk. curChunk++; // add the entire content item to this chunk if possible (to ensure better translation) if(content[i].length < chars) { chunks[curChunk] = content[i]; } else { // only split further in rare cases where text length exceeds maximum chunk size var curPos = 0; do { // retrieve the maximum amount of text that can fit in this chunk var subContent = content[i].substr(curPos,chars); // find out how many words are in this substring var words = subContent.split(" "); // chop off final word, so words aren't split up between chunks var lastWordPos = subContent.length - words[(words.length-1)].length; if(subContent.length < chars) { // [bugfix: prevent word cut-off on final iteration] lastWordPos = subContent.length} chunks[curChunk] = subContent.substr(0,lastWordPos); // store in chunk curChunk++; // remainder of text will go in next chunk curPos+=lastWordPos; // store current position in text, for further processing } while(subContent.length >= chars); // repeat until all this text has been chunked curChunk--; // because there may still be space in the current chunk! } } } return chunks; // return chunked content to calling function... } // Append elements to page (will be used to display translation messages), and specify their css styles. function addTransMsgs() { // add element to page which will contain translation messages var transCont = document.createElement("div"); document.body.appendChild(transCont); // add element to container created above - this will display the translation messages var translateMsg = document.createElement("div"); translateMsg.id = "mlt_translatemsg"; transCont.appendChild(translateMsg); // define visual styles for translation messages displayed on screen translateMsg.style.backgroundColor = "silver"; translateMsg.style.border = "3px green solid"; translateMsg.style.padding = "5px"; translateMsg.style.fontSize = "large"; translateMsg.style.fontWeight = "bold"; translateMsg.style.textAlign = "left"; translateMsg.style.color = "black"; // more translation message styles (these should not need editing!) translateMsg.style.left = "-50%"; translateMsg.style.position = "relative"; translateMsg.style.display = "none"; // define the styles for the container element transCont.style.left = "50%"; transCont.style.zIndex = "1000"; if(!(/MSIE 6/i.test(navigator.userAgent))) { // styles for all browsers except IE6 transCont.style.position = "fixed"; transCont.style.top = "0px"; } else { // styles for IE6 transCont.style.position = "absolute"; transCont.style.setExpression("top", "(i = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + 'px'"); } } // Hide 'Translating...' message (or translation error message) - runs at end of translation, or if user dismisses error message function hideTransMsg() { document.getElementById("mlt_translatemsg").innerHTML = ""; document.getElementById("mlt_translatemsg").style.display='none'; } // if the user clicks on the 'Details' link [after error(s) occurred], show details of all errors on screen function showErrDetails() { // continue to show original error message (but remove 'Details' link) document.getElementById("mlt_translatemsg").innerHTML = '<span id="mlt_transerrmsg1">' + GL_errors.length + ' Problems(s) Occurred During Translation: ' + '<a href="javascript:refresh()">Retry</a> - ' + '<a href="javascript:hideTransMsg()">Hide</a>... <br /><em>Error(s) Reported:</em></span>' + '<ul style="margin: 0px; padding: 0px;" id="mlt_transerrlist"></ul>'; // Loop through array containing details of all errors, and show them as a list on screen for(var i = 0; i < GL_errors.length; i++) { document.getElementById("mlt_transerrlist").innerHTML += '<li style="margin-left: 15px;">' + GL_errors[i] + '.</li> '; } /* create a textarea - this will show the original source text of all affected sections (as HTML) to aid debugging Note: because translations are returned using AJAX, the affected sections are not NECESSARILY in the same order as the errors reported (though in many cases, they will be!) */ document.getElementById("mlt_translatemsg").innerHTML += '<em id="mlt_transerrmsg2">Section(s) Affected:</em><br />' + '<textarea id="mlt_errsrctxt" rows="8" readonly="readonly" style="width: 99%; background-color: silver; border: 1px gray solid;">' + '</textarea>'; // Loop through Source Text array, appending to textarea. for(var i = 0; i < GL_errSrcTxt.length; i++) { document.getElementById("mlt_errsrctxt").value += "Affected Section " + (i+1) + ":\n" + GL_errSrcTxt[i] + "\n\n"; } // Translate the entire contents of the Translation Errors box (with the exception of the text inside the textarea) miniTranslate(document.getElementById("mlt_transerrmsg1")); miniTranslate(document.getElementById("mlt_transerrlist")); miniTranslate(document.getElementById("mlt_transerrmsg2")); } // function runs when the user clicks on a link to view the original source text for a translated element / chunk function showSrcTxt(curLinkId,curClassNum,curChunkId) { // if the current chunk should be shown only, display chunk on screen if((curChunkId-1) != -1) { document.getElementById("mlt_srctxt"+curLinkId).innerHTML += '<div id="mlt_srctxtcontent' + curLinkId + '">'+GL_srcContent[curClassNum][(curChunkId-1)]+']</div>'; } else { // otherwise assemble all chunks for current element, and display on screen var srcTxt = ""; for(var i = 0; i < (GL_srcContent[curClassNum].length - 1); i++) { srcTxt += GL_srcContent[curClassNum][i]; } document.getElementById("mlt_srctxt"+curLinkId).innerHTML += '<div id="mlt_srctxtcontent' + curLinkId + '">'+srcTxt+']</div>'; } // update Source Text link so that when clicked in future, the source text will be hidden instead... srcTxtLnk = document.getElementById("mlt_srctxtlnk"+curLinkId); srcTxtLnk.innerHTML = "Hide Source Text [-]"; srcTxtLnk.href = 'javascript:hideSrcTxt(' + curLinkId + ',' + curClassNum + ',' + curChunkId + ')'; miniTranslate(srcTxtLnk); // translate link text document.getElementById("mlt_srctxtbracket"+curLinkId).innerHTML = ""; // hide bracket after link } // function runs when the user clicks on a link to hide the original source text for a translated element / chunk function hideSrcTxt(curLinkId,curClassNum,curChunkId) { // remove the element containing the original source text srcTxtContent = document.getElementById("mlt_srctxtcontent"+curLinkId); document.getElementById("mlt_srctxt"+curLinkId).removeChild(srcTxtContent); // update Source Text link so that when clicked in future, the source text will be shown instead... srcTxtLnk = document.getElementById("mlt_srctxtlnk"+curLinkId); srcTxtLnk.innerHTML = "View Source Text [+]"; srcTxtLnk.href = 'javascript:showSrcTxt(' + curLinkId + ',' + curClassNum + ',' + curChunkId + ')'; miniTranslate(srcTxtLnk); // translate link text document.getElementById("mlt_srctxtbracket"+curLinkId).innerHTML = "]"; // show bracket after link } // translate small non crucial items of text into current site language function miniTranslate(item,destLang,srcTxt) { if(typeof destLang == "undefined") { var destLang = GL_curLang; // if the destLang argument was not specified, use the current site language } if(typeof srcTxt == "undefined") { var srcTxt = item.innerHTML; // if the srcText argument was not specified, use the current item contents } // loop through translated items array to see if a translation for current text already exists since page loaded for(var i = 0; i < GL_miniTransItems.length; i++) { // check if source text and destination language match a translated item (and a completed translation exists for it) if((GL_miniTransItems[i][1] == srcTxt) && (GL_miniTransItems[i][2] == destLang) && (GL_miniTransItems[i][3] != "")) { item.innerHTML = GL_miniTransItems[i][3]; // if so, display existing translation in item item.title = srcTxt.split(/<.*?>/g).join(""); // display English source text as a tooltip (strip HTML first) return; // Don't need to send a translation request to Google, so end function. } } // store item to be translated in global array for access by callback function GL_miniTransItems[GL_miniTransItems.length] = new Array(4); GL_miniTransItems[(GL_miniTransItems.length-1)][0] = item; GL_miniTransItems[(GL_miniTransItems.length-1)][1] = srcTxt; GL_miniTransItems[(GL_miniTransItems.length-1)][2] = destLang; GL_miniTransItems[(GL_miniTransItems.length-1)][3] = ""; // create source text by adding current item ID to start of item text (ID will ensure correct item is translated) srcTxt = (GL_miniTransItems.length-1) + "<br />" + srcTxt; google.language.translate(srcTxt, "en", destLang, function(result) { if (!result.error) { // split into array based on separator, so we know the id of translated item var transChunk = result.translation.split("<br />"); // [find out length of substring to chop off from start of item] var chunkSubStr = 6 + transChunk[0].length; // remove whitespace from item id (a problem with some translations) transChunk[0] = transChunk[0].replace(/^\s+|\s+$/g,""); // display english source text of translated item (with HTML stripped) if user hovers mouse over it var strippedSrcTxt = GL_miniTransItems[transChunk[0]][1].split(/<.*?>/g).join(""); GL_miniTransItems[transChunk[0]][0].title = "[" + strippedSrcTxt + "]"; // store and display translation of specified item (stripping item ID from start of text) GL_miniTransItems[transChunk[0]][3] = result.translation.substr(chunkSubStr); GL_miniTransItems[transChunk[0]][0].innerHTML = GL_miniTransItems[transChunk[0]][3]; } }); } // runs when the user changes the site language function changeLang(destLang) { if(typeof destLang != "undefined") { GL_curLang = destLang; // if the destLang argument was specified, set new site language to this document.getElementById("mlt_language").value = GL_curLang; // change listbox to display new site language } else { // otherwise get the new language requested by user GL_curLang = document.getElementById("mlt_language").value; } // store the requested language in a cookie setLangCookie(); // if the original site languages should be shown, refresh the page. if(GL_curLang == "orig") { refresh(); return; } // otherwise, start the translation startTranslation(); } // find out the value of the language cookie (if it exists) function getLangCookie() { var curStoredLang; // retrieve a list of cookies for this page, split into array elements (separated by ; if multiple cookies) var getCurLang=document.cookie.split(";"); // loop through all array elements (i.e. cookies) until one with name 'lang' is found. for(var i=0; i < getCurLang.length; i++) { // remove whitespace from cookies (a problem if there are multiple cookies) var lngCookie = getCurLang[i].replace(/^\s+|\s+$/g,""); if(lngCookie.indexOf("lang=") == 0) { // find out value of lang curStoredLang = lngCookie.substring(5); } } // if language cookie exists, set current site language to stored value if(typeof curStoredLang != "undefined") { GL_curLang = curStoredLang; // otherwise, check if an initial language has been specified } else if((GL_curLang == "") || (typeof GL_curLang == "undefined")) { detectUserLang(); // if not, find out user's language based on their settings, and offer to translate into that language GL_curLang = "orig"; // show site using original languages for now return; // don't want to store language in cookie until one has been specified, so end function } setLangCookie(); // if valid cookie exists or initial language was specified, set/renew cookie (to store new expiry date) } // If a new user has not specified a language yet, offer to translate page into their current browser / system language function detectUserLang(){ /* detect user's current language (if they are using IE this will be based on the regional settings on their system; otherwise it will be based on the default language of their current browser) */ var detectedLang = (navigator.language) ? navigator.language : navigator.userLanguage; // if language cannot be detected for some reason, end function. if((typeof detectedLang == "undefined") || (detectedLang == "")) { return; } // if language is regional dialect (e.g. "en-gb"), check last 2 letters are upper case - for google compatibility. if(detectedLang.length == 5) { detectedLang = detectedLang.substr(0,3) + detectedLang.substr(3).toUpperCase(); } // check that Google can translate content into detected language if (!google.language.isTranslatable(detectedLang)) { // if not, check if language is a regional dialect (e.g. "en-GB") if(detectedLang.length == 5) { // if so, Google may still be able to translate into a non-regional equivalent (e.g. "en") detectedLang = detectedLang.substr(0,2); if (!google.language.isTranslatable(detectedLang)) { return; // google cannot translate into non-regional equivalent, so end function } // language is not a regional dialect, and google cannot translate into it, so end function } else { return; } } var detectedLangStr = getFmtLangStr(detectedLang); // retrieve name of detected language as a formatted string /* // display message asking user if they want to translate current page into detected language document.getElementById("mlt_translatemsg").innerHTML = 'Translate this page into ' + detectedLangStr + '? ' + '<a href="javascript:changeLang(\'' + detectedLang + '\')">Yes</a> | <a href="javascript:changeLang(\'orig\')">No</a>'; miniTranslate(document.getElementById("mlt_translatemsg"),detectedLang); // translate question into detected language document.getElementById("mlt_translatemsg").style.display='block'; // show the question on screen */ // display message asking user if they want to translate current page into detected language document.getElementById("mlt_translatemsg").innerHTML = ''; miniTranslate(document.getElementById("mlt_translatemsg"),detectedLang); // translate question into detected language document.getElementById("mlt_translatemsg").style.display='none'; // show the question on screen } // create a cookie to store the current site language function setLangCookie() { // expire previous cookie (if it exists) document.cookie = "lang=; expires=-1; path=/"; // cookie will expire after 90 days. var expdate = new Date(); expdate.setTime(expdate.getTime()+7776000000); // create the cookie document.cookie = "lang=" + GL_curLang + "; expires=" + expdate.toGMTString() + "; path=/"; } // refresh the current page [runs if the Original Languages option was selected, or if requested by user after error(s)] function refresh() { hideTransMsg(); window.location.reload(true); } // run the 'initialise' function once the page has loaded. google.setOnLoadCallback(initialise); ****************The End***************************** *****************Save it as googlelanguage.js****************** if (!window['google']) { window['google'] = {}; } if (!window['google']['loader']) { window['google']['loader'] = {}; google.loader.ServiceBase = 'http://www.google.com/uds'; google.loader.GoogleApisBase = 'http://ajax.googleapis.com/ajax'; google.loader.ApiKey = 'notsupplied'; google.loader.KeyVerified = true; google.loader.LoadFailure = false; google.loader.Secure = false; google.loader.GoogleLocale = 'www.google.com'; google.loader.ClientLocation = {"latitude":17.385044,"longitude":78.486671,"address":{"city":"Hyderabad","region":"Andhra Pradesh","country":"India","country_code":"IN"}}; google.loader.AdditionalParams = ''; (function() {var d=true,g=null,h=false,j=encodeURIComponent,l=window,n=undefined,o=document;function p(a,b){return a.load=b}var q="push",r="replace",s="charAt",t="ServiceBase",u="name",v="getTime",w="length",x="prototype",y="setTimeout",z="loader",A="substring",B="join",C="toLowerCase";function D(a){if(a in E)return E[a];return E[a]=navigator.userAgent[C]().indexOf(a)!=-1}var E={};function F(a,b){var c=function(){};c.prototype=b[x];a.Q=b[x];a.prototype=new c} function G(a,b){var c=Array[x].slice.call(arguments,2)||[];return function(){var e=c.concat(Array[x].slice.call(arguments));return a.apply(b,e)}}function H(a){a=Error(a);a.toString=function(){return this.message};return a}function I(a,b){for(var c=a.split(/\./),e=l,f=0;f<c[w]-1;f++){e[c[f]]||(e[c[f]]={});e=e[c[f]]}e[c[c[w]-1]]=b}function J(a,b,c){a[b]=c}if(!K)var K=I;if(!L)var L=J;google[z].t={};K("google.loader.callbacks",google[z].t);var M={},N={};google[z].eval={};K("google.loader.eval",google[z].eval); p(google,function(a,b,c){function e(k){var m=k.split(".");if(m[w]>2)throw H("Module: '"+k+"' not found!");else if(typeof m[1]!="undefined"){f=m[0];c.packages=c.packages||[];c.packages[q](m[1])}}var f=a;c=c||{};if(a instanceof Array||a&&typeof a=="object"&&typeof a[B]=="function"&&typeof a.reverse=="function")for(var i=0;i<a[w];i++)e(a[i]);else e(a);if(a=M[":"+f]){if(c&&!c.language&&c.locale)c.language=c.locale;if(c&&typeof c.callback=="string"){i=c.callback;if(i.match(/^[[\]A-Za-z0-9._]+$/)){i=l.eval(i); c.callback=i}}if((i=c&&c.callback!=g)&&!a.s(b))throw H("Module: '"+f+"' must be loaded before DOM onLoad!");else if(i)a.m(b,c)?l[y](c.callback,0):a.load(b,c);else a.m(b,c)||a.load(b,c)}else throw H("Module: '"+f+"' not found!");});K("google.load",google.load); google.P=function(a,b){if(b){if(O[w]==0){P(l,"load",Q);if(!D("msie")&&!(D("safari")||D("konqueror"))&&D("mozilla")||l.opera)l.addEventListener("DOMContentLoaded",Q,h);else if(D("msie"))o.write("<script defer onreadystatechange='google.loader.domReady()' src=//:><\/script>");else(D("safari")||D("konqueror"))&&l[y](S,10)}O[q](a)}else P(l,"load",a)};K("google.setOnLoadCallback",google.P); function P(a,b,c){if(a.addEventListener)a.addEventListener(b,c,h);else if(a.attachEvent)a.attachEvent("on"+b,c);else{var e=a["on"+b];a["on"+b]=e!=g?aa([c,e]):c}}function aa(a){return function(){for(var b=0;b<a[w];b++)a[b]()}}var O=[];google[z].K=function(){var a=l.event.srcElement;if(a.readyState=="complete"){a.onreadystatechange=g;a.parentNode.removeChild(a);Q()}};K("google.loader.domReady",google[z].K);var ba={loaded:d,complete:d};function S(){if(ba[o.readyState])Q();else O[w]>0&&l[y](S,10)} function Q(){for(var a=0;a<O[w];a++)O[a]();O.length=0} google[z].d=function(a,b,c){if(c){var e;if(a=="script"){e=o.createElement("script");e.type="text/javascript";e.src=b}else if(a=="css"){e=o.createElement("link");e.type="text/css";e.href=b;e.rel="stylesheet"}(a=o.getElementsByTagName("head")[0])||(a=o.body.parentNode.appendChild(o.createElement("head")));a.appendChild(e)}else if(a=="script")o.write('<script src="'+b+'" type="text/javascript"><\/script>');else a=="css"&&o.write('<link href="'+b+'" type="text/css" rel="stylesheet"></link>')}; K("google.loader.writeLoadTag",google[z].d);google[z].M=function(a){N=a};K("google.loader.rfm",google[z].M);google[z].O=function(a){for(var b in a)if(typeof b=="string"&&b&&b[s](0)==":"&&!M[b])M[b]=new T(b[A](1),a[b])};K("google.loader.rpl",google[z].O);google[z].N=function(a){if((a=a.specs)&&a[w])for(var b=0;b<a[w];++b){var c=a[b];if(typeof c=="string")M[":"+c]=new U(c);else{c=new V(c[u],c.baseSpec,c.customSpecs);M[":"+c[u]]=c}}};K("google.loader.rm",google[z].N); google[z].loaded=function(a){M[":"+a.module].k(a)};K("google.loader.loaded",google[z].loaded);google[z].J=function(){return"qid="+((new Date)[v]().toString(16)+Math.floor(Math.random()*1E7).toString(16))};K("google.loader.createGuidArg_",google[z].J);I("google_exportSymbol",I);I("google_exportProperty",J);google[z].b={};K("google.loader.themes",google[z].b);google[z].b.z="http://www.google.com/cse/style/look/bubblegum.css";L(google[z].b,"BUBBLEGUM",google[z].b.z);google[z].b.B="http://www.google.com/cse/style/look/greensky.css"; L(google[z].b,"GREENSKY",google[z].b.B);google[z].b.A="http://www.google.com/cse/style/look/espresso.css";L(google[z].b,"ESPRESSO",google[z].b.A);google[z].b.D="http://www.google.com/cse/style/look/shiny.css";L(google[z].b,"SHINY",google[z].b.D);google[z].b.C="http://www.google.com/cse/style/look/minimalist.css";L(google[z].b,"MINIMALIST",google[z].b.C);function U(a){this.a=a;this.q=[];this.p={};this.i={};this.e={};this.l=d;this.c=-1} U[x].g=function(a,b){var c="";if(b!=n){if(b.language!=n)c+="&hl="+j(b.language);if(b.nocss!=n)c+="&output="+j("nocss="+b.nocss);if(b.nooldnames!=n)c+="&nooldnames="+j(b.nooldnames);if(b.packages!=n)c+="&packages="+j(b.packages);if(b.callback!=g)c+="&async=2";if(b.style!=n)c+="&style="+j(b.style);if(b.other_params!=n)c+="&"+b.other_params}if(!this.l){if(google[this.a]&&google[this.a].JSHash)c+="&sig="+j(google[this.a].JSHash);var e=[];for(var f in this.p)f[s](0)==":"&&e[q](f[A](1));for(f in this.i)f[s](0)== ":"&&this.i[f]&&e[q](f[A](1));c+="&have="+j(e[B](","))}return google[z][t]+"/?file="+this.a+"&v="+a+google[z].AdditionalParams+c};U[x].v=function(a){var b=g;if(a)b=a.packages;var c=g;if(b)if(typeof b=="string")c=[a.packages];else if(b[w]){c=[];for(a=0;a<b[w];a++)typeof b[a]=="string"&&c[q](b[a][r](/^\s*|\s*$/,"")[C]())}c||(c=["default"]);b=[];for(a=0;a<c[w];a++)this.p[":"+c[a]]||b[q](c[a]);return b}; p(U[x],function(a,b){var c=this.v(b),e=b&&b.callback!=g;if(e)var f=new W(b.callback);for(var i=[],k=c[w]-1;k>=0;k--){var m=c[k];e&&f.F(m);if(this.i[":"+m]){c.splice(k,1);e&&this.e[":"+m][q](f)}else i[q](m)}if(c[w]){if(b&&b.packages)b.packages=c.sort()[B](",");for(k=0;k<i[w];k++){m=i[k];this.e[":"+m]=[];e&&this.e[":"+m][q](f)}if(!b&&N[":"+this.a]!=g&&N[":"+this.a].versions[":"+a]!=g&&!google[z].AdditionalParams&&this.l){c=N[":"+this.a];google[this.a]=google[this.a]||{};for(var R in c.properties)if(R&& R[s](0)==":")google[this.a][R[A](1)]=c.properties[R];google[z].d("script",google[z][t]+c.path+c.js,e);c.css&&google[z].d("css",google[z][t]+c.path+c.css,e)}else if(!b||!b.autoloaded)google[z].d("script",this.g(a,b),e);if(this.l){this.l=h;this.c=(new Date)[v]();if(this.c%100!=1)this.c=-1}for(k=0;k<i[w];k++){m=i[k];this.i[":"+m]=d}}}); U[x].k=function(a){if(this.c!=-1){X("al_"+this.a,"jl."+((new Date)[v]()-this.c),d);this.c=-1}this.q=this.q.concat(a.components);google[z][this.a]||(google[z][this.a]={});google[z][this.a].packages=this.q.slice(0);for(var b=0;b<a.components[w];b++){this.p[":"+a.components[b]]=d;this.i[":"+a.components[b]]=h;var c=this.e[":"+a.components[b]];if(c){for(var e=0;e<c[w];e++)c[e].I(a.components[b]);delete this.e[":"+a.components[b]]}}X("hl",this.a)};U[x].m=function(a,b){return this.v(b)[w]==0};U[x].s=function(){return d}; function W(a){this.H=a;this.n={};this.r=0}W[x].F=function(a){this.r++;this.n[":"+a]=d};W[x].I=function(a){if(this.n[":"+a]){this.n[":"+a]=h;this.r--;this.r==0&&l[y](this.H,0)}};function V(a,b,c){this.name=a;this.G=b;this.o=c;this.u=this.h=h;this.j=[];google[z].t[this[u]]=G(this.k,this)}F(V,U);p(V[x],function(a,b){var c=b&&b.callback!=g;if(c){this.j[q](b.callback);b.callback="google.loader.callbacks."+this[u]}else this.h=d;if(!b||!b.autoloaded)google[z].d("script",this.g(a,b),c);X("el",this[u])});V[x].m=function(a,b){return b&&b.callback!=g?this.u:this.h};V[x].k=function(){this.u=d;for(var a=0;a<this.j[w];a++)l[y](this.j[a],0);this.j=[]}; var Y=function(a,b){return a.string?j(a.string)+"="+j(b):a.regex?b[r](/(^.*$)/,a.regex):""};V[x].g=function(a,b){return this.L(this.w(a),a,b)}; V[x].L=function(a,b,c){var e="";if(a.key)e+="&"+Y(a.key,google[z].ApiKey);if(a.version)e+="&"+Y(a.version,b);b=google[z].Secure&&a.ssl?a.ssl:a.uri;if(c!=g)for(var f in c)if(a.params[f])e+="&"+Y(a.params[f],c[f]);else if(f=="other_params")e+="&"+c[f];else if(f=="base_domain")b="http://"+c[f]+a.uri[A](a.uri.indexOf("/",7));google[this[u]]={};if(b.indexOf("?")==-1&&e)e="?"+e[A](1);return b+e};V[x].s=function(a){return this.w(a).deferred}; V[x].w=function(a){if(this.o)for(var b=0;b<this.o[w];++b){var c=this.o[b];if(RegExp(c.pattern).test(a))return c}return this.G};function T(a,b){this.a=a;this.f=b;this.h=h}F(T,U);p(T[x],function(a,b){this.h=d;google[z].d("script",this.g(a,b),h)});T[x].m=function(){return this.h};T[x].k=function(){}; T[x].g=function(a,b){if(!this.f.versions[":"+a]){if(this.f.aliases){var c=this.f.aliases[":"+a];if(c)a=c}if(!this.f.versions[":"+a])throw H("Module: '"+this.a+"' with version '"+a+"' not found!");}c=google[z].GoogleApisBase+"/libs/"+this.a+"/"+a+"/"+this.f.versions[":"+a][b&&b.uncompressed?"uncompressed":"compressed"];X("el",this.a);return c};T[x].s=function(){return h};var ca=h,Z=[],da=(new Date)[v](),X=function(a,b,c){if(!ca){P(l,"unload",ea);ca=d}if(c){if(!google[z].Secure&&(!google[z].Options||google[z].Options.csi===h)){a=a[C]()[r](/[^a-z0-9_.]+/g,"_");b=b[C]()[r](/[^a-z0-9_.]+/g,"_");l[y](G($,g,"http://csi.gstatic.com/csi?s=uds&v=2&action="+j(a)+"&it="+j(b)),1E4)}}else{Z[q]("r"+Z[w]+"="+j(a+(b?"|"+b:"")));l[y](ea,Z[w]>5?0:15E3)}},ea=function(){if(Z[w]){$(google[z][t]+"/stats?"+Z[B]("&")+"&nc="+(new Date)[v]()+"_"+((new Date)[v]()-da));Z.length=0}},$=function(a){var b= new Image,c=fa++;ga[c]=b;b.onload=b.onerror=function(){delete ga[c]};b.src=a;b=g},ga={},fa=0;I("google.loader.recordStat",X);I("google.loader.createImageForLogging",$); }) ();google.loader.rm({"specs":[{"name":"books","baseSpec":{"uri":"http://books.google.com/books/api.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"}}}},"feeds",{"name":"friendconnect","baseSpec":{"uri":"http://www.google.com/friendconnect/script/friendconnect.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":false,"params":{}}},"spreadsheets","gdata","visualization",{"name":"sharing","baseSpec":{"uri":"http://www.google.com/s2/sharing/js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":false,"params":{"language":{"string":"hl"}}}},"search",{"name":"maps","baseSpec":{"uri":"http://maps.google.com/maps?file\u003dgoogleapi","ssl":"https://maps-api-ssl.google.com/maps?file\u003dgoogleapi","key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"regex":"callback\u003d$1\u0026async\u003d2"},"language":{"string":"hl"}}},"customSpecs":[{"uri":"http://maps.google.com/maps/api/js","ssl":"https://maps-api-ssl.google.com/maps/api/js","key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"}},"pattern":"^(3|3..*)$"}]},"annotations_v2","wave","orkut",{"name":"annotations","baseSpec":{"uri":"http://www.google.com/reviews/scripts/annotations_bootstrap.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"},"country":{"string":"gl"}}}},"language","earth","ads","elements"]}); google.loader.rfm({":search":{"versions":{":1":"1",":1.0":"1"},"path":"/api/search/1.0/2a8ff2a70ad0b091ae9dfd8b5e832141/","js":"default+en.I.js","css":"default.css","properties":{":JSHash":"2a8ff2a70ad0b091ae9dfd8b5e832141",":NoOldNames":false,":Version":"1.0"}},":language":{"versions":{":1":"1",":1.0":"1"},"path":"/api/language/1.0/62c64af2122d2da7dcb0087852fa7396/","js":"default+en.I.js","properties":{":JSHash":"62c64af2122d2da7dcb0087852fa7396",":Version":"1.0"}},":wave":{"versions":{":1":"1",":1.0":"1"},"path":"/api/wave/1.0/3b6f7573ff78da6602dda5e09c9025bf/","js":"default.I.js","properties":{":JSHash":"3b6f7573ff78da6602dda5e09c9025bf",":Version":"1.0"}},":spreadsheets":{"versions":{":0":"1",":0.3":"1"},"path":"/api/spreadsheets/0.3/8331b0bbcc74776270648505340e9200/","js":"default.I.js","properties":{":JSHash":"8331b0bbcc74776270648505340e9200",":Version":"0.3"}},":earth":{"versions":{":1":"1",":1.0":"1"},"path":"/api/earth/1.0/819ffbf1e363d238791231792a2e0a90/","js":"default.I.js","properties":{":JSHash":"819ffbf1e363d238791231792a2e0a90",":Version":"1.0"}},":annotations":{"versions":{":1":"1",":1.0":"1"},"path":"/api/annotations/1.0/11cfaf30c00ca64601d09fcac7dd8bc7/","js":"default+en.I.js","properties":{":JSHash":"11cfaf30c00ca64601d09fcac7dd8bc7",":Version":"1.0"}}}); google.loader.rpl({":scriptaculous":{"versions":{":1.8.3":{"uncompressed":"scriptaculous.js","compressed":"scriptaculous.js"},":1.8.2":{"uncompre