Yaron Koren has submitted this change and it was merged.
Change subject: Adds auto translate feature.
......................................................................
Adds auto translate feature.
Auto translates the text if
1) query string contains language=xx
2) 'lt_user_lang' cookie is set
3) user has specified a language in his preferences.
Sets a cookie on manual tranlation and on occurance of a query string with
language=xx
Complete functionability can be disabled by setting $egAutoTranslate to
false.
Change-Id: I28677e54d10a1c2073e3b063033140cdbf20ba41
---
M LiveTranslate.hooks.php
M LiveTranslate.php
M LiveTranslate_Settings.php
M includes/LiveTranslate_Functions.php
M includes/jquery.liveTranslate.js
5 files changed, 239 insertions(+), 149 deletions(-)
Approvals:
Yaron Koren: Verified; Looks good to me, approved
diff --git a/LiveTranslate.hooks.php b/LiveTranslate.hooks.php
index 499db9e..95c4512 100644
--- a/LiveTranslate.hooks.php
+++ b/LiveTranslate.hooks.php
@@ -26,7 +26,7 @@
public static function onArticleViewHeader( Article &$article,
&$outputDone, &$useParserCache ) {
global $egLiveTranslateLanguages;
$egLiveTranslateLanguages = array_unique(
$egLiveTranslateLanguages );
-
+
$title = $article->getTitle();
$currentLang = LiveTranslateFunctions::getCurrentLang( $title );
@@ -155,17 +155,21 @@
global $wgOut;
$langs = array();
-
- foreach ( LiveTranslateFunctions::getLanguages( $currentLang )
as $label => $code ) {
+ $translateLanguages = LiveTranslateFunctions::getLanguages(
$currentLang );
+
+ foreach ( $translateLanguages as $label => $code ) {
$langs[] = "$code|$label";
}
+ $autoTranslateLang =
LiveTranslateFunctions::getAutoTranslateLang( $currentLang );
+
$wgOut->addHTML(
Html::rawElement(
'div',
array(
'id' => 'livetranslatediv',
'sourcelang' => $currentLang,
- 'languages' => implode( '||', $langs )
+ 'languages' => implode( '||', $langs ),
+ 'autolang' => in_array(
$autoTranslateLang, $translateLanguages ) ? $autoTranslateLang : $currentLang
)
)
);
@@ -213,7 +217,7 @@
'memory_id',
$egLiveTranslateIP .
'/sql/LT_addTMField.sql'
);
-
+
$wgExtNewFields[] = array(
'live_translate_memories',
'memory_version_hash',
@@ -249,7 +253,7 @@
$egLiveTranslateIP .
'/sql/LT_addTMField.sql',
true
) );
-
+
$updater->addExtensionUpdate( array(
'addField',
'live_translate_memories',
@@ -322,9 +326,12 @@
return true;
}
- public static function onOutputPageParserOutput( $outputpage,
$parseroutput ) {
+ public static function onOutputPageParserOutput( OutputPage &$out,
ParserOutput $parseroutput ) {
+ if ( $out->getRequest()->getVal( 'language', '' ) !== '' ){ //
check URL to set cookies
+ LiveTranslateFunctions::setAutoTranslationCookie(
$out->getRequest()->getVal( 'language' ) );
+ }
+
$magicWords = isset( $parseroutput->mLTMagicWords ) ?
$parseroutput->mLTMagicWords : array();
return true;
}
-
}
diff --git a/LiveTranslate.php b/LiveTranslate.php
index 4cd421a..2a38c65 100644
--- a/LiveTranslate.php
+++ b/LiveTranslate.php
@@ -2,7 +2,7 @@
/**
* Initialization file for the Live Translate extension.
- *
+ *
* Documentation:
http://www.mediawiki.org/wiki/Extension:Live_Translate
* Support
http://www.mediawiki.org/wiki/Extension_talk:Live_Translate
* Source code:
http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/LiveTranslate
@@ -95,7 +95,7 @@
'remoteExtPath' => 'LiveTranslate',
'group' => 'ext.livetranslate'
);
-
+
$wgResourceModules['ext.livetranslate'] = $moduleTemplate + array(
'scripts' => array(
'includes/jquery.replaceText.js',
@@ -107,13 +107,13 @@
'dependencies' => array( 'jquery'/*, 'jquery.ui.button'*/ ),
'messages' => $egLTJSMessages
);
-
+
$wgResourceModules['ext.lt.google'] = $moduleTemplate + array(
'scripts' => array( 'includes/ext.lt.google.js' ),
'dependencies' => array( 'ext.livetranslate' ),
'messages' => array()
);
-
+
$wgResourceModules['ext.lt.ms'] = $moduleTemplate + array(
'scripts' => array( 'includes/ext.lt.ms.js' ),
'dependencies' => array( 'ext.livetranslate' ),
@@ -123,7 +123,7 @@
/**
* Enum for translation memory types.
- *
+ *
* @since 0.4
*/
define( 'TMT_LTF', 0 );
@@ -132,7 +132,7 @@
/**
* Enum for translation services.
- *
+ *
* @since 1.1
*/
define( 'LTS_GOOGLE', 0 );
diff --git a/LiveTranslate_Settings.php b/LiveTranslate_Settings.php
index 30be8ea..6c367bc 100644
--- a/LiveTranslate_Settings.php
+++ b/LiveTranslate_Settings.php
@@ -77,4 +77,7 @@
$egLiveTranslateMSAppId = '';
$egLiveTranslateLanguages[] = 'nl';
-$egLiveTranslateLanguages[] = 'de';
\ No newline at end of file
+$egLiveTranslateLanguages[] = 'de';
+
+# Auto-translation enabled.
+$egAutoTranslate = true;
diff --git a/includes/LiveTranslate_Functions.php
b/includes/LiveTranslate_Functions.php
index 03d8d70..c60524e 100644
--- a/includes/LiveTranslate_Functions.php
+++ b/includes/LiveTranslate_Functions.php
@@ -11,28 +11,28 @@
* @author Jeroen De Dauw < [email protected] >
*/
final class LiveTranslateFunctions {
-
+
/**
* Loads the needed JavaScript.
* Takes care of non-RL compatibility.
- *
+ *
* @since 0.1
*/
public static function loadJs() {
global $wgOut;
-
+
$wgOut->addScript(
Html::inlineScript(
'var ltDebugMessages = ' . FormatJson::encode(
$GLOBALS['egLiveTranslateDebugJS'] ) . ';'
)
);
-
+
// For backward compatibility with MW < 1.17.
if ( is_callable( array( $wgOut, 'addModules' ) ) ) {
$modules = array( 'ext.livetranslate' );
-
+
switch( $GLOBALS['egLiveTranslateService'] ) {
- case LTS_GOOGLE:
+ case LTS_GOOGLE:
$modules[] = 'ext.lt.google';
$wgOut->addHeadItem(
'ext.lt.google.jsapi',
@@ -48,16 +48,16 @@
);
break;
}
-
+
$wgOut->addModules( $modules );
}
else {
global $egLiveTranslateScriptPath;
-
+
self::addJSLocalisation();
-
+
$wgOut->includeJQuery();
-
+
$wgOut->addHeadItem(
'ext.livetranslate',
Html::linkedScript( $egLiveTranslateScriptPath
. '/includes/jquery.replaceText.js' ) .
@@ -66,14 +66,14 @@
Html::linkedScript( $egLiveTranslateScriptPath
. '/includes/jquery.liveTranslate.js' ) .
Html::linkedScript( $egLiveTranslateScriptPath
. '/includes/ext.lt.load.js' )
);
-
+
switch( $GLOBALS['egLiveTranslateService'] ) {
case LTS_GOOGLE:
$wgOut->addHeadItem(
'ext.lt.google.jsapi',
Html::linkedScript(
'https://www.google.com/jsapi?key=' . htmlspecialchars(
$GLOBALS['egGoogleApiKey'] ) )
);
-
+
$wgOut->addHeadItem(
'ext.lt.google',
Html::linkedScript(
$egLiveTranslateScriptPath . '/includes/ext.lt.google.js' )
@@ -91,32 +91,32 @@
);
break;
}
- }
- }
-
+ }
+ }
+
/**
* Adds the needed JS messages to the page output.
* This is for backward compatibility with pre-RL MediaWiki.
- *
+ *
* @since 0.1
*/
protected static function addJSLocalisation() {
global $egLTJSMessages, $wgOut;
-
+
$data = array();
-
+
foreach ( $egLTJSMessages as $msg ) {
$data[$msg] = wfMsgNoTrans( $msg );
}
-
- $wgOut->addInlineScript( 'var wgLTEMessages = ' .
FormatJson::encode( $data ) . ';' );
+
+ $wgOut->addInlineScript( 'var wgLTEMessages = ' .
FormatJson::encode( $data ) . ';' );
}
-
+
/**
* Returns the language code for a title.
- *
+ *
* @param Title $title
- *
+ *
* @return string
*/
public static function getCurrentLang( Title $title ) {
@@ -126,57 +126,87 @@
if ( $subPage != '' && array_key_exists( $subPage,
Language::getLanguageNames( false ) ) ) {
return $subPage;
}
-
+
global $wgLanguageCode;
return $wgLanguageCode;
}
-
+
/**
* Returns a list of languages that can be translated to.
- *
+ *
* @since 1.2
- *
+ *
* @param string $currentLang
- *
+ *
* @return array
*/
public static function getLanguages( $currentLang ) {
global $wgUser, $wgLanguageCode, $egLiveTranslateLanguages;
-
+
$allowedLanguages = array_merge( $egLiveTranslateLanguages,
array( $currentLang ) );
-
+
$targetLang = $wgLanguageCode;
-
+
$languages = Language::getLanguageNames( false );
-
+
if ( $wgUser->isLoggedIn() ) {
$userLang = $wgUser->getOption( 'language' );
-
+
if ( array_key_exists( $userLang, $languages ) &&
in_array( $userLang, $allowedLanguages ) ) {
$targetLang = $userLang;
}
}
-
+
$options = array();
ksort( $languages );
-
+
foreach ( $languages as $code => $name ) {
if ( in_array( $code, $allowedLanguages ) && $code !=
$currentLang ) {
$display = wfBCP47( $code ) . ' - ' . $name;
- $options[$display] = $code;
+ $options[$display] = $code;
}
}
return $options;
}
-
+
+ /**
+ * Returns the language that wikitext should be auto-translated to, if
$egAutoTranslate is set to true.
+ * Auto-translation happens if the query string contains language= or
the user preference for language,
+ * or even using a cookie set by Live Translate previously.
+ *
+ * @since 1.3
+ *
+ * @param string $currentLang
+ *
+ * @return string Language to auto-translate to
+ */
+ public static function getAutoTranslateLang( $currentLang ) {
+ global $wgRequest, $wgUser, $egAutoTranslate;
+
+ if( !$egAutoTranslate ) {
+ return $currentLang;
+ }
+
+ if ( $wgRequest->getVal( 'language', '' ) !== '' ){ // check URL
+ $autoLang = $wgRequest->getVal( 'language' );
+ } elseif ( isset( $_COOKIE['lt_user_lang'] ) ) { // check
cookies
+ $autoLang = $_COOKIE['lt_user_lang'];
+ } elseif ( $wgUser->isLoggedIn() ) { // check user preference
+ $autoLang = $wgUser->getOption( 'language' );
+ } else {
+ $autoLang = $currentLang;
+ }
+ return $autoLang;
+ }
+
/**
* Returns a PHP version of the JavaScript google.language.Languages
enum of the Google Translate v1 API.
* @see
https://code.google.com/apis/language/translate/v1/getting_started.html#LangNameArray
- *
+ *
* @since 0.1
- *
- * @return array LANGUAGE_NAME => 'code'
+ *
+ * @return array LANGUAGE_NAME => 'code'
*/
public static function getGTSupportedLanguages() {
return array(
@@ -203,7 +233,7 @@
'CZECH' => 'cs',
'DANISH' => 'da',
'DHIVEHI' => 'dv',
- 'DUTCH'=> 'nl',
+ 'DUTCH'=> 'nl',
'ENGLISH' => 'en',
'ESPERANTO' => 'eo',
'ESTONIAN' => 'et',
@@ -289,49 +319,49 @@
'YORUBA' => 'yo',
);
}
-
+
/**
* Returns an array with mapping from input language codes to MediaWiki
language codes.
- *
+ *
* @since 0.4
- *
- * @return array
- */
+ *
+ * @return array
+ */
public static function getInputLangMapping() {
return array(
'en-us' => 'en',
);
}
-
+
/**
* Returns an array with mapping from MediaWiki language codes to
Google Translate language codes.
- *
+ *
* @since 0.4
- *
- * @return array
- */
+ *
+ * @return array
+ */
public static function getOuputLangMapping() {
return array(
'en-us' => 'en',
'en-gb' => 'en',
);
- }
-
+ }
+
/**
* Returns the provided text starting with a letter in toggled case.
* If there is no difference between lowercase and upercase for the
first
* character, false is returned.
- *
+ *
* @since 0.1
- *
+ *
* @param string $text
- *
+ *
* @return mixed
*/
public static function getToggledCase( $text ) {
$isUpper = Language::firstChar( $text) == strtoupper(
Language::firstChar( $text) );
$isLower = Language::firstChar( $text) == strtolower(
Language::firstChar( $text) );
-
+
if ( $isUpper XOR $isLower ) {
$text = $isUpper ? Language::lcfirst( $text ) :
Language::ucfirst( $text );
return $text;
@@ -340,17 +370,17 @@
return false;
}
}
-
+
/**
* Returns the names of the pages containing a translation memory.
- *
+ *
* @since 0.4
- *
+ *
* @return array
*/
public static function getLocalMemoryNames() {
$dbr = wfGetDb( DB_MASTER );
-
+
$res = $dbr->select(
'live_translate_memories',
array( 'memory_location' ),
@@ -360,27 +390,27 @@
);
$names = array();
-
+
foreach ( $res as $tm ) {
$names[] = $tm->memory_location;
}
return $names;
}
-
+
/**
* Returns the type of a translation memory when given it's location.
* If the memory is not found, -1 is returned.
- *
+ *
* @since 0.4
- *
+ *
* @param string $location
- *
+ *
* @return integer
*/
public static function getMemoryType( $location ) {
$dbr = wfGetDb( DB_MASTER );
-
+
$res = $dbr->select(
'live_translate_memories',
array( 'memory_type' ),
@@ -395,22 +425,33 @@
$type = $row->memory_type;
break;
}
-
+
return $type;
}
-
+
/**
* Returns if there is a translation service that can be used or not.
- *
+ *
* @since 1.1.1
- *
+ *
* @return boolean
*/
public static function hasTranslationService() {
global $egLiveTranslateService, $egGoogleApiKey,
$egLiveTranslateMSClientId, $egLiveTranslateMSClientSecret,
$egLiveTranslateMSAppId;
-
+
return ( $egLiveTranslateService == LTS_GOOGLE &&
$egGoogleApiKey != '' )
|| ( $egLiveTranslateService == LTS_MS && ( (
$egLiveTranslateMSClientId != '' && $egLiveTranslateMSClientSecret != '' ) ||
$egLiveTranslateMSAppId != '' ) );
}
-
-}
\ No newline at end of file
+
+ /**
+ * Sets the cookie values for auto translation.
+ *
+ * @since 1.3
+ *
+ * @param string $autoLang
+ */
+ public static function setAutoTranslationCookie( $autoLang ) {
+ setcookie( "lt_user_lang", $autoLang, strtotime( '+5 days' ) );
+ }
+
+}
diff --git a/includes/jquery.liveTranslate.js b/includes/jquery.liveTranslate.js
index be20448..d59f74a 100644
--- a/includes/jquery.liveTranslate.js
+++ b/includes/jquery.liveTranslate.js
@@ -1,13 +1,13 @@
/**
* JavaScript for the Live Translate extension.
* @see http://www.mediawiki.org/wiki/Extension:Live_Translate
- *
+ *
* @licence GNU GPL v3 or later
* @author Jeroen De Dauw <jeroendedauw at gmail dot com>
*/
( function ( $, lt ) { $.fn.liveTranslate = function( options ) {
-
+
/**
* Regex text escaping function.
* Borrowed from http://simonwillison.net/2006/Jan/20/escape/
@@ -19,37 +19,37 @@
}
return text.replace(arguments.callee.sRE, '\\$1');
};
-
+
var _this = this;
-
+
/**
* Start both the local and remote components of the translation
process.
- *
+ *
* @since 1.2
*/
this.doTranslations = function() {
_this.runningJobs = 2;
-
+
_this.doLocalTranslation( _this.completeTranslationProcess );
_this.doRemoteTranslation( _this.completeTranslationProcess );
};
-
+
/**
* Finds and returns the special words in the page by looking
* for spans with notranslate class. This obviously only works
* after these tags have been inserted with insertSpecialWords.
- *
+ *
* @since 1.2
- *
+ *
* @return Array
*/
this.findSpecialWords = function() {
var words = [];
-
+
$.each( $( "span.notranslate" ), function( i, v ) {
words.push( $.trim( $( v ).text() ) );
} );
-
+
return words;
};
@@ -57,9 +57,9 @@
* Does the local transltaions by obtaining the
* translations for the special words and replacing
* them where a translation is available.
- *
+ *
* @since 1.2
- *
+ *
* @param {Function} callback
*/
this.doLocalTranslation = function( callback ) {
@@ -73,22 +73,22 @@
$.each( $( "span.notranslate" ), function( i, v
) {
var currentText = $(v).text();
var trimmedText = $.trim( currentText );
-
+
if ( translations[trimmedText] ) {
$( v ).text(
currentText.replace( trimmedText, translations[trimmedText] ) );
}
});
-
+
callback();
}
);
};
-
+
/**
* Does the remote translation, ie everything not in notranslate spans.
- *
+ *
* @since 1.2
- *
+ *
* @param {Function} callback
*/
this.doRemoteTranslation = function( callback ) {
@@ -102,7 +102,7 @@
* Function to be called once a transslation job has finished.
* Once there are no more running jobs, the state of the translation
* control is updated to translation completion.
- *
+ *
* @since 1.2
*/
this.completeTranslationProcess = function() {
@@ -112,19 +112,19 @@
_this.revertButton.css( 'display', 'inline' );
}
};
-
+
/**
* Inserts notranslate spans around the words specified in the passed
array in the page content.
- *
+ *
* @since 1.2
- *
+ *
* @param {Array} words
*/
this.insertSpecialWords = function( words ) {
lt.debug( 'inserting special words' );
-
+
for ( i in words ) {
- $( '#bodyContent *' ).replaceText(
+ $( '#bodyContent *' ).replaceText(
new RegExp( "(\\W)*" + RegExp.escape( words[i]
) + "(\\W)*", "g" ),
function( str ) {
return '<span class="notranslate">' +
str + '</span>';
@@ -132,12 +132,12 @@
);
}
};
-
+
/**
* Obtain the special words and wrap occurrences of them into
notranslate spans.
- *
+ *
* @since 1.2
- *
+ *
* @param {Function} callback
*/
this.obatinAndInsetSpecialWords = function( callback ) {
@@ -145,15 +145,15 @@
_this.memory.getSpecialWords( _this.currentLang, function(
specialWords ) {
_this.specialWords = specialWords;
_this.insertSpecialWords( specialWords );
-
+
callback();
} );
};
-
+
/**
* Setup the translation control.
* Should be called on construction.
- *
+ *
* @since 1.2
*/
this.setup = function() {
@@ -161,96 +161,135 @@
languages: {},
sourcelang: 'en'
};
-
+
$.extend( options, defaults );
-
+
$.each( this.attr( 'languages' ).split( '||' ), function( i,
lang ) {
var parts = lang.split( '|' );
- options.languages[parts[0]] = parts[1];
+ options.languages[parts[0]] = parts[1];
} );
-
+
_this.currentLang = this.attr( 'sourcelang' );
-
+
// For the "show original" feature.
_this.originalHtml = false;
-
+
_this.textAreaElement = document.createElement( 'textarea' );
-
+
_this.uniqueId = Math.random().toString().substring( 2 );
-
+
_this.memory = lt.memory.singleton();
-
+
_this.runningJobs = 0;
-
+
_this.buildHtml();
-
+
_this.bindEvents();
+
+ _this.autoTranslate( _this.currentLang );
};
-
+
/**
* Build up the HTML for the translation control and add it to the DOM
element.
- *
+ *
* @since 1.2
*/
this.buildHtml = function() {
_this.attr( {
style: 'display:inline; float:right'
} ).attr( 'class', 'notranslate' );
-
+
_this.html( lt.msg( 'livetranslate-translate-to' ) );
-
+
_this.select = $( '<select />' ).attr( {
id: 'ltselect' + _this.uniqueId
} );
-
+
for ( langCode in options.languages ) {
_this.select.append( $( '<option />' ).attr( 'value',
langCode ).text( options.languages[langCode] ) );
}
-
+
_this.translateButton = $( '<button />' ).attr( {
id: 'livetranslatebutton' + _this.uniqueId
} ).text( lt.msg( 'livetranslate-button-translate' ) ); //
.button()
-
+
_this.revertButton = $( '<button />' ).attr( {
id: 'ltrevertbutton' + _this.uniqueId,
style: 'display:none'
} ).text( lt.msg( 'livetranslate-button-revert' ) ); //
.button()
-
- _this.append( _this.select, _this.translateButton,
_this.revertButton );
+
+ _this.append( _this.select, _this.translateButton,
_this.revertButton );
};
-
+
/**
* Bind the event handlers to the components of the transltaion control.
- *
+ *
* @since 1.2
*/
this.bindEvents = function() {
_this.translateButton.click( function() {
_this.originalHtml = $( '#bodyContent' ).html();
-
+
$( this ).attr( "disabled", true ).text( lt.msg(
'livetranslate-button-translating' ) );
_this.select.attr( "disabled", true );
-
+
_this.obatinAndInsetSpecialWords( _this.doTranslations
);
+ _this.setCookie();
} );
-
+
_this.revertButton.click( function() {
// Replace the body content wth it's original value.
// This un-binds the jQuery selectors and event
handlers.
$( '#bodyContent' ).html( _this.originalHtml );
-
+
// Re-assing the controls.
_this.select = $( '#ltselect' + _this.uniqueId );
_this.translateButton = $( '#livetranslatebutton' +
_this.uniqueId );
_this.revertButton = $( '#ltrevertbutton' +
_this.uniqueId );
-
+
// Re-bind the events to the controls.
_this.bindEvents();
+ _this.unsetCookie();
} );
};
-
+
+ /**
+ * Auto translates for the user.
+ *
+ * @since 1.3
+ */
+ this.autoTranslate = function( currentLang ) {
+ if ( _this.attr( 'autolang' ) === currentLang ) {
+ return;
+ }
+ _this.select.val( this.attr( 'autolang' ) );
+ _this.translateButton.click();
+ };
+
+ /**
+ * Sets a cookie for this language.
+ *
+ * @since 1.3
+ */
+ this.setCookie = function() {
+ // set a cookie that expires in 5 days
+ document.cookie = "lt_user_lang=" + _this.select.val()
+ + ";expires=" + new Date( new Date().getTime() + 432000000
).toGMTString();
+ };
+
+ /**
+ * Unsets a cookie.
+ *
+ * @since 1.3
+ */
+ this.unsetCookie = function() {
+ // unset livetranslate cookies
+ document.cookie = "lt_user_lang=" + _this.select.val()
+ + ";expires=" + new Date( new Date().getTime() - 432000000
).toGMTString();
+ };
+
this.setup();
-
+
return this;
-
+
}; } )( window.jQuery, window.liveTranslate );
--
To view, visit https://gerrit.wikimedia.org/r/40348
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I28677e54d10a1c2073e3b063033140cdbf20ba41
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/LiveTranslate
Gerrit-Branch: master
Gerrit-Owner: Nischayn22 <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: Nischayn22 <[email protected]>
Gerrit-Reviewer: Yaron Koren <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits