diff --git a/pages/article/ArticleHandler.php b/pages/article/ArticleHandler.php index 07f6bfb8505..ac1800250a6 100644 --- a/pages/article/ArticleHandler.php +++ b/pages/article/ArticleHandler.php @@ -25,6 +25,7 @@ use APP\observers\events\UsageEvent; use APP\payment\ojs\OJSCompletedPaymentDAO; use APP\payment\ojs\OJSPaymentManager; +use APP\publication\Publication; use APP\security\authorization\OjsJournalMustPublishPolicy; use APP\submission\Submission; use APP\template\TemplateManager; @@ -38,6 +39,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; @@ -167,8 +169,8 @@ public function initialize($request, $args = []) $this->galley = $galley; break; - // In some cases, a URL to a galley may use the ID when it should use - // the urlPath. Redirect to the galley's correct URL. + // In some cases, a URL to a galley may use the ID when it should use + // the urlPath. Redirect to the galley's correct URL. } elseif (ctype_digit($galleyId) && $galley->getId() == $galleyId) { $request->redirect(null, $request->getRequestedPage(), $request->getRequestedOp(), [$submission->getBestId(), $galley->getBestGalleyId()]); } @@ -357,6 +359,13 @@ public function view($args, $request) $templateMgr->assign('purchaseArticleEnabled', true); } + $templateMgr->assign('pubLocaleData', $this->getPublicationLocaleData( + $publication, + $context->getPrimaryLocale(), + $templateMgr->getTemplateVars('activeTheme')->getOption('showMultilingualMetadata') ?: [], + $templateMgr->getTemplateVars('activeTheme')->getOption('showMetadata') ?: [] + )); + if (!Hook::call('ArticleHandler::view', [&$request, &$issue, &$article, $publication])) { $templateMgr->display('frontend/pages/article.tpl'); event(new UsageEvent(Application::ASSOC_TYPE_SUBMISSION, $context, $article, null, null, $this->issue)); @@ -616,4 +625,39 @@ public function userCanViewGalley($request, $articleId, $galleyId = null) } return true; } + + /** + * Format multilingual publication data for template: + * Default data at least includes in one language: full title, title, subtitle, keywords, abstract + * showMultilingualMetadataOpts adds multilingual metadata: title (by default includes fullTitle and subtitle), keywords, abstract, etc. + * showMetadataOpts: additional metadata + */ + protected function getPublicationLocaleData(Publication $publication, string $contextPrimaryLocale, array $showMultilingualMetadataOpts, array $showMetadataOpts): array + { + $titles = collect([ + 'title' => $publication->getTitles('html'), + 'subtitle' => $publication->getSubtitles('html'), + 'fullTitle' => $publication->getFullTitles('html'), + ]); + $metadataOpts = collect($showMetadataOpts)->filter(fn ($opt) => in_array($opt, Services::get('schema')->getMultilingualProps(PKPSchemaService::SCHEMA_PUBLICATION))) + ->concat(['keywords', 'abstract'])->unique()->diff($titles->keys())->values(); + $multilingualOpts = collect($showMultilingualMetadataOpts) + ->when(in_array('title', $showMultilingualMetadataOpts), fn ($m) => $m->concat(['subtitle', 'fullTitle'])->unique()->values()); + $primaryLocale = isset($titles->get('title')[$contextPrimaryLocale]) ? $contextPrimaryLocale : $publication->getData('locale'); + + $getText = fn (array $item, string $opt): array => [ + $opt => [ + 'text' => ($text = array_filter($item, fn (string $locale) => $multilingualOpts->contains($opt) || $locale === $primaryLocale, ARRAY_FILTER_USE_KEY)), + 'headingLang' => collect($text)->map(fn ($_, string $locale): string => $locale === $primaryLocale ? $contextPrimaryLocale : $locale)->toArray() + ], + ]; + + $pubLocaleData = $titles->mapWithKeys($getText) + ->union($metadataOpts->mapWithKeys(fn (string $opt): array => $getText($publication->getData($opt) ?? [], $opt))); + return $pubLocaleData + ->put('languages', $pubLocaleData->map(fn (array $item): array => array_keys($item['text'])) + ->flatten()->sort()->prepend($primaryLocale)->unique()->values()) + ->put('primaryLocale', $primaryLocale) + ->toArray(); + } } diff --git a/plugins/themes/default/DefaultThemePlugin.php b/plugins/themes/default/DefaultThemePlugin.php index 6ebcb1f4424..3f641004319 100644 --- a/plugins/themes/default/DefaultThemePlugin.php +++ b/plugins/themes/default/DefaultThemePlugin.php @@ -124,6 +124,26 @@ 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' => __('common.abstract'), + ], + ], + 'default' => [], + ]); + // Load primary stylesheet $this->addStyle('stylesheet', 'styles/index.less'); diff --git a/plugins/themes/default/locale/en/locale.po b/plugins/themes/default/locale/en/locale.po index c783e630ff5..ca1511b3132 100644 --- a/plugins/themes/default/locale/en/locale.po +++ b/plugins/themes/default/locale/en/locale.po @@ -98,3 +98,15 @@ msgstr "Next slide" msgid "plugins.themes.default.prevSlide" msgstr "Previous slide" + +msgid "plugins.themes.default.option.metadata.label" +msgstr "Show article metadata on the article landing page" + +msgid "plugins.themes.default.option.metadata.description" +msgstr "Select the article metadata to show in other languages." + +msgid "plugins.themes.default.submissionMetadataInLanguage" +msgstr "Article Metadata in English" + +msgid "plugins.themes.default.titleSubtitleSeparator" +msgstr " — " diff --git a/plugins/themes/default/styles/objects/article_details.less b/plugins/themes/default/styles/objects/article_details.less index d8c032b0a0d..85f9291cba3 100644 --- a/plugins/themes/default/styles/objects/article_details.less +++ b/plugins/themes/default/styles/objects/article_details.less @@ -37,7 +37,7 @@ margin-bottom: 0; } - > h2 + p { + > h2 + p, h3 + p { margin-top: 0; } } @@ -52,6 +52,10 @@ .main_entry { + .metadata > .page_metadata_title { + margin: 0; + } + .item { .label { @@ -61,8 +65,7 @@ font-weight: @bold; } - &.doi .label, - &.keywords .label { + &.doi .label { display: inline; font-size: @font-base; } @@ -127,8 +130,7 @@ } } - .item.doi, - .item.keywords { + .item.doi { padding-top: 0; } @@ -315,8 +317,7 @@ font-weight: @bold; } - &.doi .label, - &.keywords .label { + &.doi .label { display: inline; font-size: @font-base; } diff --git a/templates/frontend/objects/article_details.tpl b/templates/frontend/objects/article_details.tpl index 4b6b1463e1b..fc9d85c0aeb 100755 --- a/templates/frontend/objects/article_details.tpl +++ b/templates/frontend/objects/article_details.tpl @@ -64,6 +64,7 @@ * @uses $licenseUrl string URL to license. Only assigned if license should be * included with published submissions. * @uses $ccLicenseBadge string An image and text with details about the license + * @uses $pubLocaleData array Array of formatted publication locale metadata: titles, abstracts, keywords, * * @hook Templates::Article::Main [] * @hook Templates::Article::Details::Reference [] @@ -91,13 +92,12 @@ {/if} -