From 8a1068be5a138a5f195a0c5742b6effa936572cd Mon Sep 17 00:00:00 2001
From: jyhein <124268211+jyhein@users.noreply.github.com>
Date: Mon, 5 Feb 2024 12:31:24 +0200
Subject: [PATCH] pkp/pkp-lib#9425 Make submission language selection and
metadata forms independent from website language settings
---
.../I9425_SeparateUIAndSubmissionLocales.php | 31 +++++++++++++++++++
classes/publication/Repository.php | 4 +--
classes/publication/maps/Schema.php | 4 ++-
classes/submission/Repository.php | 3 +-
classes/submission/maps/Schema.php | 8 ++++-
.../articleGalleys/form/ArticleGalleyForm.php | 13 ++++----
.../20-CreateContext.cy.js | 9 ++++--
.../60-content/AmwandengaSubmission.cy.js | 4 +--
.../tests/integration/SubmissionWizard.cy.js | 22 ++++++-------
dbscripts/xml/upgrade.xml | 1 +
pages/submission/SubmissionHandler.php | 4 +--
pages/workflow/WorkflowHandler.php | 12 ++++---
schemas/galley.json | 2 +-
13 files changed, 84 insertions(+), 33 deletions(-)
create mode 100644 classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php
diff --git a/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php b/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php
new file mode 100644
index 00000000000..4a95bd2c795
--- /dev/null
+++ b/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php
@@ -0,0 +1,31 @@
+getSupportedSubmissionLocales();
- $primaryLocale = $submission->getLocale();
+ $primaryLocale = $submission->getData('locale');
// Ensure that the specified section exists
$section = null;
@@ -77,6 +76,7 @@ public function validate($publication, array $props, Submission $submission, Con
}
// Check the word count on abstracts
+ $allowedLocales = $submission->getPublicationLanguages($context->getSupportedSubmissionMetadataLocales());
foreach ($allowedLocales as $localeKey) {
if (empty($props['abstract'][$localeKey])) {
continue;
diff --git a/classes/publication/maps/Schema.php b/classes/publication/maps/Schema.php
index e01c6337286..d8d813f48ce 100644
--- a/classes/publication/maps/Schema.php
+++ b/classes/publication/maps/Schema.php
@@ -49,7 +49,9 @@ protected function mapByProperties(array $props, Publication $publication, bool
);
}
- $output = $this->schemaService->addMissingMultilingualValues(PKPSchemaService::SCHEMA_PUBLICATION, $output, $this->context->getSupportedSubmissionLocales());
+ $locales = $this->submission->getPublicationLanguages($this->context->getSupportedSubmissionMetadataLocales());
+
+ $output = $this->schemaService->addMissingMultilingualValues(PKPSchemaService::SCHEMA_PUBLICATION, $output, $locales);
ksort($output);
diff --git a/classes/submission/Repository.php b/classes/submission/Repository.php
index 579c0c9a536..10d6ee5ac46 100644
--- a/classes/submission/Repository.php
+++ b/classes/submission/Repository.php
@@ -80,7 +80,8 @@ public function validateSubmit(Submission $submission, Context $context): array
$abstracts = $publication->getData('abstract');
if ($abstracts) {
$abstractErrors = [];
- foreach ($context->getSupportedSubmissionLocales() as $localeKey) {
+ $allowedLocales = $submission->getPublicationLanguages($context->getSupportedSubmissionMetadataLocales());
+ foreach ($allowedLocales as $localeKey) {
$abstract = $publication->getData('abstract', $localeKey);
$wordCount = $abstract ? PKPString::getWordCount($abstract) : 0;
if ($wordCount > $section->getAbstractWordCount()) {
diff --git a/classes/submission/maps/Schema.php b/classes/submission/maps/Schema.php
index 272fda89697..12f2097c384 100644
--- a/classes/submission/maps/Schema.php
+++ b/classes/submission/maps/Schema.php
@@ -36,7 +36,13 @@ protected function mapByProperties(array $props, Submission $submission): array
);
}
- $output = $this->schemaService->addMissingMultilingualValues($this->schemaService::SCHEMA_SUBMISSION, $output, $this->context->getSupportedSubmissionLocales());
+ $locales = $this->context->getSupportedSubmissionMetadataLocales();
+
+ if (!in_array($primaryLocale = $submission->getData('locale'), $locales)) {
+ $locales[] = $primaryLocale;
+ }
+
+ $output = $this->schemaService->addMissingMultilingualValues($this->schemaService::SCHEMA_SUBMISSION, $output, $locales);
ksort($output);
diff --git a/controllers/grid/articleGalleys/form/ArticleGalleyForm.php b/controllers/grid/articleGalleys/form/ArticleGalleyForm.php
index 0ad5450ca89..8896f7d741e 100644
--- a/controllers/grid/articleGalleys/form/ArticleGalleyForm.php
+++ b/controllers/grid/articleGalleys/form/ArticleGalleyForm.php
@@ -62,7 +62,7 @@ public function __construct($request, $submission, $publication, $articleGalley
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
// Ensure a locale is provided and valid
- $journal = $request->getJournal();
+ $locales = $request->getJournal()->getSupportedSubmissionMetadataLocaleNames() + $submission->getPublicationLanguageNames() + ($articleGalley?->getLanguageNames() ?? []);
$this->addCheck(
new \PKP\form\validation\FormValidator(
$this,
@@ -70,9 +70,7 @@ public function __construct($request, $submission, $publication, $articleGalley
'required',
'editor.issues.galleyLocaleRequired'
),
- function ($locale) use ($journal) {
- return in_array($locale, $journal->getSupportedSubmissionLocaleNames());
- }
+ fn ($locale) => in_array($locale, $locales)
);
}
@@ -93,9 +91,12 @@ public function fetch($request, $template = null, $display = false)
'supportsDependentFiles' => $articleGalleyFile ? Repo::submissionFile()->supportsDependentFiles($articleGalleyFile) : null,
]);
}
- $context = $request->getContext();
+
+ $supportedLocales = $request->getContext()->getSupportedSubmissionMetadataLocaleNames() + $this->_submission->getPublicationLanguageNames() + ($this->_articleGalley?->getLanguageNames() ?? []);
+ ksort($supportedLocales);
+
$templateMgr->assign([
- 'supportedLocales' => $context->getSupportedSubmissionLocaleNames(),
+ 'supportedLocales' => $supportedLocales,
'submissionId' => $this->_submission->getId(),
'publicationId' => $this->_publication->getId(),
'formDisabled' => !$this->_isEditable
diff --git a/cypress/tests/data/10-ApplicationSetup/20-CreateContext.cy.js b/cypress/tests/data/10-ApplicationSetup/20-CreateContext.cy.js
index feac3e8ca6d..4d45190b0fb 100644
--- a/cypress/tests/data/10-ApplicationSetup/20-CreateContext.cy.js
+++ b/cypress/tests/data/10-ApplicationSetup/20-CreateContext.cy.js
@@ -70,8 +70,13 @@ describe('Data suite tests', function() {
cy.get('#appearance [role="status"]').contains('Saved');
cy.get('button[id="languages-button"]').click();
- cy.get('input[id^=select-cell-fr_CA-submissionLocale]').click();
- cy.contains('Locale settings saved.');
+ cy.get('input[id^="select-cell-fr_CA-formLocale"]').click();
+ cy.get('a[id^=component-grid-settings-languages-submissionlanguagegrid-addLanguageModal-button]').click();
+ cy.get('#locale-fr_CA').should('exist').click();
+ cy.get('#addLanguageForm button[name="submitFormButton"]').click();
+ cy.contains('Submission locales updated.').should('exist');
+ cy.get('input[id^="select-cell-fr_CA-submissionLocale"]').click();
+ cy.get('input[id^="select-cell-fr_CA-submissionMetadataLocale"]').should('be.checked');
cy.get('button[id="indexing-button"]').click();
cy.get('input[name="searchDescription-en"]').type(Cypress.env('contextDescriptions')['en'], {delay: 0});
diff --git a/cypress/tests/data/60-content/AmwandengaSubmission.cy.js b/cypress/tests/data/60-content/AmwandengaSubmission.cy.js
index a9c5fc14a45..a6de75ba6ba 100644
--- a/cypress/tests/data/60-content/AmwandengaSubmission.cy.js
+++ b/cypress/tests/data/60-content/AmwandengaSubmission.cy.js
@@ -224,7 +224,7 @@ describe('Data suite: Amwandenga', function() {
.find('h4').contains('Keywords').siblings('.submissionWizard__reviewPanel__item__value').contains('None provided')
.parents('.submissionWizard__reviewPanel')
.find('h4').contains('Abstract').siblings('.submissionWizard__reviewPanel__item__value').contains(submission.abstract);
- cy.get('h3').contains('Details (French)')
+ cy.get('h3').contains('Details (French (Canada))')
.parents('.submissionWizard__reviewPanel')
.find('h4').contains('Title').siblings('.submissionWizard__reviewPanel__item__value').contains('None provided')
.parents('.submissionWizard__reviewPanel')
@@ -234,7 +234,7 @@ describe('Data suite: Amwandenga', function() {
cy.get('h3').contains('For the Editors (English)')
.parents('.submissionWizard__reviewPanel')
.find('h4').contains('Comments for the Editor').siblings('.submissionWizard__reviewPanel__item__value').contains('None');
- cy.get('h3').contains('For the Editors (French)') // FIXME: Should be French
+ cy.get('h3').contains('For the Editors (French (Canada))')
// Save for later
cy.get('button').contains('Save for Later').click();
diff --git a/cypress/tests/integration/SubmissionWizard.cy.js b/cypress/tests/integration/SubmissionWizard.cy.js
index 1011d67375e..6b9e000ebd0 100644
--- a/cypress/tests/integration/SubmissionWizard.cy.js
+++ b/cypress/tests/integration/SubmissionWizard.cy.js
@@ -479,20 +479,20 @@ describe('Submission Wizard', function() {
cy.get('label:contains("Abstract *")');
cy.contains('Word Count: 0/500');
- // Change submission language to French and section to Reviews
+ // Change submission language to French (Canada) and section to Reviews
cy.contains('Submitting to the Articles section in English');
cy.get('button:contains("Change")').click();
cy.get('h2:contains("Change Submission Settings")')
.parents('.modal')
.within(() => {
- cy.get('label:contains("French")').click();
+ cy.get('label:contains("French (Canada)")').click();
cy.get('label:contains("Reviews")').click();
cy.get('button:contains("Save")').click();
});
- // Forms load with French fields displayed instead of English
- cy.contains('Submitting to the Reviews section in French');
- cy.get('span.pkpFormLocales__locale:contains("French")');
+ // Forms load with French (Canada) fields displayed instead of English
+ cy.contains('Submitting to the Reviews section in French (Canada)');
+ cy.get('span.pkpFormLocales__locale:contains("French (Canada)")');
cy.get('#titleAbstract-keywords-control-fr_CA').type('Transformation Sociale', {delay: 0});
cy.get('li:contains("Transformation Sociale")');
cy.get('#titleAbstract-keywords-control-fr_CA').type('{downarrow}{enter}', {delay: 0});
@@ -502,7 +502,7 @@ describe('Submission Wizard', function() {
cy.get('label:contains("Abstract *")').should('not.exist');
cy.get('*:contains("Word Count: 0/500")').should('not.exist');
- // Show English fields alongside French fields
+ // Show English fields alongside French (Canada) fields
cy.get('.pkpStep:contains("Submission Details") button.pkpFormLocales__locale:contains("English")').click();
cy.get('label:contains("Title in English")');
cy.get('label:contains("Keywords in English")');
@@ -523,7 +523,7 @@ describe('Submission Wizard', function() {
cy.get('button:contains("Continue")').click();
cy.get('button:contains("Continue")').click();
- // Check metadata form shows in French only at first
+ // Check metadata form shows in French (Canada) only at first
const metadata = {
subjects: "Subjects",
disciplines: "Disciplines",
@@ -539,7 +539,7 @@ describe('Submission Wizard', function() {
cy.get('label:contains("' + metadata[prop] + ' in English")').should('not.be.visible');
});
- // Show English fields alongside French fields
+ // Show English fields alongside French (Canada) fields
cy.get('.pkpStep:contains("For the Editors") button.pkpFormLocales__locale:contains("English")').click();
Object.keys(metadata).forEach((prop) => {
cy.get('label:contains("' + metadata[prop] + ' in English")');
@@ -551,13 +551,13 @@ describe('Submission Wizard', function() {
// Errors in review
cy.get('button:contains("Continue")').click();
cy.contains('There are one or more problems');
- cy.get('h3:contains("Details (French)")')
+ cy.get('h3:contains("Details (French (Canada))")')
.parents('.submissionWizard__reviewPanel')
.find('h4:contains("Title")')
.parent()
.contains('This field is required.');
- cy.contains('The given name is missing in French for one or more of the contributors.');
- cy.get('h3:contains("For the Editors (French)")')
+ cy.contains('The given name is missing in French (Canada) for one or more of the contributors.');
+ cy.get('h3:contains("For the Editors (French (Canada))")')
.parents('.submissionWizard__reviewPanel')
.find('h4:contains("Subjects")')
.parent()
diff --git a/dbscripts/xml/upgrade.xml b/dbscripts/xml/upgrade.xml
index a1ea787c3b2..5a437cc85e6 100644
--- a/dbscripts/xml/upgrade.xml
+++ b/dbscripts/xml/upgrade.xml
@@ -229,6 +229,7 @@
+
diff --git a/pages/submission/SubmissionHandler.php b/pages/submission/SubmissionHandler.php
index 6485286889c..a2718152293 100644
--- a/pages/submission/SubmissionHandler.php
+++ b/pages/submission/SubmissionHandler.php
@@ -94,7 +94,7 @@ protected function getSubmittingTo(Context $context, Submission $submission, arr
'submission.wizard.submittingToSectionInLanguage',
[
'section' => $section->getLocalizedTitle(),
- 'language' => Locale::getMetadata($submission->getData('locale'))->getDisplayName(),
+ 'language' => Locale::getSubmissionLocaleDisplayNames([$submission->getData('locale')])[$submission->getData('locale')],
]
);
} elseif ($sectionCount) {
@@ -108,7 +108,7 @@ protected function getSubmittingTo(Context $context, Submission $submission, arr
return __(
'submission.wizard.submittingInLanguage',
[
- 'language' => Locale::getMetadata($submission->getData('locale'))->getDisplayName(),
+ 'language' => Locale::getMetadata($submission->getData('locale'))->getDisplayName(withCountry: true),
]
);
}
diff --git a/pages/workflow/WorkflowHandler.php b/pages/workflow/WorkflowHandler.php
index 98c9ef4b5c2..d0547e867fb 100644
--- a/pages/workflow/WorkflowHandler.php
+++ b/pages/workflow/WorkflowHandler.php
@@ -85,11 +85,15 @@ public function setupIndex($request)
$submissionContext = Services::get('context')->get($submission->getContextId());
}
- $locales = $submissionContext->getSupportedSubmissionLocaleNames();
- $locales = array_map(fn (string $locale, string $name) => ['key' => $locale, 'label' => $name], array_keys($locales), $locales);
-
$latestPublication = $submission->getLatestPublication();
+ $submissionLocale = $submission->getData('locale');
+ $locales = collect($submissionContext->getSupportedSubmissionMetadataLocaleNames() + $submission->getPublicationLanguageNames())
+ ->map(fn (string $name, string $locale) => ['key' => $locale, 'label' => $name])
+ ->sortBy('key')
+ ->values()
+ ->toArray();
+
$latestPublicationApiUrl = $request->getDispatcher()->url($request, Application::ROUTE_API, $submissionContext->getPath(), 'submissions/' . $submission->getId() . '/publications/' . $latestPublication->getId());
$temporaryFileApiUrl = $request->getDispatcher()->url($request, Application::ROUTE_API, $submissionContext->getPath(), 'temporaryFiles');
$issueApiUrl = $request->getDispatcher()->url($request, Application::ROUTE_API, $submissionContext->getData('urlPath'), 'issues/__issueId__');
@@ -113,7 +117,7 @@ class_exists(\APP\components\forms\publication\AssignToIssueForm::class); // For
]);
$components = $templateMgr->getState('components');
- $components[FORM_ISSUE_ENTRY] = $issueEntryForm->getConfig();
+ $components[FORM_ISSUE_ENTRY] = $this->getLocalizedForm($issueEntryForm, $submissionLocale, $locales);
$canEditPublication = Repo::submission()->canEditPublication($submission->getId(), $request->getUser()->getId());
diff --git a/schemas/galley.json b/schemas/galley.json
index b0aac2e72c5..6959d0ba61e 100644
--- a/schemas/galley.json
+++ b/schemas/galley.json
@@ -48,7 +48,7 @@
"description": "The primary locale of this galley.",
"apiSummary": true,
"validation": [
- "regex:/^([a-z]{2})((_[A-Z]{2})?)(@[a-z]{0,})?$/"
+ "regex:/^([A-Za-z]{2,4})([_-]([A-Za-z]{4,5}|[0-9]{3,4}))?([_-]([A-Za-z]{2}|[0-9]{3}))?(@[A-Za-z_]{2,30})?$/"
]
},
"label": {