diff --git a/app/controllers/materialien/files.php b/app/controllers/materialien/files.php
index 25fd5b28ee9af81bd2767af3ae3c2a235a0ddbce..a8d4823d543b4ac3df169613710325e4b142ed21 100644
--- a/app/controllers/materialien/files.php
+++ b/app/controllers/materialien/files.php
@@ -147,7 +147,7 @@ class Materialien_FilesController extends MVVController
             CSRFProtection::verifyUnsafeRequest();
             $stored = false;
 
-            foreach($GLOBALS['MVV_LANGUAGES']['values'] as $key => $entry) {
+            foreach($GLOBALS['CONTENT_LANGUAGES'] as $key => $entry) {
                 if (Request::get('doc_url_'.$key)) {
                     $file = $this->upload_fileurl($mvvfile_id, Request::get('doc_url_'.$key));
                     if ($file) {
diff --git a/app/controllers/module/download.php b/app/controllers/module/download.php
index be527d5747ebf48b258c5f312bc50c76410ae8a7..e5f5be836b740ae038fe78af3bdd9a66d2f55a7e 100644
--- a/app/controllers/module/download.php
+++ b/app/controllers/module/download.php
@@ -10,14 +10,15 @@ class Module_DownloadController extends MVVController
 
     public function details_action($modul_id, $language = null)
     {
-        $language = Request::get('display_language', $language);
-        ModuleManagementModel::setLanguage($language);
-
         $modul = Modul::find($modul_id);
         if (!$modul) {
             throw new Exception(_('Ungültiges Modul'));
         }
-        $this->getDetails($modul_id, $language);
+        $language = Request::get('display_language', $language) ?? $modul->original_language;
+        I18NString::setDefaultLanguage($modul->original_language);
+        I18NString::setContentLanguage($language);
+
+        $this->getDetails($modul_id);
         $this->download = true;
         $as_pdf = Request::int('pdf');
 
@@ -51,7 +52,7 @@ class Module_DownloadController extends MVVController
         }
     }
 
-    private function getDetails($id, $language = null)
+    private function getDetails($id)
     {
         $modul = Modul::find($id);
         if (!$modul) {
@@ -81,7 +82,7 @@ class Module_DownloadController extends MVVController
         $modulTeilData = [];
 
         foreach ($modul->modulteile as $modulTeil) {
-            $deskriptor = $modulTeil->getDeskriptor($language);
+            $deskriptor = $modulTeil->getDeskriptor();
             $num_bezeichnung = $GLOBALS['MVV_MODULTEIL']['NUM_BEZEICHNUNG']['values'][$modulTeil->num_bezeichnung]['name'] ?? '';
 
             $name_kurz = sprintf('%s %d', $num_bezeichnung, $modulTeil->nummer);
@@ -134,7 +135,7 @@ class Module_DownloadController extends MVVController
         $this->semesterSelector = Semester::GetSemesterSelector(null, $currentSemester->getId(), 'semester_id', false);
         $this->modul = $modul;
         $this->pruefungsEbene = $GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$modul->pruef_ebene]['name'] ?? null;
-        $this->modulDeskriptor = $modul->getDeskriptor($language);
+        $this->modulDeskriptor = $modul->getDeskriptor();
         $this->startSemester = Semester::find($modul->start);
         if ($modul->responsible_institute->institute) {
             $this->instituteName = $modul->responsible_institute->getDisplayName();
diff --git a/app/controllers/module/module.php b/app/controllers/module/module.php
index 10674d07dc916d8ded6d027efa57f00cc72bdf0d..08597f1cacb1e383d52a979195290b75257ef2e4 100644
--- a/app/controllers/module/module.php
+++ b/app/controllers/module/module.php
@@ -15,7 +15,10 @@ class Module_ModuleController extends MVVController
     {
         parent::before_filter($action, $args);
         // set navigation
-        Navigation::activateItem($this->me . '/module/module');
+        Navigation::getItem('mvv/module/module')
+            ->setActive(static::class === Module_ModuleController::class);
+        Navigation::getItem('mvv/module/institutes')
+            ->setActive(static::class === Module_InstituteController::class);
         $this->filter = $this->sessGet('filter', []);
         $this->action = $action;
         $this->modul_id = '';
@@ -105,6 +108,14 @@ class Module_ModuleController extends MVVController
         $this->setSidebar();
     }
 
+    public function select_module_language_action()
+    {
+        $this->content_languages = $GLOBALS['CONTENT_LANGUAGES'];
+        $this->default_language = Config::get()->MVV_DEFAULT_LANGUAGE;
+        PageLayout::setTitle(_('Ausgabeprache wählen'));
+        $this->render_template('module/module/select_module_language');
+    }
+
     public function modul_action($modul_id = null, $institut_id = null)
     {
         $own_institutes = MvvPerm::getOwnInstitutes();
@@ -133,13 +144,20 @@ class Module_ModuleController extends MVVController
         if ($this->modul->isNew()) {
             PageLayout::setTitle(_('Neues Modul anlegen'));
             $success_message = ('Das Modul "%s" wurde angelegt.');
-            $this->display_language = $this->modul->getDefaultLanguage();
-            $this->deskriptor = $this->modul->getDeskriptor($this->display_language, true);
+            $language = Request::option('display_language');
+            $content_languages = $GLOBALS['CONTENT_LANGUAGES'];
+            if (!empty($content_languages[$language])) {
+                $this->display_language = $language;
+            } else {
+                $this->display_language = Config::get()->MVV_DEFAULT_LANGUAGE;
+            }
+            $this->modul->original_language = $this->display_language;
+            $this->deskriptor = $this->modul->getDeskriptor();
             $this->reset_search('Modul');
             if (!$modul_id) {
                 PageLayout::postInfo(sprintf(
-                    _('Sie legen ein neues Modul an. Das Modul muss zunächst in der Ausgabesprache <em>%s</em> angelegt werden.'),
-                    $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['name']
+                    _('Sie legen ein neues Modul an. Das Modul wird zunächst in der Ausgabesprache <em>%s</em> angelegt (Originalsprache).'),
+                    $GLOBALS['CONTENT_LANGUAGES'][$this->display_language]['name']
                 ));
             }
             // set default language of instruction
@@ -151,39 +169,37 @@ class Module_ModuleController extends MVVController
         } else {
             $this->display_language = Request::option(
                 'display_language',
-                $this->modul->getDefaultLanguage()
+                $this->modul->original_language
             );
 
-            $this->deskriptor = $this->modul->getDeskriptor($this->display_language, true);
-            $this->translations = $this->deskriptor->getAvailableTranslations();
+            $this->deskriptor = $this->modul->getDeskriptor();
+            $this->translations = $this->deskriptor->getAvailableTranslations($this->modul->original_language);
+            $content_languages = $GLOBALS['CONTENT_LANGUAGES'];
             if (!in_array($this->display_language, $this->translations)) {
-                PageLayout::setTitle(
+                PageLayout::postInfo(
                     sprintf(
-                        _('Modul: <em>%s</em> in der Ausgabesprache <em>%s</em> neu anlegen.'),
+                        _('Modul: <em>%1$s</em> in der Ausgabesprache <em>%2$s</em> neu anlegen.'),
                         $this->modul->getDisplayName(),
-                        $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['name']
+                        $content_languages[$this->display_language]['name']
                     )
                 );
-            } else {
-                PageLayout::setTitle(sprintf(
-                    _('Modul: %s bearbeiten'), $this->modul->getDisplayName()
-                ));
             }
 
             $success_message = _('Das Modul "%s" wurde geändert.');
-            // language selector as sidebar widget
-            $template_factory = $this->get_template_factory();
-            $sidebar_template = $template_factory->render('shared/deskriptor_language', [
-                'modul'   => $this->modul,
-                'sprache' => $this->display_language,
-                'link'    => $this->modulURL($this->modul->id, $this->institut_id),
-                'url'     => $this->url]
-            );
-
-            $widget  = new SidebarWidget();
-            $widget->setTitle(_('Ausgabesprache'));
-            $widget->addElement(new WidgetElement($sidebar_template));
-            $sidebar->addWidget($widget, 'language');
+            $views_widget = new ViewsWidget();
+            $views_widget->setTitle(_('Ausgabesprache'));
+            $languages = $this->translations;
+            $content_languages = array_merge(array_flip($languages), $GLOBALS['CONTENT_LANGUAGES']);
+            foreach ($content_languages as $code => $language) {
+                $views_widget->addLink($language['name']
+                    .  ' (' . ($code === $this->modul->original_language ? _('Originalfassung') . ', ' : '')
+                    . (in_array($code, $languages) ? _('bearbeiten') : _('neu anlegen')) . ')',
+                    URLHelper::getLink($this->modulURL($this->modul->id, $this->institut_id),
+                        ['display_language' => $code]
+                    )
+                )->setActive($code === $this->display_language);
+            }
+            $sidebar->insertWidget($views_widget, 'actions','language');
 
             $action_widget = $sidebar->getWidget('actions');
             $action_widget->addLink(
@@ -223,21 +239,22 @@ class Module_ModuleController extends MVVController
             // list all variants
             $variants = $this->modul->getVariants();
             if (count($variants)) {
-                $widget = new SidebarWidget();
-                $widget->setTitle(_('Varianten'));
-                $widget->addElement(new WidgetElement(
-                    $template_factory->render('shared/modul_variants',
-                        [
-                            'variants' => $variants,
-                            'link'     => $this->modulURL()
-                        ])
-                ));
+                $widget = new TemplateWidget(
+                    _('Varianten'),
+                    $this->get_template_factory()->open('shared/modul_variants'),
+                    [
+                        'variants' => $variants,
+                        'link'     => $this->modulURL(),
+                    ]
+                );
                 $sidebar->addWidget($widget, 'variants');
             }
         }
+
         $this->semester = array_reverse(Semester::getAll());
-        $this->def_lang = $this->display_language === $this->modul->getDefaultLanguage();
-        ModuleManagementModel::setContentLanguage($this->display_language);
+        $this->def_lang = $this->display_language === $this->modul->original_language;
+        I18NString::setDefaultLanguage($this->modul->original_language);
+        I18NString::setContentLanguage($this->display_language);
         if (!$this->def_lang) {
             $action_widget = $sidebar->getWidget('actions');
             $action_widget->addLink(
@@ -247,7 +264,6 @@ class Module_ModuleController extends MVVController
             );
         }
 
-        $this->language = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['content_language'];
         if (Request::isPost()) {
             CSRFProtection::verifyUnsafeRequest();
             $stored = false;
@@ -279,6 +295,13 @@ class Module_ModuleController extends MVVController
                 $this->modul->fassung_typ = Request::option('fassung_typ');
                 $this->modul->version = trim(Request::get('version'));
                 $this->modul->verantwortlich = trim(Request::get('verantwortlich'));
+                // change original language
+                if (
+                    !$this->modul->isNew()
+                    && $this->modul->original_language !== Request::option('original_language')
+                ) {
+                    $this->setOriginalLanguage($this->modul, Request::option('original_language'));
+                }
             }
 
             $deskriptor_fields = ['bezeichnung', 'verantwortlich',
@@ -290,10 +313,16 @@ class Module_ModuleController extends MVVController
 
             foreach ($deskriptor_fields as $deskriptor_field) {
                 if ($this->deskriptor->isI18nField($deskriptor_field)) {
-                    $this->deskriptor->$deskriptor_field->setLocalized(
-                        trim(Request::get($deskriptor_field)),
-                        $this->language
-                    );
+                    if ($this->display_language === $this->modul->original_language) {
+                        $this->deskriptor->$deskriptor_field->setOriginal(
+                            trim(Request::get($deskriptor_field))
+                        );
+                    } else {
+                        $this->deskriptor->$deskriptor_field->setLocalized(
+                            trim(Request::get($deskriptor_field)),
+                            $this->display_language
+                        );
+                    }
                 } else {
                     $this->deskriptor->setValue(
                         $deskriptor_field,
@@ -307,7 +336,7 @@ class Module_ModuleController extends MVVController
                 $df = $this->deskriptor->datafields->findOneBy('datafield_id', $df_key);
                 if ($df) {
                     $tdf = $df->getTypedDatafield();
-                    $tdf->setContentLanguage($this->language);
+                    $tdf->setContentLanguage($this->display_language);
                     $tdf->setValueFromSubmit($df_value);
                     $tdf->store();
                 }
@@ -652,54 +681,56 @@ class Module_ModuleController extends MVVController
         if ($this->modulteil->isNew()) {
             PageLayout::setTitle(_('Neuen Modulteil anlegen'));
             $success_message = ('Der Modulteil "%s" wurde angelegt.');
-            $this->display_language = $this->modulteil->getDefaultLanguage();
-            $this->deskriptor = $this->modulteil->getDeskriptor($this->display_language, true);
+            $this->display_language = Request::option(
+                'display_language',
+                $this->modul->original_language
+            );
+            $this->deskriptor = $this->modulteil->getDeskriptor();
             PageLayout::postInfo(sprintf(
-                _('Sie legen einen neuen Modulteil für das Modul <em>%s</em> an. Der Modulteil muss zunächst in der Ausgabesprache <em>%s</em> angelegt werden.'),
+                _('Sie legen einen neuen Modulteil für das Modul <em>%1$s</em> an. Der Modulteil muss zunächst in der Ausgabesprache <em>%2$s</em> angelegt werden.'),
                 htmlReady($this->modul->getDisplayName()),
-                htmlReady($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['name'])
+                htmlReady($GLOBALS['CONTENT_LANGUAGES'][$this->display_language]['name'])
             ));
             // set default language of instruction
-            if ($GLOBALS['MVV_MODULTEIL']['SPRACHE']['default']) {
+            if (!empty($GLOBALS['MVV_MODULTEIL']['SPRACHE']['default'])) {
                 $this->modulteil->assignLanguagesOfInstruction([
                     $GLOBALS['MVV_MODULTEIL']['SPRACHE']['default']
                 ]);
             }
         } else {
-            $this->display_language = Request::option('display_language', $this->modulteil->getDefaultLanguage());
-            $this->deskriptor = $this->modulteil->getDeskriptor($this->display_language, true);
-            $this->translations = $this->deskriptor->getAvailableTranslations();
-
+            $this->display_language = Request::option('display_language', $this->modul->original_language);
+            $this->deskriptor = $this->modulteil->getDeskriptor();
+            $this->translations = $this->deskriptor->getAvailableTranslations($this->modul->original_language);
             if (!in_array($this->display_language, $this->translations)) {
                 PageLayout::setTitle(sprintf(
-                    _('Modulteil: "%s" in der Ausgabesprache "%s" neu anlegen.'),
+                    _('Modulteil: <em>%1$s</em> in der Ausgabesprache <em>%2$s</em> neu anlegen.'),
                     $this->modulteil->getDisplayName(),
-                    $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['name']
+                    $GLOBALS['CONTENT_LANGUAGES'][$this->display_language]['name']
                 ));
             } else {
                 PageLayout::setTitle(sprintf(_('Modulteil: %s'), htmlReady($this->modulteil->getDisplayName())));
             }
-            $success_message = _('Der Modulteil "%s" wurde geändert.');
-            // sidebar widget for selecting language
-            $template_factory = $this->get_template_factory();
+            $success_message = _('Der Modulteil <em>%s</em> wurde geändert.');
+
             $sidebar = Sidebar::get();
-            $widget = new ListWidget();
-            $widget->setTitle(_('Ausgabesprache'));
-            $widget_element = new WidgetElement(
-                $template_factory->render('shared/deskriptor_language',
-                    [
-                        'modul'   => $this->modulteil,
-                        'sprache' => $this->display_language,
-                        'link'    => $this->modulteilURL($this->modulteil->id),
-                        'url'     => $this->url
-                    ]
-                )
-            );
-            $widget->addElement($widget_element);
-            $sidebar->addWidget($widget, 'languages');
+            $views_widget = new ViewsWidget();
+            $views_widget->setTitle(_('Ausgabesprache'));
+            $content_languages = array_merge(array_flip($this->translations), $GLOBALS['CONTENT_LANGUAGES']);
+            foreach ($content_languages as $code => $language) {
+                $views_widget->addLink($language['name']
+                    .  ' (' . ($code === $this->modul->original_language ? _('Originalfassung') . ', ' : '')
+                    . (in_array($code, $this->translations) ? _('bearbeiten') : _('neu anlegen')) . ')',
+                    URLHelper::getLink($this->modulteilURL($this->modulteil->id),
+                        ['display_language' => $code]
+                    )
+                )->setActive($code === $this->display_language);
+            }
+            $sidebar->insertWidget($views_widget, 'actions','language');
         }
 
-        $this->def_lang = $this->display_language === $this->modulteil->getDefaultLanguage();
+        $this->def_lang = $this->display_language === $this->modul->original_language;
+        I18NString::setDefaultLanguage($this->modul->original_language);
+        I18NString::setContentLanguage($this->display_language);
 
         if (!$this->def_lang) {
             $action_widget = $sidebar->getWidget('actions');
@@ -711,7 +742,6 @@ class Module_ModuleController extends MVVController
             );
         }
 
-        $this->language = $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['content_language'];
         if (Request::submitted('store')) {
             CSRFProtection::verifyUnsafeRequest();
             $stored = false;
@@ -748,12 +778,21 @@ class Module_ModuleController extends MVVController
 
             foreach ($deskriptor_fields as $deskriptor_field) {
                 if ($this->deskriptor->isI18nField($deskriptor_field)) {
-                    $this->deskriptor->$deskriptor_field->setLocalized(
-                        trim(Request::get($deskriptor_field)),
-                        $this->language
-                    );
+                    if ($this->display_language === $this->modul->original_language) {
+                        $this->deskriptor->$deskriptor_field->setOriginal(
+                            trim(Request::get($deskriptor_field))
+                        );
+                    } else {
+                        $this->deskriptor->$deskriptor_field->setLocalized(
+                            trim(Request::get($deskriptor_field)),
+                            $this->display_language
+                        );
+                    }
                 } else {
-                    $this->deskriptor->setValue($deskriptor_field, trim(Request::get($deskriptor_field)));
+                    $this->deskriptor->setValue(
+                        $deskriptor_field,
+                        trim(Request::get($deskriptor_field))
+                    );
                 }
             }
 
@@ -762,7 +801,7 @@ class Module_ModuleController extends MVVController
                 $df = $this->deskriptor->datafields->findOneBy('datafield_id', $df_key);
                 if ($df) {
                     $tdf = $df->getTypedDatafield();
-                    $tdf->setContentLanguage($this->language);
+                    $tdf->setContentLanguage($this->display_language);
                     $tdf->setValueFromSubmit($df_value);
                     $tdf->store();
                 }
@@ -795,23 +834,25 @@ class Module_ModuleController extends MVVController
                 return;
             }
         }
-        if ($this->display_language !== $this->modulteil->getDefaultLanguage() && $this->deskriptor->isNew()) {
+        if ($this->display_language !== $this->modul->original_language && $this->deskriptor->isNew()) {
             PageLayout::postInfo(sprintf(
                 _('Neue Beschreibung zum Modulteil "%s" in der Ausgabesprache %s anlegen.'),
                 htmlReady($this->modulteil->getDisplayName()),
-                htmlReady($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$this->display_language]['name'])
+                htmlReady($GLOBALS['CONTENT_LANGUAGES'][$this->display_language]['name'])
             ));
         }
         $this->cancel_url = $this->detailsURL($this->modulteil->modul_id);
 
-        $action_widget = Sidebar::get()->getWidget('actions');
-        $action_widget->addLink(
-            _('Log-Einträge dieses Modulteils'),
-            $this->url_for('shared/log_event/show/Modulteil/' . $this->modulteil->id,
-                ['object2_type' => 'ModulteilDeskriptor', 'object2_id' => $this->deskriptor->id]
-            ),
-            Icon::create('log')
-        )->asDialog();
+        if (!$this->modulteil->isNew()) {
+            $action_widget = Sidebar::get()->getWidget('actions');
+            $action_widget->addLink(
+                _('Log-Einträge dieses Modulteils'),
+                $this->url_for('shared/log_event/show/Modulteil/' . $this->modulteil->id,
+                    ['object2_type' => 'ModulteilDeskriptor', 'object2_id' => $this->deskriptor->id]
+                ),
+                Icon::create('log')
+            )->asDialog();
+        }
 
         $this->render_template('module/module/modulteil', $this->layout);
     }
@@ -828,7 +869,7 @@ class Module_ModuleController extends MVVController
         if (is_null($deskriptor)) {
             throw new Trails\Exception(404, _('Unbekannter Deskriptor'));
         }
-        $def_lang = $deskriptor->modulteil->getDefaultLanguage();
+        $def_lang = $deskriptor->modulteil->modul->original_language;
         if ($language === $def_lang) {
             throw new Trails\Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.'));
         }
@@ -1159,6 +1200,135 @@ class Module_ModuleController extends MVVController
         }
     }
 
+    public function change_language_action(string $module_id): void
+    {
+        $module = Modul::find($module_id);
+        if (!$module) {
+            throw new UnexpectedValueException('Unknown module.');
+        }
+        PageLayout::setTitle(_('Originalsprache ändern'));
+        $this->translations = $module->deskriptoren->getAvailableTranslations($module->original_language);
+        $this->content_languages = $GLOBALS['CONTENT_LANGUAGES'];
+        $this->original_language = $module->original_language;
+        $this->module_id = $module->id;
+    }
+
+    public function store_language_action(string $module_id): void
+    {
+        $module = Modul::find($module_id);
+        if (!$module) {
+            throw new UnexpectedValueException('Unknown module.');
+        }
+        CSRFProtection::verifyUnsafeRequest();
+        $new_language = Request::option('new_language');
+        if ($new_language !== $module->original_language) {
+            $descriptor = $module->deskriptoren;
+            if (Request::bool('swap_data')) {
+                self::swap_translation($descriptor, $new_language, $module->original_language);
+                $module->modulteile->each(
+                    fn($component) => self::swap_translation(
+                        $component->deskriptoren,
+                        $new_language,
+                        $module->original_language
+                    )
+                );
+            } else {
+                self::swap_language($module->deskriptoren, $new_language, $module->original_language);
+                $module->modulteile->each(
+                    fn($component) => self::swap_language(
+                        $component->deskriptoren,
+                        $new_language,
+                        $module->original_language
+                    )
+                );
+            }
+            $module->original_language = $new_language;
+            $module->store();
+        } else {
+            throw new UnexpectedValueException('New language has to be different from current language.');
+        }
+        $this->relocate('module/module/index');
+    }
+
+    /**
+     * Swaps the language of the descriptor, but not the translated content.
+     *
+     * @param ModulDeskriptor|ModulteilDeskriptor $descriptor The descriptor of a module or a module component.
+     * @param string $new_language The language to swap to as language code.
+     * @param string $old_language The current languageas language code.
+     * @return int|bool Number of swapped translations or false if no translation is available.
+     */
+    private static function swap_language(
+        ModulDeskriptor|ModulteilDeskriptor $descriptor,
+        string $new_language,
+        string $old_language
+    ): int|bool
+    {
+        // change language setting in i18n for this descriptor if a translation exists
+        $translations = $descriptor->getAvailableTranslations($old_language);
+        if (count($translations) > 1) {
+            $metadata = $descriptor->getTableMetadata();
+            foreach (array_keys($metadata['fields']) as $field) {
+                if ($descriptor->isI18nField($field)) {
+                    $i18n_field = $descriptor->$field;
+                    $i18n_field->setDefaultLanguage($old_language);
+                    $translation = $i18n_field->translation($new_language);
+                    if (!empty($translation)) {
+                        $translations = $i18n_field->toArray();
+                        unset($translations[$new_language]);
+                        $translations[$old_language] = $translation;
+                        $i18n_field->setTranslations($translations);
+                    }
+                    $i18n_field->setDefaultLanguage($new_language);
+                }
+            }
+            return $descriptor->store();
+        }
+        return false;
+    }
+
+    /**
+     * Swaps the language of the descriptor, swaps the translated content also.
+     *
+     * @param ModulDeskriptor|ModulteilDeskriptor $descriptor The descriptor of a module or a module component.
+     * @param string $new_language The language to swap to as language code.
+     * @param string $old_language The current language as language code.
+     * @return int|bool Number of swapped translations or false if no translation is available.
+     */
+    private static function swap_translation(
+        ModulDeskriptor|ModulteilDeskriptor $descriptor,
+        string $new_language,
+        string $old_language
+    ): int|bool
+    {
+        if (
+            !array_key_exists($new_language, $GLOBALS['CONTENT_LANGUAGES'])
+            || !array_key_exists($old_language, $GLOBALS['CONTENT_LANGUAGES'])
+        ) {
+            throw new UnexpectedValueException('Language code refers to no content language.');
+        }
+        $count = 0;
+        $meta_data = $descriptor->getTableMetadata();
+        $descriptor_class = $descriptor::class;
+        foreach ($meta_data['fields'] as $field => $foo) {
+            if ($descriptor->isI18nField($field)) {
+                $i18n_field = $descriptor->$field;
+                $i18n_field->setDefaultLanguage($old_language);
+                $new_base_content = $i18n_field->translation($new_language);
+                $old_base_content = $i18n_field->original();
+                $i18n_field->setDefaultLanguage($new_language);
+                if (!empty($new_base_content)) {
+                    $i18n_field->setOriginal($new_base_content);
+                    $i18n_field->setLocalized($old_base_content, $old_language);
+                }
+                $lang = $i18n_field->toArray();
+                unset($lang[$new_language]);
+                $i18n_field->setTranslations($lang);
+            }
+        }
+        return $descriptor->store();
+    }
+
     /**
      * do the search
      */
@@ -1332,25 +1502,14 @@ class Module_ModuleController extends MVVController
     {
         $sidebar = Sidebar::get();
 
-        $widget  = new ViewsWidget();
-        $widget->addLink(
-            _('Liste der Module'),
-            $this->url_for('module/module/index')
-        )->setActive(get_called_class() === 'Module_ModuleController');
-        $widget->addLink(
-            _('Gruppiert nach verantwortlichen Einrichtungen'),
-            $this->url_for('module/institute/index')
-        )->setActive(get_called_class() === 'Module_InstituteController');
-        $sidebar->addWidget($widget, 'views');
-
         $widget  = new ActionsWidget();
         $widget->setTitle(_('Aktionen'));
         if (MvvPerm::havePermCreate('Modul')) {
             $widget->addLink(
                 _('Neues Modul anlegen'),
-                $this->modulURL(),
+                $this->select_module_languageURL(),
                 Icon::create('add')
-            );
+            )->asDialog('size=auto');
         }
         $sidebar->addWidget($widget, 'actions');
 
@@ -1573,4 +1732,47 @@ class Module_ModuleController extends MVVController
                   WHERE `mvv_studiengang`.`abschluss_id` = ?";
         return DBManager::get()->fetchFirst($query, [$abschluss_id]);
     }
+
+    /**
+     * Sets the original language for the given module.
+     *
+     * @param Modul $module Sets the original language for this module.
+     * @param string $original_language The original language as language code.
+     * @return void
+     */
+    private function setOriginalLanguage(Modul $module, string $original_language): void
+    {
+        $content_language = $GLOBALS['CONTENT_LANGUAGES'][$original_language];
+        if (empty($content_language)) {
+            throw new InvalidArgumentException("Original language $original_language is not defined");
+        }
+        if ($module->deskriptoren) {
+            $current_language = $module->original_language;
+            $module->original_language = $original_language;
+            DBManager::get()->execute("
+                UPDATE `i18n`
+                SET `lang` = ?
+                WHERE `object_id` = ?
+                  AND `table` = 'mvv_modul_deskriptor'
+                  AND `lang` = ?",
+                [
+                    $original_language,
+                    $module->deskriptoren->id,
+                    $current_language
+                ]);
+            $module->modulteile->each(fn($component) => DBManager::get()->execute("
+                    UPDATE `i18n`
+                    SET `lang` = ?
+                    WHERE `object_id` IN (?)
+                      AND `table` = 'mvv_modulteil_deskriptor'
+                      AND `lang` = ?",
+                    [
+                        $original_language,
+                        $component->deskriptoren->id,
+                        $current_language
+                    ]
+                )
+            );
+        }
+    }
 }
diff --git a/app/controllers/search/angebot.php b/app/controllers/search/angebot.php
index f2b532197257fab72278b00072b78f80a44c2032..0c0f402f86624ae5485a8e9545d535a7c9a90a27 100644
--- a/app/controllers/search/angebot.php
+++ b/app/controllers/search/angebot.php
@@ -172,7 +172,7 @@ class Search_AngebotController extends MVVController
     public function verlauf_action($stgteil_id, $stgteil_bez_id = null,
             $studiengang_id = null)
     {
-        ModuleManagementModel::setLanguage($_SESSION['_language']);
+        ModuleManagementModel::setContentLanguage($_SESSION['_language']);
 
         $response = $this->relay('search/studiengaenge/verlauf', $stgteil_id,
                 $stgteil_bez_id, $studiengang_id);
diff --git a/app/controllers/search/studiengaenge.php b/app/controllers/search/studiengaenge.php
index 0dd5c7d9f1a7af22ab64ab27d2fcd4fa1a691d4c..8f08c329967ff7111208778dbfb853104fcbae83 100644
--- a/app/controllers/search/studiengaenge.php
+++ b/app/controllers/search/studiengaenge.php
@@ -341,15 +341,17 @@ class Search_StudiengaengeController extends MVVController
             // add links to export Modulhandbücher as PDF
             $widget = new ActionsWidget();
             $widget->setTitle(_('Aktuelle Modulhandbücher'));
-            $avl_lang = array_keys($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values']);
-
-            foreach ($avl_lang as $language) {
-                if ($language === $GLOBALS['MVV_LANGUAGES']['default']) {
+            $content_languages = array_merge(
+                ['original' => ['name' => _('Originalfassung')]],
+                $GLOBALS['CONTENT_LANGUAGES']
+            );
+            foreach (array_keys($content_languages) as $language) {
+                if ($language === 'original') {
                     $title = _('Originalfassung als PDF');
                 } else {
                     $title = sprintf(
-                        _('Zweitfassung (%s) als PDF'),
-                        $GLOBALS['MVV_LANGUAGES']['values'][$language]['name']
+                        _('Ausgabesprache (%s) als PDF'),
+                        $content_languages[$language]['name']
                     );
                 }
                 // get link without registered parameters
@@ -373,7 +375,7 @@ class Search_StudiengaengeController extends MVVController
     public function info_action($studiengang_id, $language = null)
     {
         $language = $language ?: Request::get('language', $_SESSION['_language']);
-        ModuleManagementModel::setLanguage($language);
+        ModuleManagementModel::setContentLanguage($language);
 
         $this->studiengang = Studiengang::find($studiengang_id);
         if (!$this->studiengang) {
@@ -391,23 +393,23 @@ class Search_StudiengaengeController extends MVVController
             $file = $document->mvv_file;
             if ($file->extern_visible) {
                 $mvv_file_ref = null;
-                foreach ($GLOBALS['MVV_LANGUAGES']['values'] as $key => $mvv_language) {
-                    if ($mvv_language['locale'] === $_SESSION['_language']) {
-                        $mvv_file_ref = $file->file_refs->findOneBy('file_language', $key);
+                foreach ($GLOBALS['CONTENT_LANGUAGES'] as $language_key => $mvv_language) {
+                    if ($language_key === $_SESSION['_language']) {
+                        $mvv_file_ref = $file->file_refs->findOneBy('file_language', $language_key);
                     } else {
-                        $mvv_file_ref = $file->file_refs->findOneBy('file_language', $GLOBALS['MVV_LANGUAGES']['default']);
+                        $mvv_file_ref = $file->file_refs->findOneBy('file_language', Config::get()->MVV_DEFAULT_LANGUAGE);
                     }
                 }
                 if ($mvv_file_ref) {
                     $filetype = $mvv_file_ref->file_ref->getFileType();
                     $this->all_documents[$file->category][$file->id] =
-                            [
-                                'name' => $file->getDisplayName(),
-                                'url'  => $mvv_file_ref->file_ref->getDownloadURL(),
-                                'metadata_url' => $mvv_file_ref->file_ref->file->metadata['url'] ?? null,
-                                'extension' => $mvv_file_ref->file_ref->file->getExtension(),
-                                'is_link' => ($filetype instanceof URLFile)
-                            ];
+                        [
+                            'name' => $file->getDisplayName(),
+                            'url'  => $mvv_file_ref->file_ref->getDownloadURL(),
+                            'metadata_url' => $mvv_file_ref->file_ref->file->metadata['url'] ?? null,
+                            'extension' => $mvv_file_ref->file_ref->file->getExtension(),
+                            'is_link' => ($filetype instanceof URLFile)
+                        ];
                 }
             }
         }
diff --git a/app/controllers/seminar/details.php b/app/controllers/seminar/details.php
index 3ce2fab122b681e1d45377f4b65a19b43118927b..6750fa63cb7c242a055b1d706d08dc046fbc134b 100644
--- a/app/controllers/seminar/details.php
+++ b/app/controllers/seminar/details.php
@@ -21,7 +21,7 @@ class Seminar_DetailsController extends MVVController
     public function before_filter(&$action, &$args)
     {
         parent::before_filter($action, $args);
-        ModuleManagementModel::setLanguage($_SESSION['_language']);
+        ModuleManagementModel::setContentLanguage($_SESSION['_language']);
 
         if (Request::isXhr()) {
             $this->set_layout(null);
@@ -38,4 +38,4 @@ class Seminar_DetailsController extends MVVController
         $this->mvv_pathes = MvvCourse::get($seminar_id)->getTrails($trail_classes);
     }
 
-}
\ No newline at end of file
+}
diff --git a/app/controllers/shared/download.php b/app/controllers/shared/download.php
index f94bc86f10001e11f1f109b92ca8d20178d7686f..6e3999823ece00a582c12c2f8617b8c839054aa3 100644
--- a/app/controllers/shared/download.php
+++ b/app/controllers/shared/download.php
@@ -154,7 +154,7 @@ class Shared_DownloadController extends AuthenticatedController
     public function getMVVPluginModulDescription($modul, $display_language = null)
     {
         if ($display_language == null) {
-            $display_language = $GLOBALS['MVV_LANGUAGES']['default'];
+            $display_language = Config::get()->MVV_DEFAULT_LANGUAGE;
         }
 
         $path = $GLOBALS['STUDIP_BASE_PATH'] . '/app/views/shared/modul/';
@@ -168,8 +168,7 @@ class Shared_DownloadController extends AuthenticatedController
 
         $factory = new Flexi\Factory($path);
         $type = 1;
-        if (count($modul->modulteile) == 1) {
-            $modulteil = $modul->modulteile->first();
+        if (count($modul->modulteile) === 1) {
             $type = 2;
         } elseif (count($modul->modulteile) === 0) {
             $type = 3;
diff --git a/app/controllers/shared/modul.php b/app/controllers/shared/modul.php
index d1a6ecfb21625f335418b20d88121703ebb5b37a..2cb9a8555115c1d6f35fe7a23712a2245cbc1914 100644
--- a/app/controllers/shared/modul.php
+++ b/app/controllers/shared/modul.php
@@ -13,8 +13,6 @@
  * @since       3.5
  */
 
-
-
 class Shared_ModulController extends AuthenticatedController
 {
 
@@ -28,98 +26,91 @@ class Shared_ModulController extends AuthenticatedController
     public function overview_action($modul_id, $semester_id = null)
     {
         $display_language = Request::option('display_language', $_SESSION['_language']);
-        ModuleManagementModel::setLanguage($display_language);
+        ModuleManagementModel::setContentLanguage($display_language);
 
-        $modul = Modul::find($modul_id);
-        if (!$modul->hasPublicStatus()) {
+        $this->modul = Modul::find($modul_id);
+        if (!$this->modul->hasPublicStatus()) {
             throw new AccessDeniedException();
         }
-        if ($modul) {
-            $this->details_id = $modul->getId();
+        if ($this->modul) {
+            $this->details_id = $this->modul->getId();
 
             $type = 1;
-            if (count($modul->modulteile) == 1) {
-                $modulteil = $modul->modulteile->first();
+            if (count($this->modul->modulteile) == 1) {
+                $modulteil = $this->modul->modulteile->first();
                 $type = 3;
                 if (count($modulteil->lvgruppen) > 0) {
                     $type = 2;
                 }
-            } else if (count($modul->modulteile) == 0) {
+            } else if (count($this->modul->modulteile) == 0) {
                 $type = 3;
             }
 
             if (!$semester_id) {
-                $currentSemester = Semester::findDefault();
+                $current_semester = Semester::findDefault();
             } else {
-                $currentSemester = Semester::find($semester_id);
+                $current_semester = Semester::find($semester_id);
             }
 
             $sws = 0;
-            $institut = new Institute($modul->responsible_institute->institut_id);
-            $modulTeileData = [];
-            foreach ($modul->modulteile as $modulTeil) {
-
-                $modulTeilDeskriptor = $modulTeil->getDeskriptor($display_language);
-
-                $sws += (int) $modulTeil->sws;
-
-                $num_bezeichnung = $GLOBALS['MVV_MODULTEIL']['NUM_BEZEICHNUNG']['values'][$modulTeil->num_bezeichnung]['name'] ?? '';
-
-                $name_kurz = sprintf('%s %d', $num_bezeichnung, $modulTeil->nummer);
-
-                $modulTeileData[$modulTeil->getId()] = [
-                    'name' => $modulTeil->getDisplayName(),
+            $institut = new Institute($this->modul->responsible_institute->institut_id);
+            $modulteile_data = [];
+            foreach ($this->modul->modulteile as $modulteil) {
+                $modulteil_deskriptor = $modulteil->getDeskriptor();
+                $sws += (int) $modulteil->sws;
+                $num_bezeichnung = $GLOBALS['MVV_MODULTEIL']['NUM_BEZEICHNUNG']['values'][$modulteil->num_bezeichnung]['name'] ?? '';
+                $name_kurz = sprintf('%s %d', $num_bezeichnung, $modulteil->nummer);
+                $modulteile_data[$modulteil->getId()] = [
+                    'name' => $modulteil->getDisplayName(),
                     'name_kurz' => $name_kurz,
-                    'voraussetzung' => $modulTeilDeskriptor->voraussetzung,
-                    'pruef_leistung' => $modulTeilDeskriptor->pruef_leistung,
-                    'pruef_vorleistung' => $modulTeilDeskriptor->pruef_vorleistung,
-                    'kommentar' => $modulTeilDeskriptor->kommentar,
-                    'kapazitaet' => $modulTeil->kapazitaet,
+                    'voraussetzung' => $modulteil_deskriptor->voraussetzung,
+                    'pruef_leistung' => $modulteil_deskriptor->pruef_leistung,
+                    'pruef_vorleistung' => $modulteil_deskriptor->pruef_vorleistung,
+                    'kommentar' => $modulteil_deskriptor->kommentar,
+                    'kapazitaet' => $modulteil->kapazitaet,
                     'lvGruppen' => []
                 ];
 
-                $lvGruppen = Lvgruppe::findByModulteil($modulTeil->getId());
+                $lvGruppen = Lvgruppe::findByModulteil($modulteil->getId());
                 foreach ($lvGruppen as $lvGruppe) {
-                    $ids = array_column($lvGruppe->getAssignedCoursesBySemester($currentSemester['semester_id'], $GLOBALS['user']->id), 'seminar_id');
+                    $ids = array_column($lvGruppe->getAssignedCoursesBySemester($current_semester['semester_id'], $GLOBALS['user']->id), 'seminar_id');
                     $courses = Course::findMany($ids, 'order by Veranstaltungsnummer, Name');
-                    $modulTeileData[$modulTeil->getId()]['lvGruppen'][$lvGruppe->getId()] = [
+                    $modulteile_data[$modulteil->getId()]['lvGruppen'][$lvGruppe->getId()] = [
                         'courses' => $courses,
                         'alt_texte' => $lvGruppe->alttext
                     ];
                 }
             }
-            $this->modulTeile = $modulTeileData;
-            $this->deskriptor = $modul->getDeskriptor($display_language);
+            $this->modulteile = $modulteile_data;
+            $this->deskriptor = $this->modul->getDeskriptor();
             $this->institut = $institut;
-            $this->semester = $currentSemester;
+            $this->semester = $current_semester;
             $this->sws = $sws;
 
-            $this->pruef_ebene = $GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$modul->pruef_ebene]['name'] ?? null;
-            $this->modul = $modul;
+            $this->pruef_ebene = $GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$this->modul->pruef_ebene]['name'] ?? null;
             $this->type = $type;
             $this->self_url = $this->url_for('modul/show/' . $modul_id);
             $this->detail_url = $this->url_for('modul/detail/' . $modul_id);
-            $this->teilnahmeVoraussetzung = $modul->getDeskriptor()->voraussetzung;
-            PageLayout::setTitle($modul->getDisplayName() . ' (' . _('Veranstaltungsübersicht') .')');
+            PageLayout::setTitle($this->modul->getDisplayName() . ' (' . _('Veranstaltungsübersicht') .')');
         }
     }
 
     public function description_action($id)
     {
-        $modul = Modul::find($id);
-        $perm = MvvPerm::get($modul);
-        if (!($modul->hasPublicStatus() || $perm->haveObjectPerm(MvvPerm::PERM_READ))) {
+        $this->modul = Modul::find($id);
+        $perm = MvvPerm::get($this->modul);
+        if (!($this->modul->hasPublicStatus() || $perm->haveObjectPerm(MvvPerm::PERM_READ))) {
             throw new AccessDeniedException();
         }
-        $type = 1;
-        if (count($modul->modulteile) == 1) {
-            $modulteil = $modul->modulteile->first();
-            $type = 3;
+        $this->type = 1;
+        if (count($this->modul->modulteile) == 1) {
+            $modulteil = $this->modul->modulteile->first();
+            $this->type = 3;
             if (count($modulteil->lvgruppen) > 0) {
-                $type = 2;
+                $this->type = 2;
             }
-        } else if (count($modul->modulteile) == 0) {
-            $type = 3;
+        } else if (count($this->modul->modulteile) == 0) {
+            $this->type = 3;
         }
 
         if (!Request::get('sem_select')) {
@@ -128,28 +119,27 @@ class Shared_ModulController extends AuthenticatedController
             $currentSemester = Semester::find(Request::get('sem_select'));
         }
 
-        $display_language = Request::get('display_language', $_SESSION['_language']);
-        ModuleManagementModel::setLanguage($display_language);
+        $this->display_language = Request::get('display_language', $this->modul->original_language);
+        ModuleManagementModel::setContentLanguage($this->display_language);
+        I18NString::setDefaultLanguage($this->modul->original_language);
+        I18NString::setContentLanguage($this->display_language);
 
         $this->semesterSelector = Semester::getSemesterSelector(null, $currentSemester['semester_id'], 'semester_id', false);
-        $this->modul = $modul;
-        $this->pruefungsEbene = isset($GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$modul->pruef_ebene])
-                              ? $GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$modul->pruef_ebene]['name']
+        $this->pruefungsEbene = isset($GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$this->modul->pruef_ebene])
+                              ? $GLOBALS['MVV_MODUL']['PRUEF_EBENE']['values'][$this->modul->pruef_ebene]['name']
                               : null;
-        $this->modulDeskriptor = $modul->getDeskriptor($display_language);
-        $this->startSemester = Semester::findByTimestamp($modul->start);
+        $this->modulDeskriptor = $this->modul->getDeskriptor();
+        $this->startSemester = Semester::findByTimestamp($this->modul->start);
 
-        if (!$modul->responsible_institute) {
+        if (!$this->modul->responsible_institute) {
             $this->instituteName = null;
-        } elseif ($modul->responsible_institute->institute) {
-            $this->instituteName = $modul->responsible_institute->institute->name;
+        } elseif ($this->modul->responsible_institute->institute) {
+            $this->instituteName = $this->modul->responsible_institute->institute->name;
         } else {
             $this->instituteName = _('Unbekannte Einrichtung');
         }
-        $this->type = $type;
         $this->semester = $currentSemester;
-        $this->display_language = $display_language;
-        PageLayout::setTitle($modul->getDisplayName() . ' (' . _('Vollständige Modulbeschreibung') .')');
+        PageLayout::setTitle($this->modul->getDisplayName() . ' (' . _('Vollständige Modulbeschreibung') .')');
     }
 
     public function mail_action($modul_id, $semester_id)
diff --git a/app/controllers/studiengaenge/studiengaenge.php b/app/controllers/studiengaenge/studiengaenge.php
index 44f5d83d654b377312551000f4cb57dd24ee40a5..809d1ab35906c6ab79e0091bbcd6d63a2e94f2cf 100644
--- a/app/controllers/studiengaenge/studiengaenge.php
+++ b/app/controllers/studiengaenge/studiengaenge.php
@@ -1215,11 +1215,11 @@ class Studiengaenge_StudiengaengeController extends MVVController
                 $file = $document->mvv_file;
                 if ($file->extern_visible) {
                     $mvv_file_ref = null;
-                    foreach ($GLOBALS['MVV_LANGUAGES']['values'] as $key => $mvv_language) {
-                        if ($mvv_language['locale'] === $_SESSION['_language']) {
-                            $mvv_file_ref = $file->file_refs->findOneBy('file_language', $key);
+                    foreach ($GLOBALS['CONTENT_LANGUAGES'] as $code => $content_language) {
+                        if ($code === $_SESSION['_language']) {
+                            $mvv_file_ref = $file->file_refs->findOneBy('file_language', $code);
                         } else {
-                            $mvv_file_ref = $file->file_refs->findOneBy('file_language', $GLOBALS['MVV_LANGUAGES']['default']);
+                            $mvv_file_ref = $file->file_refs->findOneBy('file_language', Config::get()->MVV_DEFAULT_LANGUAGE);
                         }
                     }
                     if ($mvv_file_ref) {
diff --git a/app/views/admin/datafields/edit.php b/app/views/admin/datafields/edit.php
index 46b7aa1dcb8c988220d3a291f4ff4aabea6fe753..c3f67b4d2fb66c6be93b0794af3d64c2d754b334 100644
--- a/app/views/admin/datafields/edit.php
+++ b/app/views/admin/datafields/edit.php
@@ -71,7 +71,7 @@ use Studip\Button, Studip\LinkButton;
 
             <select multiple name="object_class[]" id="object_class" required>
                 <option value="NULL" <? if ($item->object_class === null) echo 'selected'; ?>><?= _('alle (mehrsprachige Eingabe bei Feldtyp textline, textarea, textmarkup)') ?></option>
-            <? foreach ((array) $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'] as $key => $value) : ?>
+            <? foreach ($GLOBALS['CONTENT_LANGUAGES'] as $key => $value) : ?>
                 <option value="<?= htmlReady($key) ?>" <? if (mb_strpos($item->object_class, $key) !== false) echo 'selected'; ?>>
                     <?= htmlReady($value['name']) ?>
                 </option>
@@ -82,7 +82,7 @@ use Studip\Button, Studip\LinkButton;
 
             <select multiple name="object_class[]" id="object_class" required>
                 <option value="NULL" <? if ($item->object_class === null) echo 'selected'; ?>><?= _('alle (mehrsprachige Eingabe)') ?></option>
-            <? foreach ((array) $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'] as $key => $value) : ?>
+            <? foreach ($GLOBALS['CONTENT_LANGUAGES'] as $key => $value) : ?>
                 <option value="<?= htmlReady($key) ?>" <? if (mb_strpos($item->object_class, $key) !== false) echo 'selected'; ?>>
                     <?= htmlReady($value['name']) ?>
                 </option>
@@ -90,7 +90,7 @@ use Studip\Button, Studip\LinkButton;
             </select>
         <? elseif ($item->object_type === 'studycourse'): ?>
             <?= _('Typ/Abschnitt') ?>
-            
+
             <select name="object_class" required>
                 <option value="all_settings"<?= mb_strpos($item->object_class, 'all_settings') !== false ? ' selected' : '' ?>><?= _('alle (Abschnitt "Einstellungen")') ?></option>
                 <option value="all_info"<?= mb_strpos($item->object_class, 'all_info') !== false ? ' selected' : '' ?>><?= _('alle (Abschnitt "Inhalte und Informationen")') ?></option>
diff --git a/app/views/admin/datafields/index.php b/app/views/admin/datafields/index.php
index e62b8d6fd0004832747a165d16ad94fd22a1694b..81ac85fcd5983191410cd96763627bd30b3c1c59 100644
--- a/app/views/admin/datafields/index.php
+++ b/app/views/admin/datafields/index.php
@@ -108,7 +108,7 @@
                 <?=  $val->object_class !== null ? htmlReady($GLOBALS['INST_TYPE'][$val->object_class]['name']) : _('alle')?>
             <? elseif ($key === 'moduldeskriptor' || $key === 'modulteildeskriptor') : ?>
                 <?=  $val->object_class !== null ? htmlReady(implode(', ', array_map(function ($class) {
-                    return $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'][$class]['name'];
+                    return $GLOBALS['CONTENT_LANGUAGES'][$class]['name'];
                 }, explode(',', $val->object_class)))) : _('alle')?>
             <? elseif ($key === 'studycourse'): ?>
                 <? $object_classes =
diff --git a/app/views/admin/datafields/new.php b/app/views/admin/datafields/new.php
index e64293ff5b6f354b2abcc88072924ea1d0917a06..c749ff9cd4cc212b6fcbf4d178278b1952429d57 100644
--- a/app/views/admin/datafields/new.php
+++ b/app/views/admin/datafields/new.php
@@ -72,13 +72,13 @@ use Studip\Button, Studip\LinkButton;
         <? elseif ($object_typ === 'moduldeskriptor') : ?>
             <select multiple name="object_class[]" required>
                 <option value="NULL" selected><?= _('alle (mehrsprachige Eingabe bei Feldtyp textline, textarea, textmarkup)') ?></option>
-            <? foreach ((array) $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'] as $key => $value) : ?>
+            <? foreach ($GLOBALS['CONTENT_LANGUAGES'] as $key => $value) : ?>
                 <option value="<?= htmlReady($key) ?>"><?= htmlReady($value['name']) ?></option>
             <? endforeach; ?>
         <? elseif ($object_typ === 'modulteildeskriptor') : ?>
             <select multiple name="object_class[]" required>
                 <option value="NULL" selected><?= _('alle (mehrsprachige Eingabe bei Feldtyp textline, textarea, textmarkup)') ?></option>
-            <? foreach ((array) $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'] as $key => $value) : ?>
+            <? foreach ($GLOBALS['CONTENT_LANGUAGES'] as $key => $value) : ?>
                 <option value="<?= htmlReady($key) ?>"><?= htmlReady($value['name']) ?></option>
             <? endforeach; ?>
         <? elseif ($object_typ === 'studycourse') : ?>
diff --git a/app/views/materialien/files/add_dokument.php b/app/views/materialien/files/add_dokument.php
index 0782f088b63f99237932859edde34768f4c72220..bc72ce2446d917991c81f4c84e773fbef6ba2160 100644
--- a/app/views/materialien/files/add_dokument.php
+++ b/app/views/materialien/files/add_dokument.php
@@ -21,33 +21,33 @@
     </label>
 
     <table class="default mvv-files-table">
-    <? foreach($GLOBALS['MVV_LANGUAGES']['values'] as $key => $entry) : ?>
+    <? foreach($GLOBALS['CONTENT_LANGUAGES'] as $language_key => $entry) : ?>
         <tr>
             <td rowspan="2">
-                <?= Assets::img(MVV::getContentLanguageImagePath($key), ['alt' => $entry['name'], 'size' => 24]) ?>
+                <?= Assets::img(MVV::getContentLanguageImagePath($language_key), ['alt' => $entry['name'], 'size' => 24]) ?>
             </td>
             <td>
                 <label>
                     <?= _('Angezeigter Name des Dokuments') ?>
-                    <input name="doc_displayname_<?= $key; ?>" type="text" value="<?= !isset($documents[$key])  ? '' : htmlReady($documents[$key]->name) ?>"<?= $perm->disable('name') ?>>
+                    <input name="doc_displayname_<?= $language_key; ?>" type="text" value="<?= !isset($documents[$language_key])  ? '' : htmlReady($documents[$language_key]->name) ?>"<?= $perm->disable('name') ?>>
                 </label>
             </td>
         </tr>
         <tr>
             <td>
                 <div class="attachments" style="<?= (empty($documents) || !array_key_exists($key, $documents))  ? '' : 'display: none;'?>">
-                    <span style="cursor:pointer;" onClick="$('#fileselector_<?= $key; ?>').toggle();$(this).toggle();">
-                        <?= Icon::create('add', Icon::ROLE_CLICKABLE, ['title' => _("Datei hinzufügen"), 'class' => 'text-bottom']); ?>
-                        <?= _("Datei hinzufügen") ?>
+                    <span style="cursor:pointer;" onClick="$('#fileselector_<?= $language_key; ?>').toggle();$(this).toggle();">
+                        <?= Icon::create('add')->asImg(['title' => _('Datei hinzufügen'), 'class' => 'text-bottom']); ?>
+                        <?= _('Datei hinzufügen') ?>
                     </span>
-                    <div id="fileselector_<?= $key; ?>" style="display:none;">
+                    <div id="fileselector_<?= $language_key; ?>" style="display:none;">
                         <ul class="stgfiles list-unstyled">
                             <li style="display: none;" class="stgfile">
                                 <input type="hidden" name="document_id" id="document_id" value="<?= htmlReady($document_id ?? '') ?>">
                                 <span class="icon"></span>
                                 <span class="name"></span>
                                 <span class="size"></span>
-                                <button class="refresh_attachment as-link" data-language="<?= htmlReady($key) ?>">
+                                <button class="refresh_attachment as-link" data-language="<?= htmlReady($language_key) ?>">
                                     <?= Icon::create('refresh')->asImg([
                                         'class' => 'text-bottom',
                                         'title' => _('Datei aktualisieren'),
@@ -68,29 +68,29 @@
                             </div>
                         </div>
                         <label id="upload_chooser" style="cursor: pointer;">
-                            <input type="file" id="fileupload" multiple onChange="STUDIP.MVV.Document.upload_from_input(this, '<?= $key; ?>');" style="display: none;">
-                            <?= Icon::create('upload', 'clickable', ['title' => _("Datei hochladen"), 'class' => "text-bottom"]) ?>
+                            <input type="file" id="fileupload" multiple onChange="STUDIP.MVV.Document.upload_from_input(this, '<?= $language_key; ?>');" style="display: none;">
+                            <?= Icon::create('upload')->asImg(['title' => _('Datei hochladen'), 'class' => 'text-bottom']) ?>
                             <?= _("Datei hochladen") ?>
                         </label>
                         <br>
                         <b><?= _('oder'); ?></b>
                         <label>
                             <?= _('Link hinzufügen') ?>
-                            <input name="doc_url_<?= $key; ?>" type="text" value="" placeholder="https://...">
+                            <input name="doc_url_<?= $language_key; ?>" type="text" value="" placeholder="https://...">
                         </label>
                         <div id="upload_finished" style="display: none"><?= _("wird verarbeitet") ?></div>
                         <div id="upload_received_data" style="display: none"><?= _("gespeichert") ?></div>
                     </div>
                 </div>
-                <div id="fileviewer_<?= $key; ?>">
+                <div id="fileviewer_<?= $language_key; ?>">
                     <ul class="stgfiles list-unstyled">
-                    <? if (isset($documents[$key])): ?>
+                    <? if (isset($documents[$language_key])): ?>
                         <li class="stgfile">
-                            <input type="hidden" name="document_id" id="document_id" value="<?= htmlReady($documents[$key]->fileref_id) ?>">
+                            <input type="hidden" name="document_id" id="document_id" value="<?= htmlReady($documents[$language_key]->fileref_id) ?>">
                             <span class="icon"><?= Icon::create('file', Icon::ROLE_INFO, ['class' => 'text-bottom']); ?></span>
-                            <span class="name"><?= htmlReady($documents[$key]->filename) ?></span>
-                            <span class="size"><?= relsize($documents[$key]->file_ref->size) ?></span>
-                            <button class="refresh_attachment as-link" data-language="<?= htmlReady($key) ?>">
+                            <span class="name"><?= htmlReady($documents[$language_key]->filename) ?></span>
+                            <span class="size"><?= relsize($documents[$language_key]->file_ref->size) ?></span>
+                            <button class="refresh_attachment as-link" data-language="<?= htmlReady($language_key) ?>">
                                 <?= Icon::create('refresh')->asImg([
                                     'class' => 'text-bottom',
                                     'title' => _('Datei aktualisieren'),
diff --git a/app/views/module/institute/details.php b/app/views/module/institute/details.php
index c62b4bbab5cbb7ef03be61d52c6fd9ab6f1a4b1e..d50953d00bacd64a89adc7873f19c79c2e562bd8 100644
--- a/app/views/module/institute/details.php
+++ b/app/views/module/institute/details.php
@@ -6,7 +6,7 @@
                 <th><?= _('Modul') ?></th>
                 <th style="width: 5%;"><?= _('Fassung') ?></th>
                 <th style="width: 5%;"><?= _('Modulteile') ?></th>
-                <th style="text-align: center; width: 150px;">
+                <th style="width: 150px;">
                     <?= _('Ausgabesprachen') ?>
                 </th>
                 <th style="width: 5%; text-align: right;"><?= _('Aktionen') ?></th>
@@ -14,4 +14,4 @@
         </thead>
         <?= $this->render_partial('module/module/module') ?>
     </table>
-</td>
\ No newline at end of file
+</td>
diff --git a/app/views/module/module/change_language.php b/app/views/module/module/change_language.php
new file mode 100644
index 0000000000000000000000000000000000000000..178b93b6dc71a428b1b360f02baa6bd5c51d4ccf
--- /dev/null
+++ b/app/views/module/module/change_language.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @var Module_ModuleController $controller
+ * @var array $content_languages
+ * @var string $original_language
+ * @var string $module_id
+ * @var array $translations
+ */
+?>
+<form class="default" action="<?= $controller->store_language($module_id) ?>" method="post">
+    <?= CSRFProtection::tokenTag() ?>
+    <fieldset>
+        <legend>
+            <?= _('Wählen Sie die neue Sprache der Originalfassung') ?>
+        </legend>
+        <label>
+            <?= _('Neue Originalsprache') ?>
+            <select name="new_language">
+                <? foreach ($content_languages as $code => $language) : ?>
+                    <? if ($code !== $original_language) : ?>
+                        <option value="<?= htmlReady($code) ?>"><?= htmlReady($language['name']) ?></option>
+                    <? endif ?>
+                <? endforeach ?>
+            </select>
+        </label>
+        <? if (count($translations) > 1) : ?>
+            <label>
+                <input type="checkbox" name="swap_data" value="1">
+                <?= _('Inhalte tauschen') ?>
+            </label>
+        <? endif ?>
+    </fieldset>
+    <footer data-dialog-button>
+        <?= Studip\Button::createAccept(_('Sprache ändern'))?>
+    </footer>
+</form>
diff --git a/app/views/module/module/details.php b/app/views/module/module/details.php
index 4509d520e345caab979aa8f98a7132cdbe5aa99b..257d181b2553e1ef951ad198779733b636492c25 100644
--- a/app/views/module/module/details.php
+++ b/app/views/module/module/details.php
@@ -1,8 +1,19 @@
+<?php
+/**
+ * @var Modul $modul
+ * @var string $modulteil_id
+ * @var string $display_language
+ * @var Module_ModuleController $controller
+ * @var string $institut_id
+ */
+?>
+
 <td colspan="6">
     <table class="default collapsable sortable" id="<?= $modul->id ?>">
         <colgroup>
             <col>
-            <col span="2" style="width: 150px;">
+            <col style="width: 150px;">
+            <col style="width: 70px;">
         </colgroup>
         <? foreach ($modul->modulteile as $modulteil) : ?>
             <? $perm = MvvPerm::get($modulteil) ?>
@@ -18,10 +29,10 @@
                             <?= htmlReady($modulteil->getDisplayName()) ?>
                         <? endif; ?>
                     </td>
-                    <td class="dont-hide actions" style="white-space: nowrap; text-align: center;">
+                    <td class="dont-hide actions" style="white-space: nowrap; text-align: left;">
                         <? if ($perm->havePermWrite()) : ?>
-                            <? foreach ($modulteil->deskriptoren->getAvailableTranslations() as $language) : ?>
-                                <? $lang = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language]; ?>
+                            <? foreach ($modulteil->deskriptoren->getAvailableTranslations($modulteil->modul->original_language) as $language) : ?>
+                                <? $lang = $GLOBALS['CONTENT_LANGUAGES'][$language]; ?>
                                 <a href="<?= $controller->action_link('modulteil/' . join('/', [$modulteil->id, $institut_id]), ['display_language' => $language]) ?>">
                                     <?= Assets::img(MVV::getContentLanguageImagePath($language), ['alt' => $lang['name'], 'size' => 24]) ?>
                                 </a>
diff --git a/app/views/module/module/index.php b/app/views/module/module/index.php
index 1028a2db12067eaa8d27859ab4b35ea56605702a..37088d57acb32470249a78e8ac34daddaeb39b84 100644
--- a/app/views/module/module/index.php
+++ b/app/views/module/module/index.php
@@ -1,5 +1,21 @@
+<?php
+/**
+ * @var Module_ModuleController $controller
+ * @var int $count
+ * @var int $page
+ */
+?>
+
 <?= $controller->jsUrl() ?>
 <table class="default collapsable">
+    <colgroup>
+        <col>
+        <col>
+        <col>
+        <col>
+        <col style="width: 150px">
+        <col style="width: 70px">
+    </colgroup>
     <caption>
         <?= _('Module')?>
         <span class="actions"><?= sprintf(ngettext('%s Modul', '%s Module', $count), $count) ?></span>
@@ -10,10 +26,10 @@
             <?= $controller->renderSortLink('module/module/', _('Modul'), 'bezeichnung') ?>
             <?= $controller->renderSortLink('module/module/', _('Fassung'), 'fassung_nr', ['style' => 'width: 5%;']) ?>
             <?= $controller->renderSortLink('module/module/', _('Modulteile'), 'count_modulteile', ['style' => 'width: 5%;']) ?>
-            <th style="text-align: right; width: 150px;">
+            <th>
                 <?= _('Ausgabesprachen') ?>
             </th>
-            <th style="width: 5%; text-align: right;"><?= _('Aktionen') ?></th>
+            <th style="text-align: right;"><?= _('Aktionen') ?></th>
         </tr>
     </thead>
     <?= $this->render_partial('module/module/module') ?>
diff --git a/app/views/module/module/modul.php b/app/views/module/module/modul.php
index e209a1808b4bee1afe338827260c23784e762ffb..1a8971fb175913de8ba57332a4127916d3c6e82b 100644
--- a/app/views/module/module/modul.php
+++ b/app/views/module/module/modul.php
@@ -1,9 +1,29 @@
+<?php
+/**
+ * @var Module_ModuleController $controller
+ * @var Modul $modul
+ * @var ModulDeskriptor $deskriptor
+ * @var string $display_language
+ * @var boolean $def_lang
+ * @var QuickSearch $search_modul
+ * @var string $qs_id_module
+ * @var Semester[] $semester
+ * @var QuickSearch $search_responsible
+ * @var string $qs_id_responsible
+ * @var QuickSearch $search_institutes
+ * @var string $qs_id_institutes
+ * @var SimpleORMapCollection $contacts
+ * @var array $translations
+ * @var string $cancel_url
+ */
+?>
+
 <? use Studip\Button, Studip\LinkButton; ?>
 <?= $controller->jsUrl() ?>
 <?
 $perm   = MvvPerm::get($modul);
 $perm_d = MvvPerm::get($deskriptor);
-if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
+if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] !== $display_language) {
     $perm_d->setVariant($display_language);
 }
 ?>
@@ -144,12 +164,12 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
                 <?= _('Beschlussdatum:') ?>
                 <? if ($perm->haveFieldPerm('beschlussdatum')) : ?>
                     <input type="text" name="beschlussdatum"
-                           value="<?= ($modul->beschlussdatum ? strftime('%d.%m.%Y', $modul->beschlussdatum) : '') ?>"
+                           value="<?= $modul->beschlussdatum ? date('d.m.Y', $modul->beschlussdatum) : '' ?>"
                            placeholder="<?= _('TT.MM.JJJJ') ?>" class="with-datepicker">
                 <? else : ?>
-                    <?= ($modul->beschlussdatum ? strftime('%d.%m.%Y', $modul->beschlussdatum) : '') ?>
+                    <?= $modul->beschlussdatum ? date('d.m.Y', $modul->beschlussdatum) : '' ?>
                     <input type="hidden" name="beschlussdatum"
-                           value="<?= ($modul->beschlussdatum ? strftime('%d.%m.%Y', $modul->beschlussdatum) : '') ?>">
+                           value="<?= $modul->beschlussdatum ? date('d.m.Y', $modul->beschlussdatum) : '' ?>">
                 <? endif; ?>
             </label>
             <label for="mvv-field-modul-fassung_nr"><?= _('Fassung:') ?>
@@ -196,7 +216,7 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
             </div>
             <div id="mvv-field-modul-beschlussdatum">
                 <? printf(_('Beschlussdatum: %s'),
-                    $modul->beschlussdatum ? strftime('%d.%m.%Y', $modul->beschlussdatum) : _('nicht angegeben')) ?>
+                    $modul->beschlussdatum ? date('d.m.Y', $modul->beschlussdatum) : _('nicht angegeben')) ?>
             </div>
             <div id="mvv-field-modul-fassung_nr">
                 <?
@@ -443,7 +463,6 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
             <?= $modul->kp ? htmlReady($modul->kp) : _('keine Angabe') ?>
         <? endif; ?>
         </label>
-
     </fieldset>
 
     <fieldset class="collapsable collapsed" id="mvv-field-modul-assigned_users">
@@ -649,15 +668,16 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
                           ><?= htmlReady($deskriptor->ersatztext) ?></textarea>
             <? endif; ?>
         </label>
+        <? $default_language = array_keys($GLOBALS['CONTENT_LANGUAGES'])[0] ?>
         <? foreach ($deskriptor->datafields as $entry) : ?>
-            <? if ($entry->lang == '') : ?>
-                <? if (!$def_lang) : ?>
+            <? if (empty($entry->lang)) : ?>
+                <? if ($display_language !== $default_language) : ?>
                     <? $df = new DatafieldEntryModel(
                         [
                             $entry->datafield_id,
                             $entry->range_id,
                             $entry->sec_range_id,
-                            $language == 'de_DE' ? '' : $language
+                            $display_language
                         ]); ?>
                 <? else : ?>
                     <? $df = $entry; ?>
@@ -673,7 +693,6 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
         <? endforeach; ?>
     </fieldset>
 
-
     <input type="hidden" name="display_language" value="<?= $display_language ?>">
     <footer>
         <? if ($deskriptor->isNew()) : ?>
@@ -685,8 +704,14 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
                 <?= Button::createAccept(_('Übernehmen'), 'store', ['title' => _('Änderungen übernehmen')]) ?>
             <? endif; ?>
             <? if (!$def_lang && !$deskriptor->isNew() && in_array($display_language, $translations)) : ?>
-                <?= Button::create(_('Löschen'), 'delete', ['title'      => _('Deskriptor löschen'), 'data-confirm' => sprintf(_('Soll der Deskriptor in der Ausgabesprache %s gelöscht werden?'), $GLOBALS['MVV_LANGUAGES']['values'][$display_language]['name']),
-                                                            'formaction' => $controller->action_url('delete_modul_deskriptor', $deskriptor->id, $display_language)]); ?>
+                <? $content_languages = $GLOBALS['CONTENT_LANGUAGES'] ?>
+                <?= Button::create(
+                    _('Löschen'),
+                    'delete',
+                    [
+                        'title' => _('Deskriptor löschen'),
+                        'data-confirm' => sprintf(_('Soll der Deskriptor in der Ausgabesprache %s gelöscht werden?'), $content_languages[$display_language]['name'] ?? _('unbekannt')),
+                        'formaction' => $controller->action_url('delete_modul_deskriptor', $deskriptor->id, $display_language)]); ?>
             <? endif; ?>
         <? endif; ?>
         <?= LinkButton::createCancel(_('Abbrechen'), $cancel_url, ['title' => _('zurück zur Übersicht')]) ?>
@@ -694,6 +719,6 @@ if ($GLOBALS['MVV_MODUL']['SPRACHE']['default'] != $display_language) {
 </form>
 <? if (!$def_lang) : ?>
     <script>
-        jQuery('#modul_form').find('textarea, input[type=text]').after('<div style="padding-top:10px;"><a href="#" title="<?= _('Originalfassung anzeigen') ?>" class="mvv-show-original" data-type="modul"><?= Assets::img(MVV::getContentLanguageImagePath($modul->getDefaultLanguage()), ['alt' => _('Originalfassung'), 'size' => 24]) ?></a></div>');
+        jQuery('#modul_form').find('textarea, input[type=text]').after('<div style="padding-top:10px;"><a href="#" title="<?= _('Originalfassung anzeigen') ?>" class="mvv-show-original" data-type="modul"><?= Assets::img(MVV::getContentLanguageImagePath($modul->original_language), ['alt' => _('Originalfassung'), 'size' => 24]) ?></a></div>');
     </script>
 <? endif; ?>
diff --git a/app/views/module/module/module.php b/app/views/module/module/module.php
index d6cda88fdf11408f1d35b1f38ae29a65cde35388..839097693c279db59f0100b5e0c9e2369d21695d 100644
--- a/app/views/module/module/module.php
+++ b/app/views/module/module/module.php
@@ -1,3 +1,9 @@
+<?php
+/**
+ * @var Modul[] $module
+ */
+?>
+
 <? foreach ($module as $modul) : ?>
     <? $perm = MvvPerm::get($modul) ?>
     <tbody class="<?= $modul->count_modulteile ? '' : 'empty ' ?><?= $modul_id === $modul->getId() ? 'not-collapsed' : 'collapsed' ?>">
@@ -9,7 +15,7 @@
                     <? $details_action = $details_action ?? 'details'; ?>
                     <a class="mvv-load-in-new-row" href="<?= $controller->action_link($details_action, $modul->getId()) ?>">
                         <? if ($ampel_icon) : ?>
-                            <?= $ampel_icon->asImg(['title' => $ampelstatus, 'style' => 'vertical-align: text-top;']) ?>
+                            <?= $ampel_icon->asImg(['title' => $ampelstatus, 'style' => 'vertical-align: bottom;']) ?>
                         <? endif; ?>
                         <?= htmlReady($modul->code) ?>
                     </a>
@@ -29,25 +35,26 @@
                     <? endif;?>
                 </td>
             <? else : ?>
-                <td style="white-space:nowrap;">
+                <td style="white-space:nowrap; font-weight: 700; padding-left: 20px;">
                     <? if ($ampel_icon) : ?>
-                        <?= $ampel_icon->asImg(['title' => $ampelstatus, 'style' => 'vertical-align: text-top;']) ?>
+                        <?= $ampel_icon->asImg(['title' => $ampelstatus, 'style' => 'vertical-align: bottom;']) ?>
                     <? endif; ?>
                     <?= htmlReady($modul->code) ?>
                 </td>
-                <td class="dont-hide" style="font-weight: bold;">
+                <td class="dont-hide" style="font-weight: 700;">
                     <?= htmlReady($modul->getDisplayName()) ?>
                 </td>
             <? endif; ?>
             <td style="text-align:center;" class="dont-hide"><?= htmlReady($modul->fassung_nr) ?></td>
             <td style="text-align: center;" class="dont-hide"><?= $modul->count_modulteile ?></td>
-            <td class="dont-hide actions" style="text-align: center;">
+            <td class="dont-hide actions" style="text-align: left;">
                 <? if ($perm->havePermRead()) : ?>
-                    <? $languages = $modul->deskriptoren->getAvailableTranslations(); ?>
+                    <? $languages = $modul->deskriptoren->getAvailableTranslations($modul->original_language); ?>
+                    <? $content_languages = $GLOBALS['CONTENT_LANGUAGES'] ?>
                     <? foreach ($languages as $language) : ?>
-                        <? $lang = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language]; ?>
                         <a href="<?= $controller->action_link('modul/' . $modul->id . '/', ['display_language' => $language]) ?>">
-                            <?= Assets::img(MVV::getContentLanguageImagePath($language), ['alt' => $lang['name'], 'size' => 24]) ?>
+                            <?= Assets::img(MVV::getContentLanguageImagePath($language),
+                                ['alt' => $content_languages[$language]['name'], 'size' => 24]) ?>
                         </a>
                     <? endforeach; ?>
                 <? endif; ?>
@@ -97,6 +104,14 @@
                             ['data-dialog' => '']
                         ) ?>
                     <? endif; ?>
+                    <? if ($perm->haveFieldPerm('change_language', MvvPerm::PERM_CREATE)) : ?>
+                        <? $actionMenu->addLink(
+                            $controller->change_languageURL($modul->id),
+                            _('Originalsprache ändern'),
+                            Icon::create('support', Icon::ROLE_CLICKABLE,['title' => _('Originalsprache ändern')]),
+                            ['data-dialog' => 'size=370x270']
+                        ) ?>
+                    <? endif; ?>
                     <? if ($perm->havePermCreate()) : ?>
                         <? $actionMenu->addButton(
                             'delete',
diff --git a/app/views/module/module/modulteil.php b/app/views/module/module/modulteil.php
index ad68edee9292c508ac416d74ba1ab72e2e4a4d7d..8e06d8049f4072e347b257e6700edda0c78d53a8 100644
--- a/app/views/module/module/modulteil.php
+++ b/app/views/module/module/modulteil.php
@@ -464,11 +464,15 @@ if ($GLOBALS['MVV_MODULTEIL']['SPRACHE']['default'] != $display_language) {
         <? else : ?>
             <?= Button::createAccept(_('Übernehmen'), 'store', ['title' => _('Änderungen übernehmen')]) ?>
             <? if (!$def_lang && !$deskriptor->isNew() && in_array($display_language, $translations)) : ?>
+                <? $content_languages = $GLOBALS['CONTENT_LANGUAGES'] ?>
                 <?= Button::create(
                     _('Löschen'),
                     'delete',
-                    ['title'      => _('Deskriptor löschen'), 'data-confirm' => sprintf(_('Soll der Deskriptor in der Ausgabesprache %s gelöscht werden?'), $GLOBALS['MVV_LANGUAGES']['values'][$display_language]['name']),
-                     'formaction' => $controller->action_url('delete_modulteil_deskriptor', $deskriptor->id, $display_language)
+                    [
+                        'title'      => _('Deskriptor löschen'),
+                        'data-confirm' => sprintf(_('Soll der Deskriptor in der Ausgabesprache %s gelöscht werden?'),
+                            $content_languages[$display_language]['name'] ?? _('unbekannt')),
+                        'formaction' => $controller->action_url('delete_modulteil_deskriptor', $deskriptor->id, $display_language)
                     ]
                 ); ?>s
             <? endif; ?>
diff --git a/app/views/module/module/select_module_language.php b/app/views/module/module/select_module_language.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f1d39d60da18d4c94caed7161ab2d6023ef3352
--- /dev/null
+++ b/app/views/module/module/select_module_language.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @var Module_ModuleController $controller
+ * @var array $content_languages
+ * @var string $default_language
+ */
+?>
+<form class="default" action="<?= $controller->modulURL() ?>" method="post">
+    <?= CSRFProtection::tokenTag() ?>
+    <fieldset>
+        <legend>
+            <?= _('Wählen Sie die Sprache der Originalfassung') ?>
+        </legend>
+        <label>
+            <?= _('Sprache') ?>
+            <select name="display_language">
+                <option value="<?= htmlReady($default_language) ?>">
+                    <?= htmlReady($content_languages[$default_language]['name']) . ' (' ._('Standardsprache') . ')'?></option>
+                <? foreach ($content_languages as $code => $language) : ?>
+                    <? if ($code !== $default_language) : ?>
+                        <option value="<?= htmlReady($code) ?>"><?= htmlReady($language['name']) ?></option>
+                    <? endif ?>
+                <? endforeach ?>
+            </select>
+        </label>
+    </fieldset>
+    <footer data-dialog-button>
+        <?= Studip\Button::createAccept(_('Modul anlegen'))?>
+    </footer>
+</form>
diff --git a/app/views/shared/deskriptor_language.php b/app/views/shared/deskriptor_language.php
index 44cdb6502f3772cef416a539e7fa8377205c1558..e59f4f6934464783a45922d3f832d1dee6e5793c 100644
--- a/app/views/shared/deskriptor_language.php
+++ b/app/views/shared/deskriptor_language.php
@@ -1,11 +1,21 @@
-<? $table = get_class($modul) == 'Modul' ? 'mvv_modul_deskriptor' : 'mvv_modulteil_deskriptor'; ?>
-<? $languages = $modul->deskriptoren->getAvailableTranslations(); ?>
-<? foreach ($GLOBALS[strtoupper($table)]['SPRACHE']['values'] as $lang => $value) : ?>
+<?php
+/**
+ * @var ModulDeskriptor|ModulteilDeskriptor $descriptor
+ * @var string $original_language
+ * @var string $display_language
+ * @var string $link
+ */
+?>
+
+<? $languages = $descriptor->getAvailableTranslations($original_language) ?>
+<? $content_languages = array_merge(array_flip($languages), $GLOBALS['CONTENT_LANGUAGES']) ?>
+<? foreach ($content_languages as $code => $language) : ?>
 <div style="padding-top:10px;">
-    <a href="<?= URLHelper::getLink($link, ['display_language' => $lang]) ?>">
-        <?= Assets::img(MVV::getContentLanguageImagePath($lang), ['alt' => $value['name'], 'size' => 24]) ?>
-        <?= $value['name'] ?> (<?= in_array($lang, $languages) ? 'bearbeiten' : 'neu anlegen' ?>)
-        <?= $lang == $sprache ? Icon::create('accept', 'accept', [])->asImg() : '' ?>
+    <a href="<?= URLHelper::getLink($link, ['display_language' => $code]) ?>">
+        <?= Assets::img(MVV::getContentLanguageImagePath($code), ['alt' => $language['name'], 'size' => 24]) ?>
+        <?= $language['name'] ?> (<?= ($code === $original_language ? _('Originalfassung') : '')
+            . (in_array($code, $languages) ? '' : _('neu')) ?>)
+        <?= $code === $display_language ? Icon::create('accept', Icon::ROLE_ACCEPT) : '' ?>
     </a>
 </div>
-<? endforeach; ?>
+<? endforeach ?>
diff --git a/app/views/shared/modul/_modullv.php b/app/views/shared/modul/_modullv.php
index 99c41807e4bff80c0b4a6805478f36fecb0eadc5..70ffd64d556eecbaca1737123a37e0506af48f70 100644
--- a/app/views/shared/modul/_modullv.php
+++ b/app/views/shared/modul/_modullv.php
@@ -5,7 +5,7 @@
         <? $modulTeilSumme = $modulTeil->wl_praesenz + $modulTeil->wl_bereitung + $modulTeil->wl_selbst + $modulTeil->wl_pruef ?>
         <tr>
             <td style="width: 30%;"><strong><?= _('Lehrveranstaltungsform') ?></strong></td>
-            <td style="width: 70%;" data-mvv-field="mvv_modulteil.lernlehrform"><?= $GLOBALS['MVV_MODULTEIL']['LERNLEHRFORM']['values'][$modulTeil->lernlehrform]['name'] ?></td>
+            <td style="width: 70%;" data-mvv-field="mvv_modulteil.lernlehrform"><?= $GLOBALS['MVV_MODULTEIL']['LERNLEHRFORM']['values'][$modulTeil->lernlehrform]['name'] ?? '' ?></td>
         </tr>
         <tr>
             <td style="width: 30%;"><strong><?= _('Veranstaltungstitel') ?></strong></td>
@@ -30,7 +30,7 @@
         <tr>
             <td style="width: 30%;"><strong><?= _('Workload Prüfung incl. Vorbereitung') ?></strong></td>
             <td style="width: 70%;" data-mvv-field="mvv_modulteil.wl_pruef mvv_modulteil_deskriptor.kommentar_wl_pruef"><?= $modulTeil->wl_pruef ?> <?= MVVController::trim($modulTeilDeskriptor->kommentar_wl_pruef) ? sprintf(" (%s)", formatReady($modulTeilDeskriptor->kommentar_wl_pruef)) : '' ?></td>
-        </tr>  
+        </tr>
         <tr>
             <td style="width: 30%;"><strong><?= _('Workload insgesamt') ?></strong></td>
             <td style="width: 70%;"><?= $modulTeilSumme ?></td>
diff --git a/app/views/shared/modul/description.php b/app/views/shared/modul/description.php
index 59512bd94ea5c5b7f21481c55fb3e42651900210..758760dd769868b0afd23047f70491872bbc21db 100644
--- a/app/views/shared/modul/description.php
+++ b/app/views/shared/modul/description.php
@@ -1,7 +1,15 @@
+<?php
+/**
+ * @var Modul $modul
+ * @var int $type
+ * @var Shared_ModulController $controller
+ */
+?>
+
 <? if (count($modul->deskriptoren) > 1): ?>
 <div style="width: 100%; text-align: right;">
-    <? foreach ($modul->deskriptoren->getAvailableTranslations() as $language) : ?>
-        <? $lang = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language]; ?>
+    <? foreach ($modul->deskriptoren->getAvailableTranslations($modul->original_language) as $language) : ?>
+        <? $lang = $GLOBALS['CONTENT_LANGUAGES'][$language]; ?>
         <a data-dialog="size=auto;title='<?= htmlReady($modul->getDisplayName()) ?>'" href="<?= $controller->action_link('description/' . $modul->id . '/', ['display_language' => $language]) ?>">
             <?= Assets::img(MVV::getContentLanguageImagePath($language), ['alt' => $lang['name'], 'size' => 24]) ?>
         </a>
@@ -19,4 +27,4 @@
 <? endif; ?>
 <? if ($type === 3) : ?>
     <?= $this->render_partial('shared/modul/_modul_ohne_lv') ?>
-<? endif; ?>
\ No newline at end of file
+<? endif; ?>
diff --git a/app/views/shared/modul/overview.php b/app/views/shared/modul/overview.php
index 4bfd71efced6e1bfeaf1ad9de008c0e0504e1b02..be91c7a6a181d4f3470fd995a6d84d55e4f0b65e 100644
--- a/app/views/shared/modul/overview.php
+++ b/app/views/shared/modul/overview.php
@@ -1,3 +1,15 @@
+<?php
+/**
+ * @var Modul $modul
+ * @var Institute $institut
+ * @var ModulDeskriptor $deskriptor
+ * @var array $modulteile
+ * @var Semester $semester
+ * @var string $pruef_ebene
+ * @var int $type
+ */
+?>
+
 <table class="default mvv-modul-details nohover">
     <tr>
         <th class="mvv-modul-details-head" style="width: 30%"><?= htmlReady($modul->code) ?></th>
@@ -34,10 +46,10 @@
     <tr>
         <td colspan="4" style="padding: 0;">
             <table class="default nohover">
-                <? if (mb_strlen($teilnahmeVoraussetzung) > 0): ?>
+                <? if (mb_strlen($deskriptor->voraussetzung) > 0): ?>
                     <tr>
                         <td style="width: 20%; font-weight: bold;"><?= _('Teilnahmevoraussetzungen') ?></td>
-                        <td ><?= formatReady($teilnahmeVoraussetzung) ?></td>
+                        <td ><?= formatReady($deskriptor->voraussetzung) ?></td>
                     </tr>
                 <? endif; ?>
                 <? if (mb_strlen($deskriptor->kommentar)) : ?>
@@ -104,7 +116,7 @@
                 <th><?= _('Prüfungsleistung') ?></th>
             <? endif; ?>
         </tr>
-        <? foreach ($modulTeile as $modul_teil): ?>
+        <? foreach ($modulteile as $modul_teil): ?>
             <tr>
                 <? if ($type === 1): ?>
                 <td>
diff --git a/config/mvv_config.php b/config/mvv_config.php
index dae7c5d7c15e6bcbf36518b2036a2694372a182a..79ee9157bfb9d61120108c3f9d186b5ada8700c3 100644
--- a/config/mvv_config.php
+++ b/config/mvv_config.php
@@ -114,17 +114,6 @@ $GLOBALS['MVV_MODUL']['INSTITUT_GRUPPEN'] = [
     ]
 ];
 
-// Moduldeskriptor Ausgabesprache
-$GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE'] = [
-    'values'            => [
-        'DE'                => ['visible' => 1, 'name' => _('Originalfassung'), 'content_language' => 'de_DE'],
-        'EN'                => ['visible' => 1, 'name' => _('Englisch'), 'content_language' => 'en_GB']
-    //    'de_DE'                => array('visible' => 1, 'name' => _('Originalfassung')),
-    //    'en_GB'                => array('visible' => 1, 'name' => _('Englisch'))
-    ],
-    'default'           => 'DE'
-];
-
 // Modulteile
 $GLOBALS['MVV_MODULTEIL']['NUM_BEZEICHNUNG'] = [
     'values'            => [
@@ -201,9 +190,6 @@ $GLOBALS['MVV_MODULTEIL']['LERNLEHRFORM'] = [
     'default'           => ''
 ];
 
-// Modulteildeskriptor
-$GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE'] = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE'];
-
 // Maximale Anzahl Fachsemester
 $GLOBALS['MVV_MODULTEIL_FACHSEMESTER'] = 10;
 
@@ -230,16 +216,6 @@ $GLOBALS['MVV_STGTEILVERSION']['STATUS'] = $GLOBALS['MVV_MODUL']['STATUS'];
 
 $GLOBALS['MVV_STGTEIL']['STATUS'] = $GLOBALS['MVV_MODUL']['STATUS'];
 
-$GLOBALS['MVV_LANGUAGES'] = [
-    'values'            => [
-        'DE'                => ['visible' => 1, 'name' => _('Deutsch'),
-                                'locale' => 'de_DE'],
-        'EN'                => ['visible' => 1, 'name' => _('Englisch'),
-                                'locale' => 'en_GB']
-    ],
-    'default'           => 'DE'
-];
-
 $GLOBALS['MVV_STUDIENGANG']['FASSUNG_TYP'] = $GLOBALS['MVV_STGTEILVERSION']['FASSUNG_TYP'];
 
 $GLOBALS['MVV_STUDIENGANG']['STUDYCOURSE_TYPE'] = [
diff --git a/db/migrations/6.0.37_step_4261.php b/db/migrations/6.0.37_step_4261.php
new file mode 100644
index 0000000000000000000000000000000000000000..13a7474c860b1b59fb4e7bfb02a78d2a91ca0276
--- /dev/null
+++ b/db/migrations/6.0.37_step_4261.php
@@ -0,0 +1,64 @@
+<?php
+
+final class Step4261 extends Migration
+{
+    public function description()
+    {
+        return 'Add field to module table to store original language.';
+    }
+
+    protected function up()
+    {
+        $db = DBManager::get();
+
+        // retrieve default language from config
+        $config_language = $db->fetchColumn(
+            "SELECT `value` FROM `config` WHERE `field` = 'DEFAULT_LANGUAGE'"
+        );
+        $default_language = $config_language ?? array_keys($GLOBALS['CONTENT_LANGUAGES'])[0] ?? 'de_DE';
+        $db->execute(
+            'ALTER TABLE `mvv_modul`
+            ADD `original_language` VARCHAR(10) NOT NULL DEFAULT ? COLLATE latin1_bin AFTER `verantwortlich`',
+            [$default_language]
+        );
+
+        // use full language code for file refs
+        foreach ($GLOBALS['CONTENT_LANGUAGES'] as $code => $language) {
+            $old_code = mb_strtoupper(mb_strstr($code, '_', true));
+            $db->execute('UPDATE `mvv_files_filerefs` SET `file_language` = ? WHERE `file_language` = ?',
+                [$code, $old_code]);
+        }
+
+        $query = "INSERT INTO `config` (`field`, `value`, `type`, `range`, `section`, `mkdate`, `chdate`, `description`)
+                  VALUES ('MVV_DEFAULT_LANGUAGE', ?, 'string', 'global', 'mvv', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), ?)";
+        $db->execute($query,
+            [
+                $default_language,
+                'Code der Inhalts-Sprache, die als Original-Sprache der Deskriptoren für Module und Modulteile vorausgewählt ist.',
+            ]
+        );
+    }
+
+    protected function down()
+    {
+        $db = DBManager::get();
+
+        $db->exec(
+            "ALTER TABLE `mvv_modul`
+            DROP COLUMN `original_language`"
+        );
+
+        // use short language code for file refs
+        foreach ($GLOBALS['CONTENT_LANGUAGES'] as $code => $language) {
+            $old_code = mb_strtoupper(mb_strstr($code, '_', true));
+            $db->execute('UPDATE `mvv_files_filerefs` SET `file_language` = ? WHERE `file_language` = ?',
+                [$old_code, $code]);
+        }
+
+        $query = "DELETE `config`, `config_values`
+                  FROM `config`
+                  LEFT JOIN `config_values` USING (`field`)
+                  WHERE `field` = 'MVV_DEFAULT_LANGUAGE'";
+        $db->exec($query);
+    }
+}
diff --git a/lib/classes/MVV.php b/lib/classes/MVV.php
index b4d9edf6eec9101e18662df2e4f16eaec1332145..934195b2b482a3ace1f7a55a645a7e84d30d2396 100644
--- a/lib/classes/MVV.php
+++ b/lib/classes/MVV.php
@@ -834,7 +834,7 @@ class MVV implements Loggable {
     }
 
     /**
-     * Returns imagepath for given language, used by MVV
+     * Returns image path for given language, used by MVV
      * First tries $GLOBALS['CONTENT_LANGUAGES'], if not defined returns hardcoded path
      *
      * @param string $language e.g. 'DE'
@@ -842,8 +842,9 @@ class MVV implements Loggable {
      */
     public static function getContentLanguageImagePath($language): string
     {
-        $content_language = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language]['content_language'];
-        return 'languages/' . ($GLOBALS['CONTENT_LANGUAGES'][$content_language]['picture'] ?? 'lang_' . mb_strtolower($language) . '.gif');
+        $code = strtok($language, '_');
+        return '/images/languages/'
+            . ($GLOBALS['CONTENT_LANGUAGES'][$language]['picture'] ?? 'lang_' . mb_strtolower($code) . '_text.svg');
     }
 
 }
diff --git a/lib/classes/globalsearch/GlobalSearchModules.php b/lib/classes/globalsearch/GlobalSearchModules.php
index b9f872011409a4f13194d0488549b68783b7bc2f..f4f277f242a553bf31e8a62dc3e408b8bdd95ae9 100644
--- a/lib/classes/globalsearch/GlobalSearchModules.php
+++ b/lib/classes/globalsearch/GlobalSearchModules.php
@@ -35,7 +35,7 @@ class GlobalSearchModules extends GlobalSearchModule
         // Get language
         $language = ModuleManagementModel::getLanguage();
         if (!$language) {
-            ModuleManagementModel::setLanguage($_SESSION['_language']);
+            ModuleManagementModel::setContentLanguage($_SESSION['_language']);
             $language = ModuleManagementModel::getLanguage();
         }
 
diff --git a/lib/models/Lvgruppe.php b/lib/models/Lvgruppe.php
index 5e9eb7bef4780404d94bbd6d720c5cd08cdcdcbd..6f82215dd460fa6ab8808b4a82236f8fa86efd40 100644
--- a/lib/models/Lvgruppe.php
+++ b/lib/models/Lvgruppe.php
@@ -583,9 +583,7 @@ class Lvgruppe extends ModuleManagementModelTreeItem
         $modul = Modul::find($modul_id);
         if ($modul) {
             $name = $modul->responsible_institute->institute->getShortName();
-            $short_name_modul = $modul->getDeskriptor(
-                    $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['default'])
-                    ->bezeichnung_kurz;
+            $short_name_modul = $modul->getDeskriptor()->bezeichnung_kurz;
             $name .= $short_name_modul ? ' ' . $short_name_modul : '';
         }
          *
@@ -594,7 +592,6 @@ class Lvgruppe extends ModuleManagementModelTreeItem
         $modulteil = Modulteil::findCached($modulteil_id);
         if ($modulteil) {
             $name = $modulteil->getDeskriptor()->bezeichnung;
-            //$name = $name_modulteil ? ' ' . $name_modulteil : '';
         }
         return $name;
     }
diff --git a/lib/models/Modul.php b/lib/models/Modul.php
index 31f4bbec7f0f775d296d3862dcec2598f550de66..b6410b2bda7ac1c89e80855ee8e930193d0fb266 100644
--- a/lib/models/Modul.php
+++ b/lib/models/Modul.php
@@ -36,6 +36,7 @@
  * @property string|null $stat database column
  * @property string|null $kommentar_status database column
  * @property string|null $verantwortlich database column
+ * @property string $original_language database column
  * @property string $author_id database column
  * @property string $editor_id database column
  * @property int $mkdate database column
@@ -383,14 +384,12 @@ class Modul extends ModuleManagementModelTreeItem
      * previously set by ApplicationSimpleORMap::setLanguage() or the one
      * defined as default in mvv_config.php.
      */
-    private function setDefaultLanguage()
+    private function setDefaultLanguage(): void
     {
-        if (isset($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values']
-                [ModuleManagementModel::getLanguage()])) {
-            $this->default_language = ModuleManagementModel::getLanguage();
+        if ($this->isNew()) {
+            $this->default_language = Config::get()->MVV_DEFAULT_LANGUAGE;
         } else {
-            $this->default_language =
-                    $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['default'];
+            $this->default_language = $this->original_language;
         }
     }
 
@@ -405,18 +404,13 @@ class Modul extends ModuleManagementModelTreeItem
     }
 
     /**
-     * Returns the Deskriptor in the given language. A Modul has always a
-     * Deskriptor in the default language. If the given language is unknown, the
-     * method returns the deskriptor in the default language.
+     * Returns the descriptor. If this component has no descriptor already
+     * a new one is created and returned.
      *
-     * @param string $language The id of the language
-     * @param bool If true returns always a new descriptor
-     * @return object The Deskriptor.
+     * @return ModulDeskriptor The descriptor.
      */
-    public function getDeskriptor($language = null, $force_new = false) {
-        if (!isset($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language])) {
-            $language = $this->default_language;
-        }
+    public function getDeskriptor()
+    {
         if (!$this->deskriptoren) {
             // the module is new and has no descriptor
             // return a new descriptor in the default language
@@ -481,7 +475,7 @@ class Modul extends ModuleManagementModelTreeItem
     /**
      * Assignes languages of instruction to this part-module.
      *
-     * @param type $languages An array of language keys defined in mvv_config.php.
+     * @param array $languages An array of language keys defined in mvv_config.php.
      */
     public function assignLanguagesOfInstruction($languages)
     {
diff --git a/lib/models/ModulDeskriptor.php b/lib/models/ModulDeskriptor.php
index 5a3d07152cf27d030a2179dcbb685d3dde9b4bed..096d2d652aff65c2f0d7e13128aff00a3d1df0b0 100644
--- a/lib/models/ModulDeskriptor.php
+++ b/lib/models/ModulDeskriptor.php
@@ -140,12 +140,13 @@ class ModulDeskriptor extends ModuleManagementModel
      * @see ModuleManagementModel::getVariant()
      * @return string The language identifier.
      */
-    public function getVariant()
+    public function getVariant(): string
     {
-        if (self::getLanguage() == $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['default']) {
+        if (self::getLanguage() === Config::get()->MVV_DEFAULT_LANGUAGE) {
             return '';
         }
-        return self::getLanguage();
+        $splitted_code = explode('_', self::getLanguage());
+        return mb_strtoupper($splitted_code[0] ?? '');
     }
 
     /**
@@ -156,7 +157,6 @@ class ModulDeskriptor extends ModuleManagementModel
      */
     public function deleteTranslation($language)
     {
-        $locale = $GLOBALS['MVV_LANGUAGES']['values'][$language]['locale'];
-        return I18NString::removeAllTranslations($this->id, 'mvv_modul_deskriptor', $locale);
+        return I18NString::removeAllTranslations($this->id, 'mvv_modul_deskriptor', $language);
     }
 }
diff --git a/lib/models/ModuleManagementModel.php b/lib/models/ModuleManagementModel.php
index 608a0884a7f3f2d5da04a0a61db8a1b63eea8608..e8f684d400cb5df8156959dd12065cfad68f60f9 100644
--- a/lib/models/ModuleManagementModel.php
+++ b/lib/models/ModuleManagementModel.php
@@ -699,57 +699,42 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage
     /**
      * Sets the language for localized fields and the locale environment
      * globally.
-     * Possible values are configured in mvv_config.php.
+     * See configuration of CONTENT_LANGUAGES.
      *
      * @see mvv_config.php
-     * @param string $language The language.
+     * @param string $language The language code.
      */
-    public static final function setLanguage($language)
+    public static final function setContentLanguage($language)
     {
-        $language = mb_strtoupper(mb_strstr($language . '_', '_', true));
-        if (isset($GLOBALS['MVV_LANGUAGES']['values'][$language])) {
-            $locale = $GLOBALS['MVV_LANGUAGES']['values'][$language]['locale'];
-            setLocaleEnv($locale);
-            self::setContentLanguage($language);
-            // load config file again
-            require $GLOBALS['STUDIP_BASE_PATH'] . '/config/mvv_config.php';
-        }
-    }
-
-    /**
-     * Switches the content to the given language.
-     * Compared to ModuleManagementModel::setLanguage() strings translated with
-     * gettext are always in the prefered language selected by the user.
-     *
-     * @param string $language The language code (see mvv_config.php)
-     */
-    public static function setContentLanguage($language)
-    {
-        if (!is_array($GLOBALS['MVV_LANGUAGES']['values'][$language])) {
+        $content_languages = Config::get()->CONTENT_LANGUAGES;
+        if (empty($content_languages[$language])) {
             throw new InvalidArgumentException();
         }
-        $locale = $GLOBALS['MVV_LANGUAGES']['values'][$language]['locale'];
-        I18NString::setContentLanguage($locale);
+        setLocaleEnv($language);
+        I18NString::setContentLanguage($language);
         self::$language = $language;
+        // load config file again
+        require $GLOBALS['STUDIP_BASE_PATH'] . '/config/mvv_config.php';
     }
 
-    public function getAvailableTranslations()
+    public function getAvailableTranslations(string $original_language): array
     {
-        $translations[] = $GLOBALS['MVV_LANGUAGES']['default'];
+        $translations = [];
         $stmt = DBManager::get()->prepare('SELECT DISTINCT `lang` '
                 . 'FROM i18n '
                 . 'WHERE `object_id` = ? AND `table` = ?');
         $stmt->execute([$this->id, $this->db_table()]);
-        foreach ($stmt->fetchAll() as $locale) {
-            $language = mb_strtoupper(mb_strstr($locale['lang'], '_', true));
-            if (is_array($GLOBALS['MVV_LANGUAGES']['values'][$language])) {
-                $translations[] = $language;
+        $languages = array_merge([$original_language],
+            $stmt->fetchAll(PDO::FETCH_COLUMN));
+        $content_languages = $GLOBALS['CONTENT_LANGUAGES'];
+        foreach ($languages as $code) {
+            if (!empty($content_languages[$code])) {
+                $translations[] = $code;
             }
         }
         return $translations;
     }
 
-
     /**
      * Returns the currently selected language.
      *
diff --git a/lib/models/Modulteil.php b/lib/models/Modulteil.php
index 3b8f146de6fc2138bd2a38754e8f480976f4e080..5c769f8b9c048bf20af7f13ec8bd049358e73912 100644
--- a/lib/models/Modulteil.php
+++ b/lib/models/Modulteil.php
@@ -114,7 +114,11 @@ class Modulteil extends ModuleManagementModelTreeItem
     {
         parent::__construct($id);
         $this->object_real_name = _('Modulteil');
-        $this->default_language = $GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['default'];
+        if ($this->modul) {
+            $this->default_language = $this->modul->original_language;
+        } else {
+            $this->default_language = Config::get()->MVV_DEFAULT_LANGUAGE;
+        }
     }
 
     /**
@@ -165,7 +169,7 @@ class Modulteil extends ModuleManagementModelTreeItem
 
     public function getDisplayName()
     {
-        $deskriptor = $this->getDeskriptor(self::getLanguage());
+        $deskriptor = $this->getDeskriptor();
         $template = Config::get()->MVV_TEMPLATE_NAME_MODULTEIL;
         if (trim($template)) {
             $placeholders = [
@@ -210,19 +214,12 @@ class Modulteil extends ModuleManagementModelTreeItem
     }
 
     /**
-     * Returns the Deskriptor in the given language. A Modul has always a
-     * Deskriptor in the default language. If the given language is unknown, the
-     * method returns the deskriptor in the default language.
+     * Returns the descriptor. If this component has no descriptor already
+     * a new one is created and returned.
      *
-     * @param string $language The id of the language
-     * @param bool If true returns always a new descriptor
-     * @return object The Deskriptor.
+     * @return ModulteilDeskriptor The descriptor.
      */
-    public function getDeskriptor($language = null, $force_new = false) {
-        if (!isset($GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['values'][$language])) {
-            $language = $this->default_language;
-        }
-
+    public function getDeskriptor() {
         if (!$this->deskriptoren) {
             // the module is new and has no descriptor
             // return a new descriptor in the default language
diff --git a/lib/models/ModulteilDeskriptor.php b/lib/models/ModulteilDeskriptor.php
index aa6ddf7054bd7b287a30cc347c6c85fce0c9368e..26c38a161e28cef97e9ffdc6f577f889f54674c1 100644
--- a/lib/models/ModulteilDeskriptor.php
+++ b/lib/models/ModulteilDeskriptor.php
@@ -114,12 +114,13 @@ class ModulteilDeskriptor extends ModuleManagementModel
      * @see ModuleManagementModel::getVariant()
      * @return string The language identifier.
      */
-    public function getVariant()
+    public function getVariant(): string
     {
-        if (self::getLanguage() == $GLOBALS['MVV_MODULTEIL_DESKRIPTOR']['SPRACHE']['default']) {
+        if (self::getLanguage() === Config::get()->MVV_DEFAULT_LANGUAGE) {
             return '';
         }
-        return self::getLanguage();
+        $splitted_code = explode('_', self::getLanguage());
+        return mb_strtoupper($splitted_code[0] ?? '');
     }
 
     /**
@@ -130,7 +131,6 @@ class ModulteilDeskriptor extends ModuleManagementModel
      */
     public function deleteTranslation($language)
     {
-        $locale = $GLOBALS['MVV_LANGUAGES']['values'][$language]['locale'];
-        return I18NString::removeAllTranslations($this->id, 'mvv_modulteil_deskriptor', $locale);
+        return I18NString::removeAllTranslations($this->id, 'mvv_modulteil_deskriptor', $language);
     }
 }
diff --git a/lib/navigation/MVVNavigation.php b/lib/navigation/MVVNavigation.php
index 4aab8edfdbf1a179476a87a357a2c40952782d27..ebc4833455cd4dc17be422adf00645ab03de6d08 100644
--- a/lib/navigation/MVVNavigation.php
+++ b/lib/navigation/MVVNavigation.php
@@ -59,6 +59,9 @@ class MVVNavigation extends Navigation
         $modul_navigation->addSubNavigation('module',
                 new Navigation(_('Module'),
                 'dispatch.php/module/module'));
+        $modul_navigation->addSubNavigation('institutes',
+            new Navigation(_('Verantwortliche Einrichtungen'),
+                'dispatch.php/module/institute/index'));
         $this->addSubNavigation('module', $modul_navigation);
 
         $lvg_navigation = new Navigation(_('LV-Gruppen'));