jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/393072 )
Change subject: Added a oojs ui for managing translations
......................................................................
Added a oojs ui for managing translations
* added oojs ui window
* improved / fixed error handling
* added / fixed some i18n keys
Change-Id: I3da5e718989718d9f67164b2dfcd50ad25ffd441
---
M extension.json
M i18n/en.json
M i18n/qqq.json
A resources/ext.mlm.js
A src/Api/Tasks.php
M src/Helper.php
M src/Hooks/BeforePageDisplay.php
M src/MultiLanguageTranslation.php
M src/Specials/MultiLanguageManager.php
9 files changed, 826 insertions(+), 49 deletions(-)
Approvals:
Robert Vogel: Looks good to me, approved
Raimond Spekking: Looks good to me, but someone else must approve
jenkins-bot: Verified
diff --git a/extension.json b/extension.json
index 9c6259b..d18530b 100644
--- a/extension.json
+++ b/extension.json
@@ -47,6 +47,9 @@
"SpecialPages": {
"MultiLanguageManager":
"MultiLanguageManager\\Specials\\MultiLanguageManager"
},
+ "APIModules": {
+ "mlm-tasks": "MultiLanguageManager\\Api\\Tasks"
+ },
"ResourceFileModulePaths": {
"localBasePath": "resources",
"remoteExtPath": "MultiLanguageManager/resources"
@@ -56,6 +59,25 @@
"styles": [
"ext.mlm.less"
]
+ },
+ "ext.mlm": {
+ "scripts": [
+ "ext.mlm.js"
+ ],
+ "dependencies": [
+ "mediawiki.api",
+ "oojs",
+ "oojs-ui"
+ ],
+ "messages": [
+ "mlm-input-label-sourcetitle",
+ "mlm-input-label-translationtitles",
+ "mlm-input-label-add",
+ "mlm-input-label-save",
+ "mlm-input-label-delete",
+ "mlm-input-label-cancel",
+ "mlm-contentaction-label"
+ ]
}
},
"config_prefix": "mg",
diff --git a/i18n/en.json b/i18n/en.json
index dc7cab7..26546bd 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -7,18 +7,23 @@
"multilanguagemanager": "Multi language manager",
"mlm-desc": "Mediawiki extension to manage multi language in one
MediaWiki.",
"mlm-error-title-invalid": "Invalid page name",
- "mlm-error-title-notexists": "Page does not exist",
- "mlm-error-title-istalkpage": "Talk pages can not be translated",
- "mlm-error-title-nsnotallowed": "Invalid namespace for translation",
- "mlm-error-title-isalreadytranslation": "Page is already a translation",
- "mlm-error-title-isalreadysource": "Page is already a source",
- "mlm-error-title-isnottranslation": "Page is not a translation",
+ "mlm-error-title-notexists": "Page \"$1\" does not exist",
+ "mlm-error-title-istalkpage": "\"$1\". Talk pages can not be
translated",
+ "mlm-error-title-nsnotallowed": "\"$1\". Invalid namespace for
translation",
+ "mlm-error-title-isalreadytranslation": "Page \"$1\" is already a
translation",
+ "mlm-error-title-isalreadysource": "Page \"$1\" is already a source",
+ "mlm-error-title-isnottranslation": "Page \"$1\" is not a translation",
"mlm-error-lang-invalid": "Invalid language",
- "mlm-error-lang-notallowed": "Language is not allowed for translation",
- "mlm-error-lang-alreadytraslated": "There is already a translation for
language '$1'",
+ "mlm-error-lang-notallowed": "Language \"$1\" is not allowed for
translation",
+ "mlm-error-lang-alreadytraslated": "There is already a translation for
language \"$1\"",
"mlm-input-label-sourcetitle": "Source page",
"mlm-input-label-translationtitles": "Translation
{{plural:$1|page|pages}}",
+ "mlm-input-label-add": "Add",
"mlm-input-label-save": "Save",
"mlm-input-label-delete": "Delete",
- "mlm-contentaction-label": "Manage translations"
+ "mlm-input-label-cancel": "Cancel",
+ "mlm-contentaction-label": "Manage translations",
+ "apihelp-mlm-param-task": "The task that should be executed",
+ "apihelp-mlm-param-taskdata": "JSON string encoded object with
arbitrary data for the task",
+ "apihelp-mlm-param-format": "The format of the result"
}
\ No newline at end of file
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 771165b..8b8ddd7 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -9,18 +9,23 @@
"multilanguagemanager": "Title of the special page",
"mlm-desc":
"{{desc|name=MultiLanguageManager|url=https://www.mediawiki.org/wiki/Extension:MultiLanguageManager}}",
"mlm-error-title-invalid": "Error message in case that a invalid title
was provided",
- "mlm-error-title-notexists": "Error message in case that a provided
title does not exist",
- "mlm-error-title-istalkpage": "Error message in case that a provided
title is a talk page",
- "mlm-error-title-nsnotallowed": "Error message in case that a provided
title is in a namespace that has no translation enabled",
- "mlm-error-title-isalreadytranslation": "Error message in case that a
title already has a translation",
- "mlm-error-title-isalreadysource": "Error message in case that a title
is already declared to be the source of a translation",
- "mlm-error-title-isnottranslation": "Error message in case that a title
is no translation page",
- "mlm-error-lang-invalid": "Error message in case that a invalis
language code was provided",
- "mlm-error-lang-notallowed": "Error message in case that a specific
language code is not allowed by configuration",
+ "mlm-error-title-notexists": "Error message in case that a provided
title does not exist\n*Paramter $1 - Full page name",
+ "mlm-error-title-istalkpage": "Error message in case that a provided
title is a talk page\n*Paramter $1 - Full page name",
+ "mlm-error-title-nsnotallowed": "Error message in case that a provided
title is in a namespace that has no translation enabled\n*Paramter $1 - Full
page name",
+ "mlm-error-title-isalreadytranslation": "Error message in case that a
title already has a translation\n*Paramter $1 - Full page name",
+ "mlm-error-title-isalreadysource": "Error message in case that a title
is already declared to be the source of a translation\n*Paramter $1 - Full page
name",
+ "mlm-error-title-isnottranslation": "Error message in case that a title
is no translation page\n*Paramter $1 - Full page name",
+ "mlm-error-lang-invalid": "Error message in case that a invalid
language code was provided",
+ "mlm-error-lang-notallowed": "Error message in case that a specific
language code is not allowed by configuration\n*Paramter $1 - The language
code",
"mlm-error-lang-alreadytraslated": "Error message in case that there is
already a translation for a specific language code\n*Paramter $1 - The language
code",
"mlm-input-label-sourcetitle": "Label for a textfield that allows
specification of the source title",
"mlm-input-label-translationtitles": "Label of a section that lists
translations of an article.\n*Paramter $1 - Number of available translations",
+ "mlm-input-label-add": "Label for a add button\n{{Identical|Add}}",
"mlm-input-label-save": "Label for a save button\n{{Identical|Save}}",
"mlm-input-label-delete": "Label for a delete
button\n{{Identical|Delete}}",
- "mlm-contentaction-label": "Lable of a content action link that opens
Special:MultiLanguageManager"
+ "mlm-input-label-cancel": "Label for a delete
button\n{{Identical|Cancel}}",
+ "mlm-contentaction-label": "Label of a content action link that opens
Special:MultiLanguageManager",
+ "apihelp-mlm-param-task": "{{doc-apihelp-param|mlm-tasks|task}}",
+ "apihelp-mlm-param-taskdata":
"{{doc-apihelp-param|mlm-tasks|taskdata}}",
+ "apihelp-mlm-param-format": "{{doc-apihelp-param|mlm-tasks|format}}"
}
diff --git a/resources/ext.mlm.js b/resources/ext.mlm.js
new file mode 100644
index 0000000..7dca9fb
--- /dev/null
+++ b/resources/ext.mlm.js
@@ -0,0 +1,348 @@
+
+( function( mw, $ ){
+ mw.mlm = mw.mlm || {};
+ $(document).on( 'click', '#ca-mlm', function( e ) {
+ if( !mw.mlm.dialog ) {
+ return;
+ }
+ var windowManager = new OO.ui.WindowManager( {
+ factory: mw.mlm.factory
+ } );
+ $( 'body' ).append( windowManager.$element );
+
+ windowManager.openWindow( 'mlm' );
+ e.stopPropagation();
+ return false;
+ });
+
+ mw.loader.using( 'oojs-ui', function() {
+
+ mw.mlm.factory = new OO.Factory();
+
+ mw.mlm.srcTitle = mw.config.get(
+ 'mlmSourceTitle',
+ ''
+ );
+ mw.mlm.translations = mw.config.get(
+ 'mlmTranslations',
+ {}
+ );
+ mw.mlm.languages = mw.config.get(
+ 'mlmLanguages',
+ []
+ );
+ mw.mlm.languageFlags = mw.config.get(
+ 'mlmLanguageFlags',
+ {}
+ );
+ var lang = mw.config.get( 'wgContentLanguage' ).split('-');
+ mw.mlm.lang = lang[0];
+
+ mw.mlm.dialog = function( config ) {
+ this.translations = {};
+ mw.mlm.dialog.super.call( this, config );
+ };
+ OO.inheritClass( mw.mlm.dialog, OO.ui.ProcessDialog );
+ OO.initClass( mw.mlm.dialog );
+
+ // Specify a symbolic name (e.g., 'simple', in this example)
using the static 'name' property.
+ mw.mlm.dialog.static.name = 'mlm';
+ mw.mlm.dialog.static.title = mw.message(
+ 'mlm-contentaction-label'
+ ).plain();
+ mw.mlm.dialog.static.actions = [{
+ action: 'save',
+ label: mw.message( 'mlm-input-label-save' ).plain(),
+ flags: [ 'primary', 'constructive' ]
+ }, {
+ action: 'cancel',
+ label: mw.message( 'mlm-input-label-cancel' ).plain(),
+ flags: 'safe'
+ }, {
+ action: 'delete',
+ label: mw.message( 'mlm-input-label-delete' ).plain(),
+ flags: 'destructive'
+ }];
+
+ mw.mlm.dialog.prototype.initialize = function () {
+ mw.mlm.dialog.super.prototype.initialize.call( this );
+
+ this.panel = new OO.ui.PanelLayout( { padded: true,
expanded: false } );
+ this.content = new OO.ui.FieldsetLayout();
+ this.errorSection = new OO.ui.Layout();
+ this.errorSection.$element.css( 'color', 'red' );
+ this.errorSection.$element.css( 'font-weight', 'bold' );
+ this.errorSection.$element.css( 'text-align', 'center'
);
+
+ var options = [];
+ for( var i = 0; i < mw.mlm.languages.length; i++ ) {
+ if( mw.mlm.languages[i] === mw.mlm.lang ) {
+ continue;
+ }
+ options.push( {
+ data: mw.mlm.languages[i],
+ label: mw.mlm.languages[i]
+ });
+ }
+
+ this.srcLang = new OO.ui.ButtonWidget( {disabled: true}
);
+ this.srcLang.$element.find('a').css(
+ 'background',
+ 'url(' + mw.mlm.languageFlags[mw.mlm.lang] + ')'
+ );
+ this.srcLang.$element.find('a').css(
+ 'background-size',
+ '40px 30px'
+ );
+ this.srcLang.$element.find('a').css(
+ 'background-repeat',
+ 'no-repeat'
+ );
+ this.srcLang.$element.find('a').css(
+ 'width',
+ '40px'
+ );
+ this.srcText = new OO.ui.TextInputWidget( {
+ value: mw.mlm.srcTitle,
+ required: true,
+ label: mw.message(
'mlm-input-label-sourcetitle' ).plain(),
+ disabled: mw.mlm.srcTitle === '' ? false : true
+ });
+
+ this.srcSection = new OO.ui.HorizontalLayout( {
+ items: [
+ this.srcLang,
+ this.srcText
+ ]
+ });
+ this.srcSection.$element.css( 'display', 'flex' );
+
+ this.translationsSection = new OO.ui.FieldsetLayout();
+ for( var i = 0; i < mw.mlm.translations.length; i++ ) {
+ this.updateTranslations( mw.mlm.translations[i]
);
+ }
+
+ this.translationLang = new OO.ui.DropdownInputWidget( {
+ value: '',
+ options: options,
+ label: 'lang'
+ });
+ this.translationText = new OO.ui.TextInputWidget( {
+ value: mw.mlm.srcTitle === '' ? mw.config.get(
'wgTitle' ) : '',
+ label: mw.message(
+ 'mlm-input-label-translationtitles',
+ 1
+ ).text()
+ });
+ this.translationAdd = new OO.ui.ButtonWidget( {
+ label: mw.message( 'mlm-input-label-add'
).plain(),
+ flags: [ 'primary', 'constructive' ]
+ });
+
+ var me = this;
+ this.translationAdd.on( 'click',
me.onTranslationAdd.bind( this ) );
+
+ this.addSection = new OO.ui.FieldsetLayout( {
+ items: [
+ this.translationLang,
+ this.translationText,
+ this.translationAdd
+ ]
+ });
+
+ this.content.addItems([
+ this.errorSection,
+ this.srcSection,
+ this.addSection,
+ this.translationsSection
+ ]);
+
+ this.panel.$element.append( this.content.$element );
+ this.$body.append( this.panel.$element );
+ };
+
+ mw.mlm.dialog.prototype.save = function() {
+ var api = new mw.Api();
+ return api.postWithToken( 'csrf', {
+ action: 'mlm-tasks',
+ task: 'save',
+ format: 'json',
+ taskData: JSON.stringify( this.getData() )
+ });
+ };
+
+ mw.mlm.dialog.prototype.delete = function() {
+ var api = new mw.Api();
+ return api.postWithToken( 'csrf', {
+ action: 'mlm-tasks',
+ task: 'delete',
+ format: 'json',
+ taskData: JSON.stringify( this.getData() )
+ });
+ };
+
+ mw.mlm.dialog.prototype.getData = function() {
+ var data = {};
+
+ data.srcText = this.srcText.value;
+ data.translations = {};
+ for( var i in this.translations ) {
+ var translation = this.translations[i];
+ data.translations[i] = {
+ lang: i,
+ text: translation.input.value
+ };
+ }
+ return data;
+ };
+
+ mw.mlm.dialog.prototype.getActionProcess = function ( action ) {
+ return
mw.mlm.dialog.super.prototype.getActionProcess.call( this, action )
+ .next( function () {
+ return 1000;
+ }, this )
+ .next( function () {
+ var closing;
+ if ( action === 'save' ) {
+ if ( this.broken ) {
+ this.broken = false;
+ return new OO.ui.Error( 'Server
did not respond' );
+ }
+ var me = this;
+ return me.save().done( function( data )
{
+ //success is just emtyed out
somewhere for no reason
+ if( data.message.length === 0 )
{
+ closing = me.close( {
action: action } );
+ me.reloadPage();
+ return closing;
+ }
+ me.showRequestErrors(
data.message );
+ });
+ } else if ( action === 'cancel' ) {
+ closing = this.close( { action: action
} );
+ return closing;
+ }
+ else if ( action === 'delete' ) {
+ var me = this;
+ return this.delete().done( function(
data ) {
+ //success is just emtyed out
somewhere for no reason
+ if( data.message.length === 0 )
{
+ closing = me.close( {
action: action } );
+ me.reloadPage();
+ return closing;
+ }
+ me.showRequestErrors(
data.message );
+ });
+ return closing;
+ }
+
+ return
mw.mlm.dialog.super.prototype.getActionProcess.call(
+ this,
+ action
+ );
+ }, this );
+ };
+
+ mw.mlm.dialog.prototype.showRequestErrors = function( errors ) {
+ var errors = errors || {};
+
+ var error = '';
+ for( var i in errors ) {
+ error += errors[i] + "<br />";
+ }
+
+ this.errorSection.$element.html( error );
+ };
+
+ mw.mlm.dialog.prototype.reloadPage = function() {
+ window.location = mw.util.getUrl(
+ mw.config.get( 'wgTitle' )
+ );
+ };
+
+ mw.mlm.dialog.prototype.onTranslationAdd = function(){
+ this.updateTranslations( {
+ 'lang': this.translationLang.value,
+ 'text': this.translationText.value
+ });
+ };
+
+ mw.mlm.dialog.prototype.onTranslationDelete = function( lang ){
+ this.updateTranslations( {
+ 'lang': lang,
+ 'text': ''
+ }, true);
+ };
+
+ mw.mlm.dialog.prototype.updateTranslations = function (
translation, removeOnly ) {
+ removeOnly = removeOnly || false;
+ if( mw.mlm.srcTitle === translation.text ) {
+ return;
+ }
+ if( this.translations[translation.lang] ) {
+
this.translations[translation.lang].layout.$element.remove();
+ delete this.translations[translation.lang];
+ }
+ if( removeOnly ) {
+ return;
+ }
+ this.translations[translation.lang] = {
+ 'lang': new OO.ui.ButtonWidget( {
+ disabled: true,
+ title: translation.lang
+ }),
+ 'input': new OO.ui.TextInputWidget( {
+ value: translation.text,
+ required: true
+ }),
+ 'delete': new OO.ui.ButtonWidget( {
+ icon: 'trash',
+ flags: 'destructive',
+ title: mw.message(
'mlm-input-label-delete' ).plain()
+ })
+ };
+
+
this.translations[translation.lang].lang.$element.find('a').css(
+ 'background',
+ 'url(' + mw.mlm.languageFlags[translation.lang]
+ ')'
+ );
+
this.translations[translation.lang].lang.$element.find('a').css(
+ 'background-size',
+ '40px 30px'
+ );
+
this.translations[translation.lang].lang.$element.find('a').css(
+ 'background-repeat',
+ 'no-repeat'
+ );
+
this.translations[translation.lang].lang.$element.find('a').css(
+ 'width',
+ '40px'
+ );
+
+ this.translations[translation.lang].layout = new
OO.ui.HorizontalLayout( {
+ items: [
+
this.translations[translation.lang].lang,
+
this.translations[translation.lang].input,
+
this.translations[translation.lang].delete
+ ]
+ });
+ this.translations[translation.lang].layout.$element.css(
+ 'display',
+ 'flex'
+ );
+
+ var me = this;
+ this.translations[translation.lang].delete.on(
+ 'click',
+ me.onTranslationDelete.bind( this ),
+ [translation.lang]
+ );
+
+ this.translationsSection.addItems([
+ this.translations[translation.lang].layout
+ ]);
+ };
+
+ mw.mlm.factory.register( mw.mlm.dialog );
+ });
+})( mediaWiki, jQuery );
\ No newline at end of file
diff --git a/src/Api/Tasks.php b/src/Api/Tasks.php
new file mode 100644
index 0000000..b2a9c27
--- /dev/null
+++ b/src/Api/Tasks.php
@@ -0,0 +1,295 @@
+<?php
+
+namespace MultiLanguageManager\Api;
+
+use MultiLanguageManager\Helper;
+use MultiLanguageManager\Config;
+use MultiLanguageManager\MultiLanguageTranslation;
+
+class Tasks extends \ApiBase {
+ /**
+ * Returns an array of tasks and their required permissions
+ * array('taskname' => array('read', 'edit'))
+ * @return type
+ */
+ protected function getRequiredTaskPermissions() {
+ return [
+ 'save' => [
+ 'read',
+ Helper::getConfig()->get( Config::PERMISSION )
+ ],
+ 'delete' => [
+ 'read',
+ Helper::getConfig()->get( Config::PERMISSION )
+ ],
+ ];
+ }
+
+ protected function task_save( $taskData, $params ) {
+ $result = $this->makeStandardReturn();
+ $sysLang = Helper::getSystemLanguageCode();
+
+ //dont use errors param to prevent random unalterable client
side code
+ $result->message = [];
+ if( empty( $taskData->srcText ) ) {
+ $taskData->srcText = '';
+ }
+ $oSourceTitle = \Title::newFromText( $taskData->srcText );
+ $status = Helper::isValidTitle(
+ $oSourceTitle
+ );
+ if( !$status->isOK() ) {
+ $result->message[$sysLang] = $status->getHTML();
+ }
+
+ if( empty( $taskData->translations ) ) {
+ $taskData->translations = [];
+ }
+ if( is_object( $taskData->translations ) ) {
+ $taskData->translations = (array)
$taskData->translations;
+ }
+ foreach( $taskData->translations as $translation ) {
+ $status = Helper::isValidTitle(
+ \Title::newFromText( $translation->text )
+ );
+ if( !$status->isOK() ) {
+ $result->message[$translation->lang] =
$status->getHTML();
+ }
+ }
+ if( count( $result->message ) > 0 ) {
+ return $result;
+ }
+
+ $mlmTranslation = MultiLanguageTranslation::newFromTitle(
+ $oSourceTitle
+ );
+
+ if( !$mlmTranslation ) {
+ //very unexpected!
+ $result->message[$sysLang] = $this->msg(
+ 'mlm-error-title-invalid'
+ )->plain();
+ return $result;
+ }
+
+ if( !$mlmTranslation->isSourceTitle( $oSourceTitle ) ) {
+ $status = $mlmTranslation->setSourceTitle(
$oSourceTitle );
+ if( !$status->isOK() ) {
+ $result->message[$sysLang] = $status->getHTML();
+ return $result;
+ }
+ }
+
+ foreach( $mlmTranslation->getTranslations() as $translation ) {
+ $status = $mlmTranslation->removeTranslation(
+ \Title::newFromID( $translation->id )
+ );
+ if( !$status->isOK() ) {
+ $result->message[$translation->lang] =
$status->getHTML();
+ return $result;
+ }
+ }
+ foreach( $taskData->translations as $translation ) {
+ $status = $mlmTranslation->addTranslation(
+ \Title::newFromText( $translation->text ),
+ $translation->lang
+ );
+ if( !$status->isOK() ) {
+ $result->message[$translation->lang] =
$status->getHTML();
+ }
+ }
+ if( count( $result->message ) > 0 ) {
+ return $result;
+ }
+
+ $status = $mlmTranslation->save();
+ if( !$status->isOK() ) {
+ $result->message[$translation->lang] =
$status->getHTML();
+ return $result;
+ }
+
+ $result->success = true;
+ return $result;
+ }
+
+ protected function task_delete( $taskData, $params ) {
+ $result = $this->makeStandardReturn();
+ $sysLang = Helper::getSystemLanguageCode();
+
+ if( empty( $taskData->srcText ) ) {
+ $taskData->srcText = '';
+ }
+ $oSourceTitle = \Title::newFromText( $taskData->srcText );
+ $status = Helper::isValidTitle(
+ $oSourceTitle
+ );
+ if( !$status->isOK() ) {
+ $result->message[$sysLang] = $status->getHTML();
+ return $result;
+ }
+
+ $mlmTranslation = MultiLanguageTranslation::newFromTitle(
+ $oSourceTitle
+ );
+
+ if( !$mlmTranslation ) {
+ //very unexpected!
+ $result->message[$sysLang] = $this->msg(
+ 'mlm-error-title-invalid'
+ )->plain();
+ return $result;
+ }
+
+ $status = $mlmTranslation->delete();
+ if( !$status->isOK() ) {
+ $result->message[$sysLang] = $status->getHTML();
+ return $result;
+ }
+ return $result;
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $task = $params['task'];
+
+ $method= "task_$task";
+ $result = $this->makeStandardReturn();
+
+ if( !is_callable( array( $this, $method) ) ) {
+ $result->errors['task'] = "Task '$task' not
implemented!";
+ }
+ else {
+ $res = $this->checkTaskPermission( $task );
+ if( !$res ) {
+ if ( is_callable( [ $this, 'dieWithError' ] ) )
{
+ $this->dieWithError(
+
'apierror-permissiondenied-generic',
+ 'permissiondenied'
+ );
+ } else {
+ $this->dieUsageMsg( 'badaccess-groups'
);
+ }
+ }
+ if( wfReadOnly() ) {
+ global $wgReadOnly;
+ $result->message = wfMessage(
+ 'bs-readonly',
+ $wgReadOnly
+ )->plain();
+ }
+ else {
+ $taskData = $this->getParameter( 'taskData' );
+ if( empty( $result->errors ) && empty(
$result->message ) ) {
+ try {
+ $result = $this->$method(
$taskData , $params );
+ }
+ catch ( Exception $e ) {
+ $result->success = false;
+ $result->message =
$e->getMessage();
+ $mCode = method_exists( $e,
'getCodeString' )
+ ? $e->getCodeString()
+ : $e->getCode();
+ if( $e instanceof DBError ) {
+ //TODO: error code for
subtypes like DBQueryError or
+ //DBReadOnlyError?
+ $mCode = 'dberror';
+ }
+ $result->errors[$mCode] =
$e->getMessage();
+ $result->errors[0]['code'] =
'unknown error';
+ }
+ }
+ }
+ }
+
+ foreach( $result as $sFieldName => $mFieldValue ) {
+ if( $mFieldValue === null ) {
+ continue; //MW Api doesn't like NULL values
+ }
+
+ //Remove empty 'errors' array from respons as mw.Api in
MW 1.30+
+ //will interpret this field as indicator for a failed
request
+ if( $sFieldName === 'errors' && empty( $mFieldValue ) )
{
+ continue;
+ }
+ $this->getResult()->addValue( null, $sFieldName,
$mFieldValue );
+ }
+ }
+
+ protected function getParameterFromSettings( $paramName,
$paramSettings, $parseLimit ) {
+ $value = parent::getParameterFromSettings(
+ $paramName,
+ $paramSettings,
+ $parseLimit
+ );
+ //Unfortunately there is no way to register custom types for
parameters
+ if( $paramName == 'taskData' ) {
+ $value = \FormatJson::decode($value);
+ if( empty($value) ) {
+ return new stdClass();
+ }
+ }
+ return $value;
+ }
+
+ protected function makeStandardReturn() {
+ return (object) [
+ 'errors' => [],
+ 'success' => false,
+ 'message' => '',
+ 'payload' => [],
+ 'payload_count' => 0
+ ];
+ }
+
+ /**
+ *
+ * @param string $task
+ * @return boolean null if requested task not in list
+ * true if allowed
+ * false if not found in permission table of current user
+ */
+ public function checkTaskPermission( $task ) {
+ $taskPermissions = $this->getRequiredTaskPermissions();
+
+ if( empty($taskPermissions[$task]) ) {
+ return;
+ }
+ //lookup permission for given task
+ foreach( $taskPermissions[$task] as $sPermission ) {
+ //check if user have needed permission
+ if( $this->getUser()->isAllowed( $sPermission ) ) {
+ continue;
+ }
+ //TODO: Reflect permission in error message
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns an array of allowed parameters
+ * @return array
+ */
+ protected function getAllowedParams() {
+ return [
+ 'task' => array(
+ \ApiBase::PARAM_REQUIRED => true,
+ \ApiBase::PARAM_TYPE => 'string',
+ \ApiBase::PARAM_HELP_MSG =>
'apihelp-mlm-param-task',
+ ),
+ 'taskData' => array(
+ \ApiBase::PARAM_TYPE => 'string',
+ \ApiBase::PARAM_REQUIRED => false,
+ \ApiBase::PARAM_DFLT => '{}',
+ \ApiBase::PARAM_HELP_MSG =>
'apihelp-mlm-param-taskdata',
+ ),
+ 'format' => array(
+ \ApiBase::PARAM_DFLT => 'json',
+ \ApiBase::PARAM_TYPE => [ 'json', 'jsonfm' ],
+ \ApiBase::PARAM_HELP_MSG =>
'apihelp-mlm-param-format',
+ )
+ ];
+ }
+}
\ No newline at end of file
diff --git a/src/Helper.php b/src/Helper.php
index 3b76276..ca05836 100644
--- a/src/Helper.php
+++ b/src/Helper.php
@@ -21,19 +21,31 @@
return \Status::newFatal( 'mlm-error-title-invalid' );
}
if( !$oTitle->exists() ) {
- return \Status::newFatal( 'mlm-error-title-notexists' );
+ return \Status::newFatal(
+ 'mlm-error-title-notexists',
+ $oTitle->getFullText()
+ );
}
if( $oTitle->isTalkPage() ) {
- return \Status::newFatal( 'mlm-error-title-istalkpage'
);
+ return \Status::newFatal(
+ 'mlm-error-title-istalkpage',
+ $oTitle->getFullText()
+ );
}
if( !$oTitle->getNamespace() < 0 ) {
- return \Status::newFatal(
'mlm-error-title-nsnotallowed' );
+ return \Status::newFatal(
+ 'mlm-error-title-nsnotallowed',
+ $oTitle->getFullText()
+ );
}
$aNonTranslatableNs = static::getConfig()->get(
Config::NON_TRANSLATABLE_NAMESPACES
);
if( in_array( $oTitle->getNamespace(), $aNonTranslatableNs ) ) {
- return \Status::newFatal(
'mlm-error-title-nsnotallowed' );
+ return \Status::newFatal(
+ 'mlm-error-title-nsnotallowed',
+ $oTitle->getFullText()
+ );
}
return \Status::newGood( $oTitle );
}
@@ -63,7 +75,10 @@
static::getConfig()->get( Config::AVAILABLE_LANGUAGES )
);
if( !$bAvailableLang ) {
- return \Status::newFatal( 'mlm-error-lang-notallowed' );
+ return \Status::newFatal(
+ 'mlm-error-lang-notallowed',
+ $sLang
+ );
}
return \Status::newGood( $sLang );
}
diff --git a/src/Hooks/BeforePageDisplay.php b/src/Hooks/BeforePageDisplay.php
index 92f6547..1f78a04 100644
--- a/src/Hooks/BeforePageDisplay.php
+++ b/src/Hooks/BeforePageDisplay.php
@@ -2,6 +2,9 @@
namespace MultiLanguageManager\Hooks;
+use MultiLanguageManager\Helper;
+use MultiLanguageManager\MultiLanguageTranslation as Translation;
+
class BeforePageDisplay {
/**
@@ -33,6 +36,57 @@
*/
public function process() {
$this->oOutputPage->addModuleStyles( 'ext.mlm.styles' );
+
+ if( !Helper::isValidTitle( $this->oSkin->getTitle() )->isOK() )
{
+ return true;
+ }
+ $this->oOutputPage->addModules( 'ext.mlm' );
+
+ $availableLanguages = Helper::getAvailableLanguageCodes();
+ $this->oOutputPage->addJsConfigVars(
+ 'mlmLanguages',
+ $availableLanguages
+ );
+
+ $sysLang = Helper::getSystemLanguageCode();
+ $langFlags = [
+ $sysLang => Helper::getLangFlagUrl( $sysLang ),
+ ];
+ foreach( $availableLanguages as $lang ) {
+ $langFlags[$lang] = Helper::getLangFlagUrl( $lang );
+ }
+ $this->oOutputPage->addJsConfigVars(
+ 'mlmLanguageFlags',
+ $langFlags
+ );
+
+ $oTransations = Translation::newFromTitle(
$this->oSkin->getTitle() );
+ if( !$oTransations || !$oTransations->getSourceTitle()
instanceof \Title ) {
+ return true;
+ }
+
+ $this->oOutputPage->addJsConfigVars(
+ 'mlmSourceTitle',
+ $oTransations->getSourceTitle()->getFullText()
+ );
+
+ $translations = [];
+ foreach( $oTransations->getTranslations() as $translation ) {
+ if( !$title = \Title::newFromID( $translation->id ) ) {
+ continue;
+ }
+ $translations[] = [
+ 'text' => $title->getFullText(),
+ 'lang' => $translation->lang,
+ 'id' => $translation->id,
+ ];
+ }
+
+ $this->oOutputPage->addJsConfigVars(
+ 'mlmTranslations',
+ $translations
+ );
+
return true;
}
}
\ No newline at end of file
diff --git a/src/MultiLanguageTranslation.php b/src/MultiLanguageTranslation.php
index 6762d7a..a69535e 100644
--- a/src/MultiLanguageTranslation.php
+++ b/src/MultiLanguageTranslation.php
@@ -186,10 +186,24 @@
return \Status::newFatal( 'mlm-error-title-invalid' );
}
if( $oTranslation->isSourceTitle( $oTitle ) ) {
- return \Status::newFatal(
'mlm-error-title-isalreadysource' );
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadysource',
+ $oTitle->getFullText()
+ );
}
- if( $oTranslation->isTranslation( $oTitle ) ) {
- return \Status::newFatal(
'mlm-error-title-isalreadytranslation' );
+ if( $this->isTranslation( $oTitle ) ) {
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadysource',
+ $oTitle->getFullText()
+ );
+ }
+ if( $oTranslation->getSourceTitle()
+ && !$oTranslation->getSourceTitle()->equals(
$this->getSourceTitle() )
+ && $oTranslation->isTranslation( $oTitle ) ) {
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadysource',
+ $oTitle->getFullText()
+ );
}
if( $sLang == Helper::getSystemLanguageCode() ) {
return \Status::newFatal(
@@ -202,7 +216,8 @@
);
if( !in_array( $sLang, $aLangs ) ) {
return \Status::newFatal(
- wfMessage( "mlm-error-lang-alreadytraslated",
$sLang )
+ "mlm-error-lang-alreadytraslated",
+ $sLang
);
}
$this->aTranslations[] = (object) [
@@ -223,7 +238,10 @@
return $oStatus;
}
if( !$this->isTranslation( $oTitle ) ) {
- return \Status::newFatal(
'mlm-error-title-isnottranslation' );
+ return \Status::newFatal(
+ 'mlm-error-title-isnottranslation',
+ $oTitle->getFullText()
+ );
}
foreach( $this->aTranslations as $iKey => $oTranslation ) {
if( (int) $oTitle->getArticleID() !== $oTranslation->id
) {
@@ -245,7 +263,16 @@
return $oStatus;
}
if( $this->getSourceTitle() instanceof \Title ) {
- return \Status::newFatal(
'mlm-error-title-isalreadysource' );
+ if( $this->isSourceTitle( $oTitle ) ) {
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadysource',
+ $oTitle->getFullText()
+ );
+ }
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadytranslation',
+ $oTitle->getFullText()
+ );
}
$oTranslation = static::newFromTitle( $oTitle, true );
if( !$oTranslation ) {
@@ -253,10 +280,16 @@
return \Status::newFatal( 'mlm-error-title-invalid' );
}
if( $oTranslation->isSourceTitle( $oTitle ) ) {
- return \Status::newFatal(
'mlm-error-title-isalreadysource' );
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadysource',
+ $oTitle->getFullText()
+ );
}
if( $oTranslation->isTranslation( $oTitle ) ) {
- return \Status::newFatal(
'mlm-error-title-isalreadytranslation' );
+ return \Status::newFatal(
+ 'mlm-error-title-isalreadytranslation',
+ $oTitle->getFullText()
+ );
}
$this->oSourceTitle = $oTitle;
diff --git a/src/Specials/MultiLanguageManager.php
b/src/Specials/MultiLanguageManager.php
index 9aea9c3..38da73a 100644
--- a/src/Specials/MultiLanguageManager.php
+++ b/src/Specials/MultiLanguageManager.php
@@ -74,10 +74,10 @@
$this->getRequest()->getVal( 'mlm-sourcetitle', '' )
);
- $oStatus = Helper::isValidTitle( $oSourceTitle );
- if( !$oStatus->isOK() ) {
+ $status = Helper::isValidTitle( $oSourceTitle );
+ if( !$status->isOK() ) {
$this->outputError(
- $oStatus->getHTML(),
+ $status->getHTML(),
wfMessage( 'mlm-input-label-sourcetitle'
)->plain()
);
return false;
@@ -97,10 +97,10 @@
}
if( !$oTranslation->isSourceTitle( $oSourceTitle ) ) {
- $oStatus = $oTranslation->setSourceTitle( $oSourceTitle
);
- if( !$oStatus->isOK() ) {
+ $status = $oTranslation->setSourceTitle( $oSourceTitle
);
+ if( !$status->isOK() ) {
$this->outputError(
- $oStatus->getHTML(),
+ $status->getHTML(),
wfMessage(
'mlm-input-label-sourcetitle' )->plain()
);
return false;
@@ -108,9 +108,9 @@
}
if( $this->getRequest()->getVal( 'mlm-delete', false ) ) {
- $oStatus = $oTranslation->delete();
- if( !$oStatus->isOK() ) {
- $this->outputError( $oStatus->getHTML() );
+ $status = $oTranslation->delete();
+ if( !$status->isOK() ) {
+ $this->outputError( $status->getHTML() );
return false;
}
return true;
@@ -124,22 +124,22 @@
$oNewTranslationTitle = \Title::newFromText(
$sNewTranslation
);
- $oStatus = $oTranslation->addTranslation(
+ $status = $oTranslation->addTranslation(
$oNewTranslationTitle,
$this->getRequest()->getVal(
'mlm-newtranslation-lang', '' )
);
- if( !$oStatus->isOK() ) {
+ if( !$status->isOK() ) {
$this->outputError(
- $oStatus->getHTML(),
+ $status->getHTML(),
wfMessage(
'mlm-input-label-translationtitles', 1)->text()
);
return false;
}
}
- $oStatus = $oTranslation->save();
- if( !$oStatus->isOK() ) {
- $this->outputError( $oStatus->getHTML() );
+ $status = $oTranslation->save();
+ if( !$status->isOK() ) {
+ $this->outputError( $status->getHTML() );
}
return true;
@@ -296,9 +296,9 @@
protected function makeTitleContext( $subPage = '' ) {
if( !empty( $subPage ) ) {
$oTitle = \Title::newFromText( $subPage );
- $oStatus = Helper::isValidTitle( $oTitle );
- if( !$oStatus->isOK() ) {
- $this->outputError( $oStatus->getHTML(),
"'$subPage':" );
+ $status = Helper::isValidTitle( $oTitle );
+ if( !$status->isOK() ) {
+ $this->outputError( $status->getHTML(),
"'$subPage':" );
return false;
}
$this->oTitle = $oTitle;
--
To view, visit https://gerrit.wikimedia.org/r/393072
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I3da5e718989718d9f67164b2dfcd50ad25ffd441
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/extensions/MultiLanguageManager
Gerrit-Branch: master
Gerrit-Owner: Pwirth <[email protected]>
Gerrit-Reviewer: Pwirth <[email protected]>
Gerrit-Reviewer: Raimond Spekking <[email protected]>
Gerrit-Reviewer: Robert Vogel <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits