Index: trunk/extensions/LiveTranslate/LiveTranslate.php |
— | — | @@ -83,6 +83,9 @@ |
84 | 84 | 'livetranslate-button-translate', |
85 | 85 | 'livetranslate-button-translating', |
86 | 86 | 'livetranslate-dictionary-error', |
| 87 | + 'livetranslate-button-translate', |
| 88 | + 'livetranslate-button-revert', |
| 89 | + 'livetranslate-translate-to', |
87 | 90 | ); |
88 | 91 | |
89 | 92 | // For backward compatibility with MW < 1.17. |
— | — | @@ -95,10 +98,12 @@ |
96 | 99 | |
97 | 100 | $wgResourceModules['ext.livetranslate'] = $moduleTemplate + array( |
98 | 101 | 'scripts' => array( |
| 102 | + 'includes/ext.livetranslate.js', |
99 | 103 | 'includes/ext.lt.tm.js', |
100 | | - 'includes/ext.livetranslate.js' |
| 104 | + 'includes/jquery.replaceText.js', |
| 105 | + 'includes/jquery.liveTranslate.js' |
101 | 106 | ), |
102 | | - 'dependencies' => array( 'jquery' ), |
| 107 | + 'dependencies' => array( 'jquery', 'jquery.ui.button' ), |
103 | 108 | 'messages' => $egLTJSMessages |
104 | 109 | ); |
105 | 110 | |
Index: trunk/extensions/LiveTranslate/LiveTranslate.hooks.php |
— | — | @@ -30,7 +30,6 @@ |
31 | 31 | |
32 | 32 | $currentLang = LiveTranslateFunctions::getCurrentLang( $title ); |
33 | 33 | |
34 | | - // FIXME: Hitting the db on every page load should be avoided |
35 | 34 | if ( in_array( $title->getFullText(), LiveTranslateFunctions::getLocalMemoryNames() ) ) { |
36 | 35 | self::displayDictionaryPage( $article, $title ); |
37 | 36 | $outputDone = true; // The translations themselves should not be shown. |
— | — | @@ -154,24 +153,10 @@ |
155 | 154 | protected static function displayTranslationControl( $currentLang ) { |
156 | 155 | global $wgOut; |
157 | 156 | |
158 | | - $divContents = htmlspecialchars( wfMsg( 'livetranslate-translate-to' ) ) . |
159 | | - ' ' . |
160 | | - LiveTranslateFunctions::getLanguageSelector( $currentLang ) . |
161 | | - ' ' . |
162 | | - Html::element( |
163 | | - 'button', |
164 | | - array( 'id' => 'livetranslatebutton' ), |
165 | | - wfMsg( 'livetranslate-button-translate' ) |
166 | | - ) . |
167 | | - ' ' . |
168 | | - Html::element( |
169 | | - 'button', |
170 | | - array( 'id' => 'ltrevertbutton', 'style' => 'display:none' ), |
171 | | - wfMsg( 'livetranslate-button-revert' ) |
172 | | - ); |
173 | | - |
174 | | - if ( $GLOBALS['egLiveTranslateService'] == LTS_GOOGLE ) { |
175 | | - $divContents .= '<br /><br /><div id="googlebranding" style="display:inline; position:absolute; right: 0px"></div>'; |
| 157 | + $langs = array(); |
| 158 | + |
| 159 | + foreach ( LiveTranslateFunctions::getLanguages( $currentLang ) as $label => $code ) { |
| 160 | + $langs[] = "$code|$label"; |
176 | 161 | } |
177 | 162 | |
178 | 163 | $wgOut->addHTML( |
— | — | @@ -179,11 +164,9 @@ |
180 | 165 | 'div', |
181 | 166 | array( |
182 | 167 | 'id' => 'livetranslatediv', |
183 | | - 'style' => 'display:inline; float:right', |
184 | | - 'class' => 'notranslate', |
185 | | - 'sourcelang' => $currentLang |
186 | | - ), |
187 | | - $divContents |
| 168 | + 'sourcelang' => $currentLang, |
| 169 | + 'languages' => implode( '||', $langs ) |
| 170 | + ) |
188 | 171 | ) |
189 | 172 | ); |
190 | 173 | |
Index: trunk/extensions/LiveTranslate/includes/ext.lt.google.js |
— | — | @@ -9,11 +9,11 @@ |
10 | 10 | google.load("language", "1"); |
11 | 11 | google.setOnLoadCallback(function(){google.language.getBranding("googlebranding");}); |
12 | 12 | |
13 | | -(function( $ ){ window.translationService = function() { |
| 13 | +(function( $, lt ){ window.translationService = function() { |
14 | 14 | |
15 | 15 | var self = this; |
16 | 16 | |
17 | | - this.done = function( targetLang ){}; |
| 17 | + this.done = function(){}; |
18 | 18 | |
19 | 19 | this.runningJobs = 0; |
20 | 20 | |
— | — | @@ -32,7 +32,7 @@ |
33 | 33 | * @param {DOM element} element |
34 | 34 | */ |
35 | 35 | this.translateChunk = function( untranslatedsentences, chunks, currentMaxSize, sourceLang, targetLang, element ) { |
36 | | - ltdebug( 'Google: Translating chunk' ); |
| 36 | + lt.debug( 'Google: Translating chunk' ); |
37 | 37 | var remainingPart = false; |
38 | 38 | var partToUse = false; |
39 | 39 | var sentenceCount = 0; |
— | — | @@ -79,7 +79,7 @@ |
80 | 80 | |
81 | 81 | // If the lenght is 0, the element has been translated. |
82 | 82 | if ( chunk.length == 0 ) { |
83 | | - this.handleTranslationCompletion( targetLang ); |
| 83 | + this.handleTranslationCompletion(); |
84 | 84 | return; |
85 | 85 | } |
86 | 86 | |
— | — | @@ -92,7 +92,7 @@ |
93 | 93 | sourceLang, |
94 | 94 | targetLang, |
95 | 95 | function(result) { |
96 | | - ltdebug( 'Google: Translated chunk' ); |
| 96 | + lt.debug( 'Google: Translated chunk' ); |
97 | 97 | |
98 | 98 | if ( result.translation ) { |
99 | 99 | chunks.push( leadingSpace + result.translation + tailingSpace ); |
— | — | @@ -106,7 +106,7 @@ |
107 | 107 | // If the current chunk was smaller then the max size, node translation is complete, so update text. |
108 | 108 | self.textAreaElement.innerHTML = chunks.join( '' ); // This is a hack to decode quotes. |
109 | 109 | element.replaceData( 0, element.length, self.textAreaElement.value ); |
110 | | - self.handleTranslationCompletion( targetLang ); |
| 110 | + self.handleTranslationCompletion(); |
111 | 111 | } |
112 | 112 | else { |
113 | 113 | // If there is more work to do, move on to the next chunk. |
— | — | @@ -125,17 +125,17 @@ |
126 | 126 | * @param {string} targetLang |
127 | 127 | */ |
128 | 128 | this.translateElement = function( element, sourceLang, targetLang ) { |
129 | | - ltdebug( 'Google: Translating element' ); |
| 129 | + lt.debug( 'Google: Translating element' ); |
130 | 130 | this.runningJobs++; |
131 | 131 | |
132 | 132 | var maxChunkLength = 500; |
133 | 133 | |
134 | 134 | element.contents().each( function() { |
135 | | - ltdebug( 'Google: Element conent item' ); |
| 135 | + lt.debug( 'Google: Element conent item' ); |
136 | 136 | |
137 | 137 | // If it's a text node, then translate it. |
138 | 138 | if ( this.nodeType == 3 && typeof this.data === 'string' && $.trim( this.data ).length > 0 ) { |
139 | | - ltdebug( 'Google: Found content node' ); |
| 139 | + lt.debug( 'Google: Found content node' ); |
140 | 140 | |
141 | 141 | self.runningJobs++; |
142 | 142 | self.translateChunk( |
— | — | @@ -153,29 +153,27 @@ |
154 | 154 | && !$( this ).hasClass( 'notranslate' ) && !$( this ).hasClass( 'printfooter' ) |
155 | 155 | && $( this ).text().length > 0 ) { |
156 | 156 | |
157 | | - ltdebug( 'Google: Found child node' ); |
| 157 | + lt.debug( 'Google: Found child node' ); |
158 | 158 | self.translateElement( $( this ), sourceLang, targetLang ); |
159 | 159 | } |
160 | 160 | else { |
161 | | - ltdebug( 'Google: Found ignore node' ); |
| 161 | + lt.debug( 'Google: Found ignore node' ); |
162 | 162 | } |
163 | 163 | } ); |
164 | 164 | |
165 | | - this.handleTranslationCompletion( targetLang ); |
| 165 | + this.handleTranslationCompletion(); |
166 | 166 | } |
167 | 167 | |
168 | 168 | /** |
169 | 169 | * Should be called every time a DOM element has been translated. |
170 | 170 | * By use of the runningJobs var, completion of the translation process is detected, |
171 | 171 | * and further handled by this function. |
172 | | - * |
173 | | - * @param {string} targetLang |
174 | 172 | */ |
175 | | - this.handleTranslationCompletion = function( targetLang ) { |
| 173 | + this.handleTranslationCompletion = function() { |
176 | 174 | if ( !--this.runningJobs ) { |
177 | | - ltdebug( 'Google: translation process done' ); |
178 | | - this.done( targetLang ); |
| 175 | + lt.debug( 'Google: translation process done' ); |
| 176 | + this.done(); |
179 | 177 | } |
180 | 178 | } |
181 | 179 | |
182 | | -}; })( jQuery ); |
\ No newline at end of file |
| 180 | +}; })( jQuery, window.liveTranslate ); |
\ No newline at end of file |
Index: trunk/extensions/LiveTranslate/includes/jquery.liveTranslate.js |
— | — | @@ -0,0 +1,182 @@ |
| 2 | +/** |
| 3 | + * JavasSript for the Live Translate extension. |
| 4 | + * @see http://www.mediawiki.org/wiki/Extension:Live_Translate |
| 5 | + * |
| 6 | + * @licence GNU GPL v3 or later |
| 7 | + * @author Jeroen De Dauw <jeroendedauw at gmail dot com> |
| 8 | + */ |
| 9 | + |
| 10 | +( function ( $, lt ) { $.fn.liveTranslate = function( options ) { |
| 11 | + |
| 12 | + var _this = this; |
| 13 | + |
| 14 | + this.doTranslations = function() { |
| 15 | + _this.runningJobs = 2; |
| 16 | + |
| 17 | + _this.doLocalTranslation( _this.completeTranslationProcess ); |
| 18 | + _this.doRemoteTranslation( _this.completeTranslationProcess ); |
| 19 | + }; |
| 20 | + |
| 21 | + this.findSpecialWords = function() { |
| 22 | + var words = []; |
| 23 | + |
| 24 | + $.each( $( "span.notranslate" ), function( i, v ) { |
| 25 | + words.push( $.trim( $( v ).text() ) ); |
| 26 | + } ); |
| 27 | + |
| 28 | + return words; |
| 29 | + }; |
| 30 | + |
| 31 | + this.doLocalTranslation = function( callback ) { |
| 32 | + _this.memory.getTranslations( |
| 33 | + { |
| 34 | + source: _this.currentLang, |
| 35 | + target: _this.select.val(), |
| 36 | + words: _this.findSpecialWords() |
| 37 | + }, |
| 38 | + function( translations ) { |
| 39 | + $.each( $( "span.notranslate" ), function( i, v ) { |
| 40 | + var currentText = $(v).text(); |
| 41 | + var trimmedText = $.trim( currentText ); |
| 42 | + |
| 43 | + if ( translations[trimmedText] ) { |
| 44 | + $( v ).text( currentText.replace( trimmedText, translations[trimmedText] ) ); |
| 45 | + } |
| 46 | + }); |
| 47 | + |
| 48 | + callback(); |
| 49 | + } |
| 50 | + ); |
| 51 | + }; |
| 52 | + |
| 53 | + this.doRemoteTranslation = function( callback ) { |
| 54 | + var translator = new window.translationService(); |
| 55 | + translator.done = callback; |
| 56 | + lt.debug( 'Initiating remote translation' ); |
| 57 | + translator.translateElement( $( '#bodyContent' ), _this.currentLang, _this.select.val() ); |
| 58 | + }; |
| 59 | + |
| 60 | + this.completeTranslationProcess = function() { |
| 61 | + if ( !--_this.runningJobs ) { |
| 62 | + _this.translateButton.attr( "disabled", false ).text( lt.msg( 'livetranslate-button-translate' ) ); |
| 63 | + _this.select.attr( "disabled", false ); |
| 64 | + _this.revertButton.css( 'display', 'inline' ); |
| 65 | + } |
| 66 | + }; |
| 67 | + |
| 68 | + /** |
| 69 | + * Inserts notranslate spans around the words specified in the passed array in the page content. |
| 70 | + * |
| 71 | + * @param {Array} words |
| 72 | + */ |
| 73 | + this.insertSpecialWords = function( words ) { |
| 74 | + lt.debug( 'inserting special words' ); |
| 75 | + |
| 76 | + for ( i in words ) { |
| 77 | + $( '#bodyContent *' ).replaceText( |
| 78 | + new RegExp( "(\\W)*" + RegExp.escape( words[i] ) + "(\\W)*", "g" ), |
| 79 | + function( str ) { |
| 80 | + return '<span class="notranslate">' + str + '</span>'; |
| 81 | + } |
| 82 | + ); |
| 83 | + } |
| 84 | + }; |
| 85 | + |
| 86 | + this.obatinAndInsetSpecialWords = function( callback ) { |
| 87 | + // TODO: only run at first translation |
| 88 | + _this.memory.getSpecialWords( _this.currentLang, function( specialWords ) { |
| 89 | + _this.specialWords = specialWords; |
| 90 | + _this.insertSpecialWords( specialWords ); |
| 91 | + |
| 92 | + callback(); |
| 93 | + } ); |
| 94 | + }; |
| 95 | + |
| 96 | + this.setup = function() { |
| 97 | + var defaults = { |
| 98 | + languages: {}, |
| 99 | + sourcelang: 'en' |
| 100 | + }; |
| 101 | + |
| 102 | + $.extend( options, defaults ); |
| 103 | + |
| 104 | + $.each( this.attr( 'languages' ).split( '||' ), function( i, lang ) { |
| 105 | + var parts = lang.split( '|' ); |
| 106 | + options.languages[parts[0]] = parts[1]; |
| 107 | + } ); |
| 108 | + |
| 109 | + _this.currentLang = this.attr( 'sourcelang' ); |
| 110 | + |
| 111 | + // For the "show original" feature. |
| 112 | + _this.originalHtml = false; |
| 113 | + |
| 114 | + _this.textAreaElement = document.createElement( 'textarea' ); |
| 115 | + |
| 116 | + _this.uniqueId = Math.random().toString().substring( 2 ); |
| 117 | + |
| 118 | + _this.memory = lt.memory.singleton(); |
| 119 | + |
| 120 | + _this.runningJobs = 0; |
| 121 | + |
| 122 | + _this.buildHtml(); |
| 123 | + |
| 124 | + _this.bindEvents(); |
| 125 | + }; |
| 126 | + |
| 127 | + this.buildHtml = function() { |
| 128 | + _this.attr( { |
| 129 | + style: 'display:inline; float:right', |
| 130 | + } ).attr( 'class', 'notranslate' ); |
| 131 | + |
| 132 | + _this.html( lt.msg( 'livetranslate-translate-to' ) ); |
| 133 | + |
| 134 | + _this.select = $( '<select />' ).attr( { |
| 135 | + id: 'ltselect' + _this.uniqueId, |
| 136 | + } ); |
| 137 | + |
| 138 | + for ( langCode in options.languages ) { |
| 139 | + _this.select.append( $( '<option />' ).attr( 'value', langCode ).text( options.languages[langCode] ) ); |
| 140 | + } |
| 141 | + |
| 142 | + _this.translateButton = $( '<button />' ).attr( { |
| 143 | + id: 'livetranslatebutton' + _this.uniqueId, |
| 144 | + } ).text( lt.msg( 'livetranslate-button-translate' ) ); // .button() |
| 145 | + |
| 146 | + _this.revertButton = $( '<button />' ).attr( { |
| 147 | + id: 'ltrevertbutton' + _this.uniqueId, |
| 148 | + style: 'display:none' |
| 149 | + } ).text( lt.msg( 'livetranslate-button-revert' ) ); // .button() |
| 150 | + |
| 151 | + _this.append( _this.select, _this.translateButton, _this.revertButton ); |
| 152 | + }; |
| 153 | + |
| 154 | + this.bindEvents = function() { |
| 155 | + _this.translateButton.click( function() { |
| 156 | + _this.originalHtml = $( '#bodyContent' ).html(); |
| 157 | + |
| 158 | + $( this ).attr( "disabled", true ).text( lt.msg( 'livetranslate-button-translating' ) ); |
| 159 | + _this.select.attr( "disabled", true ); |
| 160 | + |
| 161 | + _this.obatinAndInsetSpecialWords( _this.doTranslations ); |
| 162 | + } ); |
| 163 | + |
| 164 | + _this.revertButton.click( function() { |
| 165 | + // Replace the body content wth it's original value. |
| 166 | + // This un-binds the jQuery selectors and event handlers. |
| 167 | + $( '#bodyContent' ).html( _this.originalHtml ); |
| 168 | + |
| 169 | + // Re-assing the controls. |
| 170 | + _this.select = $( '#ltselect' + _this.uniqueId ); |
| 171 | + _this.translateButton = $( '#livetranslatebutton' + _this.uniqueId ); |
| 172 | + _this.revertButton = $( '#ltrevertbutton' + _this.uniqueId ); |
| 173 | + |
| 174 | + // Re-bind the events to the controls. |
| 175 | + _this.bindEvents(); |
| 176 | + } ) |
| 177 | + }; |
| 178 | + |
| 179 | + this.setup(); |
| 180 | + |
| 181 | + return this; |
| 182 | + |
| 183 | +}; } )( jQuery, window.liveTranslate ); |
\ No newline at end of file |
Property changes on: trunk/extensions/LiveTranslate/includes/jquery.liveTranslate.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 184 | + native |
Index: trunk/extensions/LiveTranslate/includes/ext.livetranslate.js |
— | — | @@ -6,19 +6,9 @@ |
7 | 7 | * @author Jeroen De Dauw <jeroendedauw at gmail dot com> |
8 | 8 | */ |
9 | 9 | |
10 | | -(function($) { $( document ).ready( function() { |
11 | | - |
12 | | - /* |
13 | | - * jQuery replaceText - v1.1 - 11/21/2009 |
14 | | - * http://benalman.com/projects/jquery-replacetext-plugin/ |
15 | | - * |
16 | | - * Copyright (c) 2009 "Cowboy" Ben Alman |
17 | | - * Dual licensed under the MIT and GPL licenses. |
18 | | - * http://benalman.com/about/license/ |
19 | | - */ |
20 | | - $.fn.replaceText=function(b,a,c){return this.each(function(){var f=this.firstChild,g,e,d=[];if(f){do{if(f.nodeType===3){g=f.nodeValue;e=g.replace(b,a);if(e!==g){if(!c&&/</.test(e)){$(f).before(e);d.push(f)}else{f.nodeValue=e}}}}while(f=f.nextSibling)}d.length&&$(d).remove()})} |
| 10 | +window.liveTranslate = new( function() { |
21 | 11 | |
22 | | - window.ltdebug = function( message ) { |
| 12 | + this.debug = function( message ) { |
23 | 13 | if ( window.ltDebugMessages ) { |
24 | 14 | if ( typeof console === 'undefined' ) { |
25 | 15 | document.title = 'Live Translate: ' + message; |
— | — | @@ -27,21 +17,10 @@ |
28 | 18 | console.log( 'Live Translate: ' + message ); |
29 | 19 | } |
30 | 20 | } |
31 | | - }; |
| 21 | + } |
32 | 22 | |
33 | | - var currentLang = $( '#livetranslatediv' ).attr( 'sourcelang' ); |
34 | | - |
35 | | - // For the "show original" feature. |
36 | | - var originalHtml = false; |
37 | | - |
38 | | - window.textAreaElement = document.createElement( 'textarea' ); |
39 | | - |
40 | | - // Compatibility with pre-RL code. |
41 | | - // Messages will have been loaded into wgPushMessages. |
42 | | - if ( typeof mediaWiki === 'undefined' ) { |
43 | | - mediaWiki = new Object(); |
44 | | - |
45 | | - mediaWiki.msg = function() { |
| 23 | + this.msg = function() { |
| 24 | + if ( typeof mediaWiki === 'undefined' ) { |
46 | 25 | message = window.wgLTEMessages[arguments[0]]; |
47 | 26 | |
48 | 27 | for ( var i = arguments.length - 1; i > 0; i-- ) { |
— | — | @@ -50,196 +29,15 @@ |
51 | 30 | |
52 | 31 | return message; |
53 | 32 | } |
54 | | - } |
55 | | - |
56 | | - /** |
57 | | - * Disables the translation button and then either kicks of insertion of |
58 | | - * notranslate spans around special words, or when this already happened, |
59 | | - * the actual translation process. |
60 | | - */ |
61 | | - setupTranslationFeatures = function() { |
62 | | - $( this ).attr( "disabled", true ).text( mediaWiki.msg( 'livetranslate-button-translating' ) ); |
63 | | - |
64 | | - if ( originalHtml === false ) { |
65 | | - obtainAndInsertTranslations( -1 ); |
66 | | - } |
67 | 33 | else { |
68 | | - initiateTranslating(); |
| 34 | + return mediaWiki.msg.apply( this, arguments ); |
69 | 35 | } |
70 | 36 | } |
71 | 37 | |
72 | | - /** |
73 | | - * Queries a batch of special words in the source language, finds them in the page, |
74 | | - * and wraps the into notranslate spans. If there are no more words, the translation |
75 | | - * process is initaiated, otherwise the function calls itself again. |
76 | | - */ |
77 | | - function obtainAndInsertTranslations( offset ) { |
78 | | - var requestArgs = { |
79 | | - 'action': 'query', |
80 | | - 'format': 'json', |
81 | | - 'list': 'livetranslate', |
82 | | - 'ltlanguage': currentLang |
83 | | - }; |
84 | | - |
85 | | - if ( offset > 0 ) { |
86 | | - requestArgs['ltcontinue'] = offset; |
87 | | - } |
88 | | - |
89 | | - $.getJSON( |
90 | | - wgScriptPath + '/api.php', |
91 | | - requestArgs, |
92 | | - function( data ) { |
93 | | - if ( data.words ) { |
94 | | - insertNoTranslateTags( data.words ); |
95 | | - } |
96 | | - else if ( data.error && data.error.info ) { |
97 | | - alert( data.error.info ); |
98 | | - } |
99 | | - else { |
100 | | - for ( i in data ) { |
101 | | - alert( mediaWiki.msg( 'livetranslate-dictionary-error' ) ); |
102 | | - break; |
103 | | - } |
104 | | - } |
105 | | - |
106 | | - originalHtml = $( '#bodyContent' ).html(); |
107 | | - |
108 | | - if ( data['query-continue'] ) { |
109 | | - obtainAndInsertTranslations( data['query-continue'].livetranslate.ltcontinue ); |
110 | | - } |
111 | | - else { |
112 | | - initiateTranslating(); |
113 | | - } |
114 | | - } |
115 | | - ); |
116 | | - } |
| 38 | +} )(); |
| 39 | + |
| 40 | +(function( $ ) { $( document ).ready( function() { |
| 41 | + |
| 42 | + $( '#livetranslatediv' ).liveTranslate( {} ); |
117 | 43 | |
118 | | - /** |
119 | | - * Initiates the translation process. |
120 | | - * First all special words are found and send to the local API, |
121 | | - * and then replaced by their translation in the response. Then |
122 | | - * the Google Translate translation is initiated. |
123 | | - */ |
124 | | - function initiateTranslating() { |
125 | | - var words = getSpecialWords(); |
126 | | - var newLang = $( '#livetranslatelang' ).val(); |
127 | | - |
128 | | - if ( words.length == 0 ) { |
129 | | - initiateRemoteTranslating( currentLang, newLang ); |
130 | | - } |
131 | | - else { |
132 | | - $.getJSON( |
133 | | - wgScriptPath + '/api.php', |
134 | | - { |
135 | | - 'action': 'livetranslate', |
136 | | - 'format': 'json', |
137 | | - 'from': currentLang, |
138 | | - 'to': newLang, |
139 | | - 'words': words.join( '|' ) |
140 | | - }, |
141 | | - function( data ) { |
142 | | - if ( data.translations ) { |
143 | | - replaceSpecialWords( data.translations ); |
144 | | - } |
145 | | - initiateRemoteTranslating( currentLang, newLang ); |
146 | | - } |
147 | | - ); |
148 | | - } |
149 | | - } |
150 | | - |
151 | | - /** |
152 | | - * Shows the original page content, simply by setting the html to a stored copy of the original. |
153 | | - * Also re-binds the jQuery events, as they get lost when doing the html replace. |
154 | | - */ |
155 | | - showOriginal = function() { |
156 | | - currentLang = window.sourceLang; |
157 | | - $( '#bodyContent' ).html( originalHtml ); |
158 | | - $( '#livetranslatebutton' ).attr( "disabled", false ).text( mediaWiki.msg( 'livetranslate-button-translate' ) ); |
159 | | - $( '#livetranslatebutton' ).click( setupTranslationFeatures ); |
160 | | - $( '#ltrevertbutton' ).click( showOriginal ); |
161 | | - } |
162 | | - |
163 | | - // Initial binding of the button click events. |
164 | | - $( '#livetranslatebutton' ).click( setupTranslationFeatures ); |
165 | | - $( '#ltrevertbutton' ).click( showOriginal ); |
166 | | - |
167 | | - /** |
168 | | - * Regex text escaping function. |
169 | | - * Borrowed from http://simonwillison.net/2006/Jan/20/escape/ |
170 | | - */ |
171 | | - RegExp.escape = function(text) { |
172 | | - if (!arguments.callee.sRE) { |
173 | | - var specials = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\' ]; |
174 | | - arguments.callee.sRE = new RegExp( '(\\' + specials.join('|\\') + ')', 'g' ); |
175 | | - } |
176 | | - return text.replace(arguments.callee.sRE, '\\$1'); |
177 | | - } |
178 | | - |
179 | | - /** |
180 | | - * Inserts notranslate spans around the words specified in the passed array in the page content. |
181 | | - * |
182 | | - * @param {Array} words |
183 | | - */ |
184 | | - function insertNoTranslateTags( words ) { |
185 | | - for ( i in words ) { |
186 | | - $( '#bodyContent *' ).replaceText( |
187 | | - new RegExp( "(\\W)*" + RegExp.escape( words[i] ) + "(\\W)*", "g" ), |
188 | | - function( str ) { |
189 | | - return '<span class="notranslate">' + str + '</span>'; |
190 | | - } |
191 | | - ); |
192 | | - } |
193 | | - } |
194 | | - |
195 | | - /** |
196 | | - * Finds the special words in the page contents by getting the contents of all |
197 | | - * notranslate spans and pushing them onto an array. |
198 | | - * |
199 | | - * @returns {Array} |
200 | | - */ |
201 | | - function getSpecialWords() { |
202 | | - var words = []; |
203 | | - |
204 | | - $.each($( 'span.notranslate' ), function( i, v ) { |
205 | | - words.push( $(v).text() ); |
206 | | - }); |
207 | | - |
208 | | - return words; |
209 | | - } |
210 | | - |
211 | | - /** |
212 | | - * Replaced the special words in the page content by looping over them, |
213 | | - * and checking if there is a matching translation in the provided object. |
214 | | - * |
215 | | - * @param {object} translations |
216 | | - */ |
217 | | - function replaceSpecialWords( translations ) { |
218 | | - $.each($("span.notranslate"), function(i,v) { |
219 | | - var currentText = $(v).text(); |
220 | | - if ( translations[currentText] ) { |
221 | | - $(v).text( translations[currentText] ); |
222 | | - } |
223 | | - }); |
224 | | - } |
225 | | - |
226 | | - /** |
227 | | - * Initiates the remote translation process. |
228 | | - * |
229 | | - * @param {string} sourceLang |
230 | | - * @param {string} targetLang |
231 | | - */ |
232 | | - function initiateRemoteTranslating( sourceLang, targetLang ) { |
233 | | - var translator = new translationService(); |
234 | | - translator.done = handleTranslationCompletion; |
235 | | - ltdebug( 'Initiating remote translation' ); |
236 | | - translator.translateElement( $( '#bodyContent' ), sourceLang, targetLang ); |
237 | | - } |
238 | | - |
239 | | - function handleTranslationCompletion( targetLang ) { |
240 | | - ltdebug( 'Remote translation completed' ); |
241 | | - currentLang = targetLang; |
242 | | - $( '#livetranslatebutton' ).attr( "disabled", false ).text( mediaWiki.msg( 'livetranslate-button-translate' ) ); |
243 | | - $( '#ltrevertbutton' ).css( 'display', 'inline' ); |
244 | | - } |
245 | | - |
246 | | -} ); })(jQuery); |
\ No newline at end of file |
| 44 | +} ); })( jQuery ); |
Index: trunk/extensions/LiveTranslate/includes/ext.lt.ms.js |
— | — | @@ -6,16 +6,15 @@ |
7 | 7 | * @author Jeroen De Dauw <jeroendedauw at gmail dot com> |
8 | 8 | */ |
9 | 9 | |
10 | | -(function( $ ){ window.translationService = function() { |
| 10 | +(function( $, lt ){ window.translationService = function() { |
11 | 11 | |
12 | 12 | var self = this; |
13 | 13 | |
14 | | - this.done = function( targetLang ){}; |
| 14 | + this.done = function(){}; |
15 | 15 | |
16 | 16 | this.runningJobs = 0; |
17 | 17 | this.checkingForIdle = false; |
18 | 18 | this.lastCompletion; |
19 | | -// window.fooz = 0; |
20 | 19 | |
21 | 20 | /** |
22 | 21 | * Determines a chunk to translate of an DOM elements contents and calls the Microsoft Translate API. |
— | — | @@ -29,7 +28,7 @@ |
30 | 29 | * @param {DOM element} element |
31 | 30 | */ |
32 | 31 | this.translateChunk = function( untranslatedsentences, chunks, currentMaxSize, sourceLang, targetLang, element ) { |
33 | | - ltdebug( 'MS: Translating chunk' ); |
| 32 | + lt.debug( 'MS: Translating chunk' ); |
34 | 33 | var remainingPart = false; |
35 | 34 | var partToUse = false; |
36 | 35 | var sentenceCount = 0; |
— | — | @@ -76,7 +75,7 @@ |
77 | 76 | |
78 | 77 | // If the lenght is 0, the element has been translated. |
79 | 78 | if ( chunk.length == 0 ) { |
80 | | - this.handleTranslationCompletion( targetLang ); |
| 79 | + this.handleTranslationCompletion(); |
81 | 80 | return; |
82 | 81 | } |
83 | 82 | |
— | — | @@ -85,7 +84,7 @@ |
86 | 85 | var tailingSpace = ( chunk.length > 1 && chunk.substr( chunk.length - 1, 1 ) == ' ' ) ? ' ' : ''; |
87 | 86 | |
88 | 87 | var chunckTranslationDone = function( translation ) { |
89 | | - ltdebug( 'MS: Translated chunk' ); |
| 88 | + lt.debug( 'MS: Translated chunk' ); |
90 | 89 | |
91 | 90 | if ( translation ) { |
92 | 91 | chunks.push( leadingSpace + translation + tailingSpace ); |
— | — | @@ -100,8 +99,8 @@ |
101 | 100 | window.textAreaElement.innerHTML = chunks.join( '' ); // This is a hack to decode quotes. |
102 | 101 | element.replaceData( 0, element.length, window.textAreaElement.value ); |
103 | 102 | |
104 | | - ltdebug( 'MS: Translated element' ); |
105 | | - self.handleTranslationCompletion( targetLang ); |
| 103 | + lt.debug( 'MS: Translated element' ); |
| 104 | + self.handleTranslationCompletion(); |
106 | 105 | } |
107 | 106 | else { |
108 | 107 | // If there is more work to do, move on to the next chunk. |
— | — | @@ -130,17 +129,17 @@ |
131 | 130 | * @param {string} targetLang |
132 | 131 | */ |
133 | 132 | this.translateElement = function( element, sourceLang, targetLang ) { |
134 | | - ltdebug( 'MS: Translating element' ); |
| 133 | + lt.debug( 'MS: Translating element' ); |
135 | 134 | this.runningJobs++; |
136 | 135 | |
137 | 136 | var maxChunkLength = 500; |
138 | 137 | |
139 | 138 | element.contents().each( function() { |
140 | | - ltdebug( 'MS: Element conent item' ); |
| 139 | + lt.debug( 'MS: Element conent item' ); |
141 | 140 | |
142 | 141 | // If it's a text node, then translate it. |
143 | 142 | if ( this.nodeType == 3 && typeof this.data === 'string' && $.trim( this.data ).length > 0 ) { |
144 | | - ltdebug( 'MS: Found content node' ); |
| 143 | + lt.debug( 'MS: Found content node' ); |
145 | 144 | |
146 | 145 | self.runningJobs++; |
147 | 146 | |
— | — | @@ -170,28 +169,28 @@ |
171 | 170 | && !$( this ).hasClass( 'notranslate' ) && !$( this ).hasClass( 'printfooter' ) |
172 | 171 | && $( this ).text().length > 0 ) { |
173 | 172 | |
174 | | - ltdebug( 'MS: Found child node' ); |
| 173 | + lt.debug( 'MS: Found child node' ); |
175 | 174 | self.translateElement( $( this ), sourceLang, targetLang ); |
176 | 175 | } |
177 | 176 | else { |
178 | | - ltdebug( 'MS: Found ignore node' ); |
| 177 | + lt.debug( 'MS: Found ignore node' ); |
179 | 178 | } |
180 | 179 | } ); |
181 | 180 | |
182 | | - this.handleTranslationCompletion( targetLang ); |
| 181 | + this.handleTranslationCompletion(); |
183 | 182 | } |
184 | 183 | |
185 | | - this.invokeDone = function( targetLang ) { |
186 | | - ltdebug( 'MS: translation process done' ); |
187 | | - ltdebug( this.runningJobs ); |
| 184 | + this.invokeDone = function() { |
| 185 | + lt.debug( 'MS: translation process done' ); |
| 186 | + lt.debug( this.runningJobs ); |
188 | 187 | this.runningJobs = 0; |
189 | | - this.done( targetLang ); |
| 188 | + this.done(); |
190 | 189 | } |
191 | 190 | |
192 | 191 | this.checkForIdleness = function( targetLang, hits ) { |
193 | | - ltdebug( 'MS: checkForIdleness' ); |
194 | | - ltdebug( 'MS: last + 250: ' + ( this.lastCompletion + 250 ) ); |
195 | | - ltdebug( 'MS: now: ' + (new Date()).getTime() ); |
| 192 | + lt.debug( 'MS: checkForIdleness' ); |
| 193 | + lt.debug( 'MS: last + 250: ' + ( this.lastCompletion + 250 ) ); |
| 194 | + lt.debug( 'MS: now: ' + (new Date()).getTime() ); |
196 | 195 | |
197 | 196 | if ( this.lastCompletion + 250 < (new Date()).getTime() ) { |
198 | 197 | hits++; |
— | — | @@ -212,10 +211,8 @@ |
213 | 212 | * Should be called every time a DOM element has been translated. |
214 | 213 | * By use of the runningJobs var, completion of the translation process is detected, |
215 | 214 | * and further handled by this function. |
216 | | - * |
217 | | - * @param {string} targetLang |
218 | 215 | */ |
219 | | - this.handleTranslationCompletion = function( targetLang ) { |
| 216 | + this.handleTranslationCompletion = function() { |
220 | 217 | if ( !this.checkingForIdle && this.runningJobs > 1 && this.runningJobs < 20 ) { |
221 | 218 | this.checkingForIdle = true; |
222 | 219 | setTimeout( function() { self.checkForIdleness( targetLang, 0 ); }, 250 ); |
— | — | @@ -226,9 +223,9 @@ |
227 | 224 | } |
228 | 225 | |
229 | 226 | if ( !--this.runningJobs ) { |
230 | | - this.invokeDone( targetLang ); |
| 227 | + this.invokeDone(); |
231 | 228 | } |
232 | 229 | } |
233 | 230 | |
234 | 231 | |
235 | | -}; })( jQuery ); |
\ No newline at end of file |
| 232 | +}; })( jQuery, window.liveTranslate ); |
\ No newline at end of file |
Index: trunk/extensions/LiveTranslate/includes/ext.lt.tm.js |
— | — | @@ -4,131 +4,377 @@ |
5 | 5 | * |
6 | 6 | * @licence GNU GPL v3 or later |
7 | 7 | * @author Jeroen De Dauw <jeroendedauw at gmail dot com> |
| 8 | + * |
| 9 | + * This file holds the lt.memory class. |
8 | 10 | */ |
9 | 11 | |
10 | | -window.liveTranslate = new Object(); |
11 | | - |
12 | | -( function( mw, lt ) { |
| 12 | +( function( $, lt ) { |
13 | 13 | |
| 14 | + /** |
| 15 | + * An lt.memory acts as abstraction layer via which special words |
| 16 | + * (words for which a translation is specified in the wiki) and |
| 17 | + * translations of those special words can be accessed. It takes |
| 18 | + * care of obtaining these via the API and utilizing caching in |
| 19 | + * memory and LocalStorage where appropriate and possible. |
| 20 | + * |
| 21 | + * @constructor |
| 22 | + * @since 1.2 |
| 23 | + */ |
14 | 24 | lt.memory = function( options ) { |
15 | | - var _this = this; |
| 25 | + // Words to not translate using the translation services. |
| 26 | + // { en: [foo, bar, baz], nl: [ ... ] } |
| 27 | + this.words = {}; |
16 | 28 | |
17 | | - this.translations = false; |
| 29 | + // List of translations. |
| 30 | + // { en: { nl: { foo_en: foo_nl }, de: { bar_en: bar_de } }, nl: { ... } } |
| 31 | + this.translations = {}; |
| 32 | + |
| 33 | + this.options = { |
| 34 | + lsprefix: 'mw_lt_' |
| 35 | + }; |
| 36 | + |
| 37 | + this.cleanedLS = false; |
| 38 | + |
| 39 | + $.extend( this.options, options ); |
18 | 40 | }; |
19 | 41 | |
| 42 | + lt.memory.singleton = function() { |
| 43 | + if ( typeof lt.memoryinstance === 'undefined' ) { |
| 44 | + lt.memoryinstance = new lt.memory(); |
| 45 | + } |
| 46 | + |
| 47 | + return lt.memoryinstance; |
| 48 | + } |
| 49 | + |
20 | 50 | lt.memory.prototype = { |
21 | | - |
| 51 | + |
| 52 | + /** |
| 53 | + * Returns if LocalStorage can be used or not. |
| 54 | + * |
| 55 | + * @protected |
| 56 | + * @since 1.2 |
| 57 | + * |
| 58 | + * @return {boolean} |
| 59 | + */ |
22 | 60 | canUseLocalStorage: function() { |
23 | 61 | try { |
24 | 62 | return 'localStorage' in window && window['localStorage'] !== null; |
25 | 63 | } catch ( e ) { |
26 | 64 | return false; |
27 | 65 | } |
28 | | - } |
29 | | - |
30 | | - hasLocalStorage: function() { |
31 | | - if ( !_this.canUseLocalStorage() ) { |
32 | | - return false; |
33 | | - } |
| 66 | + }, |
| 67 | + |
| 68 | + hasLocalStorage: function( itemName ) { |
| 69 | + return localStorage.getItem( this.options.lsprefix + itemName ) !== null; |
| 70 | + }, |
| 71 | + |
| 72 | + obtainFromLS: function( itemName ) { |
| 73 | + return JSON.parse( localStorage.getItem( this.options.lsprefix + itemName ) ); |
| 74 | + }, |
| 75 | + |
| 76 | + writeToLS: function( itemName, object ) { |
| 77 | + localStorage.setItem( this.options.lsprefix + itemName, JSON.stringify( object ) ) |
| 78 | + }, |
| 79 | + |
| 80 | + removeFromLS: function( itemName ) { |
| 81 | + lt.debug( 'tm: removing item from LS: ' + this.options.lsprefix + itemName ); |
| 82 | + localStorage.removeItem( this.options.lsprefix + itemName ); |
| 83 | + }, |
| 84 | + |
| 85 | + getMemoryHashes: function( args, callback ) { |
| 86 | + var defaults = { |
| 87 | + apiPath: window.wgScriptPath |
| 88 | + }; |
34 | 89 | |
35 | | - var memory = localStorage.getItem( 'lt_memory' ); |
36 | | - debugger; |
37 | | - return memory; |
38 | | - } |
39 | | - |
40 | | - getMemoryHashes: function( callback ) { |
| 90 | + args = $.extend( {}, defaults, args ); |
| 91 | + |
41 | 92 | $.getJSON( |
42 | | - wgScriptPath + '/api.php', |
| 93 | + args.apiPath + '/api.php', |
43 | 94 | { |
44 | | - 'action': 'translationmemories', |
| 95 | + 'action': 'query', |
| 96 | + 'list': 'translationmemories', |
45 | 97 | 'format': 'json', |
46 | | - 'props': 'version_hash' |
| 98 | + 'qtmprops': 'version_hash' |
47 | 99 | }, |
48 | 100 | function( data ) { |
49 | 101 | if ( data.memories ) { |
50 | 102 | callback( data.memories ); |
51 | 103 | } |
52 | 104 | else { |
| 105 | + lt.debug( 'tm: failed to fetch memory hash' ); |
53 | 106 | // TODO |
54 | 107 | } |
55 | 108 | } |
56 | | - ); |
57 | | - } |
| 109 | + ); |
| 110 | + }, |
58 | 111 | |
59 | | - localStorageIsValid: function() { |
60 | | - if ( !_this.hasLocalStorage() ) { |
| 112 | + hashesMatch: function( a, b ) { |
| 113 | + if ( a === null || b === null ) { |
61 | 114 | return false; |
62 | 115 | } |
63 | 116 | |
64 | | - _this.getMemoryHashes(); |
65 | | - } |
| 117 | + for ( i in a ) { |
| 118 | + if ( b[i] ) { |
| 119 | + if ( a[i].memory_version_hash !== b[i].memory_version_hash ) { |
| 120 | + return false; |
| 121 | + } |
| 122 | + } |
| 123 | + else { |
| 124 | + return false; |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + for ( i in b ) { |
| 129 | + if ( !a[i] ) { |
| 130 | + return false; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + return true; |
| 135 | + }, |
66 | 136 | |
67 | | - obtainTranslationsFromServer: function() { |
| 137 | + cleanLocalStorage: function( options, callback ) { |
| 138 | + options = $.extend( {}, { forceCheck: false }, options ); |
| 139 | + |
| 140 | + if ( this.cleanedLS && !options.forceCheck ) { |
| 141 | + callback(); |
| 142 | + } |
| 143 | + else { |
| 144 | + var _this = this; |
| 145 | + lt.debug( 'tm: getting memory hashes' ); |
| 146 | + |
| 147 | + this.getMemoryHashes( |
| 148 | + {}, |
| 149 | + function( memories ) { |
| 150 | + if ( _this.hashesMatch( _this.obtainFromLS( 'hash' ), memories ) ) { |
| 151 | + lt.debug( 'tm: memory hashes obtained: match' ); |
| 152 | + } |
| 153 | + else { |
| 154 | + _this.removeFromLS( 'words' ); |
| 155 | + _this.removeFromLS( 'translations' ); |
| 156 | + _this.writeToLS( 'hash', memories ); |
| 157 | + lt.debug( 'tm: memory hashes obtained: no match; LS cleared' ); |
| 158 | + } |
| 159 | + |
| 160 | + _this.cleanedLS = true; |
| 161 | + callback(); |
| 162 | + } |
| 163 | + ); |
| 164 | + } |
| 165 | + }, |
| 166 | + |
| 167 | + obtainTranslationsFromServer: function( args, callback ) { |
| 168 | + var defaults = { |
| 169 | + offset: -1, |
| 170 | + words: [], |
| 171 | + language: 'en', |
| 172 | + apiPath: window.wgScriptPath |
| 173 | + }; |
| 174 | + |
| 175 | + args = $.extend( {}, defaults, args ); |
| 176 | + |
| 177 | + lt.debug( 'tm: obtaining translations from server' ); |
| 178 | + |
| 179 | + $.getJSON( |
| 180 | + args.apiPath + '/api.php', |
| 181 | + { |
| 182 | + 'action': 'livetranslate', |
| 183 | + 'format': 'json', |
| 184 | + 'from': args.source, |
| 185 | + 'to': args.target, |
| 186 | + 'words': args.words.join( '|' ) |
| 187 | + }, |
| 188 | + function( data ) { |
| 189 | + if ( data.translations ) { |
| 190 | + lt.debug( 'tm: obtained translations from server' ); |
| 191 | + callback( data.translations ); |
| 192 | + } |
| 193 | + else { |
| 194 | + // TODO |
| 195 | + } |
| 196 | + } |
| 197 | + ); |
| 198 | + }, |
| 199 | + |
| 200 | + obtainWordsFromServer: function( args, callback ) { |
| 201 | + var _this = this; |
| 202 | + |
| 203 | + var defaults = { |
| 204 | + offset: -1, |
| 205 | + allWords: [], |
| 206 | + language: 'en', |
| 207 | + apiPath: window.wgScriptPath |
| 208 | + }; |
| 209 | + |
| 210 | + args = $.extend( {}, defaults, args ); |
| 211 | + |
| 212 | + lt.debug( 'tm: obtaining special words from server, offset ' + args.offset ); |
| 213 | + |
68 | 214 | var requestArgs = { |
69 | 215 | 'action': 'query', |
70 | 216 | 'format': 'json', |
71 | 217 | 'list': 'livetranslate', |
72 | | - 'ltlanguage': currentLang |
| 218 | + 'ltlanguage': args.language |
73 | 219 | }; |
74 | 220 | |
75 | | - if ( offset > 0 ) { |
76 | | - requestArgs['ltcontinue'] = offset; |
| 221 | + if ( args.offset > 0 ) { |
| 222 | + requestArgs['ltcontinue'] = args.offset; |
77 | 223 | } |
78 | 224 | |
79 | 225 | $.getJSON( |
80 | | - wgScriptPath + '/api.php', |
| 226 | + args.apiPath + '/api.php', |
81 | 227 | requestArgs, |
82 | 228 | function( data ) { |
83 | 229 | if ( data.words ) { |
84 | | - insertNoTranslateTags( data.words ); |
| 230 | + args.allWords.push.apply( args.allWords, data.words ); |
85 | 231 | } |
86 | | - else if ( data.error && data.error.info ) { |
87 | | - alert( data.error.info ); |
88 | | - } |
89 | 232 | else { |
90 | | - for ( i in data ) { |
91 | | - alert( mediaWiki.msg( 'livetranslate-dictionary-error' ) ); |
92 | | - break; |
93 | | - } |
| 233 | + // TODO |
94 | 234 | } |
95 | 235 | |
96 | | - originalHtml = $( '#bodyContent' ).html(); |
97 | | - |
98 | 236 | if ( data['query-continue'] ) { |
99 | | - obtainAndInsertTranslations( data['query-continue'].livetranslate.ltcontinue ); |
| 237 | + _this.obtainWordsFromServer( |
| 238 | + { |
| 239 | + offset: data['query-continue'].livetranslate.ltcontinue, |
| 240 | + language: args.language, |
| 241 | + allWords: args.allWords |
| 242 | + }, |
| 243 | + callback |
| 244 | + ); |
100 | 245 | } |
101 | 246 | else { |
102 | | - initiateTranslating(); |
| 247 | + lt.debug( 'tm: obtained special words from server' ); |
| 248 | + callback( args.allWords ); |
103 | 249 | } |
104 | 250 | } |
105 | 251 | ); |
106 | | - } |
| 252 | + }, |
107 | 253 | |
108 | | - obtainTranslationsFromLS: function() { |
109 | | - return JSON.parse( localStorage.getItem( 'lt_memory' ) ); |
110 | | - } |
| 254 | + /** |
| 255 | + * |
| 256 | + */ |
| 257 | + getTranslations: function( args, callback ) { |
| 258 | + var _this = this; |
| 259 | + |
| 260 | + var defaults = { |
| 261 | + source: 'en', |
| 262 | + target: 'en', |
| 263 | + words: [] |
| 264 | + }; |
| 265 | + |
| 266 | + var translations = {}; |
| 267 | + |
| 268 | + args = $.extend( {}, defaults, args ); |
| 269 | + |
| 270 | + if ( !this.translations[args.source] ) { |
| 271 | + this.translations[args.source] = {}; |
| 272 | + } |
| 273 | + |
| 274 | + var mergeInTranslations = function( words ) { |
| 275 | + lt.debug( 'tm: merging in translations' ); |
| 276 | + var wordsAdded = []; |
| 277 | + |
| 278 | + $.each( args.words, function( index, word ) { |
| 279 | + if ( !!words[word] ) { |
| 280 | + translations[word] = words[word]; |
| 281 | + _this.translations[args.source][args.target][word] = words[word]; |
| 282 | + wordsAdded.push( index ); |
| 283 | + } |
| 284 | + } ); |
| 285 | + |
| 286 | + args.words = $.grep( args.words, function( e, index ) { |
| 287 | + return $.inArray( index, wordsAdded ) === -1; |
| 288 | + } ); |
| 289 | + }; |
| 290 | + |
| 291 | + var getFromServer = function() { |
| 292 | + _this.obtainTranslationsFromServer( args, function( obtainedTranslations ) { |
| 293 | + mergeInTranslations( obtainedTranslations ); |
| 294 | + |
| 295 | + if ( _this.canUseLocalStorage() ) { |
| 296 | + _this.writeToLS( 'translations', _this.translations ); |
| 297 | + lt.debug( 'tm: wrote translations to LS' ); |
| 298 | + } |
| 299 | + |
| 300 | + callback( translations ); |
| 301 | + } ); |
| 302 | + }; |
| 303 | + |
| 304 | + if ( this.translations[args.source][args.target] ) { |
| 305 | + mergeInTranslations( this.translations[args.source][args.target] ); |
| 306 | + } |
| 307 | + else { |
| 308 | + this.translations[args.source][args.target] = {}; |
| 309 | + } |
| 310 | + |
| 311 | + if ( args.words.length == 0 ) { |
| 312 | + callback( translations ); |
| 313 | + } |
| 314 | + else { |
| 315 | + if ( this.canUseLocalStorage() ) { |
| 316 | + this.cleanLocalStorage( {}, function() { |
| 317 | + var lsTranslations = _this.obtainFromLS( 'translations' ); |
| 318 | + |
| 319 | + if ( lsTranslations !== null && lsTranslations[args.source] && lsTranslations[args.source][args.target] ) { |
| 320 | + mergeInTranslations( lsTranslations[args.source][args.target] ); |
| 321 | + } |
| 322 | + |
| 323 | + if ( args.words.length == 0 ) { |
| 324 | + callback( translations ); |
| 325 | + } |
| 326 | + else { |
| 327 | + getFromServer(); |
| 328 | + } |
| 329 | + } ); |
| 330 | + } |
| 331 | + else { |
| 332 | + getFromServer(); |
| 333 | + } |
| 334 | + } |
| 335 | + }, |
111 | 336 | |
112 | | - writeTranslationsToLS: function() { |
113 | | - localStorage.setItem( 'lt_memory', JSON.stringify( _this.translations ) ) |
114 | | - } |
115 | | - |
116 | | - getTranslations: function() { |
117 | | - if ( _this.translations === false ) { |
118 | | - if ( _this.canUseLocalStorage() && _this.localStorageIsValid() ) { |
119 | | - _this.translations = _this.obtainTranslationsFromLS(); |
| 337 | + getSpecialWords: function( language, callback ) { |
| 338 | + var _this = this; |
| 339 | + |
| 340 | + var getFromServer = function() { |
| 341 | + _this.obtainWordsFromServer( |
| 342 | + { |
| 343 | + language: language |
| 344 | + }, |
| 345 | + function( words ) { |
| 346 | + _this.words[language] = words; |
| 347 | + |
| 348 | + if ( _this.canUseLocalStorage() ) { |
| 349 | + _this.writeToLS( 'words', _this.words ); |
| 350 | + lt.debug( 'tm: wrote special words to LS' ); |
| 351 | + } |
| 352 | + |
| 353 | + callback( words ); |
| 354 | + } |
| 355 | + ); |
| 356 | + }; |
| 357 | + |
| 358 | + if ( this.words[language] ) { |
| 359 | + callback( this.words[language] ); |
| 360 | + } |
| 361 | + else { |
| 362 | + if ( this.canUseLocalStorage() ) { |
| 363 | + this.cleanLocalStorage( {}, function() { |
| 364 | + var words = _this.obtainFromLS( 'words' ); |
| 365 | + |
| 366 | + if ( words !== null && words[language] ) { |
| 367 | + callback( words[language] ); |
| 368 | + } |
| 369 | + else { |
| 370 | + getFromServer(); |
| 371 | + } |
| 372 | + } ); |
120 | 373 | } |
121 | 374 | else { |
122 | | - _this.translations = _this.obtainTranslationsFromServer(); |
123 | | - |
124 | | - if ( _this.canUseLocalStorage() ) { |
125 | | - _this.writeTranslationsToLS(); |
126 | | - } |
| 375 | + getFromServer(); |
127 | 376 | } |
128 | 377 | } |
129 | | - |
130 | | - return _this.translations; |
131 | 378 | } |
132 | | - |
133 | 379 | }; |
134 | 380 | |
135 | | -}) ( window.mediaWiki, window.liveTranslate ); |
| 381 | +}) ( jQuery, window.liveTranslate ); |
Index: trunk/extensions/LiveTranslate/includes/jquery.replaceText.js |
— | — | @@ -0,0 +1,23 @@ |
| 2 | +/* |
| 3 | + * jQuery replaceText - v1.1 - 11/21/2009 |
| 4 | + * http://benalman.com/projects/jquery-replacetext-plugin/ |
| 5 | + * |
| 6 | + * Copyright (c) 2009 "Cowboy" Ben Alman |
| 7 | + * Dual licensed under the MIT and GPL licenses. |
| 8 | + * http://benalman.com/about/license/ |
| 9 | + */ |
| 10 | +( function ( $ ) { |
| 11 | + $.fn.replaceText=function(b,a,c){return this.each(function(){var f=this.firstChild,g,e,d=[];if(f){do{if(f.nodeType===3){g=f.nodeValue;e=g.replace(b,a);if(e!==g){if(!c&&/</.test(e)){$(f).before(e);d.push(f)}else{f.nodeValue=e}}}}while(f=f.nextSibling)}d.length&&$(d).remove()})}; |
| 12 | +} )( jQuery ); |
| 13 | + |
| 14 | +/** |
| 15 | + * Regex text escaping function. |
| 16 | + * Borrowed from http://simonwillison.net/2006/Jan/20/escape/ |
| 17 | + */ |
| 18 | +RegExp.escape = function( text ) { |
| 19 | + if ( !arguments.callee.sRE ) { |
| 20 | + var specials = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\' ]; |
| 21 | + arguments.callee.sRE = new RegExp( '(\\' + specials.join('|\\') + ')', 'g' ); |
| 22 | + } |
| 23 | + return text.replace(arguments.callee.sRE, '\\$1'); |
| 24 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/LiveTranslate/includes/jquery.replaceText.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 25 | + native |
Index: trunk/extensions/LiveTranslate/includes/LiveTranslate_Functions.php |
— | — | @@ -133,15 +133,15 @@ |
134 | 134 | } |
135 | 135 | |
136 | 136 | /** |
137 | | - * Returns the HTML for a language selector. |
| 137 | + * Returns a list of languages that can be translated to. |
138 | 138 | * |
139 | | - * @since 0.1 |
| 139 | + * @since 1.2 |
140 | 140 | * |
141 | 141 | * @param string $currentLang |
142 | 142 | * |
143 | | - * @return string |
| 143 | + * @return array |
144 | 144 | */ |
145 | | - public static function getLanguageSelector( $currentLang ) { |
| 145 | + public static function getLanguages( $currentLang ) { |
146 | 146 | global $wgUser, $wgLanguageCode, $egLiveTranslateLanguages; |
147 | 147 | |
148 | 148 | $allowedLanguages = array_merge( $egLiveTranslateLanguages, array( $currentLang ) ); |
— | — | @@ -155,7 +155,7 @@ |
156 | 156 | |
157 | 157 | if ( array_key_exists( $userLang, $languages ) && in_array( $userLang, $allowedLanguages ) ) { |
158 | 158 | $targetLang = $userLang; |
159 | | - } |
| 159 | + } |
160 | 160 | } |
161 | 161 | |
162 | 162 | $options = array(); |
— | — | @@ -167,39 +167,11 @@ |
168 | 168 | $options[$display] = $code; |
169 | 169 | } |
170 | 170 | } |
171 | | - |
172 | | - $languageSelector = new HTMLSelectField( array( |
173 | | - 'id' => 'livetranslatelang', |
174 | | - 'fieldname' => 'language', |
175 | | - 'options' => $options |
176 | | - ) ); |
177 | 171 | |
178 | | - return $languageSelector->getInputHTML( $targetLang ); |
| 172 | + return $options; |
179 | 173 | } |
180 | 174 | |
181 | 175 | /** |
182 | | - * Gets a list of all available languages. |
183 | | - * |
184 | | - * @since 0.1 |
185 | | - * |
186 | | - * @return array |
187 | | - */ |
188 | | - public static function getAvailableLanguages() { |
189 | | - $dbr = wfGetDB( DB_SLAVE ); |
190 | | - |
191 | | - $destinationLangs = array(); |
192 | | - |
193 | | - // TODO: fix index |
194 | | - $res = $dbr->query( 'SELECT DISTINCT word_language FROM ' . $dbr->tableName( 'live_translate' ) ); |
195 | | - |
196 | | - while ( $lang = $dbr->fetchObject( $res ) ) { |
197 | | - $destinationLangs[] = $lang->word_language; |
198 | | - } |
199 | | - |
200 | | - return $destinationLangs; |
201 | | - } |
202 | | - |
203 | | - /** |
204 | 176 | * Returns a PHP version of the JavaScript google.language.Languages enum of the Google Translate v1 API. |
205 | 177 | * @see https://code.google.com/apis/language/translate/v1/getting_started.html#LangNameArray |
206 | 178 | * |
— | — | @@ -207,7 +179,7 @@ |
208 | 180 | * |
209 | 181 | * @return array LANGUAGE_NAME => 'code' |
210 | 182 | */ |
211 | | - public static function getGTSupportedLanguages() { //Language::getLanguageNames( false ); |
| 183 | + public static function getGTSupportedLanguages() { |
212 | 184 | return array( |
213 | 185 | 'AFRIKAANS' => 'af', |
214 | 186 | 'ALBANIAN' => 'sq', |
Property changes on: trunk/extensions/LiveTranslate |
___________________________________________________________________ |
Added: svn:ignore |
215 | 187 | + .git |
.gitignore |