Skip to content

Commit

Permalink
Simultaneously Displaying Multilingual Metadata on the Article Landin…
Browse files Browse the repository at this point in the history
…g Page
  • Loading branch information
jyhein committed Feb 12, 2025
1 parent bc25181 commit ba3e3b6
Show file tree
Hide file tree
Showing 7 changed files with 663 additions and 54 deletions.
162 changes: 162 additions & 0 deletions pages/catalog/CatalogBookHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
use APP\security\authorization\OmpPublishedSubmissionAccessPolicy;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Illuminate\Support\Arr;
use Illuminate\Support\LazyCollection;
use PKP\author\Author;
use PKP\citation\CitationDAO;
use PKP\core\Core;
use PKP\core\PKPApplication;
Expand All @@ -41,6 +44,7 @@
use PKP\plugins\PluginRegistry;
use PKP\security\authorization\ContextRequiredPolicy;
use PKP\security\Validation;
use PKP\services\PKPSchemaService;
use PKP\submission\Genre;
use PKP\submission\GenreDAO;
use PKP\submission\PKPSubmission;
Expand Down Expand Up @@ -310,6 +314,18 @@ public function book($args, $request)
$templateMgr->addHeader('canonical', '<link rel="canonical" href="' . $url . '">');
}

$templateMgr->assign('pubLocaleData', $this->getMultilingualMetadataOpts(
$this->publication,
$templateMgr->getTemplateVars('currentLocale'),
$templateMgr->getTemplateVars('activeTheme')->getOption('showMultilingualMetadata') ?: [],
));

$templateMgr->registerPlugin('modifier', 'wrapData', fn (...$args) => $this->smartyWrapData($templateMgr, ...$args));
$templateMgr->registerPlugin('modifier', 'useFilters', fn (...$args) => $this->smartyUseFilters($templateMgr, ...$args));
$templateMgr->registerPlugin('modifier', 'getAuthorFullNames', $this->smartyGetAuthorFullNames(...));
$templateMgr->registerPlugin('modifier', 'getAffiliationNamesWithRors', $this->smartyGetAffiliationNamesWithRors(...));
$templateMgr->registerPlugin('modifier', 'getAuthorsFullNamesWithAffiliations', $this->smartyGetAuthorsFullNamesWithAffiliations(...));

// Display
if (!Hook::call('CatalogBookHandler::book', [&$request, &$submission, &$this->publication, &$this->chapter])) {
$templateMgr->display('frontend/pages/book.tpl');
Expand Down Expand Up @@ -621,4 +637,150 @@ protected function getChaptersFirstPublishedDate(Submission $submission, Chapter

return null;
}

/**
* Multilingual publication metadata for template:
* showMultilingualMetadataOpts - Show metadata in other languages: title (+ subtitle), keywords, abstract, etc.
*/
protected function getMultilingualMetadataOpts(Publication $publication, string $currentUILocale, array $showMultilingualMetadataOpts): array
{
// Affiliation languages are not in multiligual props
$authorsAffiliationLangs = collect($publication->getData('authors'))
->map(fn ($author): array => $author->getAffiliations())
->flatten()
->map(fn ($affiliation): array => array_keys(($affiliation->getRorObject() ?? $affiliation)->getData('name')))
->flatten()
->unique()
->values()
->toArray();
$langNames = collect($publication->getLanguageNames() + Locale::getSubmissionLocaleDisplayNames($authorsAffiliationLangs))
->sortKeys();
$langs = $langNames->keys();

return [
'opts' => array_flip($showMultilingualMetadataOpts),
'localeNames' => $langNames,
'langAttrs' => $langNames->map(fn ($_, $l) => preg_replace(['/@.+$/', '/_/'], ['', '-'], $l))->toArray() /* remove @ and text after */,
'localeOrder' => collect($publication->getLocalePrecedence())
->intersect($langs) /* remove locales not in publication's languages */
->concat($langs)
->unique()
->values()
->toArray(),
];
}

/**
* Publication's multilingual data to array for js and page
*/
protected function smartyWrapData(TemplateManager $templateMgr, array $data, string $switcher, ?array $filters = null, ?string $separator = null): array
{
return [
'switcher' => $switcher,
'data' => collect($data)
->map(
fn ($value): string => collect(Arr::wrap($value))
->when($filters, fn ($value) => $value->map(fn ($v) => $this->smartyUseFilters($templateMgr, $v, $filters)))
->when($separator, fn ($value): string => $value->join($separator), fn ($value): string => $value->first())
)
->toArray(),
'defaultLocale' => collect($templateMgr->getTemplateVars('pubLocaleData')['localeOrder'])
->first(fn (string $locale) => isset($data[$locale])),
];
}

/**
* Smarty template: Apply filters to given value
*/
protected function smartyUseFilters(TemplateManager $templateMgr, string $value, ?array $filters): string
{
if (!$filters) {
return $value;
}
foreach ($filters as $filter) {
$params = Arr::wrap($filter);
$funcName = array_shift($params);
if ($func = $templateMgr->registered_plugins['modifier'][$funcName][0] ?? null) {
$value = $func($value, ...$params);
}
}
return $value;
}

/**
* Smarty template: Get author's full names to multilingual array including all multilingual and affiliation languages as default localized name
*/
protected function smartyGetAuthorFullNames(Author $author): array
{
return collect($this->getAuthorLocales($author))
->mapWithKeys(fn (string $locale) => [$locale => $author->getFullName(preferredLocale: $locale)])
->toArray();
}

/**
* Smarty template: Get authors' affiliations with rors
*/
protected function smartyGetAffiliationNamesWithRors(Author $author): array
{
$affiliations = collect($author->getAffiliations());

return collect($this->getAuthorLocales($author))
->flip()
->map(
fn ($_, string $locale) => $affiliations
->map(fn ($affiliation): array => [
'name' => $affiliation->getAffiliationName($locale),
'ror' => $affiliation->getRor(),
])
->filter(fn (array $nameRor) => $nameRor['name'])
->toArray()
)
->filter()
->toArray();
}

/**
* Smarty template: Get authors' full names to multilingual array including multilingual prop and affiliation languages as default localized name,
* and affiliations with rors
*/
protected function smartyGetAuthorsFullNamesWithAffiliations(LazyCollection $authors): array
{
$locales = $authors
->map(fn (Author $author): array => $this->getAuthorLocales($author))
->flatten()
->unique()
->values()
->flip();
$affiliations = $authors
->map(fn (Author $author): array => $this->smartyGetAffiliationNamesWithRors($author));

return $locales
->map(
fn ($_, $locale): array => $authors
->map(fn (Author $author, $id): array => [
'name' => $author->getFullName(preferredLocale: $locale),
'affiliations' => Arr::only($affiliations->get($id), [$locale]),
])
->toArray()
)
->toArray();
}

/**
* Aux for smarty template functions: Get author's locales from multilingual props and affiliations
*/
protected function getAuthorLocales(Author $author): array
{
$multilingualLocales = collect(app()->get('schema')->getMultilingualProps(PKPSchemaService::SCHEMA_AUTHOR))
->map(fn (string $prop): array => array_keys($author->getData($prop) ?? []));
$affiliationLocales = collect($author->getAffiliations())
->flatten()
->map(fn ($affiliation): array => array_keys(($affiliation->getRorObject() ?? $affiliation)->getData('name')));

return $multilingualLocales
->concat($affiliationLocales)
->flatten()
->unique()
->toArray();
}
}
28 changes: 26 additions & 2 deletions plugins/themes/default/DefaultThemePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
/**
* @file plugins/themes/default/DefaultThemePlugin.php
*
* Copyright (c) 2014-2022 Simon Fraser University
* Copyright (c) 2003-2022 John Willinsky
* Copyright (c) 2014-2025 Simon Fraser University
* Copyright (c) 2003-2025 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class DefaultThemePlugin
Expand Down Expand Up @@ -126,6 +126,30 @@ public function init()
'default' => 'none',
]);

$this->addOption('showMultilingualMetadata', 'FieldOptions', [
'label' => __('plugins.themes.default.option.metadata.label'),
'description' => __('plugins.themes.default.option.metadata.description'),
'options' => [
[
'value' => 'title',
'label' => __('submission.title'),
],
[
'value' => 'keywords',
'label' => __('common.keywords'),
],
[
'value' => 'abstract',
'label' => __('submission.synopsis'),
],
[
'value' => 'author',
'label' => __('default.groups.name.author'),
],
],
'default' => [],
]);

// Load primary stylesheet
$this->addStyle('stylesheet', 'styles/index.less');

Expand Down
Loading

0 comments on commit ba3e3b6

Please sign in to comment.