diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 74dead2df..fbc15967d 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -2,10 +2,31 @@
## Release 4.10 - 2026-05-12
-### Update
+Der neue Release bringt insbesondere Veränderungen bei der Sprachverwaltung und
+den Optionen, die in der Administration editierbar sind.
+
+### Update auf OPUS 4.10
+
+Das Updateskript, `bin/update.sh`, muss ausgeführt werden, da es Änderungen an
+der Datenbank und weitere Updateschritte gibt.
+
+- Tabelle `configuration` wird angelegt
+- Tabelle `languages` wird entfernt
+- Konfiguration in `config.xml` with in die Datenbank übertragen und die
+ Datei optional gelöscht
+- Aktive Sprachen werden in neue Konfigurationsoptionen übernommen
-Das Updateskript muss ausgeführt werden, da es Änderungen an der Datenbank und
-zusätzliche Updateschritte gibt.
+### Sprachverwaltung
+
+Die Sprachverwaltung wurde aus der Administration entfernt. Dafür werden jetzt
+485 ISO 639 Sprachen im Standard unterstützt. Welche Sprachen in den Formularen
+zur Auswahl stehen sollen, lässt sich über Optionen einstellen.
+
+Mehr dazu findet sich im OPUS 4 Handbuch unter
+https://www.opus-repository.org/userdoc/admin/languages.html
+
+Beim Update werden die aktiven Sprachen automatisch in die neue Konfiguration
+übernommen.
### Konfiguration
@@ -18,8 +39,6 @@ Die editierbaren Optionen werden nun in `application/configs/options.yml`
definiert. Generell kann die Liste lokal erweitert werden. Im Standard werden
im Laufe der Zeit mehr Optionen in der Weboberfläche verfügbar gemacht werden.
-TODO Link to documentation
-
### RSS-Links
RSS-Links können nun ausgeblendet werden. Sie werden automatisch ausgeblendet,
diff --git a/application/configs/application.ini b/application/configs/application.ini
index 9a5515e18..98c5f7dc9 100644
--- a/application/configs/application.ini
+++ b/application/configs/application.ini
@@ -61,7 +61,11 @@ db.debug = 0
; LOCALE SETTINGS
resources.locale.default = 'de'
-; SUPPORTED LANGUAGES
+; Languages selectable for documents
+i18n.languages.active = deu, eng, fra, rus, spa, mul
+i18n.languages.sortByName = 0
+
+; SUPPORTED USER INTERFACE LANGUAGES
supportedLanguages = de,en
;GENERAL SETTINGS
diff --git a/application/configs/navigationModules.xml b/application/configs/navigationModules.xml
index 9f00eac02..ce1a1cf7c 100644
--- a/application/configs/navigationModules.xml
+++ b/application/configs/navigationModules.xml
@@ -364,50 +364,6 @@
-
- mvc
-
- admin_title_languages_description
- group-cafelatte
- admin
- language
- index
- languages
-
-
- mvc
-
- admin
- language
- show
-
-
-
- mvc
-
- admin
- language
- new
-
-
-
- mvc
-
- admin
- language
- edit
-
-
-
- mvc
-
- admin
- language
- delete
-
-
-
-
mvc
diff --git a/application/configs/options.yml b/application/configs/options.yml
index 4652309ad..b4c1e7851 100644
--- a/application/configs/options.yml
+++ b/application/configs/options.yml
@@ -1,3 +1,28 @@
+#
+# Defines options available in administration user interface (Settings->Options).
+#
+# The 'type' defines how the option appears in the form. Supported types are
+# - string (default)
+# - int
+# - bool
+#
+# The 'section' allows grouping options. The names are arbitrary and are used as section
+# labels if no translations for the section exist.
+#
+# 'options' can be used to pass additional options to the form element, for
+# instance to increase the size.
+#
+# The translation keys for options use the following patterns:
+# - admin_config_section_SECTIONNAME
+# - admin_config_OPTIONKEY
+# - admin_config_OPTIONKEY_description
+#
+# For instance:
+# - admin_config_section_languages
+# - admin_config_i18n.languages.active
+# - admin_config_i18n.languages.active_description
+#
+
searchengine.solr.parameterDefaults.rows:
type: int
section: searching
@@ -7,3 +32,13 @@ searchengine.solr.parameterDefaults.rows:
browsing.series.sortByTitle:
type: bool
section: browsing
+
+i18n.languages.active:
+ type: string
+ section: languages
+ options:
+ size: 60
+
+i18n.languages.sortByName:
+ type: bool
+ section: languages
diff --git a/composer.json b/composer.json
index 2de75308e..3aa80256f 100644
--- a/composer.json
+++ b/composer.json
@@ -23,8 +23,8 @@
"ext-yaml": "*",
"opus4/zf1-future": "1.25.*",
"jpgraph/jpgraph": "dev-master",
- "opus4-repo/opus4-common": "^4.9",
- "opus4-repo/framework": "dev-master as 4.10",
+ "opus4-repo/opus4-common": "dev-master as 4.10",
+ "opus4-repo/framework": "dev-lang407 as 4.10",
"opus4-repo/search": "^4.9",
"opus4-repo/opus4-bibtex": "^4.9",
"opus4-repo/opus4-import": "^4.9",
@@ -34,6 +34,7 @@
"opus4-repo/opus4-sword": "^4.9",
"opus4-repo/opus4-app-common": "dev-main as 4.10",
"opus4-repo/opus4-deepgreen": "^4.9",
+ "opus4-repo/opus4-i18n": "dev-main as 4.10",
"components/jquery": "3.4.*",
"components/jqueryui": "1.12.*",
"oomphinc/composer-installers-extender": "^2.0",
diff --git a/db/masterdata/002_create_languages.sql b/db/masterdata/002_create_languages.sql
deleted file mode 100644
index 6f44a3bd6..000000000
--- a/db/masterdata/002_create_languages.sql
+++ /dev/null
@@ -1,44 +0,0 @@
--- MySQL dump 10.11
---
--- Server version 5.0.67-0ubuntu6
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Dumping data for table `languages`
--- Based on http://sil.org/iso639-3/iso-639-3_20090210.tab
---
-
-LOCK TABLES `languages` WRITE;
-/*!40000 ALTER TABLE `languages` DISABLE KEYS */;
-INSERT INTO `languages` (`id`, `part2_b`, `part2_t`, `part1`, `scope`, `type`, `ref_name`, `comment`, `active`) VALUES
-('1','ger','deu','de','I','L','German','',1),
-('2','eng','eng','en','I','L','English','',1),
-('3','ita','ita','it','I','L','Italian','',0),
-('4','fre','fra','fr','I','L','French','',1),
-('5','por','por','pt','I','L','Portuguese','',0),
-('6','rus','rus','ru','I','L','Russian','',1),
-('7','spa','spa','es','I','L','Spanish','',1),
-('8','mul','mul','','I','L','Multiple languages','',1);
-/*!40000 ALTER TABLE `languages` ENABLE KEYS */;
-UNLOCK TABLES;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Dump completed on 2009-04-09 8:56:35
diff --git a/db/masterdata/022-set-opus-version.sql b/db/masterdata/022-set-opus-version.sql
index 9c81e0eb0..d2316260f 100644
--- a/db/masterdata/022-set-opus-version.sql
+++ b/db/masterdata/022-set-opus-version.sql
@@ -11,7 +11,7 @@ START TRANSACTION;
-- Set internal OPUS version (for controlling updates)
TRUNCATE TABLE `opus_version`;
-INSERT INTO `opus_version` (`version`) VALUES (21);
+INSERT INTO `opus_version` (`version`) VALUES (22);
COMMIT;
diff --git a/library/Application/Controller/Action/Helper/Translation.php b/library/Application/Controller/Action/Helper/Translation.php
index 17574d8c8..b92a9940c 100644
--- a/library/Application/Controller/Action/Helper/Translation.php
+++ b/library/Application/Controller/Action/Helper/Translation.php
@@ -31,7 +31,6 @@
use Opus\Common\Enrichment;
use Opus\Document;
-use Opus\Language;
/**
* Helper for handling translations.
@@ -103,12 +102,7 @@ public function getKeyForField($modelName, $fieldName)
$translationKey = $this->normalizeModelName($modelName) . '_' . $fieldName;
return preg_replace('/Opus_Common_/', 'Opus_', $translationKey); // TODO LAMINAS fix keys
} else {
- switch ($modelName) {
- case Language::class:
- return $this->normalizeModelName($modelName) . '_' . $fieldName;
- default:
- return $fieldName;
- }
+ return $fieldName;
}
}
diff --git a/library/Application/Form/Element/Language.php b/library/Application/Form/Element/Language.php
index acfe7e09f..bd65e7383 100644
--- a/library/Application/Form/Element/Language.php
+++ b/library/Application/Form/Element/Language.php
@@ -29,7 +29,10 @@
* @license http://www.gnu.org/licenses/gpl.html General Public License
*/
-use Opus\Common\Language;
+use Opus\App\Common\Configuration;
+use Opus\Common\Log;
+use Opus\I18n\I18nException;
+use Opus\I18n\Languages;
/**
* TODO override setLabel for more robust translation
@@ -52,6 +55,23 @@ public function init()
}
}
+ /**
+ * @param string|null $value
+ * @return void
+ */
+ public function setValue($value)
+ {
+ if ($value !== null) {
+ $language = Languages::getLanguage($value);
+
+ if (null !== $language) {
+ $value = $language->getId();
+ }
+ }
+
+ parent::setValue($value);
+ }
+
/**
* @return array
*/
@@ -65,15 +85,68 @@ public static function getLanguageList()
/**
* Setup language list.
+ *
+ * TODO reduce responsibilities of this function
*/
public static function initLanguageList()
{
+ $config = Configuration::getInstance()->getConfig();
+
+ if (! isset($config->i18n->languages->active)) {
+ throw new Exception('no active languages configured');
+ }
+
+ $optionValue = $config->i18n->languages->active;
+
+ if (strlen(trim($optionValue)) > 0) {
+ // Use configured languages
+ $activeLanguages = explode(',', $optionValue);
+ } else {
+ // Use all languages
+ $helper = new Languages();
+ $activeLanguages = array_keys($helper->getAllAsArray());
+ }
+
+ $activeLanguages = array_filter($activeLanguages, function ($lang) {
+ return ! empty($lang);
+ });
+
+ if (isset($config->i18n->languages->local)) {
+ $localLanguages = $config->i18n->languages->local->toArray();
+ $languages = new Languages();
+ try {
+ $languages->addLanguages($localLanguages);
+ } catch (I18nException $ex) {
+ Log::get()->err('Error loading local languages: ' . $ex->getMessage());
+ }
+ }
+
$translate = Application_Translate::getInstance();
+ $locale = $translate->getLocale();
+
$languages = [];
- foreach (Language::getAllActiveTable() as $languageRow) {
- $langId = $languageRow['part2_t'];
- $languages[$langId] = $translate->translateLanguage($langId);
+
+ foreach ($activeLanguages as $lang) {
+ $part2b = trim($lang);
+ $language = Languages::getLanguage($part2b);
+
+ if ($language === null) {
+ Log::get()->err("Language '{$part2b}' not found");
+ continue;
+ }
+
+ $langId = $language->getPart2t();
+ $translation = $language->getDisplayName($locale);
+
+ // TODO support local translations
+
+ $languages[$langId] = $translation;
}
+
+ if (isset($config->i18n->languages->sortByName) && filter_var($config->i18n->languages->sortByName, FILTER_VALIDATE_BOOLEAN)) {
+ asort($languages);
+ }
+
self::$languageList = $languages;
}
}
diff --git a/library/Application/Form/Element/LanguageType.php b/library/Application/Form/Element/LanguageType.php
deleted file mode 100644
index b00fafcea..000000000
--- a/library/Application/Form/Element/LanguageType.php
+++ /dev/null
@@ -1,44 +0,0 @@
-addMultiOption($value, 'Opus_Language_Type_Value_' . $value);
- }
- }
-}
diff --git a/library/Application/Security/AclProvider.php b/library/Application/Security/AclProvider.php
index 678ba3519..3d7256192 100644
--- a/library/Application/Security/AclProvider.php
+++ b/library/Application/Security/AclProvider.php
@@ -65,7 +65,6 @@ class Application_Security_AclProvider
'licences',
'collections',
'series',
- 'languages',
'statistics',
'institutions',
'enrichments',
diff --git a/library/Application/View/Helper/DocumentAbstract.php b/library/Application/View/Helper/DocumentAbstract.php
index 75b534ea7..5a0ba612b 100644
--- a/library/Application/View/Helper/DocumentAbstract.php
+++ b/library/Application/View/Helper/DocumentAbstract.php
@@ -30,7 +30,7 @@
*/
use Opus\Common\DocumentInterface;
-use Opus\Common\Language;
+use Opus\I18n\Languages;
/**
* Helper for printing the abstract of a OPUS document.
@@ -48,7 +48,7 @@ class Application_View_Helper_DocumentAbstract extends Application_View_Helper_D
public function documentAbstract($document = null)
{
if ($this->isPreferUserInterfaceLanguage()) {
- $language = Language::getPart2tForPart1(Application_Translate::getInstance()->getLocale());
+ $language = Languages::getPart2t(Application_Translate::getInstance()->getLocale());
$abstract = $document->getMainAbstract($language);
} else {
diff --git a/library/Application/View/Helper/DocumentTitle.php b/library/Application/View/Helper/DocumentTitle.php
index e62177eed..9672553d8 100644
--- a/library/Application/View/Helper/DocumentTitle.php
+++ b/library/Application/View/Helper/DocumentTitle.php
@@ -30,7 +30,7 @@
*/
use Opus\Common\DocumentInterface;
-use Opus\Common\Language;
+use Opus\I18n\Languages;
/**
* Helper for printing the title of a OPUS document.
@@ -55,7 +55,7 @@ class Application_View_Helper_DocumentTitle extends Application_View_Helper_Docu
public function documentTitle($document = null)
{
if ($this->isPreferUserInterfaceLanguage()) {
- $language = Language::getPart2tForPart1(Application_Translate::getInstance()->getLocale());
+ $language = Languages::getPart2t(Application_Translate::getInstance()->getLocale());
$title = $document->getMainTitle($language);
} else {
diff --git a/library/Application/View/Helper/LanguageWebForm.php b/library/Application/View/Helper/LanguageWebForm.php
index 2bad888c3..a102ee810 100644
--- a/library/Application/View/Helper/LanguageWebForm.php
+++ b/library/Application/View/Helper/LanguageWebForm.php
@@ -29,7 +29,7 @@
* @license http://www.gnu.org/licenses/gpl.html General Public License
*/
-use Opus\Common\Language;
+use Opus\I18n\Languages;
/**
* View helper for tranform long language form in short language form (Part2 in Part1).
@@ -55,8 +55,7 @@ class Application_View_Helper_LanguageWebForm extends Zend_View_Helper_Abstract
public function languageWebForm($value)
{
if (! array_key_exists($value, $this->langCache)) {
- $lang = Language::getPropertiesByPart2T($value);
- $this->langCache[$value] = $lang['part1'];
+ $this->langCache[$value] = Languages::getPart1($value);
}
return $this->langCache[$value];
}
diff --git a/modules/admin/controllers/LanguageController.php b/modules/admin/controllers/LanguageController.php
deleted file mode 100644
index 52e7238ea..000000000
--- a/modules/admin/controllers/LanguageController.php
+++ /dev/null
@@ -1,57 +0,0 @@
-setFormClass(Admin_Form_Language::class);
- parent::init();
- }
-
- /**
- * @param LanguageInterface $model
- * @return bool
- */
- public function isDeletable($model)
- {
- return ! $model->isUsed();
- }
-}
diff --git a/modules/admin/forms/Configuration.php b/modules/admin/forms/Configuration.php
index 8d850fa7b..3fb9d6375 100644
--- a/modules/admin/forms/Configuration.php
+++ b/modules/admin/forms/Configuration.php
@@ -129,7 +129,7 @@ public function updateModel($config)
if (is_array($value)) {
$value = implode(',', $value);
}
- if (strlen(trim($value)) === 0) {
+ if ($value !== null && strlen(trim($value)) === 0) {
$value = null;
}
diff --git a/modules/admin/forms/Document/Tags.php b/modules/admin/forms/Document/Tags.php
index b7ba242b5..e6ba9093c 100644
--- a/modules/admin/forms/Document/Tags.php
+++ b/modules/admin/forms/Document/Tags.php
@@ -30,7 +30,7 @@
*/
use Opus\Common\DocumentInterface;
-use Opus\Common\Language;
+use Opus\I18m\Languages;
/**
* Unterformular fuer GND Subjects im Metadaten-Formular.
@@ -186,7 +186,7 @@ public function processPost($data, $context)
$lang = $data[self::ELEMENT_LANGUAGE];
if ($lang === null) {
$translate = Application_Translate::getInstance();
- $lang = Language::getPart2tForPart1($translate->getLocale());
+ $lang = Languages::getPart2t($translate->getLocale());
}
$this->addMultipleSubjectsFromString($data[self::ELEMENT_SUBJECTS], $lang);
return Admin_Form_Document::RESULT_SHOW;
diff --git a/modules/admin/forms/Language.php b/modules/admin/forms/Language.php
deleted file mode 100644
index b7519298a..000000000
--- a/modules/admin/forms/Language.php
+++ /dev/null
@@ -1,95 +0,0 @@
-setRemoveEmptyCheckbox(false);
- $this->setLabelPrefix('Opus_Language_');
- $this->setUseNameAsLabel(true);
- $this->setModelClass(Language::class);
-
- $this->addElement('checkbox', self::ELEMENT_ACTIVE);
- $this->addElement('text', self::ELEMENT_REFNAME, ['required' => true]);
- $this->addElement('text', self::ELEMENT_PART2T, ['required' => true]);
- $this->addElement('text', self::ELEMENT_PART2B);
- $this->addElement('text', self::ELEMENT_PART1);
- $this->addElement('LanguageScope', self::ELEMENT_SCOPE);
- $this->addElement('LanguageType', self::ELEMENT_TYPE);
- $this->addElement('text', self::ELEMENT_COMMENT);
- }
-
- /**
- * @param LanguageInterface $language
- */
- public function populateFromModel($language)
- {
- $this->getElement(self::ELEMENT_MODEL_ID)->setValue($language->getId());
- $this->getElement(self::ELEMENT_ACTIVE)->setValue($language->getActive());
- $this->getElement(self::ELEMENT_PART2B)->setValue($language->getPart2B());
- $this->getElement(self::ELEMENT_PART2T)->setValue($language->getPart2T());
- $this->getElement(self::ELEMENT_PART1)->setValue($language->getPart1());
- $this->getElement(self::ELEMENT_SCOPE)->setValue($language->getScope());
- $this->getElement(self::ELEMENT_TYPE)->setValue($language->getType());
- $this->getElement(self::ELEMENT_REFNAME)->setValue($language->getRefName());
- $this->getElement(self::ELEMENT_COMMENT)->setValue($language->getComment());
- }
-
- /**
- * @param LanguageInterface $language
- */
- public function updateModel($language)
- {
- $language->setActive($this->getElementValue(self::ELEMENT_ACTIVE));
- $language->setPart2B($this->getElementValue(self::ELEMENT_PART2B));
- $language->setPart2T($this->getElementValue(self::ELEMENT_PART2T));
- $language->setPart1($this->getElementValue(self::ELEMENT_PART1));
- $language->setScope($this->getElementValue(self::ELEMENT_SCOPE));
- $language->setType($this->getElementValue(self::ELEMENT_TYPE));
- $language->setRefName($this->getElementValue(self::ELEMENT_REFNAME));
- $language->setComment($this->getElementValue(self::ELEMENT_COMMENT));
- }
-}
diff --git a/modules/admin/language/config.tmx b/modules/admin/language/config.tmx
index 1211c5130..0ca26d1ca 100644
--- a/modules/admin/language/config.tmx
+++ b/modules/admin/language/config.tmx
@@ -49,7 +49,7 @@
Browsing
- Browsing
+ Browsen
@@ -116,6 +116,33 @@
+
+
+ Selectable languages
+
+
+ Auswählbare Sprachen
+
+
+
+
+
+ Languages selectable for a document (ISO 639).
+
+
+ Sprachen, die für ein Dokument auswählbar sind (ISO 639).
+
+
+
+
+
+ Sort alphabetical
+
+
+ Alphabetisch sortieren
+
+
+