diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63ed94c..eb5e9a6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [3.1.8] - 2023-05-25
+
+* Add German translation (#104).
+
## [3.1.7] - 2023-04-19
* Remove use of old BrandSetting constants (#103).
diff --git a/lang/de/lang.php b/lang/de/lang.php
new file mode 100644
index 0000000..caa8e01
--- /dev/null
+++ b/lang/de/lang.php
@@ -0,0 +1,293 @@
+ [
+ 'name' => 'Redirect',
+ 'description' => 'Einfach Weiterleitungen verwalten',
+ ],
+ 'permission' => [
+ 'access_redirects' => [
+ 'label' => 'Redirects',
+ 'tab' => 'Redirects',
+ ],
+ ],
+ 'navigation' => [
+ 'menu_label' => 'Weiterleitungen',
+ 'menu_description' => 'Weiterleitungen verwalten',
+ ],
+ 'settings' => [
+ 'menu_label' => 'Redirects',
+ 'menu_description' => 'Redirects Einstellungen verwalten.',
+ 'logging_enabled_label' => 'Weiterleitungen aufzeichnen',
+ 'logging_enabled_comment' => 'Weiterleitungen in der Datenbank abspeichern.',
+ 'statistics_enabled_label' => 'Statistik aktivieren',
+ 'statistics_enabled_comment' => 'Für jede Weiterleitung wird eine Statistik geführt.',
+ 'test_lab_enabled_label' => 'TestLab (beta)',
+ 'test_lab_enabled_comment' => 'TestLab ermöglicht Massentests für Weiterleitungen.',
+ 'caching_enabled_label' => 'Weiterleitungen zwischenspeichern (Fortgeschritten)',
+ 'caching_enabled_comment' => 'Verbessert die Weiterleitungs-Logik wenn viele Weiterleitungen aktiv sind.'
+ . 'ACHTUNG: Die Cache-Treiber `file` und `database` werden NICHT unterstützt. '
+ . 'Empfohlene Treiber sind `memcached` oder gleichwertige "in-memory" Cache-Treiber.',
+ 'relative_paths_enabled_label' => 'Relative Pfadangaben verwenden',
+ 'relative_paths_enabled_command' => 'The Weiterleitungs-Logik generiert relative Pfadangaben, nicht absolute.',
+ ],
+ 'redirect' => [
+ 'redirect' => 'Weiterleitung',
+ 'from_url' => 'Ursprungs-Pfad',
+ 'from_url_placeholder' => '/von/beispiel',
+ 'from_url_comment' => 'Ursprungs-Pfad für die Weiterleitung.',
+ 'from_scheme' => 'Ursprungs-Schema',
+ 'from_scheme_comment' => 'Wenn http oder https ausgewählt ist, muss das Schema übereinstimmen: Bei http wird z. B. nur http://domain.com/path weitergeleitet, '
+ . 'https://domain.com/path hingegen nicht.',
+ 'to_url' => 'Ziel-Pfad oder -URL',
+ 'to_url_placeholder' => '/absoluter/pfad, relativer/pfad oder https://website.com',
+ 'to_url_comment' => 'Ziel-Pfad oder -URL für die Weiterleitung.',
+ 'to_url_required_if' => 'Das Ziel für die Weiterleitung wird benötigt',
+ 'to_scheme' => 'Ziel-Schema',
+ 'to_scheme_comment' => 'Das Schema für die Ziel-URL wird foricert. '
+ . 'wähle "automatisch" um das Schema der Website zu verwenden.',
+ 'scheme_auto' => 'Automatisch',
+ 'cms_page_required_if' => 'CMS-Seite für die Weiterleitung wird benötigt',
+ 'static_page_required_if' => 'Ziel-Seite für die Weiterleitung wird benötigt',
+ 'match_type' => 'Art',
+ 'exact' => 'Exakt',
+ 'placeholders' => 'Platzhalter',
+ 'regex' => 'Regulärer Ausdruck',
+ 'target_type' => 'Ziel-Typ',
+ 'target_type_none' => 'Keine Angabe',
+ 'target_type_path_or_url' => 'Pfad oder URL',
+ 'target_type_cms_page' => 'CMS Seite',
+ 'target_type_static_page' => 'RainLab.Pages Seite',
+ 'status_code' => 'HTTP Statuscode',
+ 'sort_order' => 'Sortierung',
+ 'requirements' => 'Bedingungen',
+ 'requirements_comment' => 'Bedingung für jeden Platzhalter.',
+ 'placeholder' => 'Platzhalter',
+ 'placeholder_comment' => 'Der Platzhaltername (inkl. geschweifter Klammern) aus dem \'Ursprungs-Pfad\' Feld. '
+ . 'z. B. {category} oder {id}',
+ 'requirement' => 'Bedingung',
+ 'requirement_comment' => 'Die Bedingung als Regulärer Ausdruck. z. B. [0-9]+ oder [a-zA-Z]+.',
+ 'requirements_prompt' => 'Bedingung hinzufügen',
+ 'replacement' => 'Ersatz',
+ 'replacement_comment' => 'Optionaler Ersatz für diesen Platzhalter. '
+ . 'Der Platzhalter wird mit diesem Wert in der Ziel-URL ersetzt.',
+ 'permanent' => '301 - Permanent',
+ 'temporary' => '302 - Temporary',
+ 'see_other' => '303 - See Other',
+ 'not_found' => '404 - Not Found',
+ 'gone' => '410 - Gone',
+ 'enabled' => 'Weiterleitung ist aktiv',
+ 'none' => 'Keine',
+ 'enabled_comment' => 'Auswählen um die Weiterleitung zu aktivieren.',
+ 'priority' => 'Priorität',
+ 'hits' => '# Treffer',
+ 'return_to_redirects' => 'Zurück zur Liste von Weiterleitungen',
+ 'return_to_categories' => 'Zurück zur LIste von Kategorien',
+ 'delete_confirm' => 'Auswahl wirklich löschen?',
+ 'created_at' => 'Erstellt',
+ 'modified_at' => 'Bearbeitet',
+ 'system_tip' => 'Vom System erstellte Weiterleitung',
+ 'user_tip' => 'Vom Benutzer erstellte Weiterleitung',
+ 'type' => 'Typ',
+ 'category' => 'Kategorie',
+ 'categories' => 'Kategorien',
+ 'description' => 'Beschreibung',
+ 'name' => 'Name',
+ 'date_time' => 'Datum/Uhrzeit',
+ 'date' => 'Datum',
+ 'truncate_confirm' => 'Sollen wirklich alle Einträge gelöscht werden?',
+ 'truncating' => 'Lösche...',
+ 'warning' => 'Warnung',
+ 'cache_warning' => 'Zwischenspeichern ist aktiviert, aber der aktive Cache-Treiber wird nicht unterstützt. '
+ . 'Die Weiterleitungen werden somit nicht zwischengespeichert.',
+ 'general_confirm' => 'Möchten Sie wirklich fortfahren?',
+ 'sparkline_30d' => 'Treffer (30 Tage)',
+ 'has_hits' => 'Hat Treffer',
+ 'minimum_hits' => 'Minimale Anzahl Treffer',
+ 'ignore_query_parameters' => 'Query-Parameter ignorieren',
+ 'ignore_query_parameters_comment' => 'Query-Parameter werden für die Weiterleitung ignoriert.',
+ 'ignore_case' => 'Gross-/Kleinschreibung ignorieren',
+ 'ignore_case_comment' => 'Gross-/Kleinschreibung wird für die Weiterleitung nicht beachtet.',
+ 'ignore_trailing_slash' => 'Schrägstrich am Ende ignorieren',
+ 'ignore_trailing_slash_comment' => 'Pfade mit und ohne Schrägstrich am Schluss werden umgeleitet.',
+ 'last_used_at' => 'Letzter Treffer',
+ 'updated_at' => 'Aktualisiert',
+ 'invalid_regex' => 'Ungültiger Regulärer Ausdruck.',
+ 'created_due_to_bad_request' => 'Erstellt wegen ungültigem Request.',
+ ],
+ 'list' => [
+ 'no_records' => 'Hier gibt es keine Weiterleitungen.',
+ 'switch_is_enabled' => 'Aktiviert',
+ 'switch_system' => 'System-Weiterleitungen',
+ ],
+ 'scheduling' => [
+ 'from_date' => 'Gültig ab',
+ 'from_date_comment' => 'Der Zeitpunkt, ab wann diese Weiterleitung aktiv wird. Optional.',
+ 'to_date' => 'Gültig bis',
+ 'to_date_comment' => 'Der Zeitpunkt, bis wann diese Weiterleitung aktiv bleibt. Optional.',
+ 'scheduling_comment' => 'Hier kann definiert werden, in welchem Zeitraum die Weiterleitung aktiv ist. ',
+ 'not_active_warning' => 'Die Weiterleitung ist nicht mehr verfügbar. Siehe \'Zeitplan\' Tab.',
+ ],
+ 'test' => [
+ 'test_comment' => 'Weiterleitungen können hier vor dem Speichern getestet werden.',
+ 'input_path' => 'Input-Pfad',
+ 'input_path_comment' => 'Der Input-Pfad für den Test. z. B. /alter/pfad/123',
+ 'input_path_placeholder' => '/input/pfad',
+ 'input_scheme' => 'Input-Schema',
+ 'test_date' => 'Testdatum',
+ 'test_date_comment' => 'Falls die Weiterleitung einen Zeitplan hat, wird dieses Datum für den Test verwendet.',
+ 'testing' => 'Teste...',
+ 'run_test' => 'Test ausführen',
+ 'no_match_label' => 'Entschuldige, keine Treffer!',
+ 'no_match' => 'Keine Treffer gefunden!',
+ 'match_success_label' => 'Treffer!',
+ ],
+ 'test_lab' => [
+ 'section_test_lab_comment' => 'TestLab ermöglicht Massentests für Weiterleitungen.',
+ 'test_lab_label' => 'In TestLab einbeziehen',
+ 'test_lab_enable' => 'Aktivieren, um diese Weiterleitung im TestLab testen zu können.',
+ 'test_lab_path_label' => 'Test-Pfad',
+ 'test_lab_path_comment' => 'Dieser Pfad wird für die Tests verwendet. '
+ . 'Platzhalter mit richten Werten ersetzen.',
+ 'start_tests' => 'Tests starten',
+ 'start_tests_description' => '"Tests starten" anklicken zum Starten.',
+ 'edit' => 'Bearbeiten',
+ 'exclude' => 'Ausschliessen',
+ 'exclude_confirm' => 'Soll diese Weiterleitung wirklich vom TestLab augeschlossen werden?',
+ 'exclude_indicator' => 'Von TestLab ausgeschlossen',
+ 're_run' => 'Erneut ausführen',
+ 're_run_indicator' => 'Führe Tests aus, bitte warten...',
+ 'loop' => 'Endlosschlaufe',
+ 'match' => 'Treffer',
+ 'response_http_code' => 'Antwort Statuscode',
+ 'response_http_code_should_be' => 'Antwort Statuscode muss einer sein von:',
+ 'redirect_count' => 'Anzahl Weiterleitungen',
+ 'final_destination' => 'Endziel',
+ 'no_redirects' => 'Es gibt keine Weiterleitungen, die für das TestLab aktiviert wurden. '
+ . 'Aktiviere die Option \'In TestLab einbeziehen\' beim Bearbeiten einer Weiterleitung.',
+ 'test_error' => 'Beim Testen der Weiterleitung ist ein Fehler aufgetreten.',
+ 'flash_test_executed' => 'Tests wurden ausgeführt.',
+ 'flash_redirect_excluded' => 'Die Weiterleitung wurde vom TestLab ausgeschlossen und wird beim nächsten Mal ignoriert.',
+ 'result_request_failed' => 'Konnte Anfrage nicht ausführen.',
+ 'redirects_followed' => 'Anzahl der Weiterleitungen: :count (limitiert auf :limit)',
+ 'not_determinate_destination_url' => 'Konnte Endziel nicht ausfindig machen.',
+ 'no_destination_url' => 'Keine Endziel URL.',
+ 'final_destination_is' => 'Endziel ist: :destination',
+ 'possible_loop' => 'Mögliche Endlosschlaufe!',
+ 'no_loop' => 'Keine Endlosschlaufe erkannt.',
+ 'not_match_redirect' => 'Keine passende Weiterleitung gefunden.',
+ 'matched' => 'Treffer',
+ 'redirect' => 'redirect',
+ 'matched_not_http_code' => 'Weiterleitung gefunden, aber der Antwort Statuscode ist falsch! '
+ . 'Erwartet :expected aber :received erhalten.',
+ 'matched_http_code' => 'Weiterleitung gefunden, Antwort Statuscode :code.',
+ 'executing_tests' => 'Führe Tests aus...',
+ ],
+ 'statistics' => [
+ 'hits_per_day' => 'Weiterleitungen pro Tag',
+ 'click_on_chart' => 'Auf Graphen klicken um zu zoomen und zu navigieren.',
+ 'requests_redirected' => 'Anfragen umgeleitet',
+ 'all_time' => 'Ganzer Zeitraum',
+ 'active_redirects' => 'Aktive Weiterleitungen',
+ 'redirects_this_month' => 'Weiterleitungen dieser Monat',
+ 'previous_month' => 'Vorheriger Monat',
+ 'latest_redirected_requests' => 'Zuletzt umgeleitete Anfrage',
+ 'redirects_per_month' => 'Weiterleitungen pro Monat',
+ 'no_data' => 'Keine Daten',
+ 'top_crawlers_this_month' => 'Top :top Crawlers dieser Monat',
+ 'top_redirects_this_month' => 'Top :top Weiterleitungen dieser Monat',
+ 'activity_last_three_months' => 'Aktivität der letzten 3 Monate',
+ 'crawler_hits' => 'Crawler Treffer',
+ 'visitor_hits' => 'Besucher Treffer',
+ ],
+ 'title' => [
+ 'import' => 'Import',
+ 'export' => 'Export',
+ 'redirects' => 'Weiterleitungen verwalten',
+ 'create_redirect' => 'Weiterleitung erstellen',
+ 'edit_redirect' => 'Weiterleitung bearbeiten',
+ 'categories' => 'Kategorien verwalten',
+ 'create_category' => 'Kategorie erstellen',
+ 'edit_category' => 'Kategorie bearbeiten',
+ 'view_redirect_log' => 'Protokoll',
+ 'statistics' => 'Statistik',
+ 'test_lab' => 'TestLab (Beta)',
+ ],
+ 'buttons' => [
+ 'add' => 'Hinzufügen',
+ 'from_request_log' => 'Aus Request-Log',
+ 'new_redirect' => 'Neue Weiterleitung',
+ 'create_redirects' => 'Weiterleitungen erstellen',
+ 'create_redirect' => 'Weiterleitung erstellen',
+ 'create_and_new' => 'Erstellen und neu',
+ 'delete' => 'Löschen',
+ 'enable' => 'Aktivieren',
+ 'disable' => 'Deaktivieren',
+ 'reorder_redirects' => 'Sortieren',
+ 'export' => 'Export',
+ 'import' => 'Import',
+ 'settings' => 'Einstellungen',
+ 'categories' => 'Kategorien',
+ 'extensions' => 'Erweiterungen',
+ 'new_category' => 'Neue Kategorie',
+ 'reset_statistics' => 'Statistik zurücksetzen',
+ 'logs' => 'Protokoll',
+ 'empty_redirect_log' => 'Protokoll leeren',
+ 'clear_cache' => 'Zwischenspeicher leeren',
+ 'stop' => 'Stop',
+ 'reset_all' => 'Statistik für alle Weiterleitungen zurücksetzen',
+ 'all_redirects' => 'Alle Weiterleitungen',
+ 'bulk_actions' => 'Massenbearbeitung',
+ ],
+ 'tab' => [
+ 'tab_general' => 'Allgemein',
+ 'tab_requirements' => 'Bedingungen',
+ 'tab_test' => 'Test',
+ 'tab_scheduling' => 'Zeitplan',
+ 'tab_test_lab' => 'TestLab',
+ 'tab_advanced' => 'Fortgeschritten',
+ 'tab_logs' => 'Protokoll',
+ ],
+ 'flash' => [
+ 'success_created_redirects' => ':count Weiterleitungen erstellt',
+ 'static_page_redirect_not_supported' => 'Diese Weiterleitung kann nicht bearbeitet werden. Das Plugin RainLab.Pages wird benötigt.',
+ 'truncate_success' => 'Alle Einträge erfolgreich gelöscht',
+ 'delete_selected_success' => 'Alle ausgewählten Einträge erfolgreich gelöscht',
+ 'cache_cleared_success' => 'Zwischenspeicher erfolgreich gelöscht',
+ 'statistics_reset_success' => 'Die Statistik wurde erfolgreich zurückgesetzt',
+ 'enabled_all_redirects_success' => 'Alle Weiterleitungen wurden aktiviert',
+ 'disabled_all_redirects_success' => 'Alle Weiterleitungen wurden deaktiviert',
+ 'deleted_all_redirects_success' => 'Alle Weiterleitungen wurden gelöscht',
+ ],
+ 'import_export' => [
+ 'match_type' => 'Art [match_type] (Erlaubt: exact, placeholders, regex)',
+ 'category_id' => 'Kategorie [category_id]',
+ 'target_type' => 'Ziel-Typ [target_type] (Erlaubt: path_or_url, cms_page, static_page, none)',
+ 'from_url' => 'Ursprungs-Pfad [from_url]',
+ 'from_scheme' => 'Ursprungs-Schema [from_scheme] (Erlaubt: http, https, auto [default])',
+ 'to_url' => 'Ziel-Pfad [to_url]',
+ 'to_scheme' => 'Ziel-Schema [to_scheme] (Erlaubt: http, https, auto [default])',
+ 'test_url' => 'Test-URL [test_url]',
+ 'cms_page' => 'CMS Seite [cms_page] (Dateiname ohne .htm)',
+ 'static_page' => 'RainLab.Pages Seite [static_page] (Dateiname ohne .htm)',
+ 'requirements' => 'Platzhalter Bedingungen [requirements]',
+ 'status_code' => 'HTTP Status Code [status_code] (Erlaubt: 301, 302, 303, 404, 410)',
+ 'hits' => 'Treffer [hits]',
+ 'from_date' => 'Zeitplan Datum ab [from_date] (YYYY-MM-DD oder leer)',
+ 'to_date' => 'Zeitplan Datum bis [to_date] (YYYY-MM-DD oder leer)',
+ 'sort_order' => 'Priorität [sort_order]',
+ 'is_enabled' => 'Aktiviert [is_enabled] (1 = aktiv, 0 = inaktiv [Standard])',
+ 'ignore_query_parameters' => 'Ignoriere Query-Parameter [ignore_query_parameters] (1 = ja, 0 = nein [Standard])',
+ 'ignore_case' => 'Ignoriere Gross-/Kleinschreibung [ignore_case] (1 = ja, 0 = nein [Standard])',
+ 'ignore_trailing_slash' => 'Schrägstrich am Ende ignorieren [ignore_trailing_slash] (1 = ja, 0 = nein [Standard])',
+ 'test_lab' => 'TestLab [test_lab] (1 = aktiviere Test Lab, 0 = deaktiviere TestLab [Standard])',
+ 'test_lab_path' => 'TestLab Pfad [test_lab_path] (Benötigt, wenn Art = "placeholders")',
+ 'system' => 'System [system] (1 = Vom System erstellt, 0 = Vom Benutzer erstellt [Standard])',
+ 'description' => 'Beschriebung [description]',
+ 'last_used_at' => 'Zuletzt verwendet [last_used_at] (YYYY-MM-DD HH:MM:SS oder leer)',
+ 'created_at' => 'Erstellt [created_at] (YYYY-MM-DD HH:MM:SS oder leer)',
+ 'updated_at' => 'Bearbeitet [updated_at] (YYYY-MM-DD HH:MM:SS oder leer)',
+ ],
+];
diff --git a/updates/version.yaml b/updates/version.yaml
index 635cb32..395b5cb 100644
--- a/updates/version.yaml
+++ b/updates/version.yaml
@@ -81,3 +81,4 @@ v3.1.4: "Fix target field not loading properly. See: https://github.com/vdlp/oc-
v3.1.5: "Minor improvements. See: https://github.com/vdlp/oc-redirect-plugin/releases/tag/3.1.5"
v3.1.6: "Add support for October CMS 3.3."
v3.1.7: "Remove use of old BrandSetting constants."
+v3.1.8: "Add German translation."