From: tgr Date: Mon, 28 Oct 2013 18:18:05 +0000 (+0000) Subject: Add language handling to imageinfo/extmetadata API X-Git-Tag: 1.31.0-rc.0~18352^2 X-Git-Url: https://git.heureux-cyclage.org/w/index.php?a=commitdiff_plain;h=042f1c77a6318b29c32eedcbdbf6c861f5616538;p=lhc%2Fweb%2Fwiklou.git Add language handling to imageinfo/extmetadata API Adds options to return metadata in all available languages, or in a single selected language. Change-Id: I78f096318904a08abd317a5ed3f74ee33d3289cb --- diff --git a/docs/hooks.txt b/docs/hooks.txt index d18679b300..3f88bf5087 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -1162,6 +1162,9 @@ underscore) magic words. Called by MagicWord. 'value' => prop value, 'source' => 'name of hook' ). $file: File object of file in question $context: RequestContext (including language to use) +$single: Only extract the current language; if false, the prop value should +be in the metadata multi-language array format: +mediawiki.org/wiki/Manual:File_metadata_handling#Multi-language_array_format &$maxCacheTime: how long the results can be cached 'GetFullURL': Modify fully-qualified URLs used in redirects/export/offsite data. diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php index 1e80f57120..81c9faf0c8 100755 --- a/includes/api/ApiQueryImageInfo.php +++ b/includes/api/ApiQueryImageInfo.php @@ -51,6 +51,8 @@ class ApiQueryImageInfo extends ApiQueryBase { $metadataOpts = array( 'version' => $params['metadataversion'], + 'language' => $params['extmetadatalanguage'], + 'multilang' => $params['extmetadatamultilang'], ); $pageIds = $this->getPageSet()->getAllTitlesByNamespace(); @@ -305,12 +307,18 @@ class ApiQueryImageInfo extends ApiQueryBase { * @param string|array $metadataOpts Options for metadata fetching. * This is an array consisting of the keys: * 'version': The metadata version for the metadata option + * 'language': The language for extmetadata property + * 'multilang': Return all translations in extmetadata property * @return Array: result array */ static function getInfo( $file, $prop, $result, $thumbParams = null, $metadataOpts = false ) { + global $wgContLang; + if ( !$metadataOpts || is_string( $metadataOpts ) ) { $metadataOpts = array( 'version' => $metadataOpts ?: 'latest', + 'language' => $wgContLang, + 'multilang' => false, ); } $version = $metadataOpts['version']; @@ -437,6 +445,8 @@ class ApiQueryImageInfo extends ApiQueryBase { // start with a letter, and all the values are strings. // Thus there should be no issue with format=xml. $format = new FormatMetadata; + $format->setSingleLanguage( !$metadataOpts['multilang'] ); + $format->getContext()->setLanguage( $metadataOpts['language'] ); $extmetaArray = $format->fetchExtendedMetadata( $file ); $vals['extmetadata'] = $extmetaArray; } @@ -515,6 +525,7 @@ class ApiQueryImageInfo extends ApiQueryBase { } public function getAllowedParams() { + global $wgContLang; return array( 'prop' => array( ApiBase::PARAM_ISMULTI => true, @@ -546,6 +557,14 @@ class ApiQueryImageInfo extends ApiQueryBase { ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_DFLT => '1', ), + 'extmetadatalanguage' => array( + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_DFLT => $wgContLang->getCode(), + ), + 'extmetadatamultilang' => array( + ApiBase::PARAM_TYPE => 'boolean', + ApiBase::PARAM_DFLT => false, + ), 'urlparam' => array( ApiBase::PARAM_DFLT => '', ApiBase::PARAM_TYPE => 'string', @@ -628,6 +647,10 @@ class ApiQueryImageInfo extends ApiQueryBase { 'end' => 'Timestamp to stop listing at', 'metadataversion' => array( "Version of metadata to use. if 'latest' is specified, use latest version.", "Defaults to '1' for backwards compatibility" ), + 'extmetadatalanguage' => array( 'What language to fetch extmetadata in. This affects both which', + 'translation to fetch, if multiple are available, as well as how things', + 'like numbers and various values are formatted.' ), + 'extmetadatamultilang' => 'If translations for extmetadata property are available, fetch all of them.', 'continue' => 'If the query response includes a continue value, use it here to get another page of results', 'localonly' => 'Look only for files in the local repository', ); diff --git a/includes/filerepo/file/ForeignAPIFile.php b/includes/filerepo/file/ForeignAPIFile.php index fc9e176cda..0b3d5dfdb0 100755 --- a/includes/filerepo/file/ForeignAPIFile.php +++ b/includes/filerepo/file/ForeignAPIFile.php @@ -57,7 +57,10 @@ class ForeignAPIFile extends File { 'titles' => 'File:' . $title->getDBkey(), 'iiprop' => self::getProps(), 'prop' => 'imageinfo', - 'iimetadataversion' => MediaHandler::getMetadataVersion() + 'iimetadataversion' => MediaHandler::getMetadataVersion(), + // extmetadata is language-dependant, accessing the current language here + // would be problematic, so we just get them all + 'iiextmetadatamultilang' => 1, ) ); $info = $repo->getImageInfo( $data ); diff --git a/includes/media/FormatMetadata.php b/includes/media/FormatMetadata.php index 17de74ab4a..b34ad650c0 100755 --- a/includes/media/FormatMetadata.php +++ b/includes/media/FormatMetadata.php @@ -47,6 +47,23 @@ */ class FormatMetadata extends ContextSource { + /** + * Only output a single language for multi-language fields + * @var boolean + * @since 1.23 + */ + protected $singleLang = false; + + /** + * Trigger only outputting single language for multilanguage fields + * + * @param Boolean $val + * @since 1.23 + */ + public function setSingleLanguage( $val ) { + $this->singleLang = $val; + } + /** * Numbers given by Exif user agents are often magical, that is they * should be replaced by a detailed explanation depending on their @@ -935,7 +952,6 @@ class FormatMetadata extends ContextSource { * languages, we don't want to show them all by default */ else { - global $wgContLang; switch ( $type ) { case 'lang': // Display default, followed by ContLang, @@ -946,7 +962,7 @@ class FormatMetadata extends ContextSource { $content = ''; - $cLang = $wgContLang->getCode(); + $priorityLanguages = $this->getPriorityLanguages(); $defaultItem = false; $defaultLang = false; @@ -961,18 +977,24 @@ class FormatMetadata extends ContextSource { $defaultItem = $vals['x-default']; unset( $vals['x-default'] ); } - // Do contentLanguage. - if ( isset( $vals[$cLang] ) ) { - $isDefault = false; - if ( $vals[$cLang] === $defaultItem ) { - $defaultItem = false; - $isDefault = true; - } - $content .= $this->langItem( - $vals[$cLang], $cLang, - $isDefault, $noHtml ); + foreach( $priorityLanguages as $pLang ) { + if ( isset( $vals[$pLang] ) ) { + $isDefault = false; + if ( $vals[$pLang] === $defaultItem ) { + $defaultItem = false; + $isDefault = true; + } + $content .= $this->langItem( + $vals[$pLang], $pLang, + $isDefault, $noHtml ); + + unset( $vals[$pLang] ); - unset( $vals[$cLang] ); + if ( $this->singleLang ) { + return Html::rawElement( 'span', + array( 'lang' => $pLang ), $vals[$pLang] ); + } + } } // Now do the rest. @@ -983,11 +1005,18 @@ class FormatMetadata extends ContextSource { } $content .= $this->langItem( $item, $lang, false, $noHtml ); + if ( $this->singleLang ) { + return Html::rawElement( 'span', + array( 'lang' => $lang ), $item ); + } } if ( $defaultItem !== false ) { $content = $this->langItem( $defaultItem, $defaultLang, true, $noHtml ) . $content; + if ( $this->singleLang ) { + return $defaultItem; + } } if ( $noHtml ) { return $content; @@ -1456,6 +1485,7 @@ class FormatMetadata extends ContextSource { $cacheKey = wfMemcKey( 'getExtendedMetadata', $this->getLanguage()->getCode(), + (int) $this->singleLang, $file->getSha1() ); @@ -1469,6 +1499,9 @@ class FormatMetadata extends ContextSource { $maxCacheTime = ( $file instanceof ForeignAPIFile ) ? 60 * 60 * 12 : 60 * 60 * 24 * 30; $fileMetadata = $this->getExtendedMetadataFromFile( $file ); $extendedMetadata = $this->getExtendedMetadataFromHook( $file, $fileMetadata, $maxCacheTime ); + if ( $this->singleLang ) { + $this->resolveMultilangMetadata( $extendedMetadata ); + } // Make sure the metadata won't break the API when an XML format is used. // This is an API-specific function so it would be cleaner to call it from // outside fetchExtendedMetadata, but this way we don't need to redo the @@ -1558,6 +1591,7 @@ class FormatMetadata extends ContextSource { &$extendedMetadata, $file, $this->getContext(), + $this->singleLang, &$maxCacheTime ) ); @@ -1572,6 +1606,64 @@ class FormatMetadata extends ContextSource { return $extendedMetadata; } + /** + * Turns an XMP-style multilang array into a single value. + * If the value is not a multilang array, it is returned unchanged. + * See mediawiki.org/wiki/Manual:File_metadata_handling#Multi-language_array_format + * @param mixed $value + * @return mixed value in best language, null if there were no languages at all + * @since 1.23 + */ + protected function resolveMultilangValue( $value ) + { + if ( + !is_array( $value ) + || !isset( $value['_type'] ) + || $value['_type'] != 'lang' + ) { + return $value; // do nothing if not a multilang array + } + + // choose the language best matching user or site settings + $priorityLanguages = $this->getPriorityLanguages(); + foreach( $priorityLanguages as $lang ) { + if ( isset( $value[$lang] ) ) { + return $value[$lang]; + } + } + + // otherwise go with the default language, if set + if ( isset( $value['x-default'] ) ) { + return $value['x-default']; + } + + // otherwise just return any one language + unset($value['_type']); + if (!empty($value)) { + return reset($value); + } + + // this should not happen; signal error + return null; + } + + /** + * Takes an array returned by the getExtendedMetadata* functions, + * and resolves multi-language values in it. + * @param array $metadata + * @since 1.23 + */ + protected function resolveMultilangMetadata( &$metadata ) { + if ( !is_array( $metadata ) ) { + return; + } + foreach ( $metadata as &$field ) { + if ( isset( $field['value'] ) ) { + $field['value'] = $this->resolveMultilangValue( $field['value'] ); + } + } + } + /** * Makes sure the given array is a valid API response fragment * (can be transformed into XML)