$metadataOpts = array(
'version' => $params['metadataversion'],
+ 'language' => $params['extmetadatalanguage'],
+ 'multilang' => $params['extmetadatamultilang'],
);
$pageIds = $this->getPageSet()->getAllTitlesByNamespace();
* @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'];
// 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;
}
}
public function getAllowedParams() {
+ global $wgContLang;
return array(
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
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',
'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',
);
*/
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
* languages, we don't want to show them all by default
*/
else {
- global $wgContLang;
switch ( $type ) {
case 'lang':
// Display default, followed by ContLang,
$content = '';
- $cLang = $wgContLang->getCode();
+ $priorityLanguages = $this->getPriorityLanguages();
$defaultItem = false;
$defaultLang = false;
$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.
}
$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;
$cacheKey = wfMemcKey(
'getExtendedMetadata',
$this->getLanguage()->getCode(),
+ (int) $this->singleLang,
$file->getSha1()
);
$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
&$extendedMetadata,
$file,
$this->getContext(),
+ $this->singleLang,
&$maxCacheTime
) );
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)