https://www.mediawiki.org/wiki/Special:Code/MediaWiki/113577
Revision: 113577
Author: nikerabbit
Date: 2012-03-11 18:17:27 +0000 (Sun, 11 Mar 2012)
Log Message:
-----------
* Support for shared TTMServer databases was added (only when using $wgConf)
* Output of TTMServer api module has changed
* TTMServer configs can override the link symbol by adding value for symbol in
the config
* Added some simple tests
Modified Paths:
--------------
trunk/extensions/Translate/README
trunk/extensions/Translate/Translate.i18n.php
trunk/extensions/Translate/Translate.php
trunk/extensions/Translate/api/ApiTTMServer.php
trunk/extensions/Translate/scripts/ttmserver-export.php
trunk/extensions/Translate/utils/TTMServer.php
trunk/extensions/Translate/utils/TranslationHelpers.php
Added Paths:
-----------
trunk/extensions/Translate/tests/TTMServerTest.php
Modified: trunk/extensions/Translate/README
===================================================================
--- trunk/extensions/Translate/README 2012-03-11 17:26:07 UTC (rev 113576)
+++ trunk/extensions/Translate/README 2012-03-11 18:17:27 UTC (rev 113577)
@@ -30,6 +30,11 @@
https://translatewiki.net/docs/Translate/html/
== Change log ==
+* 2012-03-11
+- Support for shared TTMServer databases was added
+- Suggestions from different TTMServers are now grouped
+- Output of TTMServer api module has changed
+- TTMServer configs can override the link symbol by adding value for symbol in
the config
* 2012-03-07
- $wgTranslateGroupStructure is no longer used. If you are using aggregate
message
groups, you can remove the old settings and everything still works as
expected.
Modified: trunk/extensions/Translate/Translate.i18n.php
===================================================================
--- trunk/extensions/Translate/Translate.i18n.php 2012-03-11 17:26:07 UTC
(rev 113576)
+++ trunk/extensions/Translate/Translate.i18n.php 2012-03-11 18:17:27 UTC
(rev 113577)
@@ -83,6 +83,7 @@
'translate-edit-committed' => 'Current translation in
software',
'translate-edit-warnings' => 'Warnings about incomplete
translations',
'translate-edit-tmsugs' => 'Suggestions from translation
memories and machine translation',
+ 'translate-edit-tmmatch-source' => 'Translation source text: $1',
'translate-edit-tmmatch' => '$1% match',
'translate-use-suggestion' => 'Replace current translation
with this suggestion.',
Modified: trunk/extensions/Translate/Translate.php
===================================================================
--- trunk/extensions/Translate/Translate.php 2012-03-11 17:26:07 UTC (rev
113576)
+++ trunk/extensions/Translate/Translate.php 2012-03-11 18:17:27 UTC (rev
113577)
@@ -345,8 +345,6 @@
$wgTranslateTranslationServices['TTMServer'] = array(
'database' => false, // Passed to wfGetDB
'cutoff' => 0.75,
- 'timeout-sync' => 0, // Unused
- 'timeout-async' => 0, // Unused
'type' => 'ttmserver',
'public' => false,
);
Modified: trunk/extensions/Translate/api/ApiTTMServer.php
===================================================================
--- trunk/extensions/Translate/api/ApiTTMServer.php 2012-03-11 17:26:07 UTC
(rev 113576)
+++ trunk/extensions/Translate/api/ApiTTMServer.php 2012-03-11 18:17:27 UTC
(rev 113577)
@@ -29,8 +29,8 @@
$result = $this->getResult();
foreach ( $suggestions as $sug ) {
- $result->setContent( $sug, $sug['target'] );
- unset( $sug['target'] );
+ $sug['location'] = $server->expandLocation( $sug );
+ unset( $sug['wiki'] );
$result->addValue( $this->getModuleName(), null, $sug );
}
Modified: trunk/extensions/Translate/scripts/ttmserver-export.php
===================================================================
--- trunk/extensions/Translate/scripts/ttmserver-export.php 2012-03-11
17:26:07 UTC (rev 113576)
+++ trunk/extensions/Translate/scripts/ttmserver-export.php 2012-03-11
18:17:27 UTC (rev 113577)
@@ -22,10 +22,14 @@
* @since 2012-01-26
*/
class TTMServerBootstrap extends Maintenance {
+ /// @var Array Configuration of requested TTMServer
+ protected $config;
+
public function __construct() {
parent::__construct();
$this->mDescription = 'Script to bootstrap TTMServer';
$this->addOption( 'threads', 'Number of threads',
/*required*/false, /*has arg*/true );
+ $this->addOption( 'server', 'Server configuration identifier',
/*required*/false, /*has arg*/true );
$this->setBatchSize( 100 );
$this->start = microtime( true );
}
@@ -38,23 +42,55 @@
}
public function execute() {
- $server = TTMServer::primary();
- if ( $server instanceof FakeTTMServer ) {
+ global $wgTranslateTranslationServices;
+
+ // TTMServer is the id of the enabled-by-default instance
+ $configKey = $this->getOption( 'server', 'TTMServer' );
+ if ( isset( $wgTranslateTranslationServices[$configKey] ) ) {
+ $this->config = $config =
$wgTranslateTranslationServices[$configKey];
+ $server = new TTMServer( $config );
+ } else {
$this->error( "Translation memory is not configured
properly", 1 );
}
$dbw = $server->getDB( DB_MASTER );
- $this->statusLine( 'Deleting sources.. ', 1 );
- $dbw->delete( 'translate_tms', '*', __METHOD__ );
- $this->output( 'translations.. ', 1 );
- $dbw->delete( 'translate_tmt', '*', __METHOD__ );
- $this->output( 'fulltext.. ', 1 );
- $dbw->delete( 'translate_tmf', '*', __METHOD__ );
- $table = $dbw->tableName( 'translate_tmf' );
- $dbw->query( "DROP INDEX tmf_text ON $table" );
- $this->output( 'done!', 1 );
+ if ( $server->isShared() ) {
+ $wiki = array( 'tms_wiki' => wfWikiId() );
+ $this->statusLine( 'Deleting fulltext.. ', 1 );
+ $dbw->deleteJoin(
+ 'translate_tmf', 'translate_tms',
+ 'tmf_sid', 'tms_sid',
+ $wiki, __METHOD__
+ );
+
+ $this->output( 'translations.. ', 1 );
+ $dbw->deleteJoin(
+ 'translate_tmt', 'translate_tms',
+ 'tmt_sid', 'tms_sid',
+ $wiki, __METHOD__
+ );
+
+ $this->output( 'sources.. ', 1 );
+ $dbw->delete( 'translate_tms', $wiki, __METHOD__ );
+ $this->output( 'done!', 1 );
+ } else {
+ // For dedicated databases we can just wipe out
everything,
+ // drop the index during bootstrap and readd it later.
+ $this->statusLine( 'Deleting sources.. ', 1 );
+ $dbw->delete( 'translate_tms', '*', __METHOD__ );
+ $this->output( 'translations.. ', 1 );
+ $dbw->delete( 'translate_tmt', '*', __METHOD__ );
+ $this->output( 'fulltext.. ', 1 );
+ $dbw->delete( 'translate_tmf', '*', __METHOD__ );
+ $table = $dbw->tableName( 'translate_tmf' );
+ $dbw->ignoreErrors( true );
+ $dbw->query( "DROP INDEX tmf_text ON $table" );
+ $dbw->ignoreErrors( false );
+ $this->output( 'done!', 1 );
+ }
+
$this->statusLine( 'Loading groups... ', 2 );
$groups = MessageGroups::singleton()->getGroups();
$this->output( 'done!', 2 );
@@ -99,17 +135,19 @@
pcntl_waitpid( $pid, $status );
}
- $this->statusLine( 'Adding fulltext index...', 9 );
- $table = $dbw->tableName( 'translate_tmf' );
- $dbw->query( "CREATE FULLTEXT INDEX tmf_text ON $table
(tmf_text)" );
- $this->output( ' done!', 9 );
+ if ( !$server->isShared() ) {
+ $this->statusLine( 'Adding fulltext index...', 9 );
+ $table = $dbw->tableName( 'translate_tmf' );
+ $dbw->query( "CREATE FULLTEXT INDEX tmf_text ON $table
(tmf_text)" );
+ $this->output( ' done!', 9 );
+ }
}
protected function exportGroup( MessageGroup $group, $multi = false ) {
// Make sure all existing connections are dead,
// we can't use them in forked children.
LBFactory::destroyInstance();
- $server = TTMServer::primary();
+ $server = new TTMServer( $this->config );
$id = $group->getId();
$sourceLanguage = $group->getSourceLanguage();
Added: trunk/extensions/Translate/tests/TTMServerTest.php
===================================================================
--- trunk/extensions/Translate/tests/TTMServerTest.php
(rev 0)
+++ trunk/extensions/Translate/tests/TTMServerTest.php 2012-03-11 18:17:27 UTC
(rev 113577)
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Tests for TTMServer
+ *
+ * @file
+ * @author Niklas Laxström
+ * @copyright Copyright © 2012, Niklas Laxström
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
2.0 or later
+ */
+
+class TTMServerTest extends MediaWikiTestCase {
+
+ protected $config;
+
+ protected function setUp() {
+ global $wgTranslateTranslationServices;
+ $this->config = $wgTranslateTranslationServices;
+ parent::setUp();
+
+ $wgTranslateTranslationServices = array();
+ $wgTranslateTranslationServices['localtm'] = array(
+ 'url' => 'http://example.com/sandwiki/api.php',
+ 'displayname' => 'example.com',
+ 'cutoff' => 0.75,
+ 'type' => 'ttmserver',
+ );
+
+ $wgTranslateTranslationServices['apitm'] = array(
+ 'url' => 'http://example.com/w/api.php',
+ 'displayname' => 'example.com',
+ 'cutoff' => 0.75,
+ 'timeout-sync' => 4,
+ 'timeout-async' => 4,
+ 'type' => 'remote-ttmserver',
+ );
+
+ $wgTranslateTranslationServices['sharedtm'] = array(
+ 'database' => 'sharedtm',
+ 'cutoff' => 0.75,
+ 'timeout-sync' => 4,
+ 'timeout-async' => 4,
+ 'type' => 'shared-ttmserver',
+ );
+
+ }
+
+ protected function tearDown() {
+ global $wgTranslateTranslationServices;
+ $wgTranslateTranslationServices = $this->config;
+ parent::tearDown();
+ }
+
+ public function testConstruct() {
+ $server = TTMServer::primary();
+ $this->assertEquals(
+ 'FakeTTMServer',
+ get_class( $server ),
+ 'Fake server given when default server is disabled'
+ );
+ global $wgTranslateTranslationServices;
+ $wgTranslateTranslationServices['TTMServer'] = array(
+ 'database' => false, // Passed to wfGetDB
+ 'cutoff' => 0.75,
+ 'type' => 'ttmserver',
+ 'public' => false,
+ );
+ $server = TTMServer::primary();
+ $this->assertEquals(
+ 'TTMServer',
+ get_class( $server ),
+ 'Real server given when default server is enabled'
+ );
+ unset( $wgTranslateTranslationServices['TTMServer'] );
+ }
+
+ public function testFakeTTMServer() {
+ $server = new FakeTTMServer();
+ $this->assertEquals(
+ array(),
+ $server->query( 'en', 'fi', 'daa' ),
+ 'FakeTTMServer returns no suggestions for all queries'
+ );
+
+ $title = new Title();
+ $handle = new MessageHandle( $title );
+
+ $this->assertFalse(
+ $server->update( $handle, 'text' ),
+ 'FakeTTMServer returns false on update'
+ );
+
+ $this->assertFalse(
+ $server->insertSource( $title, 'fi', 'teksti' ),
+ 'FakeTTMServer returns false on insertSource'
+ );
+ }
+
+ /**
+ * @dataProvider dataIsShared
+ */
+ public function testIsShared( $server, $value ) {
+ global $wgTranslateTranslationServices;
+ $server = new TTMServer(
$wgTranslateTranslationServices[$server] );
+ $this->assertEquals( $value, $server->isShared() );
+ }
+
+ public function dataIsShared() {
+ return array(
+ array( 'localtm', false ),
+ array( 'apitm', false ),
+ array( 'sharedtm', true ),
+ );
+ }
+
+}
Property changes on: trunk/extensions/Translate/tests/TTMServerTest.php
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: trunk/extensions/Translate/utils/TTMServer.php
===================================================================
--- trunk/extensions/Translate/utils/TTMServer.php 2012-03-11 17:26:07 UTC
(rev 113576)
+++ trunk/extensions/Translate/utils/TTMServer.php 2012-03-11 18:17:27 UTC
(rev 113577)
@@ -71,6 +71,51 @@
}
/**
+ * Determines if the suggestion returned by this TTMServer comes
+ * from this wiki or any other wiki.
+ * @return Bool
+ * @since 2012-03-11
+ */
+ public function isLocalSuggestion( array $suggestion ) {
+ $type = $this->config['type'];
+ $isLocal = $type === 'ttmserver';
+ if ( $type === 'shared-ttmserver' && $suggestion['wiki'] ===
wfWikiId() ) {
+ $isLocal = true;
+ }
+ return $isLocal;
+ }
+
+ /**
+ * Given suggestion returned by this TTMServer, constructs fully
+ * qualified URL to the location of the translation.
+ * @return String URL
+ * @since 2012-03-11
+ */
+ public function expandLocation( array $suggestion ) {
+ $type = $this->config['type'];
+ if ( $type === 'shared-ttmserver' ) {
+ $wiki = WikiMap::getWiki( $suggestion['wiki'] );
+ return $wiki->getCanonicalUrl( $suggestion['location']
);
+ } elseif ( $type === 'remote-ttmserver' ) {
+ return $suggestion['location'];
+ } else {
+ $title = Title::newFromText( $suggestion['location'] );
+ return $title->getCanonicalUrl();
+ }
+ }
+
+ /**
+ * Is this TTMServer instance using shared translation memory database.
+ * This affects the database layout, shared databases have an extra
field
+ * and we have to be considerate about data originating from other
wikies.
+ * @return Bool
+ * @since 2012-03-11
+ */
+ public function isShared() {
+ return $this->config['type'] === 'shared-ttmserver';
+ }
+
+ /**
* @param $mode int
* @return DatabaseBase
*/
@@ -111,6 +156,10 @@
'tms_context' => $title->getPrefixedText(),
'tms_text' => $definition,
);
+ if ( $this->isShared() ) {
+ $conds['tms_wiki'] = wfWikiId();
+ }
+
$sid = $dbw->selectField( 'translate_tms', 'tms_sid', $conds,
__METHOD__ );
if ( $sid === false ) {
$sid = $this->insertSource( $title, $sourceLanguage,
$definition );
@@ -142,6 +191,10 @@
'tms_context' => $context->getPrefixedText(),
);
+ if ( $this->isShared() ) {
+ $row['tms_wiki'] = wfWikiId();
+ }
+
$dbw = $this->getDB( DB_MASTER );
$dbw->insert( 'translate_tms', $row, __METHOD__ );
$sid = $dbw->insertId();
@@ -172,6 +225,10 @@
$dbr = $this->getDB( DB_SLAVE );
$tables = array( 'translate_tmt', 'translate_tms' );
$fields = array( 'tms_context', 'tms_text', 'tmt_lang',
'tmt_text' );
+ if ( $this->isShared() ) {
+ $fields[] = 'tms_wiki';
+ }
+
$conds = array(
'tms_lang' => $sourceLanguage,
'tmt_lang' => $targetLanguage,
@@ -189,10 +246,10 @@
$res = $dbr->select( $tables, $fields, $conds, __METHOD__ );
wfProfileOut( __METHOD__ );
- return $this->processQueryResults( $res, $text );
+ return $this->processQueryResults( $res, $text,
$sourceLanguage, $targetLanguage );
}
- protected function processQueryResults( $res, $text ) {
+ protected function processQueryResults( $res, $text, $sourceLanguage,
$targetLanguage ) {
wfProfileIn( __METHOD__ );
$lenA = mb_strlen( $text );
$results = array();
@@ -211,11 +268,14 @@
$quality = 1 - ( $dist / $len );
if ( $quality >= $this->config['cutoff'] ) {
+ $loc = self::contextToLocation(
$row->tms_context, $sourceLanguage, $targetLanguage );
$results[] = array(
'source' => $row->tms_text,
'target' => $row->tmt_text,
'context' => $row->tms_context,
+ 'location' => $loc,
'quality' => $quality,
+ 'wiki' => isset( $row->tms_wiki ) ?
$row->tms_wiki : false,
);
}
}
@@ -265,6 +325,18 @@
}
/**
+ * Given pagename Namespace:Page/en, replace the language code with
+ * the target language. In theory namespaces could be stored
differently,
+ * but in MediaWiki this is standard practise.
+ * @return String
+ * @since 2012-03-11
+ */
+ protected static function contextToLocation( $text, $sourceLanguage,
$targetLanguage ) {
+ $len = strlen( $sourceLanguage );
+ return substr( $text, 0, -$len ) . $targetLanguage;
+ }
+
+ /**
* The native levenshtein is limited to 255 bytes.
*/
public static function levenshtein( $str1, $str2, $length1, $length2 ) {
Modified: trunk/extensions/Translate/utils/TranslationHelpers.php
===================================================================
--- trunk/extensions/Translate/utils/TranslationHelpers.php 2012-03-11
17:26:07 UTC (rev 113576)
+++ trunk/extensions/Translate/utils/TranslationHelpers.php 2012-03-11
18:17:27 UTC (rev 113577)
@@ -258,7 +258,8 @@
$source = $this->group->getSourceLanguage();
$code = $this->handle->getCode();
$definition = $this->getDefinition();
- $suggestions = TTMServer::primary()->query( $source, $code,
$definition );
+ $TTMServer = new TTMServer( $config );
+ $suggestions = $TTMServer->query( $source, $code, $definition );
if ( count( $suggestions ) === 0 ) {
throw new TranslationHelperExpection( 'No suggestions'
);
}
@@ -319,34 +320,37 @@
$suggestions = $wrapper['suggestions'];
foreach ( $suggestions as $s ) {
- $accuracy = wfMsgHtml( 'translate-edit-tmmatch'
, sprintf( '%.2f', $s['quality'] * 100 ) );
+ $tooltip = wfMessage(
'translate-edit-tmmatch-source', $s['source'] )->plain();
+ $text = wfMessage( 'translate-edit-tmmatch',
sprintf( '%.2f', $s['quality'] * 100 ) )->plain();
+ $accuracy = Html::element( 'span', array(
'title' => $tooltip ), $text );
$legend = array( $accuracy => array() );
- if ( $config['type'] === 'remote-ttmserver' ) {
+ $TTMServer = new TTMServer( $config );
+ if ( $TTMServer->isLocalSuggestion( $s ) ) {
+ $title = Title::newFromText(
$s['location'] );
+ $symbol = isset( $config['symbol'] ) ?
$config['symbol'] : '•';
+ $legend[$accuracy][] =
self::ajaxEditLink( $title, '•' );
+ } else {
+ if ( $config['type'] ===
'remote-ttmserver' ) {
+ $displayName =
$config['displayname'];
+ } else {
+ $wiki = WikiMap::getWiki(
$s['wiki'] );
+ $displayName =
$wiki->getDisplayName() . ': ' . $s['location'];
+ }
+
$params = array(
- 'href' => $url =
$config['viewurl'] . $s['context'],
+ 'href' =>
$TTMServer->expandLocation( $s ),
'target' => '_blank',
- 'title' =>
"{$config['displayname']}: {$s['context']}",
+ 'title' => $displayName,
);
- $legend[$accuracy][] = Html::element(
'a', $params, '‣' );
- } else {
- $sourceTitle = Title::newFromText(
$s['context'] );
- $handle = new MessageHandle(
$sourceTitle );
- $targetTitle = Title::makeTitle(
$sourceTitle->getNamespace(), $handle->getKey() . "/$code" );
- if ( $targetTitle ) {
- $legend[$accuracy][] =
self::ajaxEditLink( $targetTitle, '•' );
- }
+
+ $symbol = isset( $config['symbol'] ) ?
$config['symbol'] : '‣';
+ $legend[$accuracy][] = Html::element(
'a', $params, $symbol );
}
- // Show the source text in a tooltip
- if ( isset( $s['target'] ) ) {
- $suggestion = $s['target'];
- } else {
- $suggestion = $s['*'];
-
- }
+ $suggestion = $s['target'];
$text = $this->suggestionField( $suggestion );
- $params = array( 'class' =>
'mw-sp-translate-edit-tmsug', 'title' => $s['source'] );
+ $params = array( 'class' =>
'mw-sp-translate-edit-tmsug' );
// Group identical suggestions together
if ( isset( $sugFields[$suggestion] ) ) {
@@ -386,6 +390,7 @@
$handlers = array(
'ttmserver' => 'getTTMServerBox',
+ 'shared-ttmserver' => 'getTTMServerBox',
'remote-ttmserver' => 'getRemoteTTMServerBox',
'microsoft' => 'getMicrosoftSuggestion',
'apertium' => 'getApertiumSuggestion',
@@ -395,17 +400,19 @@
$boxes = array();
$TTMSSug = array();
foreach ( $wgTranslateTranslationServices as $name => $config )
{
- if ( $async === 'async' ) {
- $config['timeout'] = $config['timeout-async'];
- } else {
- $config['timeout'] = $config['timeout-sync'];
+ $type = $config['type'];
+ if ( $type !== 'ttmserver' ) {
+ if ( $async === 'async' ) {
+ $config['timeout'] =
$config['timeout-async'];
+ } else {
+ $config['timeout'] =
$config['timeout-sync'];
+ }
}
- $type = $config['type'];
if ( isset( $handlers[$type] ) ) {
$method = $handlers[$type];
try {
- if ( $type === 'ttmserver' || $type ===
'remote-ttmserver' ) {
+ if ( $type === 'ttmserver' || $type ===
'remote-ttmserver' || $type === 'shared-ttmserver' ) {
$TTMSSug[$name] = array(
'config' => $config,
'suggestions' =>
$this->$method( $name, $config ),
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs