From a50abc138d4997b564e3065b37504cda5ce62da6 Mon Sep 17 00:00:00 2001
From: Yassine Doghri <yassine@doghri.fr>
Date: Tue, 7 Sep 2021 15:43:09 +0000
Subject: [PATCH] feat: update pine colors + create charts components

---
 app/Language/en/Common.php                    |  18 --
 app/Language/en/Contributor.php               |  41 ---
 app/Language/en/Countries.php                 | 264 ------------------
 app/Language/en/Episode.php                   | 146 ----------
 app/Language/en/MyAccount.php                 |  18 --
 app/Language/en/Pager.php                     |  21 --
 app/Language/en/Person.php                    |  66 -----
 app/Language/en/Platforms.php                 |  30 --
 app/Language/en/Podcast.php                   | 187 -------------
 app/Language/en/PodcastImport.php             |  41 ---
 app/Language/en/PodcastNavigation.php         |  38 ---
 app/Language/en/User.php                      |  54 ----
 app/Language/en/Validation.php                |  18 --
 app/Language/fr/Common.php                    |  18 --
 app/Language/fr/Contributor.php               |  42 ---
 app/Language/fr/Countries.php                 | 264 ------------------
 app/Language/fr/Episode.php                   | 147 ----------
 app/Language/fr/MyAccount.php                 |  20 --
 app/Language/fr/Pager.php                     |  21 --
 app/Language/fr/Person.php                    |  68 -----
 app/Language/fr/Platforms.php                 |  30 --
 app/Language/fr/Podcast.php                   | 189 -------------
 app/Language/fr/PodcastImport.php             |  41 ---
 app/Language/fr/PodcastNavigation.php         |  38 ---
 app/Language/fr/User.php                      |  54 ----
 app/Language/fr/Validation.php                |  18 --
 app/Libraries/ViewComponents/Component.php    |   2 +
 app/Resources/js/modules/Charts.ts            |  45 +--
 app/Resources/styles/choices.css              |   2 +-
 app/Resources/styles/formInputTabs.css        |   2 +-
 app/Resources/styles/tabs.css                 |   2 +-
 app/Views/Components/Charts/Bar.php           |  10 +
 .../Components/Charts/ChartsComponent.php     |  26 ++
 app/Views/Components/Charts/Map.php           |  10 +
 app/Views/Components/Charts/Pie.php           |  10 +
 app/Views/Components/Charts/XY.php            |  10 +
 app/Views/errors/html/error_404.php           |   2 +-
 modules/Admin/Config/Routes.php               |   4 +-
 modules/Admin/Language/en/Episode.php         |   1 -
 .../Admin/Language/en/EpisodeNavigation.php   |  19 ++
 .../Admin/Language/en/PodcastNavigation.php   |  19 +-
 .../Admin/Language/fr/EpisodeNavigation.php   |  19 ++
 .../Admin/Language/fr/PodcastNavigation.php   |  19 +-
 .../Install}/Language/en/Install.php          |   0
 .../Install}/Language/fr/Install.php          |   0
 themes/cp_admin/_layout.php                   |   4 +-
 themes/cp_admin/episode/_sidebar.php          |  60 ++++
 themes/cp_admin/episode/edit.php              |  20 +-
 themes/cp_admin/episode/list.php              |   2 +-
 themes/cp_admin/episode/view.php              | 118 +-------
 themes/cp_admin/podcast/_sidebar.php          |   2 +-
 themes/cp_admin/podcast/analytics/index.php   |  46 ++-
 .../podcast/analytics/listening_time.php      |  30 +-
 .../cp_admin/podcast/analytics/locations.php  |  47 ++--
 themes/cp_admin/podcast/analytics/players.php |  73 ++---
 .../podcast/analytics/time_periods.php        |  32 +--
 .../podcast/analytics/unique_listeners.php    |  30 +-
 .../cp_admin/podcast/analytics/webpages.php   |  66 ++---
 themes/cp_admin/podcast/latest_episodes.php   |   7 +-
 themes/cp_app/home.php                        |   2 +-
 themes/cp_app/page.php                        |   2 +-
 themes/cp_app/podcast/_layout.php             |   6 +-
 .../cp_app/podcast/_layout_authenticated.php  |  10 +-
 themes/cp_app/podcast/_partials/header.php    |   2 +-
 themes/cp_app/podcast/activity.php            |   2 +-
 .../cp_app/podcast/activity_authenticated.php |   2 +-
 themes/cp_app/podcast/episodes.php            |   2 +-
 .../cp_app/podcast/episodes_authenticated.php |   2 +-
 themes/cp_app/podcast/follow.php              |   2 +-
 themes/cp_app/podcast/post_remote_action.php  |   2 +-
 70 files changed, 389 insertions(+), 2276 deletions(-)
 delete mode 100644 app/Language/en/Contributor.php
 delete mode 100644 app/Language/en/Countries.php
 delete mode 100644 app/Language/en/MyAccount.php
 delete mode 100644 app/Language/en/Pager.php
 delete mode 100644 app/Language/en/Person.php
 delete mode 100644 app/Language/en/Platforms.php
 delete mode 100644 app/Language/en/PodcastImport.php
 delete mode 100644 app/Language/en/PodcastNavigation.php
 delete mode 100644 app/Language/en/User.php
 delete mode 100644 app/Language/en/Validation.php
 delete mode 100644 app/Language/fr/Contributor.php
 delete mode 100644 app/Language/fr/Countries.php
 delete mode 100644 app/Language/fr/MyAccount.php
 delete mode 100644 app/Language/fr/Pager.php
 delete mode 100644 app/Language/fr/Person.php
 delete mode 100644 app/Language/fr/Platforms.php
 delete mode 100644 app/Language/fr/PodcastImport.php
 delete mode 100644 app/Language/fr/PodcastNavigation.php
 delete mode 100644 app/Language/fr/User.php
 delete mode 100644 app/Language/fr/Validation.php
 create mode 100644 app/Views/Components/Charts/Bar.php
 create mode 100644 app/Views/Components/Charts/ChartsComponent.php
 create mode 100644 app/Views/Components/Charts/Map.php
 create mode 100644 app/Views/Components/Charts/Pie.php
 create mode 100644 app/Views/Components/Charts/XY.php
 create mode 100644 modules/Admin/Language/en/EpisodeNavigation.php
 create mode 100644 modules/Admin/Language/fr/EpisodeNavigation.php
 rename {app => modules/Install}/Language/en/Install.php (100%)
 rename {app => modules/Install}/Language/fr/Install.php (100%)
 create mode 100644 themes/cp_admin/episode/_sidebar.php

diff --git a/app/Language/en/Common.php b/app/Language/en/Common.php
index f05e5d6a7c..debed34830 100644
--- a/app/Language/en/Common.php
+++ b/app/Language/en/Common.php
@@ -26,24 +26,6 @@ return [
     'actions' => 'Actions',
     'pageInfo' => 'Page {currentPage} out of {pageCount}',
     'go_back' => 'Go back',
-    'forms' => [
-        'editor' => [
-            'write' => 'Write',
-            'preview' => 'Preview',
-            'help' => 'Powered by markdown',
-        ],
-        'multiSelect' => [
-            'selectText' => 'Press to select',
-            'loadingText' => 'Loading...',
-            'noResultsText' => 'No results found',
-            'noChoicesText' => 'No choices to choose from',
-            'maxItemText' => 'Cannot add more items',
-        ],
-        'image_size_hint' =>
-            'Image must be squared with at least 1400px wide and tall.',
-        'upload_file' => 'Upload a file',
-        'remote_url' => 'Remote URL',
-    ],
     'play_episode_button' => [
         'play' => 'Play',
         'playing' => 'Playing',
diff --git a/app/Language/en/Contributor.php b/app/Language/en/Contributor.php
deleted file mode 100644
index 087e4f6d5f..0000000000
--- a/app/Language/en/Contributor.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'podcast_contributors' => 'Podcast contributors',
-    'view' => "{username}'s contribution to {podcastTitle}",
-    'add' => 'Add contributor',
-    'add_contributor' => 'Add a contributor for {0}',
-    'edit_role' => 'Update role for {0}',
-    'edit' => 'Edit',
-    'remove' => 'Remove',
-    'list' => [
-        'username' => 'Username',
-        'role' => 'Role',
-    ],
-    'form' => [
-        'user' => 'User',
-        'user_placeholder' => 'Select a user…',
-        'role' => 'Role',
-        'role_placeholder' => 'Select its role…',
-        'submit_add' => 'Add contributor',
-        'submit_edit' => 'Update role',
-    ],
-    'roles' => [
-        'podcast_admin' => 'Podcast admin',
-    ],
-    'messages' => [
-        'removeOwnerContributorError' => "You can't remove the podcast owner!",
-        'removeContributorSuccess' =>
-            'You have successfully removed {username} from {podcastTitle}',
-        'alreadyAddedError' =>
-            "The contributor you're trying to add has already been added!",
-    ],
-];
diff --git a/app/Language/en/Countries.php b/app/Language/en/Countries.php
deleted file mode 100644
index b682d306f7..0000000000
--- a/app/Language/en/Countries.php
+++ /dev/null
@@ -1,264 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * ISO 3166 country codes
- *
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'AD' => 'Andorra',
-    'AE' => 'United Arab Emirates',
-    'AF' => 'Afghanistan',
-    'AG' => 'Antigua and Barbuda',
-    'AI' => 'Anguilla',
-    'AL' => 'Albania',
-    'AM' => 'Armenia',
-    'AO' => 'Angola',
-    'AQ' => 'Antarctica',
-    'AR' => 'Argentina',
-    'AS' => 'American Samoa',
-    'AT' => 'Austria',
-    'AU' => 'Australia',
-    'AW' => 'Aruba',
-    'AX' => 'Ã…land Islands',
-    'AZ' => 'Azerbaijan',
-    'BA' => 'Bosnia and Herzegovina',
-    'BB' => 'Barbados',
-    'BD' => 'Bangladesh',
-    'BE' => 'Belgium',
-    'BF' => 'Burkina Faso',
-    'BG' => 'Bulgaria',
-    'BH' => 'Bahrain',
-    'BI' => 'Burundi',
-    'BJ' => 'Benin',
-    'BL' => 'Saint Barthélemy',
-    'BM' => 'Bermuda',
-    'BN' => 'Brunei Darussalam',
-    'BO' => 'Bolivia, Plurinational State of',
-    'BQ' => 'Bonaire, Sint Eustatius and Saba',
-    'BR' => 'Brazil',
-    'BS' => 'Bahamas',
-    'BT' => 'Bhutan',
-    'BV' => 'Bouvet Island',
-    'BW' => 'Botswana',
-    'BY' => 'Belarus',
-    'BZ' => 'Belize',
-    'CA' => 'Canada',
-    'CC' => 'Cocos (Keeling) Islands',
-    'CD' => 'Congo, the Democratic Republic of the',
-    'CF' => 'Central African Republic',
-    'CG' => 'Congo',
-    'CH' => 'Switzerland',
-    'CI' => "Côte d'Ivoire",
-    'CK' => 'Cook Islands',
-    'CL' => 'Chile',
-    'CM' => 'Cameroon',
-    'CN' => 'China',
-    'CO' => 'Colombia',
-    'CR' => 'Costa Rica',
-    'CU' => 'Cuba',
-    'CV' => 'Cape Verde',
-    'CW' => 'Curaçao',
-    'CX' => 'Christmas Island',
-    'CY' => 'Cyprus',
-    'CZ' => 'Czech Republic',
-    'DE' => 'Germany',
-    'DJ' => 'Djibouti',
-    'DK' => 'Denmark',
-    'DM' => 'Dominica',
-    'DO' => 'Dominican Republic',
-    'DZ' => 'Algeria',
-    'EC' => 'Ecuador',
-    'EE' => 'Estonia',
-    'EG' => 'Egypt',
-    'EH' => 'Western Sahara',
-    'ER' => 'Eritrea',
-    'ES' => 'Spain',
-    'ET' => 'Ethiopia',
-    'FI' => 'Finland',
-    'FJ' => 'Fiji',
-    'FK' => 'Falkland Islands (Malvinas)',
-    'FM' => 'Micronesia, Federated States of',
-    'FO' => 'Faroe Islands',
-    'FR' => 'France',
-    'GA' => 'Gabon',
-    'GB' => 'United Kingdom',
-    'GD' => 'Grenada',
-    'GE' => 'Georgia',
-    'GF' => 'French Guiana',
-    'GG' => 'Guernsey',
-    'GH' => 'Ghana',
-    'GI' => 'Gibraltar',
-    'GL' => 'Greenland',
-    'GM' => 'Gambia',
-    'GN' => 'Guinea',
-    'GP' => 'Guadeloupe',
-    'GQ' => 'Equatorial Guinea',
-    'GR' => 'Greece',
-    'GS' => 'South Georgia and the South Sandwich Islands',
-    'GT' => 'Guatemala',
-    'GU' => 'Guam',
-    'GW' => 'Guinea-Bissau',
-    'GY' => 'Guyana',
-    'HK' => 'Hong Kong',
-    'HM' => 'Heard Island and McDonald Islands',
-    'HN' => 'Honduras',
-    'HR' => 'Croatia',
-    'HT' => 'Haiti',
-    'HU' => 'Hungary',
-    'ID' => 'Indonesia',
-    'IE' => 'Ireland',
-    'IL' => 'Israel',
-    'IM' => 'Isle of Man',
-    'IN' => 'India',
-    'IO' => 'British Indian Ocean Territory',
-    'IQ' => 'Iraq',
-    'IR' => 'Iran, Islamic Republic of',
-    'IS' => 'Iceland',
-    'IT' => 'Italy',
-    'JE' => 'Jersey',
-    'JM' => 'Jamaica',
-    'JO' => 'Jordan',
-    'JP' => 'Japan',
-    'KE' => 'Kenya',
-    'KG' => 'Kyrgyzstan',
-    'KH' => 'Cambodia',
-    'KI' => 'Kiribati',
-    'KM' => 'Comoros',
-    'KN' => 'Saint Kitts and Nevis',
-    'KP' => "Korea, Democratic People's Republic of",
-    'KR' => 'Korea, Republic of',
-    'KW' => 'Kuwait',
-    'KY' => 'Cayman Islands',
-    'KZ' => 'Kazakhstan',
-    'LA' => "Lao People's Democratic Republic",
-    'LB' => 'Lebanon',
-    'LC' => 'Saint Lucia',
-    'LI' => 'Liechtenstein',
-    'LK' => 'Sri Lanka',
-    'LR' => 'Liberia',
-    'LS' => 'Lesotho',
-    'LT' => 'Lithuania',
-    'LU' => 'Luxembourg',
-    'LV' => 'Latvia',
-    'LY' => 'Libya',
-    'MA' => 'Morocco',
-    'MC' => 'Monaco',
-    'MD' => 'Moldova, Republic of',
-    'ME' => 'Montenegro',
-    'MF' => 'Saint Martin (French part)',
-    'MG' => 'Madagascar',
-    'MH' => 'Marshall Islands',
-    'MK' => 'Macedonia, the Former Yugoslav Republic of',
-    'ML' => 'Mali',
-    'MM' => 'Myanmar',
-    'MN' => 'Mongolia',
-    'MO' => 'Macao',
-    'MP' => 'Northern Mariana Islands',
-    'MQ' => 'Martinique',
-    'MR' => 'Mauritania',
-    'MS' => 'Montserrat',
-    'MT' => 'Malta',
-    'MU' => 'Mauritius',
-    'MV' => 'Maldives',
-    'MW' => 'Malawi',
-    'MX' => 'Mexico',
-    'MY' => 'Malaysia',
-    'MZ' => 'Mozambique',
-    'N/A' => 'Not Applicable (local IP…)',
-    'NA' => 'Namibia',
-    'NC' => 'New Caledonia',
-    'NE' => 'Niger',
-    'NF' => 'Norfolk Island',
-    'NG' => 'Nigeria',
-    'NI' => 'Nicaragua',
-    'NL' => 'Netherlands',
-    'NO' => 'Norway',
-    'NP' => 'Nepal',
-    'NR' => 'Nauru',
-    'NU' => 'Niue',
-    'NZ' => 'New Zealand',
-    'OM' => 'Oman',
-    'PA' => 'Panama',
-    'PE' => 'Peru',
-    'PF' => 'French Polynesia',
-    'PG' => 'Papua New Guinea',
-    'PH' => 'Philippines',
-    'PK' => 'Pakistan',
-    'PL' => 'Poland',
-    'PM' => 'Saint Pierre and Miquelon',
-    'PN' => 'Pitcairn',
-    'PR' => 'Puerto Rico',
-    'PS' => 'Palestine, State of',
-    'PT' => 'Portugal',
-    'PW' => 'Palau',
-    'PY' => 'Paraguay',
-    'QA' => 'Qatar',
-    'RE' => 'Réunion',
-    'RO' => 'Romania',
-    'RS' => 'Serbia',
-    'RU' => 'Russian Federation',
-    'RW' => 'Rwanda',
-    'SA' => 'Saudi Arabia',
-    'SB' => 'Solomon Islands',
-    'SC' => 'Seychelles',
-    'SD' => 'Sudan',
-    'SE' => 'Sweden',
-    'SG' => 'Singapore',
-    'SH' => 'Saint Helena, Ascension and Tristan da Cunha',
-    'SI' => 'Slovenia',
-    'SJ' => 'Svalbard and Jan Mayen',
-    'SK' => 'Slovakia',
-    'SL' => 'Sierra Leone',
-    'SM' => 'San Marino',
-    'SN' => 'Senegal',
-    'SO' => 'Somalia',
-    'SR' => 'Suriname',
-    'SS' => 'South Sudan',
-    'ST' => 'Sao Tome and Principe',
-    'SV' => 'El Salvador',
-    'SX' => 'Sint Maarten (Dutch part)',
-    'SY' => 'Syrian Arab Republic',
-    'SZ' => 'Swaziland',
-    'TC' => 'Turks and Caicos Islands',
-    'TD' => 'Chad',
-    'TF' => 'French Southern Territories',
-    'TG' => 'Togo',
-    'TH' => 'Thailand',
-    'TJ' => 'Tajikistan',
-    'TK' => 'Tokelau',
-    'TL' => 'Timor-Leste',
-    'TM' => 'Turkmenistan',
-    'TN' => 'Tunisia',
-    'TO' => 'Tonga',
-    'TR' => 'Turkey',
-    'TT' => 'Trinidad and Tobago',
-    'TV' => 'Tuvalu',
-    'TW' => 'Taiwan, Province of China',
-    'TZ' => 'Tanzania, United Republic of',
-    'UA' => 'Ukraine',
-    'UG' => 'Uganda',
-    'UM' => 'United States Minor Outlying Islands',
-    'US' => 'United States',
-    'UY' => 'Uruguay',
-    'UZ' => 'Uzbekistan',
-    'VA' => 'Holy See (Vatican City State)',
-    'VC' => 'Saint Vincent and the Grenadines',
-    'VE' => 'Venezuela, Bolivarian Republic of',
-    'VG' => 'Virgin Islands, British',
-    'VI' => 'Virgin Islands, U.S.',
-    'VN' => 'Viet Nam',
-    'VU' => 'Vanuatu',
-    'WF' => 'Wallis and Futuna',
-    'WS' => 'Samoa',
-    'YE' => 'Yemen',
-    'YT' => 'Mayotte',
-    'ZA' => 'South Africa',
-    'ZM' => 'Zambia',
-    'ZW' => 'Zimbabwe',
-];
diff --git a/app/Language/en/Episode.php b/app/Language/en/Episode.php
index 06855b9d71..565b7ba1f6 100644
--- a/app/Language/en/Episode.php
+++ b/app/Language/en/Episode.php
@@ -25,150 +25,4 @@ return [
     }',
     'all_podcast_episodes' => 'All podcast episodes',
     'back_to_podcast' => 'Go back to podcast',
-    'edit' => 'Edit',
-    'publish' => 'Publish',
-    'publish_edit' => 'Edit publication',
-    'unpublish' => 'Unpublish',
-    'publish_error' => 'Episode is already published.',
-    'publish_edit_error' => 'Episode is already published.',
-    'publish_cancel_error' => 'Episode is already published.',
-    'unpublish_error' => 'Episode is not published.',
-    'delete' => 'Delete',
-    'go_to_page' => 'Go to page',
-    'create' => 'Add an episode',
-    'publication_status' => [
-        'published' => 'Published',
-        'scheduled' => 'Scheduled',
-        'not_published' => 'Not published',
-    ],
-    'list' => [
-        'episode' => 'Episode',
-        'visibility' => 'Visibility',
-        'comments' => 'Comments',
-        'actions' => 'Actions',
-    ],
-    'form' => [
-        'warning' =>
-            'In case of fatal error, try increasing the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server.<br />These values must be higher than the audio file you wish to upload.',
-        'audio_file' => 'Audio file',
-        'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.',
-        'info_section_title' => 'Episode info',
-        'info_section_subtitle' => '',
-        'image' => 'Cover image',
-        'image_hint' =>
-            'If you do not set an image, the podcast cover will be used instead.',
-        'title' => 'Title',
-        'title_hint' =>
-            'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.',
-        'permalink' => 'Permalink',
-        'season_number' => 'Season',
-        'episode_number' => 'Episode',
-        'type' => [
-            'label' => 'Type',
-            'hint' =>
-                '- <strong>full</strong>: complete content the episode.<br/>- <strong>trailer</strong>: short, promotional piece of content that represents a preview of the current show.<br/>- <strong>bonus</strong>: extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show.',
-            'full' => 'Full',
-            'trailer' => 'Trailer',
-            'bonus' => 'Bonus',
-        ],
-        'parental_advisory' => [
-            'label' => 'Parental advisory',
-            'hint' => 'Does the episode contain explicit content?',
-            'undefined' => 'undefined',
-            'clean' => 'Clean',
-            'explicit' => 'Explicit',
-        ],
-        'show_notes_section_title' => 'Show notes',
-        'show_notes_section_subtitle' =>
-            'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.',
-        'description' => 'Description',
-        'description_footer' => 'Description footer',
-        'description_footer_hint' =>
-            'This text is added at the end of each episode description, it is a good place to input your social links for example.',
-        'additional_files_section_title' => 'Additional files',
-        'additional_files_section_subtitle' =>
-            'These files may be used by other platforms to provide better experience to your audience.<br />See the {podcastNamespaceLink} for more information.',
-        'location_section_title' => 'Location',
-        'location_section_subtitle' => 'What place is this episode about?',
-        'location_name' => 'Location name or address',
-        'location_name_hint' => 'This can be a real or fictional location',
-        'transcript' => 'Transcript or closed captions',
-        'transcript_hint' => 'Allowed formats are txt, html, srt or json.',
-        'transcript_file' => 'Transcript file',
-        'transcript_file_remote_url' => 'Remote url for transcript',
-        'transcript_file_delete' => 'Delete transcript file',
-        'chapters' => 'Chapters',
-        'chapters_hint' => 'File must be in JSON Chapters format.',
-        'chapters_file' => 'Chapters file',
-        'chapters_file_remote_url' => 'Remote url for chapters file',
-        'chapters_file_delete' => 'Delete chapters file',
-        'advanced_section_title' => 'Advanced Parameters',
-        'advanced_section_subtitle' =>
-            'If you need RSS tags that Castopod does not handle, set them here.',
-        'custom_rss' => 'Custom RSS tags for the episode',
-        'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.',
-        'block' => 'Episode should be hidden from all platforms',
-        'block_hint' =>
-            'The episode show or hide post. If you want this episode removed from the Apple directory, toggle this on.',
-        'submit_create' => 'Create episode',
-        'submit_edit' => 'Save episode',
-    ],
-    'publish_form' => [
-        'back_to_episode_dashboard' => 'Back to episode dashboard',
-        'post' => 'Your announcement post',
-        'post_hint' =>
-            "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.",
-        'publication_date' => 'Publication date',
-        'publication_method' => [
-            'now' => 'Now',
-            'schedule' => 'Schedule',
-        ],
-        'scheduled_publication_date' => 'Scheduled publication date',
-        'scheduled_publication_date_clear' => 'Clear publication date',
-        'scheduled_publication_date_hint' =>
-            'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm',
-        'submit' => 'Publish',
-        'submit_edit' => 'Edit publication',
-        'cancel_publication' => 'Cancel publication',
-        'message_warning' => 'You did not write a message for your announcement post!',
-        'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.',
-        'message_warning_submit' => 'Publish anyways',
-    ],
-    'unpublish_form' => [
-        'disclaimer' =>
-            "Unpublishing the episode will delete all the notes associated with the episode and remove it from the podcast's RSS feed.",
-        'understand' => 'I understand, I want to unpublish the episode',
-        'submit' => 'Unpublish',
-    ],
-    'soundbites' => 'Soundbites',
-    'soundbites_form' => [
-        'title' => 'Edit soundbites',
-        'info_section_title' => 'Episode soundbites',
-        'info_section_subtitle' => 'Add, edit or delete soundbites',
-        'start_time' => 'Start',
-        'start_time_hint' =>
-            'The first second of the soundbite, it can be a decimal number.',
-        'duration' => 'Duration',
-        'duration_hint' =>
-            'The duration of the soundbite (in seconds), it can be a decimal number.',
-        'label' => 'Label',
-        'label_hint' => 'Text that will be displayed.',
-        'play' => 'Play soundbite',
-        'delete' => 'Delete soundbite',
-        'bookmark' =>
-            'Click while playing to get current position, click again to get duration.',
-        'submit_edit' => 'Save all soundbites',
-    ],
-    'embeddable_player' => [
-        'add' => 'Add embeddable player',
-        'title' => 'Embeddable player',
-        'label' =>
-            'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.',
-        'clipboard_iframe' => 'Copy embeddable player to clipboard',
-        'clipboard_url' => 'Copy address to clipboard',
-        'dark' => 'Dark',
-        'dark-transparent' => 'Dark transparent',
-        'light' => 'Light',
-        'light-transparent' => 'Light transparent',
-    ],
 ];
diff --git a/app/Language/en/MyAccount.php b/app/Language/en/MyAccount.php
deleted file mode 100644
index 68e79e82d9..0000000000
--- a/app/Language/en/MyAccount.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'info' => 'My account info',
-    'changePassword' => 'Change my password',
-    'messages' => [
-        'wrongPasswordError' => "You've entered the wrong password, try again.",
-        'passwordChangeSuccess' => 'Password has been successfully changed!',
-    ],
-];
diff --git a/app/Language/en/Pager.php b/app/Language/en/Pager.php
deleted file mode 100644
index 3b6fb25355..0000000000
--- a/app/Language/en/Pager.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'pageNavigation' => 'Page navigation',
-    'first' => 'First',
-    'previous' => 'Previous',
-    'next' => 'Next',
-    'last' => 'Last',
-    'older' => 'Older',
-    'newer' => 'Newer',
-    'invalidTemplate' => '{0} is not a valid Pager template.',
-    'invalidPaginationGroup' => '{0} is not a valid Pagination group.',
-];
diff --git a/app/Language/en/Person.php b/app/Language/en/Person.php
deleted file mode 100644
index 7306ed270c..0000000000
--- a/app/Language/en/Person.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'persons' => 'Persons',
-    'all_persons' => 'All persons',
-    'no_person' => 'Nobody found!',
-    'create' => 'Create a person',
-    'view' => 'View person',
-    'edit' => 'Edit person',
-    'delete' => 'Delete person',
-    'form' => [
-        'identity_section_title' => 'Identity',
-        'identity_section_subtitle' => 'Who is working on the podcast',
-        'image' => 'Picture',
-        'image_size_hint' =>
-            'Image must be squared with at least 400px wide and tall.',
-        'full_name' => 'Full name',
-        'full_name_hint' => 'This is the full name or alias of the person.',
-        'unique_name' => 'Unique name',
-        'unique_name_hint' => 'Used for URLs',
-        'information_url' => 'Information URL',
-        'information_url_hint' =>
-            'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.',
-        'submit_create' => 'Create person',
-        'submit_edit' => 'Save person',
-    ],
-    'podcast_form' => [
-        'title' => 'Manage persons',
-        'manage_section_title' => 'Management',
-        'manage_section_subtitle' => 'Remove persons from this podcast',
-        'add_section_title' => 'Add persons to this podcast',
-        'add_section_subtitle' => 'You may pick several persons and roles.',
-        'persons' => 'Persons',
-        'persons_hint' =>
-            'You may select one or several persons with the same roles. You need to create the persons first.',
-        'roles' => 'Roles',
-        'roles_hint' =>
-            'You may select none, one or several roles for a person.',
-        'submit_add' => 'Add person(s)',
-        'remove' => 'Remove',
-    ],
-    'episode_form' => [
-        'title' => 'Manage persons',
-        'manage_section_title' => 'Management',
-        'manage_section_subtitle' => 'Remove persons from this episode',
-        'add_section_title' => 'Add persons to this episode',
-        'add_section_subtitle' => 'You may pick several persons and roles.',
-        'persons' => 'Persons',
-        'persons_hint' =>
-            'You may select one or several persons with the same roles. You need to create the persons first.',
-        'roles' => 'Roles',
-        'roles_hint' =>
-            'You may select none, one or several roles for a person.',
-        'submit_add' => 'Add person(s)',
-        'remove' => 'Remove',
-    ],
-    'credits' => 'Credits',
-];
diff --git a/app/Language/en/Platforms.php b/app/Language/en/Platforms.php
deleted file mode 100644
index 27582cdad8..0000000000
--- a/app/Language/en/Platforms.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'title' => 'Platforms',
-    'home_url' => 'Go to {platformName} website',
-    'submit_url' => 'Submit your podcast on {platformName}',
-    'visible' => 'Display in podcast homepage?',
-    'on_embeddable_player' => 'Display on embeddable player?',
-    'remove' => 'Remove {platformName}',
-    'submit' => 'Save',
-    'messages' => [
-        'updateSuccess' => 'Platform links have been successfully updated!',
-        'removeLinkSuccess' => 'The platform link has been removed.',
-        'removeLinkError' =>
-            'The platform link could not be removed. Try again.',
-    ],
-    'description' => [
-        'podcasting' => 'The podcast ID on this platform',
-        'social' => 'The podcast account ID on this platform',
-        'funding' => 'Call to action message',
-    ],
-];
diff --git a/app/Language/en/Podcast.php b/app/Language/en/Podcast.php
index 946b0b1be4..ec83a05e73 100644
--- a/app/Language/en/Podcast.php
+++ b/app/Language/en/Podcast.php
@@ -23,193 +23,6 @@ return [
     'go_to_page' => 'Go to page',
     'latest_episodes' => 'Latest episodes',
     'see_all_episodes' => 'See all episodes',
-    'form' => [
-        'identity_section_title' => 'Podcast identity',
-        'identity_section_subtitle' => 'These fields allow you to get noticed.',
-        'image' => 'Cover image',
-        'title' => 'Title',
-        'handle' => 'Handle',
-        'handle_hint' =>
-            'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.',
-        'type' => [
-            'label' => 'Type',
-            'hint' =>
-                '- <strong>episodic</strong>: if episodes are intended to be consumed without any specific order. Newest episodes will be presented first.<br/>- <strong>serial</strong>: if episodes are intended to be consumed in sequential order. The oldest episodes will be presented first.',
-            'episodic' => 'Episodic',
-            'serial' => 'Serial',
-        ],
-        'description' => 'Description',
-        'classification_section_title' => 'Classification',
-        'classification_section_subtitle' =>
-            'These fields will impact your audience and competition.',
-        'language' => 'Language',
-        'category' => 'Category',
-        'category_placeholder' => 'Select a category…',
-        'other_categories' => 'Other categories',
-        'parental_advisory' => [
-            'label' => 'Parental advisory',
-            'hint' => 'Does it contain explicit content?',
-            'undefined' => 'undefined',
-            'clean' => 'Clean',
-            'explicit' => 'Explicit',
-        ],
-        'author_section_title' => 'Author',
-        'author_section_subtitle' => 'Who is managing the podcast?',
-        'owner_name' => 'Owner name',
-        'owner_name_hint' =>
-            'For administrative use only. Visible in the public RSS feed.',
-        'owner_email' => 'Owner email',
-        'owner_email_hint' =>
-            'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.',
-        'publisher' => 'Publisher',
-        'publisher_hint' =>
-            'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.',
-        'copyright' => 'Copyright',
-        'location_section_title' => 'Location',
-        'location_section_subtitle' => 'What place is this podcast about?',
-        'location_name' => 'Location name or address',
-        'location_name_hint' => 'This can be a real place or fictional',
-        'monetization_section_title' => 'Monetization',
-        'monetization_section_subtitle' =>
-            'Earn money thanks to your audience.',
-        'payment_pointer' => 'Payment Pointer for Web Monetization',
-        'payment_pointer_hint' =>
-            'This is your where you will receive money thanks to Web Monetization',
-        'advanced_section_title' => 'Advanced Parameters',
-        'advanced_section_subtitle' =>
-            'If you need RSS tags that Castopod does not handle, set them here.',
-        'custom_rss' => 'Custom RSS tags for the podcast',
-        'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.',
-        'partnership' => 'Partnership',
-        'partner_id' => 'ID',
-        'partner_link_url' => 'Link URL',
-        'partner_image_url' => 'Image URL',
-        'partner_id_hint' => 'Your own partner ID',
-        'partner_link_url_hint' => 'The generic partner link address',
-        'partner_image_url_hint' => 'The generic partner image address',
-        'status_section_title' => 'Status',
-        'status_section_subtitle' => 'Dead or alive?',
-        'block' => 'Podcast should be hidden from all platforms',
-        'complete' => 'Podcast will not be having new episodes',
-        'lock' => 'Prevent podcast from being copied',
-        'lock_hint' =>
-            'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.',
-        'submit_create' => 'Create podcast',
-        'submit_edit' => 'Save podcast',
-    ],
-    'category_options' => [
-        'uncategorized' => 'uncategorized',
-        'arts' => 'Arts',
-        'business' => 'Business',
-        'comedy' => 'Comedy',
-        'education' => 'Education',
-        'fiction' => 'Fiction',
-        'government' => 'Government',
-        'health_and_fitness' => 'Health &amp Fitness',
-        'history' => 'History',
-        'kids_and_family' => 'Kids &amp Family',
-        'leisure' => 'Leisure',
-        'music' => 'Music',
-        'news' => 'News',
-        'religion_and_spirituality' => 'Religion &amp Spirituality',
-        'science' => 'Science',
-        'society_and_culture' => 'Society &amp Culture',
-        'sports' => 'Sports',
-        'technology' => 'Technology',
-        'true_crime' => 'True Crime',
-        'tv_and_film' => 'TV &amp Film',
-        'books' => 'Books',
-        'design' => 'Design',
-        'fashion_and_beauty' => 'Fashion &amp Beauty',
-        'food' => 'Food',
-        'performing_arts' => 'Performing Arts',
-        'visual_arts' => 'Visual Arts',
-        'careers' => 'Careers',
-        'entrepreneurship' => 'Entrepreneurship',
-        'investing' => 'Investing',
-        'management' => 'Management',
-        'marketing' => 'Marketing',
-        'non_profit' => 'Non-Profit',
-        'comedy_interviews' => 'Comedy Interviews',
-        'improv' => 'Improv',
-        'stand_up' => 'Stand-Up',
-        'courses' => 'Courses',
-        'how_to' => 'How To',
-        'language_learning' => 'Language Learning',
-        'self_improvement' => 'Self-Improvement',
-        'comedy_fiction' => 'Comedy Fiction',
-        'drama' => 'Drama',
-        'science_fiction' => 'Science Fiction',
-        'alternative_health' => 'Alternative Health',
-        'fitness' => 'Fitness',
-        'medicine' => 'Medicine',
-        'mental_health' => 'Mental Health',
-        'nutrition' => 'Nutrition',
-        'sexuality' => 'Sexuality',
-        'education_for_kids' => 'Education for Kids',
-        'parenting' => 'Parenting',
-        'pets_and_animals' => 'Pets &amp Animals',
-        'stories_for_kids' => 'Stories for Kids',
-        'animation_and_manga' => 'Animation &amp Manga',
-        'automotive' => 'Automotive',
-        'aviation' => 'Aviation',
-        'crafts' => 'Crafts',
-        'games' => 'Games',
-        'hobbies' => 'Hobbies',
-        'home_and_garden' => 'Home &amp Garden',
-        'video_games' => 'Video Games',
-        'music_commentary' => 'Music Commentary',
-        'music_history' => 'Music History',
-        'music_interviews' => 'Music Interviews',
-        'business_news' => 'Business News',
-        'daily_news' => 'Daily News',
-        'entertainment_news' => 'Entertainment News',
-        'news_commentary' => 'News Commentary',
-        'politics' => 'Politics',
-        'sports_news' => 'Sports News',
-        'tech_news' => 'Tech News',
-        'buddhism' => 'Buddhism',
-        'christianity' => 'Christianity',
-        'hinduism' => 'Hinduism',
-        'islam' => 'Islam',
-        'judaism' => 'Judaism',
-        'religion' => 'Religion',
-        'spirituality' => 'Spirituality',
-        'astronomy' => 'Astronomy',
-        'chemistry' => 'Chemistry',
-        'earth_sciences' => 'Earth Sciences',
-        'life_sciences' => 'Life Sciences',
-        'mathematics' => 'Mathematics',
-        'natural_sciences' => 'Natural Sciences',
-        'nature' => 'Nature',
-        'physics' => 'Physics',
-        'social_sciences' => 'Social Sciences',
-        'documentary' => 'Documentary',
-        'personal_journals' => 'Personal Journals',
-        'philosophy' => 'Philosophy',
-        'places_and_travel' => 'Places &amp Travel',
-        'relationships' => 'Relationships',
-        'baseball' => 'Baseball',
-        'basketball' => 'Basketball',
-        'cricket' => 'Cricket',
-        'fantasy_sports' => 'Fantasy Sports',
-        'football' => 'Football',
-        'golf' => 'Golf',
-        'hockey' => 'Hockey',
-        'rugby' => 'Rugby',
-        'running' => 'Running',
-        'soccer' => 'Soccer',
-        'swimming' => 'Swimming',
-        'tennis' => 'Tennis',
-        'volleyball' => 'Volleyball',
-        'wilderness' => 'Wilderness',
-        'wrestling' => 'Wrestling',
-        'after_shows' => 'After Shows',
-        'film_history' => 'Film History',
-        'film_interviews' => 'Film Interviews',
-        'film_reviews' => 'Film Reviews',
-        'tv_reviews' => 'TV Reviews',
-    ],
     'by' => 'By {publisher}',
     'season' => 'Season {seasonNumber}',
     'list_of_episodes_year' => '{year} episodes ({episodeCount})',
diff --git a/app/Language/en/PodcastImport.php b/app/Language/en/PodcastImport.php
deleted file mode 100644
index b6e8774c2a..0000000000
--- a/app/Language/en/PodcastImport.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'warning' =>
-        'This procedure may take a long time.<br/>As the current version does not show any progress while it runs, you will not see anything updated until it is done.<br/>In case of timeout error, increase `max_execution_time` value.',
-    'old_podcast_section_title' => 'The podcast to import',
-    'old_podcast_section_subtitle' =>
-        'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.',
-    'imported_feed_url' => 'Feed URL',
-    'imported_feed_url_hint' => 'The feed must be in xml or rss format.',
-    'new_podcast_section_title' => 'The new podcast',
-    'advanced_params_section_title' => 'Advanced parameters',
-    'advanced_params_section_subtitle' =>
-        'Keep the default values if you have no idea of what the fields are for.',
-    'slug_field' => [
-        'label' => 'Which field should be used to calculate episode slug',
-        'link' => '&lt;link&gt;',
-        'title' => '&lt;title&gt;',
-    ],
-    'description_field' =>
-        'Source field used for episode description / show notes',
-    'force_renumber' => 'Force episodes renumbering',
-    'force_renumber_hint' =>
-        'Use this if your podcast does not have episode numbers but wish to set them during import.',
-    'season_number' => 'Season number',
-    'season_number_hint' =>
-        'Use this if your podcast does not have a season number but wish to set one during import. Leave blank otherwise.',
-    'max_episodes' => 'Maximum number of episodes to import',
-    'max_episodes_hint' => 'Leave blank to import all episodes',
-    'lock_import' =>
-        'This feed is protected. You cannot import it. If you are the owner, unprotect it on the origin platform.',
-    'submit' => 'Import podcast',
-];
diff --git a/app/Language/en/PodcastNavigation.php b/app/Language/en/PodcastNavigation.php
deleted file mode 100644
index 147eebb6a6..0000000000
--- a/app/Language/en/PodcastNavigation.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'go_to_page' => 'Go to podcast page',
-    'dashboard' => 'Podcast dashboard',
-    'podcast-view' => 'Home',
-    'podcast-edit' => 'Edit podcast',
-    'episodes' => 'Episodes',
-    'episode-list' => 'All episodes',
-    'episode-create' => 'New episode',
-    'fediverse' => 'Fediverse',
-    'fediverse-block_lists' => 'Block lists',
-    'analytics' => 'Analytics',
-    'persons' => 'Persons',
-    'podcast-person-manage' => 'Manage persons',
-    'contributors' => 'Contributors',
-    'contributor-list' => 'All contributors',
-    'contributor-add' => 'Add contributor',
-    'platforms' => 'External platforms',
-    'platforms-podcasting' => 'Podcasting',
-    'platforms-social' => 'Social Networks',
-    'platforms-funding' => 'Funding',
-    'podcast-analytics' => 'Audience overview',
-    'podcast-analytics-webpages' => 'Web pages visits',
-    'podcast-analytics-locations' => 'Locations',
-    'podcast-analytics-unique-listeners' => 'Unique listeners',
-    'podcast-analytics-players' => 'Players',
-    'podcast-analytics-listening-time' => 'Listening time',
-    'podcast-analytics-time-periods' => 'Time periods',
-];
diff --git a/app/Language/en/User.php b/app/Language/en/User.php
deleted file mode 100644
index 97cfe2f73c..0000000000
--- a/app/Language/en/User.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'edit_roles' => "Edit {username}'s roles",
-    'forcePassReset' => 'Force pass reset',
-    'ban' => 'Ban',
-    'unban' => 'Unban',
-    'delete' => 'Delete',
-    'create' => 'New user',
-    'view' => "{username}'s info",
-    'all_users' => 'All users',
-    'list' => [
-        'user' => 'User',
-        'roles' => 'Roles',
-        'banned' => 'Banned?',
-    ],
-    'form' => [
-        'email' => 'Email',
-        'username' => 'Username',
-        'password' => 'Password',
-        'new_password' => 'New Password',
-        'roles' => 'Roles',
-        'permissions' => 'Permissions',
-        'submit_create' => 'Create user',
-        'submit_edit' => 'Save',
-        'submit_password_change' => 'Change!',
-    ],
-    'roles' => [
-        'superadmin' => 'Super admin',
-    ],
-    'messages' => [
-        'createSuccess' =>
-            'User created successfully! {username} will be prompted with a password reset upon first authentication.',
-        'rolesEditSuccess' =>
-            "{username}'s roles have been successfully updated.",
-        'forcePassResetSuccess' =>
-            '{username} will be prompted with a password reset upon next visit.',
-        'banSuccess' => '{username} has been banned.',
-        'unbanSuccess' => '{username} has been unbanned.',
-        'banSuperAdminError' =>
-            '{username} is a superadmin, one does not simply ban a superadmin…',
-        'deleteSuperAdminError' =>
-            '{username} is a superadmin, one does not simply delete a superadmin…',
-        'deleteSuccess' => '{username} has been deleted.',
-    ],
-];
diff --git a/app/Language/en/Validation.php b/app/Language/en/Validation.php
deleted file mode 100644
index ae627c4b21..0000000000
--- a/app/Language/en/Validation.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'min_dims' =>
-        '{field} is either not an image, or it is not wide or tall enough.',
-    'is_image_squared' =>
-        '{field} is either not an image, or it is not squared (width and height differ).',
-    'validate_url' =>
-        'The {field} field must be a valid URL (eg. https://example.com/).',
-];
diff --git a/app/Language/fr/Common.php b/app/Language/fr/Common.php
index 2ab2171c70..6fc0c30d38 100644
--- a/app/Language/fr/Common.php
+++ b/app/Language/fr/Common.php
@@ -26,24 +26,6 @@ return [
     'actions' => 'Actions',
     'pageInfo' => 'Page {currentPage} sur {pageCount}',
     'go_back' => 'Retour en arrière',
-    'forms' => [
-        'editor' => [
-            'write' => 'Écrire',
-            'preview' => 'Aperçu',
-            'help' => 'Propulsé par markdown',
-        ],
-        'multiSelect' => [
-            'selectText' => 'Cliquez pour selectionner',
-            'loadingText' => 'Chargement...',
-            'noResultsText' => 'Aucun résultat trouvé',
-            'noChoicesText' => 'Aucune sélection possible',
-            'maxItemText' => 'Impossible de rajouter un élément',
-        ],
-        'image_size_hint' =>
-            'L’image doit être carrée, avec au minimum 1400px de long et de large.',
-        'upload_file' => 'Téléversez un fichier',
-        'remote_url' => 'URL distante',
-    ],
     'play_episode_button' => [
         'play' => 'Lire',
         'playing' => 'En cours',
diff --git a/app/Language/fr/Contributor.php b/app/Language/fr/Contributor.php
deleted file mode 100644
index 7e62309e4c..0000000000
--- a/app/Language/fr/Contributor.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'podcast_contributors' => 'Contributeurs du podcast',
-    'view' => 'Contribution de {username} à {podcastTitle}',
-    'add' => 'Ajouter un contributeur',
-    'add_contributor' => 'Ajouter un contributeur pour {0}',
-    'edit_role' => 'Modifier le rôle de {0}',
-    'edit' => 'Modifier',
-    'remove' => 'Supprimer',
-    'list' => [
-        'username' => 'Identifiant',
-        'role' => 'Rôle',
-    ],
-    'form' => [
-        'user' => 'Utilisateur',
-        'user_placeholder' => 'Sélectionnez un utilisateur…',
-        'role' => 'Rôle',
-        'role_placeholder' => 'Sélectionnez son rôle…',
-        'submit_add' => 'Ajouter le contributeur',
-        'submit_edit' => 'Mettre à jour le rôle',
-    ],
-    'roles' => [
-        'podcast_admin' => 'Administrateur de Podcasts',
-    ],
-    'messages' => [
-        'removeOwnerContributorError' =>
-            'Vous ne pouvez pas retirer le propriétaire du podcast !',
-        'removeContributorSuccess' =>
-            'Vous avez retiré {username} de {podcastTitle}',
-        'alreadyAddedError' =>
-            'Le contributeur que vous essayez d’ajouter est déjà présent.',
-    ],
-];
diff --git a/app/Language/fr/Countries.php b/app/Language/fr/Countries.php
deleted file mode 100644
index f1974eee7d..0000000000
--- a/app/Language/fr/Countries.php
+++ /dev/null
@@ -1,264 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * ISO 3166 country codes
- *
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'AF ' => 'Afghanistan',
-    'ZA ' => 'Afrique Du Sud',
-    'AX ' => 'Ã…land, ÃŽles',
-    'AL ' => 'Albanie',
-    'DZ ' => 'Algérie',
-    'DE ' => 'Allemagne',
-    'AD ' => 'Andorre',
-    'AO ' => 'Angola',
-    'AI ' => 'Anguilla',
-    'AQ ' => 'Antarctique',
-    'AG ' => 'Antigua-Et-Barbuda',
-    'SA ' => 'Arabie Saoudite',
-    'AR ' => 'Argentine',
-    'AM ' => 'Arménie',
-    'AW ' => 'Aruba',
-    'AU ' => 'Australie',
-    'AT ' => 'Autriche',
-    'AZ ' => 'Azerbaïdjan',
-    'BS ' => 'Bahamas',
-    'BH ' => 'Bahreïn',
-    'BD ' => 'Bangladesh',
-    'BB ' => 'Barbade',
-    'BY ' => 'Bélarus',
-    'BE ' => 'Belgique',
-    'BZ ' => 'Belize',
-    'BJ ' => 'Bénin',
-    'BM ' => 'Bermudes',
-    'BT ' => 'Bhoutan',
-    'BO ' => 'Bolivie, État Plurinational De',
-    'BQ ' => 'Bonaire, Saint-Eustache Et Saba',
-    'BA ' => 'Bosnie-Herzégovine',
-    'BW ' => 'Botswana',
-    'BV ' => 'Bouvet, ÃŽle',
-    'BR ' => 'Brésil',
-    'BN ' => 'Brunéi Darussalam',
-    'BG ' => 'Bulgarie',
-    'BF ' => 'Burkina Faso',
-    'BI ' => 'Burundi',
-    'KY ' => 'Caïmanes, Îles',
-    'KH ' => 'Cambodge',
-    'CM ' => 'Cameroun',
-    'CA ' => 'Canada',
-    'CV ' => 'Cabo Verde',
-    'CF ' => 'Centrafricaine, République',
-    'CL ' => 'Chili',
-    'CN ' => 'Chine',
-    'CX ' => 'Christmas, ÃŽle',
-    'CY ' => 'Chypre',
-    'CC ' => 'Cocos (Keeling), ÃŽles',
-    'CO ' => 'Colombie',
-    'KM ' => 'Comores',
-    'CG ' => 'Congo',
-    'CD ' => 'Congo, La République Démocratique Du',
-    'CK ' => 'Cook, ÃŽles',
-    'KR ' => 'Corée, République De',
-    'KP ' => 'Corée, République Populaire Démocratique De',
-    'CR ' => 'Costa Rica',
-    'CI ' => 'Côte D’ivoire',
-    'HR ' => 'Croatie',
-    'CU ' => 'Cuba',
-    'CW ' => 'Curaçao',
-    'DK ' => 'Danemark',
-    'DJ ' => 'Djibouti',
-    'DO ' => 'Dominicaine, République',
-    'DM ' => 'Dominique',
-    'EG ' => 'Égypte',
-    'SV ' => 'El Salvador',
-    'AE ' => 'Émirats Arabes Unis',
-    'EC ' => 'Équateur',
-    'ER ' => 'Érythrée',
-    'ES ' => 'Espagne',
-    'EE ' => 'Estonie',
-    'US ' => 'États-Unis',
-    'ET ' => 'Éthiopie',
-    'FK ' => 'Falkland, ÃŽles (Malvinas)',
-    'FO ' => 'Féroé, Îles',
-    'FJ ' => 'Fidji',
-    'FI ' => 'Finlande',
-    'FR ' => 'France',
-    'GA ' => 'Gabon',
-    'GM ' => 'Gambie',
-    'GE ' => 'Géorgie',
-    'GS ' => 'Géorgie Du Sud Et Les Îles Sandwich Du Sud',
-    'GH ' => 'Ghana',
-    'GI ' => 'Gibraltar',
-    'GR ' => 'Grèce',
-    'GD ' => 'Grenade',
-    'GL ' => 'Groenland',
-    'GP ' => 'Guadeloupe',
-    'GU ' => 'Guam',
-    'GT ' => 'Guatemala',
-    'GG ' => 'Guernesey',
-    'GN ' => 'Guinée',
-    'GW ' => 'Guinée-Bissau',
-    'GQ ' => 'Guinée Équatoriale',
-    'GY ' => 'Guyana',
-    'GF ' => 'Guyane Française',
-    'HT ' => 'Haïti',
-    'HM ' => 'Heard Et Macdonald, ÃŽles',
-    'HN ' => 'Honduras',
-    'HK ' => 'Hong Kong',
-    'HU ' => 'Hongrie',
-    'IM ' => 'ÃŽle De Man',
-    'UM ' => 'Îles Mineures Éloignées Des États-Unis',
-    'VG ' => 'ÃŽles Vierges Britanniques',
-    'VI ' => 'Îles Vierges Des États-Unis',
-    'IN ' => 'Inde',
-    'ID ' => 'Indonésie',
-    'IR ' => "Iran, République Islamique D'",
-    'IQ ' => 'Iraq',
-    'IE ' => 'Irlande',
-    'IS ' => 'Islande',
-    'IL ' => 'Israël',
-    'IT ' => 'Italie',
-    'JM ' => 'Jamaïque',
-    'JP ' => 'Japon',
-    'JE ' => 'Jersey',
-    'JO ' => 'Jordanie',
-    'KZ ' => 'Kazakhstan',
-    'KE ' => 'Kenya',
-    'KG ' => 'Kirghizistan',
-    'KI ' => 'Kiribati',
-    'KW ' => 'Koweït',
-    'LA ' => 'Lao, République Démocratique Populaire',
-    'LS ' => 'Lesotho',
-    'LV ' => 'Lettonie',
-    'LB ' => 'Liban',
-    'LR ' => 'Libéria',
-    'LY ' => 'Libye',
-    'LI ' => 'Liechtenstein',
-    'LT ' => 'Lituanie',
-    'LU ' => 'Luxembourg',
-    'MO ' => 'Macao',
-    'MK ' => 'République De Macédoine',
-    'MG ' => 'Madagascar',
-    'MY ' => 'Malaisie',
-    'MW ' => 'Malawi',
-    'MV ' => 'Maldives',
-    'ML ' => 'Mali',
-    'MT ' => 'Malte',
-    'MP ' => 'Mariannes Du Nord, ÃŽles',
-    'MA ' => 'Maroc',
-    'MH ' => 'Marshall, ÃŽles',
-    'MQ ' => 'Martinique',
-    'MU ' => 'Maurice',
-    'MR ' => 'Mauritanie',
-    'YT ' => 'Mayotte',
-    'MX ' => 'Mexique',
-    'FM ' => 'Micronésie, États Fédérés De',
-    'MD ' => 'Moldavie',
-    'MC ' => 'Monaco',
-    'MN ' => 'Mongolie',
-    'ME ' => 'Monténégro',
-    'MS ' => 'Montserrat',
-    'MZ ' => 'Mozambique',
-    'MM ' => 'Myanmar',
-    'NA ' => 'Namibie',
-    'N/A' => 'Non Applicable (IP locale…)',
-    'NR ' => 'Nauru',
-    'NP ' => 'Népal',
-    'NI ' => 'Nicaragua',
-    'NE ' => 'Niger',
-    'NG ' => 'Nigéria',
-    'NU ' => 'Niué',
-    'NF ' => 'Norfolk, ÃŽle',
-    'NO ' => 'Norvège',
-    'NC ' => 'Nouvelle-Calédonie',
-    'NZ ' => 'Nouvelle-Zélande',
-    'IO ' => "Océan Indien, Territoire Britannique De L'",
-    'OM ' => 'Oman',
-    'UG ' => 'Ouganda',
-    'UZ ' => 'Ouzbékistan',
-    'PK ' => 'Pakistan',
-    'PW ' => 'Palaos',
-    'PS ' => 'État De Palestine',
-    'PA ' => 'Panama',
-    'PG ' => 'Papouasie-Nouvelle-Guinée',
-    'PY ' => 'Paraguay',
-    'NL ' => 'Pays-Bas',
-    'PE ' => 'Pérou',
-    'PH ' => 'Philippines',
-    'PN ' => 'Pitcairn',
-    'PL ' => 'Pologne',
-    'PF ' => 'Polynésie Française',
-    'PR ' => 'Porto Rico',
-    'PT ' => 'Portugal',
-    'QA ' => 'Qatar',
-    'RE ' => 'Réunion',
-    'RO ' => 'Roumanie',
-    'GB ' => 'Royaume-Uni',
-    'RU ' => 'Russie, Fédération De',
-    'RW ' => 'Rwanda',
-    'EH ' => 'Sahara Occidental',
-    'BL ' => 'Saint-Barthélemy',
-    'KN ' => 'Saint-Kitts-Et-Nevis',
-    'SM ' => 'Saint-Marin',
-    'MF ' => 'Saint-Martin (Partie Française)',
-    'SX ' => 'Saint-Martin (Partie Néerlandaise)',
-    'PM ' => 'Saint-Pierre-Et-Miquelon',
-    'VA ' => 'Saint-Siège (État De La Cité Du Vatican)',
-    'VC ' => 'Saint-Vincent-Et-Les-Grenadines',
-    'SH ' => 'Sainte-Hélène, Ascension Et Tristan Da Cunha',
-    'LC ' => 'Sainte-Lucie',
-    'SB ' => 'Salomon, ÃŽles',
-    'WS ' => 'Samoa',
-    'AS ' => 'Samoa Américaines',
-    'ST ' => 'Sao Tomé-Et-Principe',
-    'SN ' => 'Sénégal',
-    'RS ' => 'Serbie',
-    'SC ' => 'Seychelles',
-    'SL ' => 'Sierra Leone',
-    'SG ' => 'Singapour',
-    'SK ' => 'Slovaquie',
-    'SI ' => 'Slovénie',
-    'SO ' => 'Somalie',
-    'SD ' => 'Soudan',
-    'SS ' => 'Soudan Du Sud',
-    'LK ' => 'Sri Lanka',
-    'SE ' => 'Suède',
-    'CH ' => 'Suisse',
-    'SR ' => 'Suriname',
-    'SJ ' => 'Svalbard Et ÃŽle Jan Mayen',
-    'SZ ' => 'Eswatini',
-    'SY ' => 'Syrienne, République Arabe',
-    'TJ ' => 'Tadjikistan',
-    'TW ' => 'Taïwan, Province De Chine',
-    'TZ ' => 'Tanzanie, République Unie De',
-    'TD ' => 'Tchad',
-    'CZ ' => 'Tchéquie',
-    'TF ' => 'Terres Australes Françaises',
-    'TH ' => 'Thaïlande',
-    'TL ' => 'Timor-Leste',
-    'TG ' => 'Togo',
-    'TK ' => 'Tokelau',
-    'TO ' => 'Tonga',
-    'TT ' => 'Trinité-Et-Tobago',
-    'TN ' => 'Tunisie',
-    'TM ' => 'Turkménistan',
-    'TC ' => 'Turks Et Caïques, Îles',
-    'TR ' => 'Turquie',
-    'TV ' => 'Tuvalu',
-    'UA ' => 'Ukraine',
-    'UY ' => 'Uruguay',
-    'VU ' => 'Vanuatu',
-    'VE ' => 'Venezuela, République Bolivarienne Du',
-    'VN ' => 'Viet Nam',
-    'WF ' => 'Wallis-Et-Futuna',
-    'YE ' => 'Yémen',
-    'ZM ' => 'Zambie',
-    'ZW ' => 'Zimbabwe',
-];
diff --git a/app/Language/fr/Episode.php b/app/Language/fr/Episode.php
index fc3d49364e..c6f565c855 100644
--- a/app/Language/fr/Episode.php
+++ b/app/Language/fr/Episode.php
@@ -25,151 +25,4 @@ return [
     }',
     'all_podcast_episodes' => 'Tous les épisodes du podcast',
     'back_to_podcast' => 'Revenir au podcast',
-    'edit' => 'Modifier',
-    'publish' => 'Publier',
-    'publish_edit' => 'Modifier la publication',
-    'unpublish' => 'Dépublier',
-    'publish_error' => 'L’épisode est déjà publié.',
-    'publish_edit_error' => 'L’épisode est déjà publié.',
-    'publish_cancel_error' => 'L’épisode est déjà publié.',
-    'unpublish_error' => 'L’épisode n’est pas publié.',
-    'delete' => 'Supprimer',
-    'go_to_page' => 'Voir',
-    'create' => 'Ajouter un épisode',
-    'publication_status' => [
-        'published' => 'Publié',
-        'scheduled' => 'Planifié',
-        'not_published' => 'Non publié',
-    ],
-    'list' => [
-        'episode' => 'Épisode',
-        'visibility' => 'Visibilité',
-        'comments' => 'Commentaires',
-        'actions' => 'Actions',
-    ],
-    'form' => [
-        'warning' =>
-            'En cas d’erreur fatale, essayez d’augmenter les valeurs de `memory_limit`, `upload_max_filesize` et `post_max_size` dans votre fichier de configuration php puis redémarrez votre serveur web.<br />Les valeurs doivent être plus grandes que le fichier audio que vous souhaitez téléverser.',
-        'audio_file' => 'Fichier audio',
-        'audio_file_hint' => 'Sélectionnez un fichier audio .mp3 ou .m4a.',
-        'info_section_title' => 'Informations épisode',
-        'info_section_subtitle' => '',
-        'image' => 'Image de couverture',
-        'image_hint' =>
-            'Si vous ne définissez pas d’image, celle du podcast sera utilisée à la place.',
-        'title' => 'Titre',
-        'title_hint' =>
-            'Doit contenir un titre d’épisode clair et concis. Ne précisez ici aucun numéro de saison ou d’épisode.',
-        'permalink' => 'Lien permanent',
-        'season_number' => 'Saison',
-        'episode_number' => 'Épisode',
-        'type' => [
-            'label' => 'Type',
-            'hint' =>
-                '- <strong>complet</strong>: épisode complet.<br/>- <strong>bande-annonce</strong>: extrait court, promotionnel du podcast.<br/>- <strong>bonus</strong> :  contenu supplémentaire pour le podcast (par exemple des informations sur les coulisses ou des interviews avec les acteurs) ou du contenu promotionnel croisé pour un autre podcast.',
-            'full' => 'Complet',
-            'trailer' => 'Bande-annonce',
-            'bonus' => 'Bonus',
-        ],
-        'parental_advisory' => [
-            'label' => 'Avertissement parental',
-            'hint' => 'L’épisode contient-il un contenu explicite ?',
-            'undefined' => 'non défini',
-            'clean' => 'Convenable',
-            'explicit' => 'Explicite',
-        ],
-        'show_notes_section_title' => 'Notes d’épisode (Show Notes)',
-        'show_notes_section_subtitle' =>
-            'Jusque 4000 caractères, soyez clairs et concis. Les notes d’épisode aident les auditeurs potentiels à le trouver.',
-        'description' => 'Description',
-        'description_footer' => 'Pied de description',
-        'description_footer_hint' =>
-            'Ce texte est ajouté à la fin de chaque description d’épisode, c’est un bon endroit pour placer vos liens sociaux par exemple.',
-        'additional_files_section_title' => 'Fichiers additionels',
-        'additional_files_section_subtitle' =>
-            'Ces fichiers pourront être utilisées par d’autres plate-formes pour procurer une meilleure expérience à vos auditeurs.<br />Consulter le {podcastNamespaceLink} pour plus d’informations.',
-        'location_section_title' => 'Localisation',
-        'location_section_subtitle' => 'De quel lieu cet épisode parle-t-il ?',
-        'location_name' => 'Nom ou adresse du lieu',
-        'location_name_hint' => 'Ce lieu peut être réel ou fictif',
-        'transcript' => 'Transcription ou sous-titrage',
-        'transcript_hint' =>
-            'Les formats autorisés sont txt, html, srt ou json.',
-        'transcript_file' => 'Fichier de transcription',
-        'transcript_file_remote_url' =>
-            'URL distante pour le fichier de transcription',
-        'transcript_file_delete' => 'Supprimer le fichier de transcription',
-        'chapters' => 'Chapitrage',
-        'chapters_hint' => 'Le fichier doit être en format “JSON Chapters”.',
-        'chapters_file' => 'Fichier de chapitrage',
-        'chapters_file_remote_url' =>
-            'URL distante pour le fichier de chapitrage',
-        'chapters_file_delete' => 'Supprimer le fichier de chapitrage',
-        'advanced_section_title' => 'Paramètres avancés',
-        'advanced_section_subtitle' =>
-            'Si vous avez besoin d’une balise que Castopod ne couvre pas, définissez-la ici.',
-        'custom_rss' => 'Balises RSS personnalisées pour l’épisode',
-        'custom_rss_hint' => 'Ceci sera injecté dans la balise ❬item❭.',
-        'block' => 'L’épisode doit être masqué de toutes les plateformes',
-        'block_hint' =>
-            'La visibilité de l’épisode. Si vous souhaitez retirer cet épisode de l’index Apple, activez ce champ.',
-        'submit_create' => 'Créer l’épisode',
-        'submit_edit' => 'Enregistrer l’épisode',
-    ],
-    'publish_form' => [
-        'back_to_episode_dashboard' => 'Retour au tableau de bord de l’épisode',
-        'post' => 'Votre message de publication',
-        'post_hint' =>
-            'Écrivez un message pour annoncer la publication de votre épisode. Le message sera diffusé à toutes les personnes qui vous suivent dans le fédiverse et mis en évidence sur la page d’accueil de votre podcast.',
-        'publication_date' => 'Date de publication',
-        'publication_date_clear' => 'Effacer la date de publication',
-        'publication_date_hint' =>
-            'Vous pouvez planifier la sortie de l’épisode en saisissant une date de publication future. Ce champ doit être au format YYYY-MM-DD HH:mm',
-        'publication_method' => [
-            'now' => 'Maintenant',
-            'schedule' => 'Planifier',
-        ],
-        'scheduled_publication_date' => 'Date de publication programmée',
-        'scheduled_publication_date_clear' => 'Effacer la date de publication',
-        'scheduled_publication_date_hint' =>
-            'Vous pouvez planifier la sortie de l’épisode en saisissant une date de publication future. Ce champ doit être au format YYYY-MM-DD HH:mm',
-        'submit' => 'Publier',
-        'submit_edit' => 'Modifier la publication',
-        'cancel_publication' => 'Annuler la publication',
-        'message_warning' => 'Vous n’avez pas saisi de message pour l’annonce de votre épisode !',
-        'message_warning_hint' => 'Ajouter un message augmente l’engagement social, menant à une meilleure visibilité pour votre épisode.',
-        'message_warning_submit' => 'Publish quand même',
-    ],
-    'soundbites' => 'Extraits sonores',
-    'soundbites_form' => [
-        'title' => 'Modifier les extraits sonores',
-        'info_section_title' => 'Extraits sonores de l’épisode',
-        'info_section_subtitle' =>
-            'Ajouter, modifier ou supprimer des extraits sonores',
-        'start_time' => 'Début',
-        'start_time_hint' =>
-            'La première seconde de l’extrait sonore, cela peut être un nombre décimal.',
-        'duration' => 'Durée',
-        'duration_hint' =>
-            'La durée de l’extrait sonore (en secondes), cela peut être un nombre décimal.',
-        'label' => 'Libellé',
-        'label_hint' => 'Texte qui sera affiché.',
-        'play' => 'Écouter l’extrait sonore',
-        'delete' => 'Supprimer l’extrait sonore',
-        'bookmark' =>
-            'Cliquez pour récupérer la position actuelle, cliquez à nouveau pour récupérer la durée.',
-        'submit_edit' => 'Enregistrer tous les extraits sonores',
-    ],
-    'embeddable_player' => [
-        'add' => 'Ajouter un lecteur intégré',
-        'title' => 'Lecteur intégré',
-        'label' =>
-            'Sélectionnez une couleur de thème, copiez le code dans le presse-papier, puis collez-le sur votre site internet.',
-        'clipboard_iframe' => 'Copier le lecteur dans le presse papier',
-        'clipboard_url' => 'Copier l’adresse dans le presse papier',
-        'dark' => 'Sombre',
-        'dark-transparent' => 'Sombre transparent',
-        'light' => 'Clair',
-        'light-transparent' => 'Clair transparent',
-    ],
 ];
diff --git a/app/Language/fr/MyAccount.php b/app/Language/fr/MyAccount.php
deleted file mode 100644
index 837b04f460..0000000000
--- a/app/Language/fr/MyAccount.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'info' => 'Informations de mon compte',
-    'changePassword' => 'Modifier mon mot de passe',
-    'messages' => [
-        'wrongPasswordError' =>
-            'Le mot de passe que vous avez saisi est invalide.',
-        'passwordChangeSuccess' =>
-            'Le mot de passe a été modifié avec succès !',
-    ],
-];
diff --git a/app/Language/fr/Pager.php b/app/Language/fr/Pager.php
deleted file mode 100644
index 4dcbffa71a..0000000000
--- a/app/Language/fr/Pager.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'pageNavigation' => 'Navigation',
-    'first' => 'Première',
-    'previous' => 'Précédent',
-    'next' => 'Suivant',
-    'last' => 'Dernière',
-    'older' => 'Plus ancien',
-    'newer' => 'Plus récent',
-    'invalidTemplate' => '{0} n’est pas un modèle valide.',
-    'invalidPaginationGroup' => '{0} n’est pas un groupe valide.',
-];
diff --git a/app/Language/fr/Person.php b/app/Language/fr/Person.php
deleted file mode 100644
index ad2aeda23c..0000000000
--- a/app/Language/fr/Person.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'persons' => 'Intervenants',
-    'all_persons' => 'Tous les intervenants',
-    'no_person' => 'Aucun intervenant trouvé !',
-    'create' => 'Créer un intervenant',
-    'view' => 'Voir l’intervenant',
-    'edit' => 'Modifier l’intervenant',
-    'delete' => 'Supprimer l’intervenant',
-    'form' => [
-        'identity_section_title' => 'Identité',
-        'identity_section_subtitle' => 'Qui intervient sur le podcast',
-        'image' => 'Photo',
-        'image_size_hint' =>
-            'L’image doit être carrée et avoir au moins 400px de largeur et de hauteur.',
-        'full_name' => 'Nom complet',
-        'full_name_hint' => 'Le nom complet ou le pseudonyme de l’intervenant',
-        'unique_name' => 'Nom unique',
-        'unique_name_hint' => 'Utilisé pour les URLs',
-        'information_url' => 'Adresse d’information',
-        'information_url_hint' =>
-            'URL pointant vers des informations relatives à l’intervenant, telle qu’une page personnelle ou une page de profil sur une plateforme tierce.',
-        'submit_create' => 'Créer l’intervenant',
-        'submit_edit' => 'Enregistrer l’intervenant',
-    ],
-    'podcast_form' => [
-        'title' => 'Gérer les intervenants',
-        'manage_section_title' => 'Gestion',
-        'manage_section_subtitle' => 'Retirer des intervenants de ce podcast',
-        'add_section_title' => 'Ajouter des intervenants à ce podcast',
-        'add_section_subtitle' =>
-            'Vous pouvez sélectionner plusieurs intervenants et rôles.',
-        'person' => 'Intervenants',
-        'person_hint' =>
-            'Vous pouvez selectionner un ou plusieurs intervenants ayant les mêmes rôles. Les intervenants doivent avoir été préalablement créés.',
-        'group_role' => 'Groupes et rôles',
-        'group_role_hint' =>
-            'Vous pouvez sélectionner aucun, un ou plusieurs groupes et rôles par intervenant.',
-        'submit_add' => 'Ajouter un/des intervenant(s)',
-        'remove' => 'Retirer',
-    ],
-    'episode_form' => [
-        'title' => 'Gérer les intervenants',
-        'manage_section_title' => 'Gestion',
-        'manage_section_subtitle' => 'Retirer des intervenants de cet épisode',
-        'add_section_title' => 'Ajouter des intervenants à cet épisode',
-        'add_section_subtitle' =>
-            'Vous pouvez sélectionner plusieurs intervenants et rôles.',
-        'person' => 'Intervenants',
-        'person_hint' =>
-            'Vous pouvez selectionner un ou plusieurs intervenants ayant les mêmes rôles. Les intervenants doivent avoir été préalablement créés.',
-        'group_role' => 'Groupes et rôles',
-        'group_role_hint' =>
-            'Vous pouvez sélectionner aucun, un ou plusieurs groupes et rôles par intervenant.',
-        'submit_add' => 'Ajouter un/des intervenant(s)',
-        'remove' => 'Retirer',
-    ],
-    'credits' => 'Crédits',
-];
diff --git a/app/Language/fr/Platforms.php b/app/Language/fr/Platforms.php
deleted file mode 100644
index 1a5a59c4d4..0000000000
--- a/app/Language/fr/Platforms.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'title' => 'Plateformes',
-    'home_url' => 'Aller au site {platformName}',
-    'submit_url' => 'Soumettez votre podcast sur {platformName}',
-    'visible' => 'Afficher sur la page d’accueil du podcast ?',
-    'on_embeddable_player' => 'Afficher sur le lecteur intégré ?',
-    'remove' => 'Supprimer {platformName}',
-    'submit' => 'Enregistrer',
-    'messages' => [
-        'updateSuccess' => 'Les liens ont été enregistrés avec succès !',
-        'removeLinkSuccess' => 'Le lien a été supprimé.',
-        'removeLinkError' =>
-            'Le lien n’a pas pu être supprimé. Merci d’essayer à nouveau.',
-    ],
-    'description' => [
-        'podcasting' => 'L’identifiant du podcast sur cette plate-forme',
-        'social' => 'L’identifiant du compte du podcast sur cette plate-forme',
-        'funding' => 'Message d’incitation à l’action',
-    ],
-];
diff --git a/app/Language/fr/Podcast.php b/app/Language/fr/Podcast.php
index 1ef22cd776..12e9bba317 100644
--- a/app/Language/fr/Podcast.php
+++ b/app/Language/fr/Podcast.php
@@ -23,195 +23,6 @@ return [
     'go_to_page' => 'Aller à la page',
     'latest_episodes' => 'Derniers épisodes',
     'see_all_episodes' => 'Voir tous les épisodes',
-    'form' => [
-        'identity_section_title' => 'Informations sur le Podcast',
-        'identity_section_subtitle' =>
-            'Ces champs vous permettent de vous faire remarquer.',
-        'image' => 'Image de couverture',
-        'title' => 'Titre',
-        'handle' => 'Identifiant',
-        'handle_hint' =>
-            'Utilisé pour identifier le podcast. Les majuscules, les minuscules, les chiffres et le caractère souligné « _ » sont acceptés.',
-        'type' => [
-            'label' => 'Type',
-            'hint' =>
-                '- <strong>épisodique</strong> : si les épisodes sont destinés à être consommés sans ordre spécifique. Les épisodes les plus récents seront présentés en premier.<br/>- <strong>série</strong>: si les épisodes sont destinés à être consommés dans un ordre séquentiel bien défini. Les épisodes les plus anciens seront présentés en premier.',
-            'episodic' => 'Épisodique',
-            'serial' => 'Série',
-        ],
-        'description' => 'Description',
-        'classification_section_title' => 'Classification',
-        'classification_section_subtitle' =>
-            'Ces champs auront un impact sur votre audience et votre concurrence.',
-        'language' => 'Langue',
-        'category' => 'Catégorie',
-        'category_placeholder' => 'Sélectionner une catégorie…',
-        'other_categories' => 'Autres catégories',
-        'parental_advisory' => [
-            'label' => 'Avertissement parental',
-            'hint' => 'Contient-il un contenu explicite ?',
-            'undefined' => 'non défini',
-            'clean' => 'Convenable',
-            'explicit' => 'Explicite',
-        ],
-        'author_section_title' => 'Auteur / Autrice',
-        'author_section_subtitle' => 'Qui gère le podcast ?',
-        'owner_name' => 'Nom du/de la propriétaire',
-        'owner_name_hint' =>
-            'Pour usage administratif uniquement. Visible dans le flux RSS public.',
-        'owner_email' => 'E-mail du/de la propriétaire',
-        'owner_email_hint' =>
-            'Utilisé par la plupart des plateformes pour vérifier la propriété du podcast. Visible dans le flux RSS public.',
-        'publisher' => 'Éditeur / Éditrice',
-        'publisher_hint' =>
-            'Le groupe responsable de la création du podcast. Fait souvent référence à la société mère ou au réseau d’un podcast. Ce champ est parfois appelé « Auteur ».',
-        'copyright' => 'Droit d’auteur',
-        'location_section_title' => 'Localisation',
-        'location_section_subtitle' => 'De quel lieu ce podcast parle-t-il ?',
-        'location_name' => 'Nom ou adresse du lieu',
-        'location_name_hint' => 'Ce lieu peut être réel ou fictif',
-        'monetization_section_title' => 'Monétisation',
-        'monetization_section_subtitle' =>
-            'Gagnez de l’argent grâce à votre audience.',
-        'payment_pointer' =>
-            'Adresse de paiement (Payment Pointer) pour Web Monetization',
-        'payment_pointer_hint' =>
-            'L’adresse où vous recevrez de l’argent grâce à Web Monetization',
-        'advanced_section_title' => 'Paramètres avancés',
-        'advanced_section_subtitle' =>
-            'Si vous avez besoin d’une balise que nous n’avons pas couverte, définissez-la ici.',
-        'custom_rss' => 'Balises RSS personnalisées pour le podcast',
-        'custom_rss_hint' => 'Ceci sera injecté dans la balise ❬channel❭.',
-        'partnership' => 'Partenariat',
-        'partner_id' => 'ID',
-        'partner_link_url' => 'URL lien',
-        'partner_image_url' => 'URL image',
-        'partner_id_hint' => 'Votre identifiant personnel partenaire',
-        'partner_link_url_hint' => 'L’adresse générique des liens partenaire',
-        'partner_image_url_hint' => 'L’adresse générique des images partenaire',
-        'status_section_title' => 'Statut',
-        'status_section_subtitle' => 'Vivant ou mort ?',
-        'block' => 'Le podcast doit être masqué sur toutes les plateformes',
-        'complete' => 'Le podcast n’aura plus de nouveaux épisodes.',
-        'lock' => 'Empêcher la copie du podcast',
-        'lock_hint' =>
-            'Le but est d’indiquer aux autres plates-formes de podcast si elles sont autorisées à importer ce flux. La valeur « oui » signifie que toute tentative d’importation de ce flux dans une nouvelle plateforme doit être rejetée.',
-        'submit_create' => 'Créer le podcast',
-        'submit_edit' => 'Enregistrer le podcast',
-    ],
-    'category_options' => [
-        'uncategorized' => 'non catégorisé',
-        'arts' => 'Arts',
-        'business' => 'Entreprise',
-        'comedy' => 'Comédie',
-        'education' => 'Éducation',
-        'fiction' => 'Fiction',
-        'government' => 'Gouvernement',
-        'health_and_fitness' => 'Santé et remise en forme',
-        'history' => 'Histoire',
-        'kids_and_family' => 'Enfants et famille',
-        'Leisure' => 'Loisirs',
-        'music' => 'Musique',
-        'news' => 'Actualités',
-        'religion_and_spirituality' => 'Religion et spiritualité',
-        'science' => 'Science',
-        'society_and_culture' => 'Société et Culture',
-        'sports' => 'Sports',
-        'technology' => 'Technologie',
-        'true_crime' => 'Documentaire criminel',
-        'tv_and_film' => 'Télévision et films',
-        'books' => 'Livres',
-        'design' => 'Design',
-        'fashion_and_beauty' => 'Mode et beauté',
-        'food' => 'Nourriture',
-        'performing_arts' => 'Arts du spectacle',
-        'visual_arts' => 'Arts visuels',
-        'careers' => 'Carrières',
-        'entrepreneurship' => 'Entrepreneuriat',
-        'investment' => 'Investissement',
-        'management' => 'Gestion',
-        'marketing' => 'Marketing',
-        'non_profit' => 'À but non lucratif',
-        'comedy_interviews' => 'Entretiens comiques',
-        'improv' => 'Improvisation',
-        'stand_up' => 'Stand up',
-        'courses' => 'Cours',
-        'how_to' => 'Tutoriels',
-        'language_learning' => 'Apprentissage des langues',
-        'self_improvement' => 'Développement personnel',
-        'comedy_fiction' => 'Comédie Fiction',
-        'drama' => 'Drame',
-        'science_fiction' => 'Science Fiction',
-        'alternative_health' => 'Santé alternative',
-        'fitness' => 'Remise en forme',
-        'medicine' => 'Médecine',
-        'mental_health' => 'Santé mentale',
-        'nutrition' => 'Nutrition',
-        'sexuality' => 'Sexualité',
-        'education_for_kids' => 'Éducation pour les enfants',
-        'parenting' => 'Parentalité',
-        'pets_and_animals' => 'Animaux de compagnie et animaux',
-        'stories_for_kids' => 'Histoires pour enfants',
-        'animation_and_manga' => 'Animation et Manga',
-        'Automotive' => 'Automobile',
-        'aviation' => 'Aviation',
-        'craft' => 'Artisanat',
-        'games' => 'Jeux',
-        'hobbies' => 'Loisirs',
-        'home_and_garden' => 'Maison et jardin',
-        'video_games' => 'Jeux vidéo',
-        'music_commentary' => 'Commentaire musical',
-        'music_history' => 'Histoire de la musique',
-        'music_interviews' => 'Entretiens musicaux',
-        'business_news' => 'Actualités économiques',
-        'daily_news' => 'Actualités quotidiennes',
-        'entertainment_news' => 'Actualités du divertissement',
-        'news_commentary' => 'Commentaire d’actualité',
-        'politique' => 'Politique',
-        'sports_news' => 'Actualités sportives',
-        'tech_news' => 'Actualités techniques',
-        'buddhism' => 'Bouddhisme',
-        'christianity' => 'Christianisme',
-        'hinduism' => 'Hindouisme',
-        'islam' => 'Islam',
-        'judaism' => 'Judaïsme',
-        'religion' => 'Religion',
-        'spiritualité' => 'Spiritualité',
-        'astronomy' => 'Astronomie',
-        'chemistry' => 'Chimie',
-        'earth_sciences' => 'Sciences de la Terre',
-        'life_sciences' => 'Sciences de la vie',
-        'Mathématiques' => 'Mathématiques',
-        'natural_sciences' => 'Sciences naturelles',
-        'nature' => 'Nature',
-        'physics' => 'Physique',
-        'social_sciences' => 'Sciences sociales',
-        'documentary' => 'Documentaire',
-        'personal_journals' => 'Journaux personnels',
-        'philosophie' => 'Philosophie',
-        'places_and_travel' => 'Lieux et voyages',
-        'relations' => 'Relations',
-        'baseball' => 'Baseball',
-        'basketball' => 'Basketball',
-        'cricket' => 'Cricket',
-        'fantasy_sports' => 'Sports fantastiques',
-        'football' => 'Football',
-        'golf' => 'Golf',
-        'hockey' => 'Hockey',
-        'rugby' => 'Rugby',
-        'running' => 'Course',
-        'soccer' => 'Football',
-        'swimming' => 'Natation',
-        'tennis' => 'Tennis',
-        'volleyball' => 'Volleyball',
-        'wilderness' => 'Naturalité',
-        'wrestling' => 'Lutte',
-        'after_shows' => 'Après spectacle',
-        'film_history' => 'Histoire du cinéma',
-        'film_interviews' => 'Entretiens de films',
-        'film_reviews' => 'Critiques de films',
-        'tv_reviews' => 'Critiques TV',
-    ],
     'by' => 'Par {publisher}',
     'season' => 'Saison {seasonNumber}',
     'list_of_episodes_year' => 'Épisodes de {year} ({episodeCount})',
diff --git a/app/Language/fr/PodcastImport.php b/app/Language/fr/PodcastImport.php
deleted file mode 100644
index 94b3167df4..0000000000
--- a/app/Language/fr/PodcastImport.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'warning' =>
-        'Cette procédure peut prendre du temps.<br/>Dans la mesure où la version actuelle ne montre aucune progression durant l’exécution, vous ne pourrez voir aucun changement avant la fin.<br/>En cas d’erreur de timeout,  augmentez la valeur de `max_execution_time`.',
-    'old_podcast_section_title' => 'Le podcast à importer',
-    'old_podcast_section_subtitle' =>
-        'Assurez-vous d’être détenteur des droits du podcast avant de l’importer. Copier et diffuser un podcast sans en détenir les droits est assimilable à de la contrefaçon et est passible de poursuites.',
-    'imported_feed_url' => 'Adresse du flux',
-    'imported_feed_url_hint' => 'Le flux doit être au format xml ou rss.',
-    'new_podcast_section_title' => 'Le nouveau podcast',
-    'advanced_params_section_title' => 'Paramètres avancés',
-    'advanced_params_section_subtitle' =>
-        'Si vous ne savez pas à quoi servent ces champs, conservez les valeurs par défaut.',
-    'slug_field' => [
-        'label' =>
-            'Quel champ utiliser pour calculer l’identifiant de l’épisode',
-        'link' => '&lt;link&gt; (adresse)',
-        'title' => '&lt;title&gt; (titre)',
-    ],
-    'description_field' => 'Champs pour la description des épisodes',
-    'force_renumber' => 'Forcer la re-numérotation des épisodes',
-    'force_renumber_hint' =>
-        'Utilisez ceci si le podcast à importer ne contient pas de numéros d’épisodes mais que vous souhaitez en ajouter pendant l’import.',
-    'season_number' => 'Numéro de saison',
-    'season_number_hint' =>
-        'Utilisez ceci si le podcast à importer ne contient pas de numéros de saison mais que vous souhaitez en définir un. Laissez vide sinon.',
-    'max_episodes' => 'Nombre maximum d’épisodes à importer',
-    'max_episodes_hint' => 'Laissez vide pour importer tous les épisodes',
-    'lock_import' =>
-        'Ce flux est protégé. Vous ne pouvez pas l’importer. Si en vous êtes le propriétaire, déprotégez-le sur la plate-forme d’origine.',
-    'submit' => 'Importer le podcast',
-];
diff --git a/app/Language/fr/PodcastNavigation.php b/app/Language/fr/PodcastNavigation.php
deleted file mode 100644
index 6939725432..0000000000
--- a/app/Language/fr/PodcastNavigation.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'go_to_page' => 'Aller à la page du podcast',
-    'dashboard' => 'Tableau de bord du podcast',
-    'podcast-view' => 'Accueil',
-    'podcast-edit' => 'Modifier le podcast',
-    'episodes' => 'Épisodes',
-    'episode-list' => 'Tous les épisodes',
-    'episode-create' => 'Créer un épisode',
-    'fediverse' => 'Fédiverse',
-    'fediverse-block_lists' => 'Listes de blocage',
-    'analytics' => 'Mesures d’audience',
-    'persons' => 'Intervenants',
-    'podcast-person-manage' => 'Gestion des intervenants',
-    'contributors' => 'Contributeurs',
-    'contributor-list' => 'Tous les contributeurs',
-    'contributor-add' => 'Ajouter un contributeur',
-    'platforms' => 'Plate-formes externes',
-    'platforms-podcasting' => 'Podcasts',
-    'platforms-social' => 'Réseaux Sociaux',
-    'platforms-funding' => 'Financement',
-    'podcast-analytics' => 'Vue d’ensemble',
-    'podcast-analytics-webpages' => 'Visites des pages web',
-    'podcast-analytics-locations' => 'Localisations',
-    'podcast-analytics-unique-listeners' => 'Auditeurs uniques',
-    'podcast-analytics-players' => 'Lecteurs',
-    'podcast-analytics-listening-time' => 'Durée d’écoute',
-    'podcast-analytics-time-periods' => 'Périodes',
-];
diff --git a/app/Language/fr/User.php b/app/Language/fr/User.php
deleted file mode 100644
index ccb262b158..0000000000
--- a/app/Language/fr/User.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'edit_roles' => 'Modifier les rôles de {username}',
-    'forcePassReset' => 'Forcer la réinitialisation du mot de passe',
-    'ban' => 'Bloquer',
-    'unban' => 'Débloquer',
-    'delete' => 'Supprimer',
-    'create' => 'Créer un utilisateur',
-    'view' => 'Informations de {username}',
-    'all_users' => 'Tous les utilisateurs',
-    'list' => [
-        'user' => 'Utilisateurs',
-        'roles' => 'Rôles',
-        'banned' => 'Bloqué ?',
-    ],
-    'form' => [
-        'email' => 'E-mail',
-        'username' => 'Identifiant',
-        'password' => 'Mot de passe',
-        'new_password' => 'Nouveau mot de passe',
-        'roles' => 'Rôles',
-        'permissions' => 'Permissions',
-        'submit_create' => 'Créer un utilisateur',
-        'submit_edit' => 'Enregistrer',
-        'submit_password_change' => 'Valider !',
-    ],
-    'roles' => [
-        'superadmin' => 'Super-utilisateur',
-    ],
-    'messages' => [
-        'createSuccess' =>
-            'Utilisateur créé avec succès ! {username} devra modifier son mot de passe à la première authentification.',
-        'rolesEditSuccess' =>
-            'Les rôles de {username} ont été mis à jour avec succès.',
-        'forcePassResetSuccess' =>
-            '{username} devra modifier son mot de passe à la prochaine visite.',
-        'banSuccess' => '{username} a été bloqué.',
-        'unbanSuccess' => '{username} a été débloqué.',
-        'banSuperAdminError' =>
-            '{username} est un super-utilisateur, on ne bloque pas un super-utilisateur comme ça…',
-        'deleteSuperAdminError' =>
-            '{username} est un super-utilisateur, on ne supprime pas un super-utilisateur comme ça…',
-        'deleteSuccess' => '{username} a été supprimé.',
-    ],
-];
diff --git a/app/Language/fr/Validation.php b/app/Language/fr/Validation.php
deleted file mode 100644
index 12b45319f9..0000000000
--- a/app/Language/fr/Validation.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-return [
-    'min_dims' =>
-        '{field} n’est pas une image ou n’a pas la taille minimale requise.',
-    'is_image_squared' =>
-        '{field} n’est pas une image ou n’est pas carré (largeur et hauteur différentes).',
-    'validate_url' =>
-        'Le champs {field} doit être une adresse valide (par exemple https://exemple.com/).',
-];
diff --git a/app/Libraries/ViewComponents/Component.php b/app/Libraries/ViewComponents/Component.php
index 81d08f1eb1..779d12c298 100644
--- a/app/Libraries/ViewComponents/Component.php
+++ b/app/Libraries/ViewComponents/Component.php
@@ -8,6 +8,8 @@ class Component implements ComponentInterface
 {
     protected string $slot = '';
 
+    protected string $class = '';
+
     /**
      * @var array<string, string>
      */
diff --git a/app/Resources/js/modules/Charts.ts b/app/Resources/js/modules/Charts.ts
index 886fa62008..bac6f232d2 100644
--- a/app/Resources/js/modules/Charts.ts
+++ b/app/Resources/js/modules/Charts.ts
@@ -5,9 +5,12 @@ import * as am4maps from "@amcharts/amcharts4/maps";
 import * as am4plugins_sliceGrouper from "@amcharts/amcharts4/plugins/sliceGrouper";
 import am4themes_material from "@amcharts/amcharts4/themes/material";
 
-const drawPieChart = (chartDivId: string, dataUrl: string | null): void => {
+const drawPieChart = (
+  chartDiv: HTMLDivElement,
+  dataUrl: string | null
+): void => {
   // Create chart instance
-  const chart = am4core.create(chartDivId, am4charts.PieChart);
+  const chart = am4core.create(chartDiv, am4charts.PieChart);
   am4core.percent(100);
   chart.exporting.menu = new am4core.ExportMenu();
   chart.exporting.menu.align = "left";
@@ -43,9 +46,12 @@ const drawPieChart = (chartDivId: string, dataUrl: string | null): void => {
   chart.legend.scrollable = true;
 };
 
-const drawXYChart = (chartDivId: string, dataUrl: string | null): void => {
+const drawXYChart = (
+  chartDiv: HTMLDivElement,
+  dataUrl: string | null
+): void => {
   // Create chart instance
-  const chart = am4core.create(chartDivId, am4charts.XYChart);
+  const chart = am4core.create(chartDiv, am4charts.XYChart);
   am4core.percent(100);
   chart.exporting.menu = new am4core.ExportMenu();
   chart.exporting.menu.align = "right";
@@ -88,9 +94,12 @@ const drawXYChart = (chartDivId: string, dataUrl: string | null): void => {
   chart.scrollbarX = new am4core.Scrollbar();
 };
 
-const drawBarChart = (chartDivId: string, dataUrl: string | null): void => {
+const drawBarChart = (
+  chartDiv: HTMLDivElement,
+  dataUrl: string | null
+): void => {
   // Create chart instance
-  const chart = am4core.create(chartDivId, am4charts.XYChart);
+  const chart = am4core.create(chartDiv, am4charts.XYChart);
   am4core.percent(100);
   chart.exporting.menu = new am4core.ExportMenu();
   chart.exporting.menu.align = "right";
@@ -121,11 +130,11 @@ const drawBarChart = (chartDivId: string, dataUrl: string | null): void => {
 };
 
 const drawXYDurationChart = (
-  chartDivId: string,
+  chartDiv: HTMLDivElement,
   dataUrl: string | null
 ): void => {
   // Create chart instance
-  const chart = am4core.create(chartDivId, am4charts.XYChart);
+  const chart = am4core.create(chartDiv, am4charts.XYChart);
   am4core.percent(100);
   chart.exporting.menu = new am4core.ExportMenu();
   chart.exporting.menu.align = "right";
@@ -171,9 +180,12 @@ const drawXYDurationChart = (
   chart.scrollbarX = new am4core.Scrollbar();
 };
 
-const drawMapChart = (chartDivId: string, dataUrl: string | null): void => {
+const drawMapChart = (
+  chartDiv: HTMLDivElement,
+  dataUrl: string | null
+): void => {
   // Create map instance
-  const chart = am4core.create(chartDivId, am4maps.MapChart);
+  const chart = am4core.create(chartDiv, am4maps.MapChart);
   am4core.percent(100);
   chart.exporting.menu = new am4core.ExportMenu();
   chart.exporting.menu.align = "left";
@@ -238,22 +250,19 @@ const DrawCharts = (): void => {
 
     switch (chartType) {
       case "pie-chart":
-        drawPieChart(chartDiv.id, chartDiv.getAttribute("data-chart-url"));
+        drawPieChart(chartDiv, chartDiv.getAttribute("data-chart-url"));
         break;
       case "xy-chart":
-        drawXYChart(chartDiv.id, chartDiv.getAttribute("data-chart-url"));
+        drawXYChart(chartDiv, chartDiv.getAttribute("data-chart-url"));
         break;
       case "bar-chart":
-        drawBarChart(chartDiv.id, chartDiv.getAttribute("data-chart-url"));
+        drawBarChart(chartDiv, chartDiv.getAttribute("data-chart-url"));
         break;
       case "xy-duration-chart":
-        drawXYDurationChart(
-          chartDiv.id,
-          chartDiv.getAttribute("data-chart-url")
-        );
+        drawXYDurationChart(chartDiv, chartDiv.getAttribute("data-chart-url"));
         break;
       case "map-chart":
-        drawMapChart(chartDiv.id, chartDiv.getAttribute("data-chart-url"));
+        drawMapChart(chartDiv, chartDiv.getAttribute("data-chart-url"));
         break;
       default:
         console.error("Unknown chart type:" + chartType);
diff --git a/app/Resources/styles/choices.css b/app/Resources/styles/choices.css
index cb815ff89a..073342617d 100644
--- a/app/Resources/styles/choices.css
+++ b/app/Resources/styles/choices.css
@@ -207,7 +207,7 @@
   }
 
   .choices__list--multiple .choices__item.is-highlighted {
-    @apply bg-pine-700;
+    @apply bg-pine-500;
   }
 
   .is-disabled .choices__list--multiple .choices__item {
diff --git a/app/Resources/styles/formInputTabs.css b/app/Resources/styles/formInputTabs.css
index 011d39a96e..38d323df14 100644
--- a/app/Resources/styles/formInputTabs.css
+++ b/app/Resources/styles/formInputTabs.css
@@ -25,7 +25,7 @@
   }
 
   .form-input-tabs > input:checked + label::after {
-    @apply absolute inset-x-0 bottom-0 w-full mx-auto bg-pine-700;
+    @apply absolute inset-x-0 bottom-0 w-full mx-auto bg-pine-500;
     content: "";
     height: 0.2rem;
   }
diff --git a/app/Resources/styles/tabs.css b/app/Resources/styles/tabs.css
index 6fb8e78144..4389ead476 100644
--- a/app/Resources/styles/tabs.css
+++ b/app/Resources/styles/tabs.css
@@ -24,7 +24,7 @@
   }
 
   .tabset > input:checked + label::after {
-    @apply absolute inset-x-0 bottom-0 w-1/3 h-1 mx-auto bg-pine-700;
+    @apply absolute inset-x-0 bottom-0 w-1/3 h-1 mx-auto bg-pine-500;
     content: "";
   }
 
diff --git a/app/Views/Components/Charts/Bar.php b/app/Views/Components/Charts/Bar.php
new file mode 100644
index 0000000000..d5fbc5684c
--- /dev/null
+++ b/app/Views/Components/Charts/Bar.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Components\Charts;
+
+class Bar extends ChartsComponent
+{
+    protected string $type = 'bar-chart';
+}
diff --git a/app/Views/Components/Charts/ChartsComponent.php b/app/Views/Components/Charts/ChartsComponent.php
new file mode 100644
index 0000000000..c5bf4b891c
--- /dev/null
+++ b/app/Views/Components/Charts/ChartsComponent.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Components\Charts;
+
+use ViewComponents\Component;
+
+class ChartsComponent extends Component
+{
+    protected string $title = '';
+
+    protected string $dataUrl = '';
+
+    protected string $type = '';
+
+    public function render(): string
+    {
+        return <<<HTML
+            <div class="bg-white border rounded-xl border-pine-100 {$this->class}">
+                <h2 class="px-6 py-4 text-xl">{$this->title}</h2>
+                <div class="w-full h-[500px]" data-chart-type="{$this->type}" data-chart-url="{$this->dataUrl}"></div>
+            </div>
+        HTML;
+    }
+}
diff --git a/app/Views/Components/Charts/Map.php b/app/Views/Components/Charts/Map.php
new file mode 100644
index 0000000000..d010ee616b
--- /dev/null
+++ b/app/Views/Components/Charts/Map.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Components\Charts;
+
+class Map extends ChartsComponent
+{
+    protected string $type = 'map-chart';
+}
diff --git a/app/Views/Components/Charts/Pie.php b/app/Views/Components/Charts/Pie.php
new file mode 100644
index 0000000000..2ecc43aa62
--- /dev/null
+++ b/app/Views/Components/Charts/Pie.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Components\Charts;
+
+class Pie extends ChartsComponent
+{
+    protected string $type = 'pie-chart';
+}
diff --git a/app/Views/Components/Charts/XY.php b/app/Views/Components/Charts/XY.php
new file mode 100644
index 0000000000..ef0e5bead3
--- /dev/null
+++ b/app/Views/Components/Charts/XY.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Views\Components\Charts;
+
+class XY extends ChartsComponent
+{
+    protected string $type = 'xy-chart';
+}
diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php
index e26342668e..e036b59ac5 100644
--- a/app/Views/errors/html/error_404.php
+++ b/app/Views/errors/html/error_404.php
@@ -19,7 +19,7 @@
             Sorry! Cannot seem to find the page you were looking for.
         <?php endif; ?>
     </p>
-    <button class="inline-flex items-center justify-center px-3 py-1 text-sm font-semibold text-white rounded-full shadow-xs focus:outline-none focus:ring md:px-4 md:py-2 md:text-base bg-pine-700 hover:bg-pine-800"><?= lang('Common.go_back') ?></button>
+    <button class="inline-flex items-center justify-center px-3 py-1 text-sm font-semibold text-white rounded-full shadow-xs focus:outline-none focus:ring md:px-4 md:py-2 md:text-base bg-pine-500 hover:bg-pine-800"><?= lang('Common.go_back') ?></button>
 </body>
 
 </html>
diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php
index f70dcd97ed..bb5b6a4391 100644
--- a/modules/Admin/Config/Routes.php
+++ b/modules/Admin/Config/Routes.php
@@ -90,7 +90,7 @@ $routes->group(
 
                 $routes->group('persons', function ($routes): void {
                     $routes->get('/', 'PodcastPersonController/$1', [
-                        'as' => 'podcast-person-manage',
+                        'as' => 'podcast-persons-manage',
                         'filter' => 'permission:podcast-edit',
                     ]);
                     $routes->post(
@@ -322,7 +322,7 @@ $routes->group(
 
                         $routes->group('persons', function ($routes): void {
                             $routes->get('/', 'EpisodePersonController/$1/$2', [
-                                'as' => 'episode-person-manage',
+                                'as' => 'episode-persons-manage',
                                 'filter' => 'permission:podcast_episodes-edit',
                             ]);
                             $routes->post(
diff --git a/modules/Admin/Language/en/Episode.php b/modules/Admin/Language/en/Episode.php
index 06855b9d71..6f90e69c49 100644
--- a/modules/Admin/Language/en/Episode.php
+++ b/modules/Admin/Language/en/Episode.php
@@ -160,7 +160,6 @@ return [
         'submit_edit' => 'Save all soundbites',
     ],
     'embeddable_player' => [
-        'add' => 'Add embeddable player',
         'title' => 'Embeddable player',
         'label' =>
             'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.',
diff --git a/modules/Admin/Language/en/EpisodeNavigation.php b/modules/Admin/Language/en/EpisodeNavigation.php
new file mode 100644
index 0000000000..bbc0d29832
--- /dev/null
+++ b/modules/Admin/Language/en/EpisodeNavigation.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'go_to_page' => 'View episode page',
+    'dashboard' => 'Episode dashboard',
+    'episode-view' => 'Home',
+    'episode-edit' => 'Edit episode',
+    'episode-persons-manage' => 'Manage persons',
+    'embeddable-player-add' => 'Embeddable player',
+    'soundbites-edit' => 'Soundbites',
+];
diff --git a/modules/Admin/Language/en/PodcastNavigation.php b/modules/Admin/Language/en/PodcastNavigation.php
index 147eebb6a6..66cfce54f6 100644
--- a/modules/Admin/Language/en/PodcastNavigation.php
+++ b/modules/Admin/Language/en/PodcastNavigation.php
@@ -13,21 +13,11 @@ return [
     'dashboard' => 'Podcast dashboard',
     'podcast-view' => 'Home',
     'podcast-edit' => 'Edit podcast',
+    'podcast-persons-manage' => 'Manage persons',
     'episodes' => 'Episodes',
     'episode-list' => 'All episodes',
     'episode-create' => 'New episode',
-    'fediverse' => 'Fediverse',
-    'fediverse-block_lists' => 'Block lists',
     'analytics' => 'Analytics',
-    'persons' => 'Persons',
-    'podcast-person-manage' => 'Manage persons',
-    'contributors' => 'Contributors',
-    'contributor-list' => 'All contributors',
-    'contributor-add' => 'Add contributor',
-    'platforms' => 'External platforms',
-    'platforms-podcasting' => 'Podcasting',
-    'platforms-social' => 'Social Networks',
-    'platforms-funding' => 'Funding',
     'podcast-analytics' => 'Audience overview',
     'podcast-analytics-webpages' => 'Web pages visits',
     'podcast-analytics-locations' => 'Locations',
@@ -35,4 +25,11 @@ return [
     'podcast-analytics-players' => 'Players',
     'podcast-analytics-listening-time' => 'Listening time',
     'podcast-analytics-time-periods' => 'Time periods',
+    'contributors' => 'Contributors',
+    'contributor-list' => 'All contributors',
+    'contributor-add' => 'Add contributor',
+    'platforms' => 'External platforms',
+    'platforms-podcasting' => 'Podcasting',
+    'platforms-social' => 'Social Networks',
+    'platforms-funding' => 'Funding',
 ];
diff --git a/modules/Admin/Language/fr/EpisodeNavigation.php b/modules/Admin/Language/fr/EpisodeNavigation.php
new file mode 100644
index 0000000000..9ba3693724
--- /dev/null
+++ b/modules/Admin/Language/fr/EpisodeNavigation.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'go_to_page' => 'Aller à la page de l’épisode',
+    'dashboard' => 'Tableau de bord de l’épisode',
+    'episode-view' => 'Accueil',
+    'episode-edit' => 'Modifier l’épisode',
+    'episode-persons-manage' => 'Gestion des intervenants',
+    'embeddable-player-add' => 'Lecteur intégré',
+    'soundbites-edit' => 'Extraits sonores',
+];
diff --git a/modules/Admin/Language/fr/PodcastNavigation.php b/modules/Admin/Language/fr/PodcastNavigation.php
index 6939725432..c22fd12b6d 100644
--- a/modules/Admin/Language/fr/PodcastNavigation.php
+++ b/modules/Admin/Language/fr/PodcastNavigation.php
@@ -13,21 +13,11 @@ return [
     'dashboard' => 'Tableau de bord du podcast',
     'podcast-view' => 'Accueil',
     'podcast-edit' => 'Modifier le podcast',
+    'podcast-persons-manage' => 'Gestion des intervenants',
     'episodes' => 'Épisodes',
     'episode-list' => 'Tous les épisodes',
     'episode-create' => 'Créer un épisode',
-    'fediverse' => 'Fédiverse',
-    'fediverse-block_lists' => 'Listes de blocage',
     'analytics' => 'Mesures d’audience',
-    'persons' => 'Intervenants',
-    'podcast-person-manage' => 'Gestion des intervenants',
-    'contributors' => 'Contributeurs',
-    'contributor-list' => 'Tous les contributeurs',
-    'contributor-add' => 'Ajouter un contributeur',
-    'platforms' => 'Plate-formes externes',
-    'platforms-podcasting' => 'Podcasts',
-    'platforms-social' => 'Réseaux Sociaux',
-    'platforms-funding' => 'Financement',
     'podcast-analytics' => 'Vue d’ensemble',
     'podcast-analytics-webpages' => 'Visites des pages web',
     'podcast-analytics-locations' => 'Localisations',
@@ -35,4 +25,11 @@ return [
     'podcast-analytics-players' => 'Lecteurs',
     'podcast-analytics-listening-time' => 'Durée d’écoute',
     'podcast-analytics-time-periods' => 'Périodes',
+    'contributors' => 'Contributeurs',
+    'contributor-list' => 'Tous les contributeurs',
+    'contributor-add' => 'Ajouter un contributeur',
+    'platforms' => 'Plate-formes externes',
+    'platforms-podcasting' => 'Podcasts',
+    'platforms-social' => 'Réseaux Sociaux',
+    'platforms-funding' => 'Financement',
 ];
diff --git a/app/Language/en/Install.php b/modules/Install/Language/en/Install.php
similarity index 100%
rename from app/Language/en/Install.php
rename to modules/Install/Language/en/Install.php
diff --git a/app/Language/fr/Install.php b/modules/Install/Language/fr/Install.php
similarity index 100%
rename from app/Language/fr/Install.php
rename to modules/Install/Language/fr/Install.php
diff --git a/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php
index 174f9cc06e..7b9e6acfc3 100644
--- a/themes/cp_admin/_layout.php
+++ b/themes/cp_admin/_layout.php
@@ -59,7 +59,9 @@
         </nav>
     </header>
     <aside id="admin-sidebar" class="sticky z-50 flex flex-col text-white transition duration-200 ease-in-out transform -translate-x-full border-r top-10 border-pine-900 bg-pine-800 holy-grail__sidebar md:translate-x-0">
-        <?php if (isset($podcast)): ?>
+        <?php if (isset($podcast) && isset($episode)): ?>
+            <?= $this->include('episode/_sidebar') ?>
+        <?php elseif (isset($podcast)): ?>
             <?= $this->include('podcast/_sidebar') ?>
         <?php else: ?>
             <?= $this->include('_sidebar') ?>
diff --git a/themes/cp_admin/episode/_sidebar.php b/themes/cp_admin/episode/_sidebar.php
new file mode 100644
index 0000000000..d2e75b97c8
--- /dev/null
+++ b/themes/cp_admin/episode/_sidebar.php
@@ -0,0 +1,60 @@
+<?php
+$podcastNavigation = [
+    'dashboard' => [
+        'icon' => 'dashboard',
+        'items' => ['episode-view', 'episode-edit', 'episode-persons-manage', 'embeddable-player-add', 'soundbites-edit'],
+    ],
+]; ?>
+
+<a href="<?= route_to('podcast-view', $podcast->id) ?>" class="flex items-center px-4 py-2 border-b border-pine-900 focus:ring">
+    <?= icon('arrow-left', 'mr-2' ) ?>
+    <img
+    src="<?= $podcast->image->thumbnail_url ?>"
+    alt="<?= $podcast->title ?>"
+    class="object-cover w-6 h-6 rounded"
+    />
+    <span class="flex-1 w-full px-2 text-xs font-semibold truncate" title="<?= $podcast->title ?>"><?= $podcast->title ?></span>
+</a>
+<div class="flex items-center px-4 py-2 border-b border-pine-900">
+    <img
+    src="<?= $episode->image->thumbnail_url ?>"
+    alt="<?= $episode->title ?>"
+    class="object-cover w-16 h-16 rounded"
+    />
+    <div class="flex flex-col items-start flex-1 w-48 px-2">
+        <span class="w-full font-semibold truncate" title="<?= $episode->title ?>"><?= $episode->title ?></span>
+        <a href="<?= route_to(
+            'episode',
+            $podcast->handle,
+            $episode->slug,
+        ) ?>" class="inline-flex items-center text-xs outline-none hover:underline focus:ring"><?= lang(
+            'EpisodeNavigation.go_to_page',
+        ) ?>
+        <?= icon('external-link', 'ml-1 opacity-60') ?>
+        </a>
+    </div>
+</div>
+<nav class="flex flex-col flex-1 py-4 overflow-y-auto gap-y-4">
+    <?php foreach ($podcastNavigation as $section => $data): ?>
+    <div>
+        <button class="inline-flex items-center w-full px-4 py-1 font-semibold outline-none focus:ring" type="button">
+            <?= icon($data['icon'], 'opacity-60 text-2xl mr-4') .
+                lang('EpisodeNavigation.' . $section) ?>
+        </button>
+        <ul class="flex flex-col">
+            <?php foreach ($data['items'] as $item): ?>
+                <?php $isActive = url_is(route_to($item, $podcast->id, $episode->id)); ?>
+            <li class="inline-flex">
+                <a class="w-full py-1 pl-14 pr-2 text-sm outline-none hover:opacity-100 focus:ring <?= $isActive
+                    ? 'font-semibold opacity-100 inline-flex items-center'
+                    : 'opacity-75' ?>" href="<?= route_to(
+                    $item,
+                    $podcast->id,
+                    $episode->id
+                ) ?>"><?= ($isActive ? icon('chevron-right', 'mr-2') : '') .lang('EpisodeNavigation.' . $item) ?></a>
+            </li>
+            <?php endforeach; ?>
+        </ul>
+    </div>
+    <?php endforeach; ?>
+</nav>
diff --git a/themes/cp_admin/episode/edit.php b/themes/cp_admin/episode/edit.php
index be1470944f..04112312b6 100644
--- a/themes/cp_admin/episode/edit.php
+++ b/themes/cp_admin/episode/edit.php
@@ -400,12 +400,20 @@
 
 <Forms.Toggler id="block" name="block" value="yes" checked="<?= old('block', $episode->is_blocked) ?>" hint="<?= lang('Episode.form.block_hint') ?>"><?= lang('Episode.form.block') ?></Forms.Toggler>
 
-<?= button(
-    lang('Episode.form.submit_edit'),
-    '',
-    ['variant' => 'primary'],
-    ['type' => 'submit', 'class' => 'self-end'],
-) ?>
+<div class="flex items-center justify-between">
+    <?= button(
+        lang('Episode.delete'),
+        route_to('episode-delete', $podcast->id, $episode->id),
+        ['variant' => 'danger', 'iconLeft' => 'delete-bin'],
+    ) ?>
+
+    <?= button(
+        lang('Episode.form.submit_edit'),
+        '',
+        ['variant' => 'primary'],
+        ['type' => 'submit', 'class' => 'self-end'],
+    ) ?>
+</div>
 
 <?= form_close() ?>
 
diff --git a/themes/cp_admin/episode/list.php b/themes/cp_admin/episode/list.php
index 6e033f3983..1c3f28b3ba 100644
--- a/themes/cp_admin/episode/list.php
+++ b/themes/cp_admin/episode/list.php
@@ -94,7 +94,7 @@
                         'Episode.embeddable_player.add',
                     ) . '</a>' .
                     '<a class="px-4 py-1 hover:bg-gray-100" href="' . route_to(
-                        'episode-person-manage',
+                        'episode-persons-manage',
                         $podcast->id,
                         $episode->id,
                     ) . '">' . lang('Person.persons') . '</a>' .
diff --git a/themes/cp_admin/episode/view.php b/themes/cp_admin/episode/view.php
index 54ce4b1519..9f49d541d2 100644
--- a/themes/cp_admin/episode/view.php
+++ b/themes/cp_admin/episode/view.php
@@ -26,128 +26,28 @@
 
 
 <?= $this->section('content') ?>
-   
-<div class="flex flex-wrap">
-    <div class="w-full max-w-sm mb-6 md:mr-4">
-        <div class="mb-6">
-            <img
-            src="<?= $episode->image->medium_url ?>"
-            alt="Episode cover"
-            class="object-cover w-full"
-            />
-            <?= audio_player($episode->audio_file_url, $episode->audio_file_mimetype) ?>
-        </div>
 
-        <div class="flex justify-around">
-        <?= button(
-            lang('Episode.edit'),
-            route_to('episode-edit', $podcast->id, $episode->id),
-            ['variant' => 'info', 'iconLeft' => 'edit'],
-        ) ?>
-        <?= button(
-            lang('Episode.go_to_page'),
-            route_to('episode', $podcast->handle, $episode->slug),
-            ['variant' => 'secondary', 'iconLeft' => 'external-link'],
-        ) ?>
-        <?= button(
-            lang('Episode.delete'),
-            route_to('episode-delete', $podcast->id, $episode->id),
-            ['variant' => 'danger', 'iconLeft' => 'delete-bin'],
-        ) ?>
-        </div>
-    </div>
-
-    <section class="w-full max-w-sm prose">
-    <?= location_link($episode->location, 'text-sm') ?>
-    <?= $episode->description_html ?>
-    </section>
+<div class="mb-12">
+    <?= audio_player($episode->audio_file_url, $episode->audio_file_mimetype) ?>
 </div>
 
-    <div class="mb-12">
-    <?= button(
-        lang('Episode.embeddable_player.add'),
-        route_to('embeddable-player-add', $podcast->id, $episode->id),
-        ['variant' => 'info', 'iconLeft' => 'movie'],
-        ['class' => 'mb-4'],
-    ) ?>
-    <?= button(
-        lang('Episode.soundbites_form.title'),
-        route_to('soundbites-edit', $podcast->id, $episode->id),
-        ['variant' => 'info', 'iconLeft' => 'edit'],
-        ['class' => 'mb-4'],
-    ) ?>
-    <?= button(
-        lang('Person.episode_form.title'),
-        route_to('episode-person-manage', $podcast->id, $episode->id),
-        ['variant' => 'info', 'iconLeft' => 'folder-user'],
-        ['class' => 'mb-4'],
-    ) ?>
-    <?php if (count($episode->soundbites) > 0): ?>
-    <?= data_table(
-        [
-            [
-                'header' => 'Play',
-                'cell' => function ($soundbite): string {
-                    return icon_button(
-                        'play',
-                        lang('Episode.soundbites_form.play'),
-                        '',
-                        ['variant' => 'primary'],
-                        [
-                            'class' => 'mb-1 mr-1',
-                            'data-type' => 'play-soundbite',
-                            'data-soundbite-start-time' =>
-                                $soundbite->start_time,
-                            'data-soundbite-duration' => $soundbite->duration,
-                        ],
-                    );
-                },
-            ],
-            [
-                'header' => lang('Episode.soundbites_form.start_time'),
-                'cell' => function ($soundbite): string {
-                    return format_duration($soundbite->start_time);
-                },
-            ],
-            [
-                'header' => lang('Episode.soundbites_form.duration'),
-                'cell' => function ($soundbite): string {
-                    return $soundbite->duration . 's';
-                },
-            ],
-            [
-                'header' => lang('Episode.soundbites_form.label'),
-                'cell' => function ($soundbite) {
-                    return $soundbite->label;
-                },
-            ],
-        ],
-        $episode->soundbites,
-    ) ?>
-    <?php endif; ?>
-    </div>
-
-    <div class="mb-12 text-center">
-    <h2><?= lang('Charts.episode_by_day') ?></h2>
-    <div class="chart-xy" id="by-day-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.XY title="<?= lang('Charts.episode_by_day') ?>" dataUrl="<?= route_to(
         'analytics-filtered-data',
         $podcast->id,
         'PodcastByEpisode',
         'ByDay',
         $episode->id,
-    ) ?>"></div>
-    </div>
-    
-    <div class="mb-12 text-center">
-    <h2><?= lang('Charts.episode_by_month') ?></h2>
-    <div class="chart-xy" id="by-month-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
+    ) ?>"/>
+
+    <Charts.XY title="<?= lang('Charts.episode_by_month') ?>" dataUrl="<?= route_to(
         'analytics-filtered-data',
         $podcast->id,
         'PodcastByEpisode',
         'ByMonth',
         $episode->id,
-    ) ?>"></div>
-    </div>
+    ) ?>"/>
+</div>
 
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/_sidebar.php b/themes/cp_admin/podcast/_sidebar.php
index c59afc43b1..ecd2d9d405 100644
--- a/themes/cp_admin/podcast/_sidebar.php
+++ b/themes/cp_admin/podcast/_sidebar.php
@@ -2,7 +2,7 @@
 $podcastNavigation = [
     'dashboard' => [
         'icon' => 'dashboard',
-        'items' => ['podcast-view', 'podcast-edit', 'podcast-person-manage'],
+        'items' => ['podcast-view', 'podcast-edit', 'podcast-persons-manage'],
     ],
     'episodes' => [
         'icon' => 'mic',
diff --git a/themes/cp_admin/podcast/analytics/index.php b/themes/cp_admin/podcast/analytics/index.php
index 028deac2e5..3fea6b28e2 100644
--- a/themes/cp_admin/podcast/analytics/index.php
+++ b/themes/cp_admin/podcast/analytics/index.php
@@ -9,34 +9,28 @@
 <?= $this->endSection() ?>
 
 <?= $this->section('content') ?>
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.podcast_by_day') ?></h2>
-<div class="chart-xy" id="by-day-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'ByDay',
-) ?>"></div>
-</div>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.podcast_by_month') ?></h2>
-<div class="chart-xy" id="by-month-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'ByMonth',
-) ?>"></div>
-</div>
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.podcast_by_day') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'ByDay',
+    ) ?>"/>
+
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.podcast_by_month') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'ByMonth',
+    ) ?>"/>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.podcast_by_bandwidth') ?></h2>
-<div class="chart-xy" id="by-bandwidth-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'BandwidthByDay',
-) ?>"></div>
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.podcast_by_bandwidth') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'BandwidthByDay',
+    ) ?>"/>
 </div>
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/analytics/listening_time.php b/themes/cp_admin/podcast/analytics/listening_time.php
index 0a1c7b2960..223ec84c82 100644
--- a/themes/cp_admin/podcast/analytics/listening_time.php
+++ b/themes/cp_admin/podcast/analytics/listening_time.php
@@ -10,24 +10,20 @@
 
 <?= $this->section('content') ?>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.daily_listening_time') ?></h2>
-<div class="chart-xy" id="by-day-listening-time-graph" data-chart-type="xy-duration-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'TotalListeningTimeByDay',
-) ?>"></div>
-</div>
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.daily_listening_time') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'TotalListeningTimeByDay',
+    ) ?>"/>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.monthly_listening_time') ?></h2>
-<div class="chart-xy" id="by-month-listening-time-graph" data-chart-type="xy-duration-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'TotalListeningTimeByMonth',
-) ?>"></div>
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.monthly_listening_time') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'TotalListeningTimeByMonth',
+    ) ?>"/>
 </div>
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/analytics/locations.php b/themes/cp_admin/podcast/analytics/locations.php
index 05cb4fd8a4..eaa7d1c75c 100644
--- a/themes/cp_admin/podcast/analytics/locations.php
+++ b/themes/cp_admin/podcast/analytics/locations.php
@@ -10,35 +10,24 @@
 
 <?= $this->section('content') ?>
 
-<div class="lg:divide-x lg:grid lg:grid-cols-2">
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_country_weekly') ?></h2>
-        <div class="chart-pie" id="by-country-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByCountry',
-            'Weekly',
-        ) ?>"></div>
-    </div>
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_country_yearly') ?></h2>
-        <div class="chart-pie" id="by-country-by-year-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByCountry',
-            'Yearly',
-        ) ?>"></div>
-    </div>
-</div>
-
-<div class="mb-12 mr-6 text-center">
-<h2><?= lang('Charts.podcast_by_region') ?></h2>
-<div class="chart-map" id="by-region-map" data-chart-type="map-chart" data-chart-url="<?= route_to(
-    'analytics-full-data',
-    $podcast->id,
-    'PodcastByRegion',
-) ?>"></div>
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.Pie title="<?= lang('Charts.by_country_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByCountry',
+        'Weekly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_country_yearly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByCountry',
+        'Yearly',
+    ) ?>" />
+    <Charts.Map class="col-span-2" title="<?= lang('Charts.podcast_by_region') ?>" dataUrl="<?= route_to(
+        'analytics-full-data',
+        $podcast->id,
+        'PodcastByRegion',
+    ) ?>" />
 </div>
 
 
diff --git a/themes/cp_admin/podcast/analytics/players.php b/themes/cp_admin/podcast/analytics/players.php
index e76c9e3ac7..faa249bd39 100644
--- a/themes/cp_admin/podcast/analytics/players.php
+++ b/themes/cp_admin/podcast/analytics/players.php
@@ -10,56 +10,37 @@
 
 <?= $this->section('content') ?>
 
-<div class="lg:divide-x lg:grid lg:grid-cols-2">
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_player_weekly') ?></h2>
-        <div class="chart-pie" id="by-app-weekly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByPlayer',
-            'ByAppWeekly',
-        ) ?>"></div>
-    </div>
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_service_weekly') ?></h2>
-        <div class="chart-pie" id="by-service-weekly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByService',
-            'ByServiceWeekly',
-        ) ?>"></div>
-    </div>
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_device_weekly') ?></h2>
-        <div class="chart-pie" id="by-device-weekly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByPlayer',
-            'ByDeviceWeekly',
-        ) ?>"></div>
-    </div>
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_os_weekly') ?></h2>
-        <div class="chart-pie" id="by-os-yearly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'PodcastByPlayer',
-            'ByOsWeekly',
-        ) ?>"></div>
-    </div>
-</div>
-
-<div class="mb-12 mr-6 text-center">
-    <h2><?= lang('Charts.podcast_bots') ?></h2>
-    <div class="chart-xy" id="bots-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.Pie title="<?= lang('Charts.by_player_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByPlayer',
+        'ByAppWeekly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_service_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByService',
+        'ByServiceWeekly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_device_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByPlayer',
+        'ByDeviceWeekly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_os_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'PodcastByPlayer',
+        'ByOsWeekly',
+    ) ?>" />
+    <Charts.XY class="col-span-2" title="<?= lang('Charts.podcast_bots') ?>" dataUrl="<?= route_to(
         'analytics-data',
         $podcast->id,
         'PodcastByPlayer',
         'Bots',
-    ) ?>"></div>
+    ) ?>" />
 </div>
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/analytics/time_periods.php b/themes/cp_admin/podcast/analytics/time_periods.php
index 7c8bef9180..bf492fce3f 100644
--- a/themes/cp_admin/podcast/analytics/time_periods.php
+++ b/themes/cp_admin/podcast/analytics/time_periods.php
@@ -10,26 +10,18 @@
 
 <?= $this->section('content') ?>
 
-<div class="lg:divide-x lg:grid lg:grid-cols-2">
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_weekday') ?></h2>
-        <div class="chart-xy" id="by-weekday-barchart" data-chart-type="bar-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'Podcast',
-            'ByWeekday',
-        ) ?>"></div>
-    </div>
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_hour') ?></h2>
-        <div class="chart-xy" id="by-hour-barchart" data-chart-type="bar-chart" data-chart-url="<?= route_to(
-            'analytics-full-data',
-            $podcast->id,
-            'PodcastByHour',
-        ) ?>"></div>
-    </div>
-
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.Bar title="<?= lang('Charts.by_weekday') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'ByWeekday',
+    ) ?>" />
+    <Charts.Bar title="<?= lang('Charts.by_hour') ?>" dataUrl="<?= route_to(
+        'analytics-full-data',
+        $podcast->id,
+        'PodcastByHour',
+    ) ?>" />
 </div>
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/analytics/unique_listeners.php b/themes/cp_admin/podcast/analytics/unique_listeners.php
index 5b6c4c2555..f7129e56c6 100644
--- a/themes/cp_admin/podcast/analytics/unique_listeners.php
+++ b/themes/cp_admin/podcast/analytics/unique_listeners.php
@@ -10,24 +10,20 @@
 
 <?= $this->section('content') ?>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.unique_daily_listeners') ?></h2>
-<div class="chart-xy" id="by-day-listeners-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'UniqueListenersByDay',
-) ?>"></div>
-</div>
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.unique_daily_listeners') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'UniqueListenersByDay',
+    ) ?>"/>
 
-<div class="mb-12 text-center">
-<h2><?= lang('Charts.unique_monthly_listeners') ?></h2>
-<div class="chart-xy" id="by-month-listeners-graph" data-chart-type="xy-chart" data-chart-url="<?= route_to(
-    'analytics-data',
-    $podcast->id,
-    'Podcast',
-    'UniqueListenersByMonth',
-) ?>"></div>
+    <Charts.XY class="col-span-1" title="<?= lang('Charts.unique_monthly_listeners') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'Podcast',
+        'UniqueListenersByMonth',
+    ) ?>"/>
 </div>
 
 <?= service('vite')->asset('js/charts.ts', 'js') ?>
diff --git a/themes/cp_admin/podcast/analytics/webpages.php b/themes/cp_admin/podcast/analytics/webpages.php
index 58b2178f10..dfa0ae21cf 100644
--- a/themes/cp_admin/podcast/analytics/webpages.php
+++ b/themes/cp_admin/podcast/analytics/webpages.php
@@ -10,49 +10,29 @@
 
 <?= $this->section('content') ?>
 
-<div class="lg:divide-x lg:grid lg:grid-cols-2">
-    
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_domain_weekly') ?></h2>
-        <div class="chart-pie" id="by-domain-weekly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'WebsiteByReferer',
-            'ByDomainWeekly',
-        ) ?>"></div>
-    </div>
-
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_domain_yearly') ?></h2>
-        <div class="chart-pie" id="by-domain-yearly-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-data',
-            $podcast->id,
-            'WebsiteByReferer',
-            'ByDomainYearly',
-        ) ?>"></div>
-    </div>
-
-
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_entry_page') ?></h2>
-        <div class="chart-pie" id="by-entry-page-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-full-data',
-            $podcast->id,
-            'WebsiteByEntryPage',
-        ) ?>"></div>
-    </div>
-
-    
-    <div class="mb-12 mr-6 text-center">
-        <h2><?= lang('Charts.by_browser') ?></h2>
-        <div class="chart-pie" id="by-browser-pie" data-chart-type="pie-chart" data-chart-url="<?= route_to(
-            'analytics-full-data',
-            $podcast->id,
-            'WebsiteByBrowser',
-        ) ?>"></div>
-    </div>
-    
+<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
+    <Charts.Pie title="<?= lang('Charts.by_domain_weekly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'WebsiteByReferer',
+        'ByDomainWeekly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_domain_yearly') ?>" dataUrl="<?= route_to(
+        'analytics-data',
+        $podcast->id,
+        'WebsiteByReferer',
+        'ByDomainYearly',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_entry_page') ?>" dataUrl="<?= route_to(
+        'analytics-full-data',
+        $podcast->id,
+        'WebsiteByEntryPage',
+    ) ?>" />
+    <Charts.Pie title="<?= lang('Charts.by_browser') ?>" dataUrl="<?= route_to(
+        'analytics-full-data',
+        $podcast->id,
+        'WebsiteByBrowser',
+    ) ?>" />
 </div>
 
 
diff --git a/themes/cp_admin/podcast/latest_episodes.php b/themes/cp_admin/podcast/latest_episodes.php
index b1861cbfbd..f7985df77b 100644
--- a/themes/cp_admin/podcast/latest_episodes.php
+++ b/themes/cp_admin/podcast/latest_episodes.php
@@ -1,6 +1,6 @@
 <section class="flex flex-col">
     <header class="flex justify-between py-2">
-        <h1 class="text-xl"><?= lang('Podcast.latest_episodes') ?></h1>
+        <h2 class="text-xl"><?= lang('Podcast.latest_episodes') ?></h1>
         <a href="<?= route_to(
             'episode-list',
             $podcast->id,
@@ -14,14 +14,13 @@
         <?php foreach ($episodes as $episode): ?>
             <article class="snap-center flex flex-col flex-shrink-0 flex-1 w-full min-w-[12rem] max-w-[17rem] overflow-hidden bg-white border-2 border-pine-100 rounded-xl">
                 <div class="relative">
-                    <div class=""></div>
                     <?= publication_pill(
                         $episode->published_at,
                         $episode->publication_status,
                         'absolute top-2 right-2 text-sm'
                     ); ?>
                     <img
-                    src="<?= $episode->image->thumbnail_url ?>"
+                    src="<?= $episode->image->medium_url ?>"
                     alt="<?= $episode->title ?>" class="object-cover w-full" />
                 </div>
                 <div class="flex items-start justify-between p-2">
@@ -72,7 +71,7 @@
     'Episode.embeddable_player.add',
 ) ?></a>
                             <a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
-                                'episode-person-manage',
+                                'episode-persons-manage',
                                 $podcast->id,
                                 $episode->id,
                             ) ?>"><?= lang('Person.persons') ?></a>
diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php
index ee5e5ac811..b871f9b2a0 100644
--- a/themes/cp_app/home.php
+++ b/themes/cp_app/home.php
@@ -12,7 +12,7 @@
 </head>
 
 <body class="flex flex-col min-h-screen mx-auto bg-pine-50">
-    <header class="py-8 text-white border-b bg-pine-900">
+    <header class="py-8 text-white border-b bg-pine-800">
         <div class="container flex items-center justify-between px-2 py-4 mx-auto">
             <a href="<?= route_to(
                 'home',
diff --git a/themes/cp_app/page.php b/themes/cp_app/page.php
index e71877f03d..98317ebe1b 100644
--- a/themes/cp_app/page.php
+++ b/themes/cp_app/page.php
@@ -11,7 +11,7 @@
 </head>
 
 <body class="flex flex-col min-h-screen mx-auto">
-    <header class="py-8 text-white border-b bg-pine-900">
+    <header class="py-8 text-white border-b bg-pine-800">
         <div class="container flex flex-col px-2 py-4 mx-auto">
             <a href="<?= route_to('home') ?>"
             class="inline-flex items-center mb-2"><?= icon(
diff --git a/themes/cp_app/podcast/_layout.php b/themes/cp_app/podcast/_layout.php
index 641e71314f..f6480bab2b 100644
--- a/themes/cp_app/podcast/_layout.php
+++ b/themes/cp_app/podcast/_layout.php
@@ -22,7 +22,7 @@
     <?= $this->include('podcast/_partials/header') ?>
 
     <main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
-        <nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-900">
+        <nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-800">
                 <button
                 data-toggle="main-header"
                 data-toggle-class="sticky -translate-x-full"
@@ -64,7 +64,7 @@
     data-toggle="main-sidebar"
     data-toggle-class="translate-x-full"
     data-toggle-body-class="-ml-64"
-    class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-900 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
+    class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-800 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
         'menu',
     ) ?><span class="sr-only"><?= lang(
     'Podcast.toggle_podcast_sidebar',
@@ -73,7 +73,7 @@
     <!-- Funding links modal -->
     <div id="funding-links" class="fixed top-0 left-0 z-50 flex items-center justify-center hidden w-screen h-screen">
         <div
-        class="absolute w-full h-full bg-pine-900 bg-opacity-90"
+        class="absolute w-full h-full bg-pine-800 bg-opacity-90"
         role="button"
         data-toggle="funding-links"
         data-toggle-class="hidden"
diff --git a/themes/cp_app/podcast/_layout_authenticated.php b/themes/cp_app/podcast/_layout_authenticated.php
index 83914136f0..1619282354 100644
--- a/themes/cp_app/podcast/_layout_authenticated.php
+++ b/themes/cp_app/podcast/_layout_authenticated.php
@@ -19,7 +19,7 @@
 </head>
 
 <body class="flex w-full min-h-screen pt-12 pb-20 overflow-x-hidden bg-pine-50 lg:mx-auto lg:container sm:pb-0">
-    <div class="fixed top-0 left-0 z-50 flex items-center justify-between w-full h-12 px-4 text-white shadow bg-pine-900">
+    <div class="fixed top-0 left-0 z-50 flex items-center justify-between w-full h-12 px-4 text-white shadow bg-pine-800">
         <?= anchor(
             route_to('admin'),
             'castopod' . svg('castopod-logo', 'h-5 ml-1'),
@@ -55,7 +55,7 @@
                             </span>
                             <?= icon(
                                 'check',
-                                'ml-4 bg-pine-900 text-white rounded-full',
+                                'ml-4 bg-pine-800 text-white rounded-full',
                             ) ?>
                         <?php endif; ?>
                         </button>
@@ -67,7 +67,7 @@
     <?= $this->include('podcast/_partials/header') ?>
 
     <main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
-        <nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-900">
+        <nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-800">
                 <button
                 data-toggle="main-header"
                 data-toggle-class="sticky -translate-x-full"
@@ -105,7 +105,7 @@
 
     <?= $this->include('podcast/_partials/sidebar') ?>
 
-    <button data-toggle="main-sidebar" data-toggle-class="translate-x-full" data-toggle-body-class="-ml-64" class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-900 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
+    <button data-toggle="main-sidebar" data-toggle-class="translate-x-full" data-toggle-body-class="-ml-64" class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-800 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
         'menu',
     ) ?><span class="sr-only"><?= lang(
     'Podcast.toggle_podcast_sidebar',
@@ -113,7 +113,7 @@
 
     <!-- Funding links modal -->
     <div id="funding-links" class="fixed top-0 left-0 z-50 flex items-center justify-center hidden w-screen h-screen">
-        <div class="absolute w-full h-full bg-pine-900 bg-opacity-90" role="button" data-toggle="funding-links" data-toggle-class="hidden" aria-label="<?= lang(
+        <div class="absolute w-full h-full bg-pine-800 bg-opacity-90" role="button" data-toggle="funding-links" data-toggle-class="hidden" aria-label="<?= lang(
             'Common.close',
         ) ?>"></div>
         <div class="z-10 w-full max-w-xl bg-white rounded-lg shadow-2xl">
diff --git a/themes/cp_app/podcast/_partials/header.php b/themes/cp_app/podcast/_partials/header.php
index 85679ae9d4..1466fc08ba 100644
--- a/themes/cp_app/podcast/_partials/header.php
+++ b/themes/cp_app/podcast/_partials/header.php
@@ -1,6 +1,6 @@
 <header id="main-header" class="fixed top-0 left-0 flex-col flex-shrink-0 h-screen transform -translate-x-full sm:left-auto sm:-translate-x-0 sm:sticky w-80 sm:w-64 lg:w-80 xl:w-112 sm:flex">
     <img src="<?= $podcast->actor
-        ->cover_image_url ?>" alt="" class="object-cover w-full h-48 bg-pine-900"/>
+        ->cover_image_url ?>" alt="" class="object-cover w-full h-48 bg-pine-800"/>
     <div class="flex items-center justify-between px-4 py-2 mb-4 lg:px-6 -mt-14 lg:-mt-16 xl:-mt-20">
         <img src="<?= $podcast->image
             ->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="h-24 rounded-full shadow-xl xl:h-36 lg:h-28 ring-4 ring-pine-50" />
diff --git a/themes/cp_app/podcast/activity.php b/themes/cp_app/podcast/activity.php
index a6d91f94dc..1625533b9f 100644
--- a/themes/cp_app/podcast/activity.php
+++ b/themes/cp_app/podcast/activity.php
@@ -28,7 +28,7 @@
 <a href="<?= route_to(
     'podcast-activity',
     $podcast->handle,
-) ?>" class="px-4 py-1 mr-8 font-semibold border-b-4 text-pine-800 border-pine-800"><?= lang(
+) ?>" class="px-4 py-1 mr-8 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
     'Podcast.activity',
 ) ?></a>
     <a href="<?= route_to(
diff --git a/themes/cp_app/podcast/activity_authenticated.php b/themes/cp_app/podcast/activity_authenticated.php
index 2042857073..5bfec40fd5 100644
--- a/themes/cp_app/podcast/activity_authenticated.php
+++ b/themes/cp_app/podcast/activity_authenticated.php
@@ -28,7 +28,7 @@
 <a href="<?= route_to(
     'podcast-activity',
     $podcast->handle,
-) ?>" class="px-4 py-1 mr-8 font-semibold border-b-4 text-pine-800 border-pine-800"><?= lang(
+) ?>" class="px-4 py-1 mr-8 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
     'Podcast.activity',
 ) ?></a>
     <a href="<?= route_to(
diff --git a/themes/cp_app/podcast/episodes.php b/themes/cp_app/podcast/episodes.php
index 1cc3d7becc..b496252ec2 100644
--- a/themes/cp_app/podcast/episodes.php
+++ b/themes/cp_app/podcast/episodes.php
@@ -33,7 +33,7 @@
     <a href="<?= route_to(
         'podcast-episodes',
         $podcast->handle,
-    ) ?>" class="px-4 py-1 font-semibold border-b-4 text-pine-800 border-pine-800"><?= lang(
+    ) ?>" class="px-4 py-1 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
     'Podcast.episodes',
 ) ?></a>
     <?php if ($activeQuery): ?>
diff --git a/themes/cp_app/podcast/episodes_authenticated.php b/themes/cp_app/podcast/episodes_authenticated.php
index ade11b0eeb..fa6ad386a0 100644
--- a/themes/cp_app/podcast/episodes_authenticated.php
+++ b/themes/cp_app/podcast/episodes_authenticated.php
@@ -33,7 +33,7 @@
     <a href="<?= route_to(
                     'podcast-episodes',
                     $podcast->handle,
-                ) ?>" class="px-4 py-1 font-semibold border-b-4 text-pine-800 border-pine-800"><?= lang(
+                ) ?>" class="px-4 py-1 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
                                                                                                     'Podcast.episodes',
                                                                                                 ) ?></a>
     <?php if ($activeQuery) : ?>
diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php
index 68de706e9a..5bc26b5376 100644
--- a/themes/cp_app/podcast/follow.php
+++ b/themes/cp_app/podcast/follow.php
@@ -29,7 +29,7 @@
 
 <body class="flex flex-col min-h-screen bg-pine-50">
     <header class="flex flex-col items-center mb-8">
-        <h1 class="w-full pt-8 pb-32 text-center text-white bg-pine-900"><?= lang(
+        <h1 class="w-full pt-8 pb-32 text-center text-white bg-pine-800"><?= lang(
             'Fediverse.follow.subtitle',
         ) ?></h1>
         <div class="flex flex-col w-full max-w-xs -mt-24 overflow-hidden bg-white shadow rounded-xl">
diff --git a/themes/cp_app/podcast/post_remote_action.php b/themes/cp_app/podcast/post_remote_action.php
index 8feeb6c31e..8ed2f7f4c5 100644
--- a/themes/cp_app/podcast/post_remote_action.php
+++ b/themes/cp_app/podcast/post_remote_action.php
@@ -29,7 +29,7 @@
 </head>
 
 <body class="min-h-screen mx-auto bg-pine-50">
-    <header class="pt-8 pb-32 bg-pine-900">
+    <header class="pt-8 pb-32 bg-pine-800">
         <h1 class="text-lg font-semibold text-center text-white"><?= lang(
             'Fediverse.' . $action . '.subtitle',
         ) ?></h1>
-- 
GitLab