diff --git a/Gemfile b/Gemfile
index 327f358c466fa70f93d266df4914a1fbe647b145..3965ec4501bc74ed118980561f109216a452ec8a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -27,6 +27,8 @@ gem "font-awesome-sass"
 gem "front_matter_parser"
 gem "gdpr"
 gem "gitlab"
+gem "hal_openscience", "~> 0.1"
+# gem "hal_openscience", path: "../hal_openscience"
 gem "has_scope", "~> 0.8.0"
 gem "hash_dot"
 gem "image_processing"
diff --git a/Gemfile.lock b/Gemfile.lock
index fb1b1ce7973b280eb36202aa9e5c3c3468e1937c..2d5afe7f2c7fc9695c119d4085b58e1a736cc517 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -226,6 +226,10 @@ GEM
       terminal-table (>= 1.5.1)
     globalid (1.0.0)
       activesupport (>= 5.0)
+    hal_openscience (0.1.0)
+      json
+      net-http
+      open-uri
     has_scope (0.8.0)
       actionpack (>= 5.2)
       activesupport (>= 5.2)
@@ -307,6 +311,8 @@ GEM
     mustermann (3.0.0)
       ruby2_keywords (~> 0.0.1)
     nesty (1.0.2)
+    net-http (0.3.2)
+      uri
     net-imap (0.3.4)
       date
       net-protocol
@@ -343,6 +349,10 @@ GEM
     omniauth-saml (2.1.0)
       omniauth (~> 2.0)
       ruby-saml (~> 1.12)
+    open-uri (0.3.0)
+      stringio
+      time
+      uri
     orm_adapter (0.5.0)
     pexels (0.5.0)
       requests (~> 1.0.2)
@@ -467,10 +477,13 @@ GEM
       actionpack (>= 5.2)
       activesupport (>= 5.2)
       sprockets (>= 3.0.0)
+    stringio (3.0.4)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
     thor (1.2.1)
     tilt (2.0.11)
+    time (0.2.1)
+      date
     timeout (0.3.1)
     typhoeus (1.4.0)
       ethon (>= 0.9.0)
@@ -485,6 +498,7 @@ GEM
       faraday-multipart (~> 1.0.4)
       httparty (~> 0.20)
       oauth2 (>= 2.0.8)
+    uri (0.12.0)
     vcr (6.1.0)
     version_gem (1.1.1)
     warden (1.2.9)
@@ -546,6 +560,7 @@ DEPENDENCIES
   front_matter_parser
   gdpr
   gitlab
+  hal_openscience (~> 0.1)
   has_scope (~> 0.8.0)
   hash_dot
   image_processing
diff --git a/app/assets/images/admin/administration-thumb.jpg b/app/assets/images/admin/administration-thumb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..05135236bbbeaf8cc6ba5ad1d0106622795e0b8d
Binary files /dev/null and b/app/assets/images/admin/administration-thumb.jpg differ
diff --git a/app/assets/images/admin/administration.jpg b/app/assets/images/admin/administration.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c32c6437bd4e6848f1bba9fd3163bc9cb5ff9d1f
Binary files /dev/null and b/app/assets/images/admin/administration.jpg differ
diff --git a/app/assets/images/admin/communication-thumb.jpg b/app/assets/images/admin/communication-thumb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..988082ca54102771f11d83bf7cf641c98dee6347
Binary files /dev/null and b/app/assets/images/admin/communication-thumb.jpg differ
diff --git a/app/assets/images/admin/communication.jpg b/app/assets/images/admin/communication.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..65cbc768609ed8d7b94e52a7be5ce6b2c4edd0c4
Binary files /dev/null and b/app/assets/images/admin/communication.jpg differ
diff --git a/app/assets/images/admin/education-thumb.jpg b/app/assets/images/admin/education-thumb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d92d5e0ab732d7fc159511dd1b021fa930e1e316
Binary files /dev/null and b/app/assets/images/admin/education-thumb.jpg differ
diff --git a/app/assets/images/admin/education.jpg b/app/assets/images/admin/education.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..df65722162ded13d30e776842cf6ee788cd6ae0c
Binary files /dev/null and b/app/assets/images/admin/education.jpg differ
diff --git a/app/assets/images/admin/research-thumb.jpg b/app/assets/images/admin/research-thumb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ae6b5571f55a41234326a88abf292a4ad7bc11e2
Binary files /dev/null and b/app/assets/images/admin/research-thumb.jpg differ
diff --git a/app/assets/images/admin/research.jpg b/app/assets/images/admin/research.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..99ad60212f074a7657ec8b67c06af4def8efa318
Binary files /dev/null and b/app/assets/images/admin/research.jpg differ
diff --git a/app/assets/images/admin/university-thumb.jpg b/app/assets/images/admin/university-thumb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..70314f327527048620d6fff57f2851ca73bc3920
Binary files /dev/null and b/app/assets/images/admin/university-thumb.jpg differ
diff --git a/app/assets/images/admin/university.jpg b/app/assets/images/admin/university.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1d3b0c7ecd377645b0467608ba45ec1462bc572b
Binary files /dev/null and b/app/assets/images/admin/university.jpg differ
diff --git a/app/assets/images/avatar.jpg b/app/assets/images/avatar.jpg
index 6dbd8c060517f220694f1ff5d2c9f43c6bd199f8..33a945224ba900826d3bf663f8791d5e494904a3 100644
Binary files a/app/assets/images/avatar.jpg and b/app/assets/images/avatar.jpg differ
diff --git a/app/assets/javascripts/admin/communication/websites.js b/app/assets/javascripts/admin/communication/websites.js
index 677df2eb65e8c59b5747c7fd81efe6995caf4869..d27e2bf1b60fd7858eb8ea2a56d9962ea24a234e 100644
--- a/app/assets/javascripts/admin/communication/websites.js
+++ b/app/assets/javascripts/admin/communication/websites.js
@@ -5,8 +5,10 @@ window.osuny.communication.websites = {
         this.languagesCheckboxes = document.querySelectorAll('.js-languages input[type="checkbox"]');
         this.defaultLanguageSelect = document.querySelector('.js-default-language');
         this.defaultLanguageOptions = this.defaultLanguageSelect.querySelectorAll('option');
-        this.initEvents();
-        this.onChangeCheckbox();
+        if (this.defaultLanguageSelect) {
+            this.initEvents();
+            this.onChangeCheckbox();
+        }
     },
 
     initEvents: function () {
diff --git a/app/assets/stylesheets/admin/appstack/style.sass b/app/assets/stylesheets/admin/appstack/style.sass
index 1853079914fc84a1ba924f0a138c6156b2e110b5..a168205a25c7e22483089b13022ce339e3d4c300 100644
--- a/app/assets/stylesheets/admin/appstack/style.sass
+++ b/app/assets/stylesheets/admin/appstack/style.sass
@@ -72,7 +72,7 @@ p
     pointer-events: none
 .sidebar-link, a.sidebar-link
     color: rgba(255, 255, 255, 0.8)
-.sidebar-item.active .sidebar-link:hover, 
+.sidebar-item.active .sidebar-link:hover,
 .sidebar-item.active > .sidebar-link
     color: white
 
@@ -147,4 +147,8 @@ p
             &:nth-child(even)
                 background: $table-striped-bg
             &:hover
-                background: $table-hover-bg
\ No newline at end of file
+                background: $table-hover-bg
+
+/* used in admin/communication/websites/XXX and the selected item is over the bottom menu bar */
+.list-group-item.active
+    z-index: auto
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin/commons/table.sass b/app/assets/stylesheets/admin/commons/table.sass
index a9f375aa740f6ac52276f8138bd2d55d9fb276b4..509bff9c9fc776c3d195eecd85d08be267960f46 100644
--- a/app/assets/stylesheets/admin/commons/table.sass
+++ b/app/assets/stylesheets/admin/commons/table.sass
@@ -3,6 +3,7 @@
     td:first-of-type
         padding-left: 0
     &--with-actions
-        td:last-of-type
+        td:last-of-type,
+        th:last-of-type
             padding-right: 0
             text-align: right
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin/pure/navigation.sass b/app/assets/stylesheets/admin/pure/navigation.sass
index 02cd813268f12a9346ea734208ae563dd1efdd8a..92d103f33038bd70fbe9d2b09caa4b70be360b9d 100644
--- a/app/assets/stylesheets/admin/pure/navigation.sass
+++ b/app/assets/stylesheets/admin/pure/navigation.sass
@@ -22,21 +22,22 @@
     right: 0
     top: 0
     z-index: 1000
-    .avatar
-        width: 80px
+    .image
+        border-radius: 100%
+        margin-bottom: 20px
+        width: 100px
     .menu-content
         margin-top: 150px
         position: relative
+        h2
+            font-weight: bold
         ul
             list-style-type: none
             padding: 0
             li
-                padding: 5px 0
+                padding-bottom: 5px
                 span
                     opacity: 0.2
         a
             color: white
-            text-decoration-color: rgba(255, 255, 255, 0.2)
-            text-decoration-line: underline
-            &:hover
-                text-decoration-color: rgba(255, 255, 255, 1)
+            text-decoration: none
diff --git a/app/assets/stylesheets/admin/pure/style.sass b/app/assets/stylesheets/admin/pure/style.sass
index 511469210c475bef716565923075c68cdac9a452..62a97e91ef5b00ff6341391b3da74ebffcfd4d4e 100644
--- a/app/assets/stylesheets/admin/pure/style.sass
+++ b/app/assets/stylesheets/admin/pure/style.sass
@@ -14,6 +14,10 @@
     &__separation
         border-width: 10px
         margin-bottom: $spacing3
+    &__chapter
+        &__image
+            @media (min-width: 992px)
+                margin-top: -200px
 
 .dashboard-index
     .pure__section
@@ -87,7 +91,7 @@ p + .form-label
     &.kind--selected
         background: $color-accent
         border-color: $color-accent
-        &, p
+        &, p, label
             color: $color-background
         
 
diff --git a/app/controllers/admin/administration/application_controller.rb b/app/controllers/admin/administration/application_controller.rb
index 34ecbb945e646863c90619eb4a97be896c0fae8b..fa3f322a8ccb1854e491f7bf2ced29fa41b17d45 100644
--- a/app/controllers/admin/administration/application_controller.rb
+++ b/app/controllers/admin/administration/application_controller.rb
@@ -1,6 +1,9 @@
 class Admin::Administration::ApplicationController < Admin::ApplicationController
+ 
+  protected
+
   def breadcrumb
     super
-    add_breadcrumb Administration.model_name.human
+    add_breadcrumb Administration.model_name.human, admin_administration_root_path
   end
 end
diff --git a/app/controllers/admin/administration/dashboard_controller.rb b/app/controllers/admin/administration/dashboard_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b4d6fb38a59655df734f1afda747da3900023b58
--- /dev/null
+++ b/app/controllers/admin/administration/dashboard_controller.rb
@@ -0,0 +1,9 @@
+class Admin::Administration::DashboardController < Admin::Administration::ApplicationController
+
+  def index
+    @namespace = Administration
+    breadcrumb
+    render 'admin/dashboard/namespace'
+  end
+
+end
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index 3a0fedef61919ef02f94d6a12bd1a46c36fac6d5..44877c2ca6c1bad74748e8d284e6308881751e23 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -1,7 +1,7 @@
 class Admin::ApplicationController < ApplicationController
   layout 'admin/layouts/application'
 
-  before_action :load_filters, only: :index
+  include Admin::Filterable
 
   def set_theme
     current_user.update_column :admin_theme, params[:theme]
@@ -22,15 +22,10 @@ class Admin::ApplicationController < ApplicationController
 
   def breadcrumb_for(object, **options)
     return unless object
-    object.persisted? ? add_breadcrumb(object, [:admin, object, options])
+    title = object.to_s.truncate(50)
+    object.persisted? ? add_breadcrumb(title, [:admin, object, options])
                       : add_breadcrumb(t('create'))
   end
 
-  def load_filters
-    @filters = []
-    filter_class_name = "::Filters::#{self.class.to_s.gsub('Controller', '')}"
-    # filter_class will be nil if filter does not exist
-    filter_class = filter_class_name.safe_constantize
-    @filters = filter_class.new(current_user).list unless filter_class.nil?
-  end
+
 end
diff --git a/app/controllers/admin/communication/application_controller.rb b/app/controllers/admin/communication/application_controller.rb
index 9c3c780ff6a2f21ab0975890352b32d440dc19a4..d077f67100283dad25c338e23f5388c366c81388 100644
--- a/app/controllers/admin/communication/application_controller.rb
+++ b/app/controllers/admin/communication/application_controller.rb
@@ -3,21 +3,8 @@ class Admin::Communication::ApplicationController < Admin::ApplicationController
   protected
 
   def breadcrumb
-    if current_user.can_display_global_menu?
-      if @website
-        short_breadcrumb
-        breadcrumb_for @website
-      else
-        super
-        add_breadcrumb Communication.model_name.human
-      end
-    else
-      super
-      if @website
-        add_breadcrumb Communication::Website.model_name.human(count: 2), admin_communication_websites_path
-        breadcrumb_for @website
-      end
-
-    end
+    super
+    add_breadcrumb Communication.model_name.human, admin_communication_root_path
+    @menu_collapsed = true if @website
   end
 end
diff --git a/app/controllers/admin/communication/blocks_controller.rb b/app/controllers/admin/communication/blocks_controller.rb
index 806c3911ceb0751c7c985c02f5d62b1dca709645..ee36c58203abe3812194f54682744f5729ea3a70 100644
--- a/app/controllers/admin/communication/blocks_controller.rb
+++ b/app/controllers/admin/communication/blocks_controller.rb
@@ -77,7 +77,9 @@ class Admin::Communication::BlocksController < Admin::Communication::Application
   def about_path
     # La formation ou la page concernée
     path_method = "admin_#{@block.about.class.base_class.to_s.parameterize.underscore}_path"
-    send path_method, id: @block.about_id, website_id: website_id
+    path_method_options = { id: @block.about_id, website_id: website_id }
+    path_method_options[:lang] = @block.about.language.iso_code if @block.about.respond_to?(:language)
+    public_send path_method, **path_method_options
   end
 
   def breadcrumb
diff --git a/app/controllers/admin/communication/dashboard_controller.rb b/app/controllers/admin/communication/dashboard_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..89729cd1742fd794533e9ed3161e3644272b1928
--- /dev/null
+++ b/app/controllers/admin/communication/dashboard_controller.rb
@@ -0,0 +1,9 @@
+class Admin::Communication::DashboardController < Admin::Communication::ApplicationController
+
+  def index
+    @namespace = Communication
+    breadcrumb
+    render 'admin/dashboard/namespace'
+  end
+
+end
diff --git a/app/controllers/admin/communication/websites/application_controller.rb b/app/controllers/admin/communication/websites/application_controller.rb
index 253b5a04ddf61d021238d3c2786457541fa161e6..f5111244d3ac6ba18697d14938e0ae8550d29ae3 100644
--- a/app/controllers/admin/communication/websites/application_controller.rb
+++ b/app/controllers/admin/communication/websites/application_controller.rb
@@ -6,10 +6,23 @@ class Admin::Communication::Websites::ApplicationController < Admin::Communicati
 
   protected
 
+  def current_website_language
+    @current_website_language ||= @website.best_language_for(params[:lang])
+  end
+  helper_method :current_website_language
+
+  def breadcrumb
+    super
+    add_breadcrumb Communication::Website.model_name.human(count: 2), admin_communication_websites_path
+    breadcrumb_for @website
+  end
+
   def default_url_options
-    return {} unless params.has_key? :website_id
-    {
-      website_id: params[:website_id]
-    }
+    options = {}
+    if @website.present?
+      options[:website_id] = @website.id
+      options[:lang] = current_website_language.iso_code
+    end
+    options
   end
 end
diff --git a/app/controllers/admin/communication/websites/categories_controller.rb b/app/controllers/admin/communication/websites/categories_controller.rb
index b0fe23ac07eb54a65f5573a31f8433feb8286ea7..175cf6cfffdf9a5ea2fb367eb19206e002863122 100644
--- a/app/controllers/admin/communication/websites/categories_controller.rb
+++ b/app/controllers/admin/communication/websites/categories_controller.rb
@@ -1,10 +1,12 @@
 class Admin::Communication::Websites::CategoriesController < Admin::Communication::Websites::ApplicationController
   load_and_authorize_resource class: Communication::Website::Category, through: :website
 
+  include Admin::Translatable
+
   before_action :get_root_categories, only: [:index, :new, :create, :edit, :update]
 
   def index
-    @categories = @website.categories.ordered
+    @categories = @website.categories.for_language(current_website_language).ordered
     breadcrumb
   end
 
@@ -30,7 +32,7 @@ class Admin::Communication::Websites::CategoriesController < Admin::Communicatio
 
   def children
     return unless request.xhr?
-    @category = @website.categories.find(params[:id])
+    @category = @website.categories.for_language(current_website_language).find(params[:id])
     @children = @category.children.ordered
   end
 
@@ -84,7 +86,7 @@ class Admin::Communication::Websites::CategoriesController < Admin::Communicatio
   protected
 
   def get_root_categories
-    @root_categories = @website.categories.root.ordered
+    @root_categories = @website.categories.root.for_language(current_website_language).ordered
   end
 
   def breadcrumb
@@ -97,9 +99,12 @@ class Admin::Communication::Websites::CategoriesController < Admin::Communicatio
   def category_params
     params.require(:communication_website_category)
           .permit(
-            :website_id, :name, :meta_description, :summary, :slug, :parent_id,
+            :name, :meta_description, :summary, :slug, :parent_id,
             :featured_image, :featured_image_delete, :featured_image_infos, :featured_image_alt, :featured_image_credit
           )
-          .merge(university_id: current_university.id)
+          .merge(
+            university_id: current_university.id,
+            language_id: current_website_language.id
+          )
   end
 end
diff --git a/app/controllers/admin/communication/websites/menus_controller.rb b/app/controllers/admin/communication/websites/menus_controller.rb
index 7f32950f9effbbd7f214922455716ae1f502a46b..f738bbb5e0f4004db87fe9095973069f01a050b9 100644
--- a/app/controllers/admin/communication/websites/menus_controller.rb
+++ b/app/controllers/admin/communication/websites/menus_controller.rb
@@ -1,8 +1,10 @@
 class Admin::Communication::Websites::MenusController < Admin::Communication::Websites::ApplicationController
   load_and_authorize_resource class: Communication::Website::Menu, through: :website
 
+  include Admin::Translatable
+
   def index
-    @menus = @menus.ordered.page(params[:page])
+    @menus = @menus.for_language(current_website_language).ordered.page(params[:page])
     breadcrumb
   end
 
@@ -58,7 +60,10 @@ class Admin::Communication::Websites::MenusController < Admin::Communication::We
 
   def menu_params
     params.require(:communication_website_menu)
-          .permit(:website_id, :title, :identifier)
-          .merge(university_id: current_university.id)
+          .permit(:title, :identifier)
+          .merge(
+            university_id: current_university.id,
+            language_id: current_website_language.id
+          )
   end
 end
diff --git a/app/controllers/admin/communication/websites/pages_controller.rb b/app/controllers/admin/communication/websites/pages_controller.rb
index 896913746ee9f9c4a2a9be773026d520b1b2f0ad..887f3e1ae8ab2d6219bc6d1e0998bca1923a023b 100644
--- a/app/controllers/admin/communication/websites/pages_controller.rb
+++ b/app/controllers/admin/communication/websites/pages_controller.rb
@@ -2,9 +2,12 @@ class Admin::Communication::Websites::PagesController < Admin::Communication::We
   load_and_authorize_resource class: Communication::Website::Page,
                               through: :website
 
+  include Admin::Translatable
+
   def index
-    @homepage = @website.special_page(Communication::Website::Page::Home)
+    @homepage = @website.special_page(Communication::Website::Page::Home, language: current_website_language)
     @first_level_pages = @homepage.children.ordered
+    @pages = @website.pages.for_language(current_website_language)
     breadcrumb
   end
 
@@ -105,8 +108,12 @@ class Admin::Communication::Websites::PagesController < Admin::Communication::We
             :communication_website_id, :title, :breadcrumb_title, :bodyclass,
             :meta_description, :summary, :header_text, :text, :slug, :published, :full_width,
             :featured_image, :featured_image_delete, :featured_image_infos, :featured_image_alt, :featured_image_credit,
-            :parent_id, :language_id
+            :parent_id
+          )
+          .merge(
+            university_id: current_university.id,
+            language_id: current_website_language.id
           )
-          .merge(university_id: current_university.id)
   end
+
 end
diff --git a/app/controllers/admin/communication/websites/posts/curations_controller.rb b/app/controllers/admin/communication/websites/posts/curations_controller.rb
index 98bb804cfcd3a1f2ad685d67e1337c19681ee6d9..111b201ca983bcdff52ddcaab87b9036a5123c46 100644
--- a/app/controllers/admin/communication/websites/posts/curations_controller.rb
+++ b/app/controllers/admin/communication/websites/posts/curations_controller.rb
@@ -4,7 +4,7 @@ class Admin::Communication::Websites::Posts::CurationsController < Admin::Commun
   end
 
   def create
-    @curator = Curator.new @website, current_user, curation_params[:url]
+    @curator = Curator.new @website, current_user, current_website_language, curation_params[:url]
     if @curator.valid?
       redirect_to [:admin, @curator.post],
                   notice: t('admin.successfully_created_html', model: @curator.post.to_s)
diff --git a/app/controllers/admin/communication/websites/posts_controller.rb b/app/controllers/admin/communication/websites/posts_controller.rb
index 92fbb46fe980d4f00769d13c9ca4550634fc5681..2bd77c0533e969dd494b495d654e0a8559aec167 100644
--- a/app/controllers/admin/communication/websites/posts_controller.rb
+++ b/app/controllers/admin/communication/websites/posts_controller.rb
@@ -3,7 +3,10 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
 
   load_and_authorize_resource class: Communication::Website::Post, through: :website
 
+  include Admin::Translatable
+
   before_action :load_filters, only: :index
+  before_action :load_categories, only: [:new, :edit]
 
   has_scope :for_search_term
   has_scope :for_author
@@ -11,11 +14,12 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
   has_scope :for_pinned
 
   def index
-    @posts = apply_scopes(@posts).ordered.page params[:page]
-    @authors =  @website.authors.accessible_by(current_ability)
+    @posts = apply_scopes(@posts).for_language(current_website_language).ordered.page params[:page]
+    @authors =  @website.authors.for_language(current_website_language)
+                                .accessible_by(current_ability)
                                 .ordered
                                 .page(params[:authors_page])
-    @root_categories = @website.categories.root.ordered
+    @root_categories = @website.categories.for_language(current_website_language).root.ordered
     breadcrumb
   end
 
@@ -48,7 +52,9 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
 
   def new
     @post.website = @website
-    @post.author_id = current_user.person&.id
+    if current_user.person.present?
+      @post.author_id = current_user.person.find_or_translate!(current_website_language).id
+    end
     breadcrumb
   end
 
@@ -63,6 +69,7 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
     if @post.save_and_sync
       redirect_to admin_communication_website_post_path(@post), notice: t('admin.successfully_created_html', model: @post.to_s)
     else
+      load_categories
       breadcrumb
       render :new, status: :unprocessable_entity
     end
@@ -73,6 +80,7 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
     if @post.update_and_sync(post_params)
       redirect_to admin_communication_website_post_path(@post), notice: t('admin.successfully_updated_html', model: @post.to_s)
     else
+      load_categories
       breadcrumb
       add_breadcrumb t('edit')
       render :edit, status: :unprocessable_entity
@@ -95,16 +103,23 @@ class Admin::Communication::Websites::PostsController < Admin::Communication::We
 
   def post_params
     params.require(:communication_website_post)
-          .permit(
-            :university_id, :website_id, :title, :meta_description, :summary, :text,
-            :published, :published_at, :slug, :pinned,
-            :featured_image, :featured_image_delete, :featured_image_infos, :featured_image_alt, :featured_image_credit,
-            :author_id, :language_id, category_ids: []
-          )
-          .merge(university_id: current_university.id)
+    .permit(
+      :title, :meta_description, :summary, :text,
+      :published, :published_at, :slug, :pinned,
+      :featured_image, :featured_image_delete, :featured_image_infos, :featured_image_alt, :featured_image_credit,
+      :author_id, category_ids: []
+    )
+    .merge(
+      university_id: current_university.id,
+      language_id: current_website_language.id
+    )
   end
 
   def load_filters
     @filters = ::Filters::Admin::Communication::Website::Posts.new(current_user, @website).list
   end
+
+  def load_categories
+    @categories = @website.categories.for_language(current_website_language)
+  end
 end
diff --git a/app/controllers/admin/communication/websites_controller.rb b/app/controllers/admin/communication/websites_controller.rb
index 4b9c570dd2f28fa603324a9b730023dc5f8bb994..d83628439f6b2d87ab09005347ef20cd8f185d65 100644
--- a/app/controllers/admin/communication/websites_controller.rb
+++ b/app/controllers/admin/communication/websites_controller.rb
@@ -1,8 +1,4 @@
-class Admin::Communication::WebsitesController < Admin::Communication::ApplicationController
-  load_and_authorize_resource class: Communication::Website,
-                              through: :current_university,
-                              through_association: :communication_websites
-
+class Admin::Communication::WebsitesController < Admin::Communication::Websites::ApplicationController
   has_scope :for_search_term
   has_scope :for_about_type
 
@@ -13,8 +9,10 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati
   end
 
   def show
-    @pages = @website.pages.accessible_by(current_ability).recent
-    @posts = @website.posts.accessible_by(current_ability).recent
+    @all_pages = @website.pages.accessible_by(current_ability).for_language(current_website_language)
+    @pages = @all_pages.recent
+    @all_posts = @website.posts.accessible_by(current_ability).for_language(current_website_language)
+    @posts = @all_posts.recent
     breadcrumb
   end
 
@@ -80,9 +78,18 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati
   protected
 
   def website_params
-    params.require(:communication_website).permit(
+    attribute_names = [
       :name, :url, :repository, :access_token, :about_type, :about_id, :in_production,
-      :git_provider, :git_endpoint, :git_branch, :plausible_url, :default_language_id, language_ids: []
-    )
+      :git_provider, :git_endpoint, :git_branch, :plausible_url, language_ids: []
+    ]
+    # For now, default language can't be changed, too many implications, especially around special pages.
+    attribute_names << :default_language_id unless @website&.persisted?
+    params.require(:communication_website).permit(*attribute_names)
+  end
+
+  def default_url_options
+    options = {}
+    options[:lang] = current_website_language.iso_code if @website&.persisted?
+    options
   end
 end
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index e0e535237c07549f059928a02f7aa315f127f1a1..bec6f2d82b3d6e9cbd2bfcf02aab4f78c8e5d6b9 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,5 +1,11 @@
 class Admin::DashboardController < Admin::ApplicationController
   def index
+    @namespaces = [
+      Education,
+      Research,
+      Communication,
+      Administration
+    ]
     breadcrumb
   end
 end
diff --git a/app/controllers/admin/education/application_controller.rb b/app/controllers/admin/education/application_controller.rb
index 2fc99b4a74bf0263639b57b4f67a59f834ce98cf..a46e4c0dcae54a796fb6e2e90bcff314bdbf273f 100644
--- a/app/controllers/admin/education/application_controller.rb
+++ b/app/controllers/admin/education/application_controller.rb
@@ -1,11 +1,10 @@
 class Admin::Education::ApplicationController < Admin::ApplicationController
-  def breadcrumb
-    if @program
-      short_breadcrumb
-    else
-      super
-      add_breadcrumb Education.model_name.human
-    end
 
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb Education.model_name.human, admin_education_root_path
+    @menu_collapsed = true if @program
   end
 end
diff --git a/app/controllers/admin/education/dashboard_controller.rb b/app/controllers/admin/education/dashboard_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9e66bb7488220fae88acbce1e87d134d49d137ed
--- /dev/null
+++ b/app/controllers/admin/education/dashboard_controller.rb
@@ -0,0 +1,9 @@
+class Admin::Education::DashboardController < Admin::Education::ApplicationController
+
+  def index
+    @namespace = Education
+    breadcrumb
+    render 'admin/dashboard/namespace'
+  end
+
+end
diff --git a/app/controllers/admin/education/diplomas_controller.rb b/app/controllers/admin/education/diplomas_controller.rb
index 0898fac6fb041c9feb6d6f988a22f869d4f2aa96..f6ef994b2d969633a98889cc2fa57a3fa3ade32d 100644
--- a/app/controllers/admin/education/diplomas_controller.rb
+++ b/app/controllers/admin/education/diplomas_controller.rb
@@ -14,6 +14,7 @@ class Admin::Education::DiplomasController < Admin::Education::ApplicationContro
   def static
     @about = @diploma
     @website = @diploma.websites&.first
+    @programs = @website.education_programs.root.ordered
     render layout: false
   end
 
diff --git a/app/controllers/admin/education/programs/roles_controller.rb b/app/controllers/admin/education/programs/roles_controller.rb
index d934a5c64c7e4a40896052da431beff06e8f0a51..fa6a9d1228b5bf2510798764e4609a34f127575d 100644
--- a/app/controllers/admin/education/programs/roles_controller.rb
+++ b/app/controllers/admin/education/programs/roles_controller.rb
@@ -70,6 +70,10 @@ class Admin::Education::Programs::RolesController < Admin::Education::Programs::
   end
 
   def load_administration_people
-    @administration_people = current_university.people.administration.accessible_by(current_ability).ordered
+    @administration_people =  current_university.people
+                                                .for_language_id(current_university.default_language_id)
+                                                .administration
+                                                .accessible_by(current_ability)
+                                                .ordered
   end
 end
diff --git a/app/controllers/admin/education/programs/teachers_controller.rb b/app/controllers/admin/education/programs/teachers_controller.rb
index 00261353a60815b84ad4dc2766f830924fcb5233..e5f379ea2a96f00884ca4f94a11d267cbbac7b9b 100644
--- a/app/controllers/admin/education/programs/teachers_controller.rb
+++ b/app/controllers/admin/education/programs/teachers_controller.rb
@@ -51,7 +51,12 @@ class Admin::Education::Programs::TeachersController < Admin::Education::Program
 
   def get_available_people
     used_person_ids = @program.university_person_involvements.where.not(id: @involvement.id).pluck(:person_id)
-    @available_people = current_university.people.teachers.where.not(id: used_person_ids).accessible_by(current_ability).ordered
+    @available_people = current_university.people
+                                          .for_language_id(current_university.default_language_id)
+                                          .teachers
+                                          .where.not(id: used_person_ids)
+                                          .accessible_by(current_ability)
+                                          .ordered
   end
 
   def breadcrumb
diff --git a/app/controllers/admin/education/programs_controller.rb b/app/controllers/admin/education/programs_controller.rb
index 2aa617c06b74f800626a1b70ad88eb4458502b28..9a24a588efd2597671eb6af488eba4ee0642c8b8 100644
--- a/app/controllers/admin/education/programs_controller.rb
+++ b/app/controllers/admin/education/programs_controller.rb
@@ -123,6 +123,7 @@ class Admin::Education::ProgramsController < Admin::Education::ApplicationContro
 
   def load_teacher_people
     @teacher_people = current_university.people
+                                        .for_language_id(current_university.default_language_id)
                                         .teachers
                                         .accessible_by(current_ability)
                                         .ordered
diff --git a/app/controllers/admin/education/schools/roles_controller.rb b/app/controllers/admin/education/schools/roles_controller.rb
index 8c1e62e8b8dbbe548f600e08304baa95fcf65a7d..cff87cbf661b4d3575fff42d001ee235207a5221 100644
--- a/app/controllers/admin/education/schools/roles_controller.rb
+++ b/app/controllers/admin/education/schools/roles_controller.rb
@@ -70,6 +70,10 @@ class Admin::Education::Schools::RolesController < Admin::Education::Schools::Ap
   end
 
   def load_administration_people
-    @administration_people = current_university.people.administration.accessible_by(current_ability).ordered
+    @administration_people =  current_university.people
+                                                .for_language_id(current_university.default_language_id)
+                                                .administration
+                                                .accessible_by(current_ability)
+                                                .ordered
   end
 end
diff --git a/app/controllers/admin/education/teachers_controller.rb b/app/controllers/admin/education/teachers_controller.rb
index 16f8f93320553ca7474a5257d20074e29e1b41c7..455019b4d887f55d39f1e430f915e710d50316e4 100644
--- a/app/controllers/admin/education/teachers_controller.rb
+++ b/app/controllers/admin/education/teachers_controller.rb
@@ -7,6 +7,7 @@ class Admin::Education::TeachersController < Admin::Education::ApplicationContro
   def index
     @teachers = apply_scopes(
       current_university.people
+                        .for_language_id(current_university.default_language_id)
                         .teachers
                         .accessible_by(current_ability)
     ).ordered.page(params[:page])
@@ -42,12 +43,13 @@ class Admin::Education::TeachersController < Admin::Education::ApplicationContro
 
   def breadcrumb
     super
-    add_breadcrumb t('education.teachers', count: 2), admin_education_teachers_path
+    add_breadcrumb University::Person::Teacher.model_name.human(count: 2), admin_education_teachers_path
     add_breadcrumb @teacher, admin_education_teacher_path(@teacher) if @teacher
   end
 
   def load_teacher
     @teacher = current_university.people
+                                 .for_language_id(current_university.default_language_id)
                                  .teachers
                                  .accessible_by(current_ability)
                                  .find(params[:id])
diff --git a/app/controllers/admin/research/application_controller.rb b/app/controllers/admin/research/application_controller.rb
index 181ceaa185af59ab1dc650034edbee62ee94bbd5..8d9d22d30852c8f30b61c79a75b7be6996676f1c 100644
--- a/app/controllers/admin/research/application_controller.rb
+++ b/app/controllers/admin/research/application_controller.rb
@@ -3,15 +3,8 @@ class Admin::Research::ApplicationController < Admin::ApplicationController
   protected
 
   def breadcrumb
-    if @journal
-      short_breadcrumb
-      breadcrumb_for @journal
-    elsif @laboratory
-      short_breadcrumb
-      breadcrumb_for @laboratory
-    else
-      super
-      add_breadcrumb Research.model_name.human
-    end
+    super
+    add_breadcrumb Research.model_name.human, admin_research_root_path
+    @menu_collapsed = true if @journal || @laboratory
   end
 end
diff --git a/app/controllers/admin/research/dashboard_controller.rb b/app/controllers/admin/research/dashboard_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ab32c0ed1fa51224fd3e83f254966ce6491cbf47
--- /dev/null
+++ b/app/controllers/admin/research/dashboard_controller.rb
@@ -0,0 +1,9 @@
+class Admin::Research::DashboardController < Admin::Research::ApplicationController
+
+  def index
+    @namespace = Research
+    breadcrumb
+    render 'admin/dashboard/namespace'
+  end
+
+end
diff --git a/app/controllers/admin/research/journals_controller.rb b/app/controllers/admin/research/journals_controller.rb
index 048aaaef7d1dee966ad1213e3f027704aea1738a..88d765513cb792405f77f19e0e29a4b390063f6d 100644
--- a/app/controllers/admin/research/journals_controller.rb
+++ b/app/controllers/admin/research/journals_controller.rb
@@ -8,7 +8,6 @@ class Admin::Research::JournalsController < Admin::Research::ApplicationControll
   def index
     @journals = apply_scopes(@journals).ordered.page(params[:page])
     breadcrumb
-    add_breadcrumb Research::Journal.model_name.human(count: 2), admin_research_journals_path
   end
 
   def show
@@ -53,6 +52,12 @@ class Admin::Research::JournalsController < Admin::Research::ApplicationControll
 
   protected
 
+  def breadcrumb
+    super
+    add_breadcrumb Research::Journal.model_name.human(count: 2), admin_research_journals_path
+    breadcrumb_for @journal
+  end
+
   def journal_params
     params.require(:research_journal)
           .permit(:title, :meta_description, :summary, :issn)
diff --git a/app/controllers/admin/research/publications_controller.rb b/app/controllers/admin/research/publications_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8f78f046d986c20aee6da2c0ce2ad2a05ad18db5
--- /dev/null
+++ b/app/controllers/admin/research/publications_controller.rb
@@ -0,0 +1,31 @@
+class Admin::Research::PublicationsController < Admin::Research::ApplicationController
+  before_action :load_publication, except: :index
+
+  def index
+    @publications = Research::Publication.ordered.page(params[:page])
+    breadcrumb
+  end
+
+  def show
+    breadcrumb
+  end
+
+  def static
+    @about = @publication
+    render layout: false
+  end
+
+  protected
+
+  def load_publication
+    @publication = Research::Publication.find params[:id]
+  end
+
+  def breadcrumb
+    super
+    add_breadcrumb Research::Publication.model_name.human(count: 2),
+                   admin_research_publications_path
+    breadcrumb_for @publication
+  end
+
+end
diff --git a/app/controllers/admin/research/researchers_controller.rb b/app/controllers/admin/research/researchers_controller.rb
index 3dad9c5fe9adc5c9f6c1b4006acbdef0141837f9..a96265b0cf05169b47da7655f8e677c871546bfd 100644
--- a/app/controllers/admin/research/researchers_controller.rb
+++ b/app/controllers/admin/research/researchers_controller.rb
@@ -1,25 +1,51 @@
 class Admin::Research::ResearchersController < Admin::Research::ApplicationController
+  before_action :load_researcher, except: :index
 
   has_scope :for_search_term
 
   def index
-    @researchers = apply_scopes(current_university.people.researchers.accessible_by(current_ability)).ordered.page(params[:page])
+    @researchers = apply_scopes(current_university.people)
+                    .for_language_id(current_university.default_language_id)
+                    .researchers
+                    .accessible_by(current_ability)
+                    .ordered
+                    .page(params[:page])
     breadcrumb
   end
 
   def show
-    @researcher = current_university.people.researchers.accessible_by(current_ability).find(params[:id])
+    @papers = @researcher.research_journal_papers.ordered.page(params[:page])
+    @possible_hal_authors = @researcher.possible_hal_authors unless @researcher.hal_identity?
     @papers = @researcher.research_journal_papers.ordered.page(params[:page])
     breadcrumb
+    add_breadcrumb @researcher
+  end
+
+  def update
+    [
+      :hal_doc_identifier,
+      :hal_form_identifier,
+      :hal_person_identifier
+    ].each do |key|
+      @researcher.update_column key, params[key] if params.has_key?(key)
+    end
+    @researcher.import_research_publications_from_hal_without_delay!
+    redirect_to admin_research_researcher_path(@researcher)
   end
 
   protected
 
+  def load_researcher
+    @researcher = current_university.people
+                                    .for_language_id(current_university.default_language_id)
+                                    .researchers
+                                    .accessible_by(current_ability)
+                                    .find(params[:id])
+  end
+
   def breadcrumb
     super
-    add_breadcrumb t('research.researchers', count: 2),
-                   admin_research_researchers_path
-    breadcrumb_for @researcher
+    add_breadcrumb t('research.researchers', count: 2), admin_research_researchers_path
   end
 
 end
diff --git a/app/controllers/admin/university/alumni_controller.rb b/app/controllers/admin/university/alumni_controller.rb
index c267f090afd414dc189d33fecfb7cbf0712e0674..9171fc22e8e60f1137f57d7784e30089e8e14350 100644
--- a/app/controllers/admin/university/alumni_controller.rb
+++ b/app/controllers/admin/university/alumni_controller.rb
@@ -9,10 +9,12 @@ class Admin::University::AlumniController < Admin::University::ApplicationContro
   has_scope :for_alumni_year
 
   def index
-    @alumni = apply_scopes(@alumni).alumni
-                     .accessible_by(current_ability)
-                     .ordered
-                     .page(params[:page])
+    @alumni = apply_scopes(@alumni)
+                .for_language_id(current_university.default_language_id)
+                .alumni
+                .accessible_by(current_ability)
+                .ordered
+                .page(params[:page])
     breadcrumb
   end
 
diff --git a/app/controllers/admin/university/application_controller.rb b/app/controllers/admin/university/application_controller.rb
index 1da4eec6c03825738ea0803a244c74e34813f600..157451d1625655809be9f316629bbe3e892c8824 100644
--- a/app/controllers/admin/university/application_controller.rb
+++ b/app/controllers/admin/university/application_controller.rb
@@ -1,6 +1,9 @@
 class Admin::University::ApplicationController < Admin::ApplicationController
+
+  protected
+
   def breadcrumb
     super
-    add_breadcrumb University.model_name.human
+    add_breadcrumb University.model_name.human, admin_university_root_path
   end
 end
diff --git a/app/controllers/admin/university/dashboard_controller.rb b/app/controllers/admin/university/dashboard_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cabcce423f099b175c878231d3ff9dd674d53109
--- /dev/null
+++ b/app/controllers/admin/university/dashboard_controller.rb
@@ -0,0 +1,9 @@
+class Admin::University::DashboardController < Admin::University::ApplicationController
+
+  def index
+    @namespace = University
+    breadcrumb
+    render 'admin/dashboard/namespace'
+  end
+
+end
diff --git a/app/controllers/admin/university/people_controller.rb b/app/controllers/admin/university/people_controller.rb
index 0fde20c47221f4f77130ce72b000508af047e904..8df8bb77175192afcc4e18f1f758bc926cb0b251 100644
--- a/app/controllers/admin/university/people_controller.rb
+++ b/app/controllers/admin/university/people_controller.rb
@@ -8,7 +8,10 @@ class Admin::University::PeopleController < Admin::University::ApplicationContro
   has_scope :for_role
 
   def index
-    @people = apply_scopes(@people).ordered.page(params[:page])
+    @people = apply_scopes(@people)
+                .for_language_id(current_university.default_language_id)
+                .ordered
+                .page(params[:page])
     breadcrumb
   end
 
@@ -18,6 +21,18 @@ class Admin::University::PeopleController < Admin::University::ApplicationContro
     breadcrumb
   end
 
+  def in_language
+    language = Language.find_by!(iso_code: params[:lang])
+    translation = @person.find_or_translate!(language)
+    if translation.newly_translated
+      # There's an attribute accessor named "newly_translated" that we set to true
+      # when we just created the translation. We use it to redirect to the form instead of the show.
+      redirect_to [:edit, :admin, translation.becomes(translation.class.base_class)]
+    else
+      redirect_to [:admin, translation.becomes(translation.class.base_class)]
+    end
+  end
+
   def static
     @about = @person
     @website = @person.websites&.first
@@ -34,6 +49,7 @@ class Admin::University::PeopleController < Admin::University::ApplicationContro
   end
 
   def create
+    @person.language_id = current_university.default_language_id
     if @person.save_and_sync
       redirect_to admin_university_person_path(@person),
                   notice: t('admin.successfully_created_html', model: @person.to_s)
@@ -78,7 +94,7 @@ class Admin::University::PeopleController < Admin::University::ApplicationContro
       :biography,  :picture, :picture_delete, :picture_infos,
       :habilitation, :tenure, :url, :linkedin, :twitter, :mastodon,
       :is_researcher, :is_teacher, :is_administration, :is_alumnus,
-      :user_id
+      :hal_person_identifier, :hal_doc_identifier, :hal_form_identifier, :user_id
     ).merge(university_id: current_university.id)
   end
 end
diff --git a/app/controllers/concerns/admin/filterable.rb b/app/controllers/concerns/admin/filterable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..db61a29a4e763eb5bb2f23b9462e06056e9bffcc
--- /dev/null
+++ b/app/controllers/concerns/admin/filterable.rb
@@ -0,0 +1,18 @@
+module Admin::Filterable
+  extend ActiveSupport::Concern
+
+  included do
+    before_action :load_filters, only: :index
+  end
+
+  protected
+
+  def load_filters
+    @filters = []
+    filter_class_name = "::Filters::#{self.class.to_s.gsub('Controller', '')}"
+    # filter_class will be nil if filter does not exist
+    filter_class = filter_class_name.safe_constantize
+    @filters = filter_class.new(current_user).list unless filter_class.nil?
+  end
+
+end
diff --git a/app/controllers/concerns/admin/translatable.rb b/app/controllers/concerns/admin/translatable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..429d34711d86130e045d67c844dd11e7f079804e
--- /dev/null
+++ b/app/controllers/concerns/admin/translatable.rb
@@ -0,0 +1,41 @@
+module Admin::Translatable
+  extend ActiveSupport::Concern
+
+  included do
+    before_action :check_or_redirect_translatable_resource, only: [:show, :edit, :update, :destroy]
+
+    protected
+
+    # If we don't have a website, it will not work
+
+    def check_or_redirect_translatable_resource
+      # Early return if language is correct
+      return if resource.language_id == current_website_language.id
+      # Look up for translation or translate (with blocks and all) from resource
+      translation = resource.find_or_translate!(current_website_language)
+      # Redirect to the translation
+      redirect_to_translation(translation)
+    end
+
+    def redirect_to_translation(translation)
+      if ['edit', 'update'].include?(action_name) || translation.newly_translated
+        # Safety net on update action if called on wrong language
+        # There's an attribute accessor named "newly_translated" that we set to true
+        # when we just created the translation. We use it to redirect to the form instead of the show.
+        redirect_to [:edit, :admin, translation.becomes(translation.class.base_class)]
+      else
+        # Safety net on destroy action if called on wrong language
+        redirect_to [:admin, translation.becomes(translation.class.base_class)]
+      end
+    end
+
+    def resource_name
+      self.class.to_s.remove("Controller").demodulize.singularize.underscore
+    end
+
+    def resource
+      instance_variable_get("@#{resource_name}")
+    end
+  end
+
+end
diff --git a/app/controllers/extranet/persons_controller.rb b/app/controllers/extranet/persons_controller.rb
index 73df7551cfe7721522c9cef5004de5afb9519a82..4ab759241764783d6ce4115c3f6914903e6eb014 100644
--- a/app/controllers/extranet/persons_controller.rb
+++ b/app/controllers/extranet/persons_controller.rb
@@ -1,7 +1,7 @@
 class Extranet::PersonsController < Extranet::ApplicationController
   def index
     @facets = University::Person::Alumnus::Facets.new params[:facets], {
-      model: about&.university_person_alumni,
+      model: about&.university_person_alumni.for_language_id(current_university.default_language_id),
       about: about
     }
     @people = @facets.results
diff --git a/app/controllers/server/application_controller.rb b/app/controllers/server/application_controller.rb
index b6a2a5b819a02011c3538b5ef02877b57e51ed6c..15ed3b9a9354c93889e6ee07cd0c0feef2ad220f 100644
--- a/app/controllers/server/application_controller.rb
+++ b/app/controllers/server/application_controller.rb
@@ -1,10 +1,16 @@
 class Server::ApplicationController < ApplicationController
   layout 'server/layouts/application'
 
+  include Admin::Filterable
+
   before_action :authenticate_user!, :ensure_user_if_server_admin
 
   protected
 
+  def current_admin_theme
+    'pure'
+  end
+
   def breadcrumb
     add_breadcrumb t('admin.dashboard'), :server_root_path
   end
diff --git a/app/controllers/server/universities_controller.rb b/app/controllers/server/universities_controller.rb
index 5628d8d2b472d1566188e0f1732df2daaa254fb6..985c8bb3abee721ecf3b4329d918a2899d1a4797 100644
--- a/app/controllers/server/universities_controller.rb
+++ b/app/controllers/server/universities_controller.rb
@@ -59,7 +59,7 @@ class Server::UniversitiesController < Server::ApplicationController
   end
 
   def university_params
-    params.require(:university).permit(:name,
+    params.require(:university).permit(:name, :default_language_id,
       :address, :zipcode, :city, :country,
       :private, :identifier, :logo, :logo_delete, :sms_sender_name,
       :has_sso, :sso_target_url, :sso_cert, :sso_name_identifier_format, :sso_mapping, :sso_button_label,
diff --git a/app/controllers/server/websites_controller.rb b/app/controllers/server/websites_controller.rb
index f61e76457f86ad025d057f0d98e3a6dc68d023bc..a318cc32a881ca74c0241bf73b81e6160e97ef5c 100644
--- a/app/controllers/server/websites_controller.rb
+++ b/app/controllers/server/websites_controller.rb
@@ -1,7 +1,10 @@
 class Server::WebsitesController < Server::ApplicationController
 
+  has_scope :for_theme_version
+  has_scope :for_search_term
+
   def index
-    @websites = Communication::Website.all.ordered
+    @websites = apply_scopes(Communication::Website.all).ordered
     breadcrumb
     add_breadcrumb Communication::Website.model_name.human(count: 2), server_websites_path
   end
@@ -9,7 +12,6 @@ class Server::WebsitesController < Server::ApplicationController
   def refresh
     @website = Communication::Website.find params[:id]
     @website.get_current_theme_version!
-    redirect_back fallback_location: server_websites_path
   end
 
-end
\ No newline at end of file
+end
diff --git a/app/helpers/admin/application_helper.rb b/app/helpers/admin/application_helper.rb
index 449763dbc83d21409d17b65e2108001e73f0cae0..add42b2f3515f126f6ac4e2eb2ad6749a8cb5665 100644
--- a/app/helpers/admin/application_helper.rb
+++ b/app/helpers/admin/application_helper.rb
@@ -50,12 +50,13 @@ module Admin::ApplicationHelper
     raw "<a href=\"#{path}\" class=\"btn btn-light btn-xs\">#{t 'static' }</a>"
   end
 
-  def osuny_panel(title = nil, subtitle: nil, action: nil, &block)
+  def osuny_panel(title = nil, subtitle: nil, action: nil, image: nil, &block)
     render  layout: "admin/layouts/themes/#{current_admin_theme}/panel",
             locals: { 
               title: title, 
               subtitle: subtitle,
-              action: action
+              action: action,
+              image: image
             } do
       capture(&block)
     end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 78c91ac1be684c53d5a3dbf26a38b60044cfdb61..c926276058f5f30fa4903246573c466c638918b4 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -18,12 +18,14 @@ class Ability
     can :read, Communication::Website, university_id: @user.university_id, id: managed_websites_ids
     can :manage, Communication::Website::Post, university_id: @user.university_id, communication_website_id: managed_websites_ids, author_id: @user.person&.id
     cannot :publish, Communication::Website::Post
+    can :manage, Research::Journal
   end
 
   def author
     managed_websites_ids = @user.websites_to_manage.pluck(:communication_website_id)
     can :read, Communication::Website, university_id: @user.university_id, id: managed_websites_ids
     can :manage, Communication::Website::Post, university_id: @user.university_id, communication_website_id: managed_websites_ids, author_id: @user.person&.id
+    can :manage, Research::Journal
   end
 
   def teacher
@@ -34,6 +36,7 @@ class Ability
     can :manage, University::Person::Involvement, person_id: @user.person&.id
     can :read, University::Person::Involvement, university_id: @user.university_id
     can :manage, Communication::Block, university_id: @user.university_id, about_type: 'Education::Program', about_id: Education::Program.where(university_id: @user.university_id).pluck(:id)
+    can :manage, Research::Journal
   end
 
   def program_manager
@@ -48,6 +51,7 @@ class Ability
     can :manage, Communication::Website::Post, university_id: @user.university_id
     can :manage, Communication::Block, university_id: @user.university_id, about_type: 'Education::Program', about_id: managed_programs_ids
     can :create, Communication::Block
+    can :manage, Research::Journal
   end
 
   def website_manager
@@ -66,9 +70,11 @@ class Ability
     can :manage, Communication::Block, university_id: @user.university_id, about_type: 'Communication::Website::Page', about_id: managed_pages_ids
     can :manage, Communication::Block, university_id: @user.university_id, about_type: 'Communication::Website::Post', about_id: managed_posts_ids
     can :create, Communication::Block
+    can :manage, Research::Journal
   end
 
   def admin
+    can :read, Administration::Qualiopi
     can :read, Administration::Qualiopi::Criterion
     can :read, Administration::Qualiopi::Indicator
     can :manage, University::Person
diff --git a/app/models/administration.rb b/app/models/administration.rb
index 2be8b6a2e939d0974afa00ee26b20ede1b1ba961..364c98970f7677d08c1cf3c1adc5ee5eaedb689e 100644
--- a/app/models/administration.rb
+++ b/app/models/administration.rb
@@ -5,4 +5,10 @@ module Administration
   def self.table_name_prefix
     'administration_'
   end
+
+  def self.parts
+    [
+      [Administration::Qualiopi, :admin_administration_qualiopi_criterions_path],
+    ]
+  end
 end
diff --git a/app/models/communication.rb b/app/models/communication.rb
index a0de835696ab4dfd5bcbff4089f50751dd4f8824..3c3458024dd02437d83fb22d31ac06f5fadd7633 100644
--- a/app/models/communication.rb
+++ b/app/models/communication.rb
@@ -5,4 +5,11 @@ module Communication
   def self.table_name_prefix
     'communication_'
   end
+
+  def self.parts
+    [
+      [Communication::Website, :admin_communication_websites_path],
+      [Communication::Extranet, :admin_communication_extranets_path],
+    ]
+  end
 end
diff --git a/app/models/communication/block.rb b/app/models/communication/block.rb
index 29f0ef5cf08814656a2bb7a7c78b0d15db1566fc..9c1a12b62e18038f9c59966f9222933de883c357 100644
--- a/app/models/communication/block.rb
+++ b/app/models/communication/block.rb
@@ -65,7 +65,7 @@ class Communication::Block < ApplicationRecord
     utilities: [:files, :definitions, :embed, :contact]
   }
 
-  scope :published, -> { where(published: true) } 
+  scope :published, -> { where(published: true) }
 
   before_save :attach_template_blobs
 
@@ -97,12 +97,25 @@ class Communication::Block < ApplicationRecord
     @template = nil
   end
 
+  def language
+    return @language if defined?(@language)
+    @language ||= about.respond_to?(:language) ? about.language : nil
+  end
+
   def duplicate
     block = self.dup
     block.save
     block
   end
 
+  def translate!(about_translation)
+    translation = self.dup
+    translation.about = about_translation
+    translation.template.translate!
+    translation.data = translation.template.data
+    translation.save
+  end
+
   def to_s
     title.blank?  ? "#{Communication::Block.model_name.human} #{position}"
                   : "#{title}"
diff --git a/app/models/communication/block/component/base.rb b/app/models/communication/block/component/base.rb
index 50089bb53a0312b04b9b140136ea84f232625e07..b0e3accc8fd9b0ca49593b863d10e67669a60350 100644
--- a/app/models/communication/block/component/base.rb
+++ b/app/models/communication/block/component/base.rb
@@ -32,4 +32,8 @@ class Communication::Block::Component::Base
   def website
     template.block.about&.website
   end
+
+  def translate!
+    # By default, does nothing. Specific cases are handled in their own definitions. (example: post)
+  end
 end
diff --git a/app/models/communication/block/component/category.rb b/app/models/communication/block/component/category.rb
index a7db68fa12e70859a1274757e1c5e04ac46f043d..dc0b84dfc19f494d1be0278c8f6bdae1f68d37f7 100644
--- a/app/models/communication/block/component/category.rb
+++ b/app/models/communication/block/component/category.rb
@@ -9,4 +9,9 @@ class Communication::Block::Component::Category < Communication::Block::Componen
     [category, category&.best_featured_image&.blob]
   end
 
+  def translate!
+    return unless category.present?
+    @data = category.find_or_translate!(template.language).id
+  end
+
 end
diff --git a/app/models/communication/block/component/organization.rb b/app/models/communication/block/component/organization.rb
index dd52f491f0a92429259d137c7344772b3c6f2883..f76dff77147a332ced94c9f7d93ec8280ea4b319 100644
--- a/app/models/communication/block/component/organization.rb
+++ b/app/models/communication/block/component/organization.rb
@@ -12,4 +12,8 @@ class Communication::Block::Component::Organization < Communication::Block::Comp
     ]
   end
 
+  def translate!
+    # TODO: Traduction des Organisations à faire
+  end
+
 end
diff --git a/app/models/communication/block/component/page.rb b/app/models/communication/block/component/page.rb
index 2f5617ad6d5f1b5b17bc5aa48ace9ae2f945db70..6c28a4321d126a115a1176a3529c529927a60fe2 100644
--- a/app/models/communication/block/component/page.rb
+++ b/app/models/communication/block/component/page.rb
@@ -9,4 +9,10 @@ class Communication::Block::Component::Page < Communication::Block::Component::B
     [page, page&.best_featured_image&.blob]
   end
 
+  def translate!
+    return unless website && data.present?
+    source_page = website.pages.find_by(id: data)
+    @data = source_page.find_or_translate!(template.language).id if source_page.present?
+  end
+
 end
diff --git a/app/models/communication/block/component/person.rb b/app/models/communication/block/component/person.rb
index e082a01394a75e991c08c73e1357c74c78adfd20..0a5f7dbbd167337816f273d985ad56f874f2d76f 100644
--- a/app/models/communication/block/component/person.rb
+++ b/app/models/communication/block/component/person.rb
@@ -8,4 +8,9 @@ class Communication::Block::Component::Person < Communication::Block::Component:
     [person, person&.picture&.blob]
   end
 
+  def translate!
+    return unless data.present?
+    @data = person.find_or_translate!(template.language).id
+  end
+
 end
diff --git a/app/models/communication/block/component/post.rb b/app/models/communication/block/component/post.rb
index 8b08eb17d0ae81a98a31f7993824300b7f025e11..094386831cada1289724f4338334f30258beda84 100644
--- a/app/models/communication/block/component/post.rb
+++ b/app/models/communication/block/component/post.rb
@@ -14,4 +14,10 @@ class Communication::Block::Component::Post < Communication::Block::Component::B
     ]
   end
 
+  def translate!
+    return unless website && data.present?
+    source_post = website.posts.find_by(id: data)
+    @data = source_post.find_or_translate!(template.language).id if source_post.present?
+  end
+
 end
diff --git a/app/models/communication/block/component/program.rb b/app/models/communication/block/component/program.rb
index 8153ac398cdf80d0a73d24d1dd21237e94d43902..d8a1f80259095aaef93e498a5f7f6fa48e694145 100644
--- a/app/models/communication/block/component/program.rb
+++ b/app/models/communication/block/component/program.rb
@@ -7,4 +7,8 @@ class Communication::Block::Component::Program < Communication::Block::Component
   def git_dependencies
     [program, program&.best_featured_image&.blob]
   end
+
+  def translate!
+    # TODO: Traduction des Formations à faire
+  end
 end
diff --git a/app/models/communication/block/template.rb b/app/models/communication/block/template.rb
deleted file mode 100644
index 4cab374a72d2c461bbc15c2711428f8124d5074c..0000000000000000000000000000000000000000
--- a/app/models/communication/block/template.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-class Communication::Block::Template
-  attr_reader :block
-
-  def initialize(block)
-    @block = block
-  end
-
-  def sanitized_data
-    data
-  end
-
-  def git_dependencies
-    unless @git_dependencies
-      @git_dependencies = []
-      build_git_dependencies
-      @git_dependencies.uniq!
-    end
-    @git_dependencies
-  end
-
-  def active_storage_blobs
-    []
-  end
-
-  def allowed_for_about?
-    template.allowed_for_about?
-  end
-
-  protected
-
-  def build_git_dependencies
-  end
-
-  def add_dependency(dependency)
-    if dependency.is_a? Array
-      @git_dependencies += dependency
-    else
-      @git_dependencies += [dependency]
-    end
-  end
-
-  def find_blob(object, key)
-    id = object.dig(key, 'id')
-    return if id.blank?
-    university.active_storage_blobs.find id
-  end
-
-  def data
-    block.data || {}
-  end
-
-  def elements
-    data.has_key?('elements') ? data['elements']
-                              : []
-  end
-
-  def exclude_for
-    []
-  end
-
-  def university
-    block.university
-  end
-end
diff --git a/app/models/communication/block/template/base.rb b/app/models/communication/block/template/base.rb
index 55d8e165465622259b41c515ba91d93c30d91d1a..fbc8a7f2a6881f24ef3aba3f527b71c44dab4f01 100644
--- a/app/models/communication/block/template/base.rb
+++ b/app/models/communication/block/template/base.rb
@@ -9,6 +9,7 @@ class Communication::Block::Template::Base
 
   delegate :university, to: :block
   delegate :about, to: :block
+  delegate :language, to: :block
   delegate :template_kind, to: :block
   alias :kind :template_kind
 
@@ -93,6 +94,11 @@ class Communication::Block::Template::Base
     hash
   end
 
+  def translate!
+    components.each(&:translate!)
+    elements.each(&:translate!) if has_element_class?
+  end
+
   def git_dependencies
     unless @git_dependencies
       @git_dependencies = []
diff --git a/app/models/communication/block/template/page.rb b/app/models/communication/block/template/page.rb
index f4784136816a8a6852f6a6c5a8315cacb4436fd5..21d8ebf0dd8fa7ce7f7898da49fcd98781b7cbe6 100644
--- a/app/models/communication/block/template/page.rb
+++ b/app/models/communication/block/template/page.rb
@@ -36,7 +36,7 @@ class Communication::Block::Template::Page < Communication::Block::Template::Bas
 
   def selected_pages_children
     return [] unless page
-    page.children.published.ordered
+    page.children.for_language(block.language).published.ordered
   end
 
 end
diff --git a/app/models/communication/block/template/post.rb b/app/models/communication/block/template/post.rb
index 5d95ffd1bd70e04297e6890bc675c49a36f9e7c9..eb7b6ec57c559f42777e19c5684585cd68fb2587 100644
--- a/app/models/communication/block/template/post.rb
+++ b/app/models/communication/block/template/post.rb
@@ -34,6 +34,7 @@ class Communication::Block::Template::Post < Communication::Block::Template::Bas
   def selected_posts_all
     block.about&.website
                 .posts
+                .for_language(block.language)
                 .published
                 .ordered
                 .limit(posts_quantity)
@@ -42,7 +43,8 @@ class Communication::Block::Template::Post < Communication::Block::Template::Bas
   def selected_posts_category
     return [] if category.nil?
     category_ids = [category.id, category.descendants.map(&:id)].flatten
-    university.communication_website_posts.joins(:categories)
+    university.communication_website_posts.for_language(block.language)
+                                          .joins(:categories)
                                           .where(categories: { id: category_ids })
                                           .distinct
                                           .published
@@ -60,6 +62,7 @@ class Communication::Block::Template::Post < Communication::Block::Template::Bas
     return if id.blank?
     block.about&.website
                 .posts
+                .for_language(block.language)
                 .published
                 .find_by(id: id)
   end
diff --git a/app/models/communication/website.rb b/app/models/communication/website.rb
index 361cbb6b04c8f67256764b3fabdf1d667999e08c..52a48b87fc60d8ecb08e652ddf6c199fdd42cbf7 100644
--- a/app/models/communication/website.rb
+++ b/app/models/communication/website.rb
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
@@ -62,9 +62,11 @@ class Communication::Website < ApplicationRecord
                           association_foreign_key: 'language_id'
 
   validates :languages, length: { minimum: 1 }
+  validate :languages_must_include_default_language
 
   scope :ordered, -> { order(:name) }
   scope :in_production, -> { where(in_production: true) }
+  scope :for_theme_version, -> (version) { where(theme_version: version) }
   scope :for_search_term, -> (term) {
     where("
       unaccent(communication_websites.name) ILIKE unaccent(:term) OR
@@ -96,4 +98,16 @@ class Communication::Website < ApplicationRecord
     dependencies += about.git_dependencies(website) if about.present?
     dependencies
   end
+
+  def best_language_for(iso_code)
+    # We look for the language by the ISO code in the websites languages.
+    # If not found, we fallback to the default language.
+    languages.find_by(iso_code: iso_code) || default_language
+  end
+
+  protected
+
+  def languages_must_include_default_language
+    errors.add(:languages, :must_include_default) unless language_ids.include?(default_language_id)
+  end
 end
diff --git a/app/models/communication/website/category.rb b/app/models/communication/website/category.rb
index ba31fe5647d9d23b7538539e105754248c51f586..2658bb7db55f7c209366e7cb7c5edfe23c41abb3 100644
--- a/app/models/communication/website/category.rb
+++ b/app/models/communication/website/category.rb
@@ -16,6 +16,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  program_id               :uuid             indexed
 #  university_id            :uuid             not null, indexed
@@ -23,12 +25,16 @@
 # Indexes
 #
 #  idx_communication_website_post_cats_on_communication_website_id  (communication_website_id)
+#  index_communication_website_categories_on_language_id            (language_id)
+#  index_communication_website_categories_on_original_id            (original_id)
 #  index_communication_website_categories_on_parent_id              (parent_id)
 #  index_communication_website_categories_on_program_id             (program_id)
 #  index_communication_website_categories_on_university_id          (university_id)
 #
 # Foreign Keys
 #
+#  fk_rails_3186d8e327  (language_id => languages.id)
+#  fk_rails_52bd5968c9  (original_id => communication_website_categories.id)
 #  fk_rails_86a9ce3cea  (parent_id => communication_website_categories.id)
 #  fk_rails_9d4210dc43  (university_id => universities.id)
 #  fk_rails_c7c9f7ddc7  (communication_website_id => communication_websites.id)
@@ -46,6 +52,7 @@ class Communication::Website::Category < ApplicationRecord
   include WithTree
   include WithPermalink
   include WithPosition
+  include WithTranslations
 
   has_one                 :imported_category,
                           class_name: 'Communication::Website::Imported::Category',
@@ -121,11 +128,11 @@ class Communication::Website::Category < ApplicationRecord
   protected
 
   def last_ordered_element
-    website.categories.where(parent_id: parent_id).ordered.last
+    website.categories.where(parent_id: parent_id, language_id: language_id).ordered.last
   end
 
   def slug_unavailable?(slug)
-    self.class.unscoped.where(communication_website_id: self.communication_website_id, slug: slug).where.not(id: self.id).exists?
+    self.class.unscoped.where(communication_website_id: self.communication_website_id, language_id: language_id, slug: slug).where.not(id: self.id).exists?
   end
 
   def explicit_blob_ids
diff --git a/app/models/communication/website/configs/default_languages.rb b/app/models/communication/website/configs/default_languages.rb
index 59fe8171043cb2553e2140e62078890c1f926e80..cd5602c6af1c9bf7e055f79f7456961cb1f97cdb 100644
--- a/app/models/communication/website/configs/default_languages.rb
+++ b/app/models/communication/website/configs/default_languages.rb
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
diff --git a/app/models/communication/website/configs/default_permalinks.rb b/app/models/communication/website/configs/default_permalinks.rb
index 287cc69e45154237b21677063f1b003ccfba144c..f3d35ca03d71b003f36952e923e912ee85d8b5ee 100644
--- a/app/models/communication/website/configs/default_permalinks.rb
+++ b/app/models/communication/website/configs/default_permalinks.rb
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
diff --git a/app/models/communication/website/configs/development_config.rb b/app/models/communication/website/configs/development_config.rb
index d3b15c0ecb92c2bfdf2720b3fd61d1ec973026e2..e9f4d3e2085f903d4f38e7a0747483da81bcc632 100644
--- a/app/models/communication/website/configs/development_config.rb
+++ b/app/models/communication/website/configs/development_config.rb
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
diff --git a/app/models/communication/website/configs/production_config.rb b/app/models/communication/website/configs/production_config.rb
index c6eb64a6533cb745c5086090a09880ac823395fd..b9290cbe22e7a9c16a52062ea82eac515a4f7e00 100644
--- a/app/models/communication/website/configs/production_config.rb
+++ b/app/models/communication/website/configs/production_config.rb
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
diff --git a/app/models/communication/website/menu.rb b/app/models/communication/website/menu.rb
index 44f048cbdcf5f61678fc528192bd0b50d5ccbae5..0642a267e1977d83bdb1365e02d2eeaedf22efdb 100644
--- a/app/models/communication/website/menu.rb
+++ b/app/models/communication/website/menu.rb
@@ -9,15 +9,21 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
 # Indexes
 #
 #  idx_comm_website_menus_on_communication_website_id  (communication_website_id)
+#  index_communication_website_menus_on_language_id    (language_id)
+#  index_communication_website_menus_on_original_id    (original_id)
 #  index_communication_website_menus_on_university_id  (university_id)
 #
 # Foreign Keys
 #
+#  fk_rails_2901ebb799  (original_id => communication_website_menus.id)
+#  fk_rails_4d43d36541  (language_id => languages.id)
 #  fk_rails_8d6227916e  (university_id => universities.id)
 #  fk_rails_dcc7198fc5  (communication_website_id => communication_websites.id)
 #
@@ -25,12 +31,13 @@ class Communication::Website::Menu < ApplicationRecord
   include WithUniversity
   include Sanitizable
   include WithGit
+  include WithTranslations
 
   belongs_to :website, foreign_key: :communication_website_id
   has_many :items, class_name: 'Communication::Website::Menu::Item', dependent: :destroy
 
   validates :title, :identifier, presence: true
-  validates :identifier, uniqueness: { scope: :communication_website_id }
+  validates :identifier, uniqueness: { scope: [:communication_website_id, :language_id] }
 
   scope :ordered, -> { order(created_at: :asc) }
 
@@ -39,13 +46,40 @@ class Communication::Website::Menu < ApplicationRecord
   end
 
   def git_path(website)
-    path = "data/menus/"
-    # TODO I18n : Right now, we continue to send only a master version
-    # path += "#{website.default_language.iso_code}/" if website.languages.any?
-    "#{path}#{identifier}.yml"
+    "data/menus/#{language.iso_code}/#{identifier}.yml"
   end
 
   def template_static
     "admin/communication/websites/menus/static"
   end
+
+  def translate_additional_data!(translation)
+    items.root.ordered.each { |item| translate_menu_item!(item, translation) }
+  end
+
+  def translate_menu_item!(item, menu_translation, parent_translation = nil)
+    item_translation = item.dup
+    item_translation.menu = menu_translation
+    item_translation.parent = parent_translation
+
+    # TODO : I18n
+    # For now, only pages, posts, categories are handled.
+    # We need to translate programs, diplomas, volumes and papers
+    set_item_translation_attributes(item_translation, item, menu_translation)
+
+    # If no translation and no children to translate, translation won't be save, as about is nil and kind requires one.
+    if item_translation.save
+      item.children.ordered.each do |child|
+        translate_menu_item!(child, menu_translation, item_translation)
+      end
+    end
+  end
+
+  def set_item_translation_attributes(item_translation, item, menu_translation)
+    return unless item.about.present? && item.about.respond_to?(:translation_for)
+    # Search for the target translation based on the given language.
+    item_translation.about = item.about.translation_for(menu_translation.language)
+    # If no target translation found, convert to a blank menu item if item has children.
+    item_translation.kind = 'blank' if item_translation.about.nil? && item.children.any?
+  end
 end
diff --git a/app/models/communication/website/menu/item.rb b/app/models/communication/website/menu/item.rb
index f66fa1e69f565d1ea0e4ce6b45ace2007123a787..c2bd314353df08e931b8040a7a21c98b30091558 100644
--- a/app/models/communication/website/menu/item.rb
+++ b/app/models/communication/website/menu/item.rb
@@ -67,7 +67,7 @@ class Communication::Website::Menu::Item < ApplicationRecord
 
   def self.icon_for(kind)
     icons = {
-      'blank' => 'font',
+      'blank' => Icon::COMMUNICATION_WEBSITE_MENU_BLANK,
       'diploma' => Icon::EDUCATION_DIPLOMA,
       'post' => Icon::COMMUNICATION_WEBSITE_POST,
       'category' => Icon::COMMUNICATION_WEBSITE_POST,
@@ -75,9 +75,9 @@ class Communication::Website::Menu::Item < ApplicationRecord
       'program' => Icon::EDUCATION_PROGRAM,
       'paper' => Icon::RESEARCH_LABORATORY,
       'volume' => Icon::RESEARCH_LABORATORY,
-      'url' => 'globe',
+      'url' => Icon::COMMUNICATION_WEBSITE_MENU_URL,
     }
-    "fas fa-#{icons[kind]}" if icons.has_key? kind
+    icons[kind] if icons.has_key? kind
   end
 
   def to_s
diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index a5003b607d12fc8c588dd28f2ebef9a2c32e2404..a58825dc58e7315e23063c414b40fe19454c62ed 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 
@@ -48,21 +51,25 @@ class Communication::Website::Page < ApplicationRecord
   include WithUniversity
   include WithBlobs
   include WithBlocks
-  include WithGit
   include WithFeaturedImage
+  include WithGit
   include WithMenuItemTarget
   include WithPosition
   include WithTree
   include WithPath
   include WithType
   include WithPermalink
+  include WithTranslations
 
   belongs_to :website,
              foreign_key: :communication_website_id
   belongs_to :parent,
              class_name: 'Communication::Website::Page',
              optional: true
-  belongs_to :language, optional: true
+  belongs_to :original,
+             class_name: 'Communication::Website::Page',
+             optional: true
+  belongs_to :language
   has_one    :imported_page,
              class_name: 'Communication::Website::Imported::Page',
              dependent: :nullify
@@ -70,6 +77,9 @@ class Communication::Website::Page < ApplicationRecord
              class_name: 'Communication::Website::Page',
              foreign_key: :parent_id,
              dependent: :destroy
+  has_many   :translations,
+             class_name: 'Communication::Website::Page',
+             foreign_key: :original_id
 
   validates :title, presence: true
 
@@ -139,7 +149,7 @@ class Communication::Website::Page < ApplicationRecord
   end
 
   def last_ordered_element
-    website.pages.where(parent_id: parent_id).ordered.last
+    website.pages.where(parent_id: parent_id, language_id: language_id).ordered.last
   end
 
   def explicit_blob_ids
diff --git a/app/models/communication/website/page/accessibility.rb b/app/models/communication/website/page/accessibility.rb
index ef0fd58644fee35315173bb0b4054fad8995cf4d..b2a97fa5d352f38eaaa980add592d7b72f4e9cdd 100644
--- a/app/models/communication/website/page/accessibility.rb
+++ b/app/models/communication/website/page/accessibility.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Accessibility < Communication::Website::Page
diff --git a/app/models/communication/website/page/administrator.rb b/app/models/communication/website/page/administrator.rb
index c39764290a06a55d3a85f493c0090d88a432385e..af96e7e54cdb47a236bc7800a61ebdeff9357ea4 100644
--- a/app/models/communication/website/page/administrator.rb
+++ b/app/models/communication/website/page/administrator.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Administrator < Communication::Website::Page
@@ -53,7 +56,7 @@ class Communication::Website::Page::Administrator < Communication::Website::Page
   end
 
   def default_parent
-    website.special_page(Communication::Website::Page::Person)
+    website.special_page(Communication::Website::Page::Person, language: language)
   end
 
   def type_git_dependencies
diff --git a/app/models/communication/website/page/author.rb b/app/models/communication/website/page/author.rb
index d80c8daede27aec05f573ec3b5b4b4b8ac305255..ece2d2cfdf3b08956ad0dec5f15601db42e21631 100644
--- a/app/models/communication/website/page/author.rb
+++ b/app/models/communication/website/page/author.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Author < Communication::Website::Page
@@ -48,7 +51,7 @@ class Communication::Website::Page::Author < Communication::Website::Page
   end
 
   def default_parent
-    website.special_page(Communication::Website::Page::Person)
+    website.special_page(Communication::Website::Page::Person, language: language)
   end
 
   def type_git_dependencies
diff --git a/app/models/communication/website/page/communication_post.rb b/app/models/communication/website/page/communication_post.rb
index 418530277d70a1cfa3d82fdab2f8ab0b0d95ace3..ce811f85eb8e5f7f04e060ddd22f3a0f4fd28f87 100644
--- a/app/models/communication/website/page/communication_post.rb
+++ b/app/models/communication/website/page/communication_post.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::CommunicationPost < Communication::Website::Page
diff --git a/app/models/communication/website/page/education_diploma.rb b/app/models/communication/website/page/education_diploma.rb
index 11ab1648a52782c99c7a7167be64f2e9a12f050f..1c1933758bb26498411b45362f1fa69aba01b231 100644
--- a/app/models/communication/website/page/education_diploma.rb
+++ b/app/models/communication/website/page/education_diploma.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::EducationDiploma < Communication::Website::Page
diff --git a/app/models/communication/website/page/education_program.rb b/app/models/communication/website/page/education_program.rb
index 74fd9b65350f537e7d5450e982447bcf54881dd7..a91fd7f06abae57684613331d900a6ea335f89f0 100644
--- a/app/models/communication/website/page/education_program.rb
+++ b/app/models/communication/website/page/education_program.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::EducationProgram < Communication::Website::Page
diff --git a/app/models/communication/website/page/home.rb b/app/models/communication/website/page/home.rb
index 5e4ee047a0a31f90738a49ca6c5465aaebaf41a6..f7e48dd76699736f501aa7aa55414cde3c5cce4d 100644
--- a/app/models/communication/website/page/home.rb
+++ b/app/models/communication/website/page/home.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Home < Communication::Website::Page
diff --git a/app/models/communication/website/page/legal_term.rb b/app/models/communication/website/page/legal_term.rb
index 607cf9cf2709beeb9f445d5ffe745076925972b0..cc33f3bb6a3aa33ce8f6cc3acc04e01ec1f1ad52 100644
--- a/app/models/communication/website/page/legal_term.rb
+++ b/app/models/communication/website/page/legal_term.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::LegalTerm < Communication::Website::Page
diff --git a/app/models/communication/website/page/organization.rb b/app/models/communication/website/page/organization.rb
index 0fe98cfcce3b38aa8d7bf184575147e0e29c62de..c4ad7051d22e710800792ed469481c42d49062a6 100644
--- a/app/models/communication/website/page/organization.rb
+++ b/app/models/communication/website/page/organization.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Organization < Communication::Website::Page
diff --git a/app/models/communication/website/page/person.rb b/app/models/communication/website/page/person.rb
index e035d5dd9085984c67003592f68424c943a11902..07f991cd0f3a8d1bb994525cf7e8022e7cbe0c1f 100644
--- a/app/models/communication/website/page/person.rb
+++ b/app/models/communication/website/page/person.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Person < Communication::Website::Page
diff --git a/app/models/communication/website/page/privacy_policy.rb b/app/models/communication/website/page/privacy_policy.rb
index e94f7b8854b23d129df9afc513bf8ee8fb945b4a..478783031efce361ff29e566fe8b37532f38bb3a 100644
--- a/app/models/communication/website/page/privacy_policy.rb
+++ b/app/models/communication/website/page/privacy_policy.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::PrivacyPolicy < Communication::Website::Page
diff --git a/app/models/communication/website/page/research_paper.rb b/app/models/communication/website/page/research_paper.rb
index a485ea2e8eacc31e1a5cc7648425ba7f43b34872..ea15cbfe84d6cfeb814235d414f48021b3dda5ce 100644
--- a/app/models/communication/website/page/research_paper.rb
+++ b/app/models/communication/website/page/research_paper.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::ResearchPaper < Communication::Website::Page
diff --git a/app/models/communication/website/page/research_volume.rb b/app/models/communication/website/page/research_volume.rb
index 0cb730dab1dca26cdab01fdadddf2e0fa22c58aa..2eff7f3a6d4ac8cce23d62dd46169b0e24d6992e 100644
--- a/app/models/communication/website/page/research_volume.rb
+++ b/app/models/communication/website/page/research_volume.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::ResearchVolume < Communication::Website::Page
diff --git a/app/models/communication/website/page/researcher.rb b/app/models/communication/website/page/researcher.rb
index 4dc3ca98d7c6bb366ead2726157c86b42f095fd6..4fe548b24d4d69c8d7f20db9771316c36c6b3856 100644
--- a/app/models/communication/website/page/researcher.rb
+++ b/app/models/communication/website/page/researcher.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Researcher < Communication::Website::Page
@@ -46,13 +49,13 @@ class Communication::Website::Page::Researcher < Communication::Website::Page
   end
 
   protected
-  
+
   def current_git_path
     @current_git_path ||= "#{git_path_prefix}researchers/_index.html"
   end
 
   def default_parent
-    website.special_page(Communication::Website::Page::Person)
+    website.special_page(Communication::Website::Page::Person, language: language)
   end
 
   def type_git_dependencies
diff --git a/app/models/communication/website/page/sitemap.rb b/app/models/communication/website/page/sitemap.rb
index 6da00584bc11275950ea23f0411cae9d3415d1e1..3675c8417c7b17d5dead1738be3353cd3f18113b 100644
--- a/app/models/communication/website/page/sitemap.rb
+++ b/app/models/communication/website/page/sitemap.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Sitemap < Communication::Website::Page
diff --git a/app/models/communication/website/page/teacher.rb b/app/models/communication/website/page/teacher.rb
index d9d1daacb49fb42432ad5155aa9d4d579030b7ce..0332253ad6cf1bd28bd14b910324b408df1bb35c 100644
--- a/app/models/communication/website/page/teacher.rb
+++ b/app/models/communication/website/page/teacher.rb
@@ -22,7 +22,8 @@
 #  created_at               :datetime         not null
 #  updated_at               :datetime         not null
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  parent_id                :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
@@ -30,6 +31,7 @@
 #
 #  index_communication_website_pages_on_communication_website_id  (communication_website_id)
 #  index_communication_website_pages_on_language_id               (language_id)
+#  index_communication_website_pages_on_original_id               (original_id)
 #  index_communication_website_pages_on_parent_id                 (parent_id)
 #  index_communication_website_pages_on_university_id             (university_id)
 #
@@ -37,6 +39,7 @@
 #
 #  fk_rails_1a42003f06  (parent_id => communication_website_pages.id)
 #  fk_rails_280107c62b  (communication_website_id => communication_websites.id)
+#  fk_rails_304f57360f  (original_id => communication_website_pages.id)
 #  fk_rails_d208d15a73  (university_id => universities.id)
 #
 class Communication::Website::Page::Teacher < Communication::Website::Page
@@ -46,13 +49,13 @@ class Communication::Website::Page::Teacher < Communication::Website::Page
   end
 
   protected
-  
+
   def current_git_path
     @current_git_path ||= "#{git_path_prefix}teachers/_index.html"
   end
 
   def default_parent
-    website.special_page(Communication::Website::Page::Person)
+    website.special_page(Communication::Website::Page::Person, language: language)
   end
 
   def type_git_dependencies
diff --git a/app/models/communication/website/page/with_path.rb b/app/models/communication/website/page/with_path.rb
index 99b4692e3c6dbc8efee742b5d5a6185543c07d23..1444d93b5081e35ad6ba2c261550c109b26a5a08 100644
--- a/app/models/communication/website/page/with_path.rb
+++ b/app/models/communication/website/page/with_path.rb
@@ -8,9 +8,8 @@ module Communication::Website::Page::WithPath
 
   def path
     path = ''
-    # TODO i18n remplacer le choix de la langue
     if website.languages.many?
-      path += "/#{website.default_language.iso_code}"
+      path += "/#{language.iso_code}"
     end
     path += "/#{slug_with_ancestors}/"
     path.gsub(/\/+/, '/')
@@ -55,7 +54,7 @@ module Communication::Website::Page::WithPath
 
   def slug_unavailable?(slug)
     self.class.unscoped
-              .where(communication_website_id: self.communication_website_id, slug: slug)
+              .where(communication_website_id: self.communication_website_id, language_id: language_id, slug: slug)
               .where.not(id: self.id)
               .exists?
   end
@@ -67,11 +66,11 @@ module Communication::Website::Page::WithPath
   end
 
   def slug_must_be_present
-    errors.add(:slug, ActiveRecord::Errors.default_error_messages[:absent]) if slug.blank?
+    errors.add(:slug, :absent) if slug.blank?
   end
 
   def slug_must_be_unique
-    errors.add(:slug, ActiveRecord::Errors.default_error_messages[:taken]) if slug_unavailable?(slug)
+    errors.add(:slug, :taken) if slug_unavailable?(slug)
   end
 
   def slug_must_have_proper_format
diff --git a/app/models/communication/website/page/with_type.rb b/app/models/communication/website/page/with_type.rb
index c465ecd000765298eb3fe26fdbe044371d2e4586..861602c81e09ff5c161b3797aded0a4a5987cd13 100644
--- a/app/models/communication/website/page/with_type.rb
+++ b/app/models/communication/website/page/with_type.rb
@@ -88,7 +88,7 @@ module Communication::Website::Page::WithType
   protected
 
   def default_parent
-    website.special_page(Communication::Website::Page::Home)
+    website.special_page(Communication::Website::Page::Home, language: language)
   end
 
   def type_git_dependencies
@@ -103,5 +103,5 @@ module Communication::Website::Page::WithType
     self.full_width = full_width_by_default?
     self.published = published_by_default?
   end
-  
+
 end
diff --git a/app/models/communication/website/permalink.rb b/app/models/communication/website/permalink.rb
index 276d8df83af5f599212cc2f6cc269c287ae73505..88f821fd28202d11e3338cce0ff2accac97f517b 100644
--- a/app/models/communication/website/permalink.rb
+++ b/app/models/communication/website/permalink.rb
@@ -54,9 +54,9 @@ class Communication::Website::Permalink < ApplicationRecord
   scope :current, -> { where(is_current: true) }
   scope :not_current, -> { where(is_current: false) }
 
-  def self.config_in_website(website)
+  def self.config_in_website(website, language)
     required_kinds_in_website(website).map { |permalink_class|
-      [permalink_class.static_config_key, permalink_class.pattern_in_website(website)]
+      [permalink_class.static_config_key, permalink_class.pattern_in_website(website, language)]
     }.to_h
   end
 
@@ -84,12 +84,13 @@ class Communication::Website::Permalink < ApplicationRecord
     MAPPING.keys.include?(lookup_key)
   end
 
-  def self.pattern_in_website(website)
+  def self.pattern_in_website(website, language)
     raise NotImplementedError
   end
 
   def pattern
-    self.class.pattern_in_website(website)
+    language = about.respond_to?(:language) ? about.language : website.default_language
+    self.class.pattern_in_website(website, language)
   end
 
   def computed_path
@@ -122,8 +123,9 @@ class Communication::Website::Permalink < ApplicationRecord
   # Can be overwritten (Page for example)
   def published_path
     # TODO I18n doit prendre la langue du about
+    language = about.respond_to?(:language) ? about.language : website.default_language
     p = ""
-    p += "/#{website.default_language.iso_code}" if website.languages.many?
+    p += "/#{language.iso_code}" if website.languages.many?
     p += pattern
     substitutions.each do |key, value|
       p.gsub! ":#{key}", "#{value}"
diff --git a/app/models/communication/website/permalink/administrator.rb b/app/models/communication/website/permalink/administrator.rb
index 9a95d44d5c83cced6089ee19483dbe44e0f0f4fe..7270c11c7daa32b803ad45ff9bac8c3151c4e464 100644
--- a/app/models/communication/website/permalink/administrator.rb
+++ b/app/models/communication/website/permalink/administrator.rb
@@ -33,7 +33,7 @@ class Communication::Website::Permalink::Administrator < Communication::Website:
   end
 
   # /equipe/:slug/roles/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Person).slug_with_ancestors}/:slug/roles/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Person, language: language).slug_with_ancestors}/:slug/roles/"
   end
 end
diff --git a/app/models/communication/website/permalink/author.rb b/app/models/communication/website/permalink/author.rb
index 8c0b639b40240d817036818b4b92b9546e5b8fa3..0740788a9694c43ba9768718e3984d381abb2474 100644
--- a/app/models/communication/website/permalink/author.rb
+++ b/app/models/communication/website/permalink/author.rb
@@ -34,7 +34,7 @@ class Communication::Website::Permalink::Author < Communication::Website::Permal
   end
 
   # /equipe/:slug/actualites/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Person).slug_with_ancestors}/:slug/#{website.special_page(Communication::Website::Page::CommunicationPost).slug}/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Person, language: language).slug_with_ancestors}/:slug/#{website.special_page(Communication::Website::Page::CommunicationPost, language: language).slug}/"
   end
 end
diff --git a/app/models/communication/website/permalink/category.rb b/app/models/communication/website/permalink/category.rb
index 852dbfb3fe07c16c8b5f671e225666688caccb49..b4ae97e26c4ebf150a1e5579a75cfa5e7317c8e4 100644
--- a/app/models/communication/website/permalink/category.rb
+++ b/app/models/communication/website/permalink/category.rb
@@ -33,8 +33,8 @@ class Communication::Website::Permalink::Category < Communication::Website::Perm
   end
 
   # /actualites/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::CommunicationPost).slug_with_ancestors}/:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::CommunicationPost, language: language).slug_with_ancestors}/:slug/"
   end
 
   protected
diff --git a/app/models/communication/website/permalink/diploma.rb b/app/models/communication/website/permalink/diploma.rb
index 64e9f2a9e37862da851be2f0019635105dbbfd7c..8b46f82a384e6ec208415bf4460a328432d040c6 100644
--- a/app/models/communication/website/permalink/diploma.rb
+++ b/app/models/communication/website/permalink/diploma.rb
@@ -33,7 +33,7 @@ class Communication::Website::Permalink::Diploma < Communication::Website::Perma
   end
 
   # /diplomes/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::EducationDiploma).slug_with_ancestors}/:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::EducationDiploma, language: language).slug_with_ancestors}/:slug/"
   end
 end
diff --git a/app/models/communication/website/permalink/organization.rb b/app/models/communication/website/permalink/organization.rb
index c3d3e8ec7d1c9e200d83eba3e935a80b801a82a1..6c203f9e8ab5895887ed9c0683c06a311b669f87 100644
--- a/app/models/communication/website/permalink/organization.rb
+++ b/app/models/communication/website/permalink/organization.rb
@@ -33,7 +33,7 @@ class Communication::Website::Permalink::Organization < Communication::Website::
   end
 
   # /organisations/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Organization).slug_with_ancestors}/:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Organization, language: language).slug_with_ancestors}/:slug/"
   end
 end
diff --git a/app/models/communication/website/permalink/paper.rb b/app/models/communication/website/permalink/paper.rb
index 430fee83b4743d2f765a2391b1576e27da5fd88a..2ef3f41e6fb8c3c8d8b447d1d8aefb1cf7bfd1e7 100644
--- a/app/models/communication/website/permalink/paper.rb
+++ b/app/models/communication/website/permalink/paper.rb
@@ -33,8 +33,8 @@ class Communication::Website::Permalink::Paper < Communication::Website::Permali
   end
 
   # /papiers/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::ResearchPaper).slug_with_ancestors}/:year-:month-:day-:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::ResearchPaper, language: language).slug_with_ancestors}/:year-:month-:day-:slug/"
   end
 
   protected
diff --git a/app/models/communication/website/permalink/person.rb b/app/models/communication/website/permalink/person.rb
index 760c5d9ce0c3ca9a8b5eab4031de9bf0f26bc4bb..82cee2af84fae0494a11e73228a0dd2e3766ef74 100644
--- a/app/models/communication/website/permalink/person.rb
+++ b/app/models/communication/website/permalink/person.rb
@@ -33,7 +33,7 @@ class Communication::Website::Permalink::Person < Communication::Website::Permal
   end
 
   # /equipe/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Person).slug_with_ancestors}/:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Person, language: language).slug_with_ancestors}/:slug/"
   end
 end
diff --git a/app/models/communication/website/permalink/post.rb b/app/models/communication/website/permalink/post.rb
index 8525ea0e63446354baa41106427fb8556fa2debd..b12ce72babd5d143531909e42f75e1f207deeacf 100644
--- a/app/models/communication/website/permalink/post.rb
+++ b/app/models/communication/website/permalink/post.rb
@@ -33,8 +33,8 @@ class Communication::Website::Permalink::Post < Communication::Website::Permalin
   end
 
   # /actualites/2022-10-21-un-article/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::CommunicationPost).slug_with_ancestors}/:year-:month-:day-:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::CommunicationPost, language: language).slug_with_ancestors}/:year-:month-:day-:slug/"
   end
 
   protected
diff --git a/app/models/communication/website/permalink/program.rb b/app/models/communication/website/permalink/program.rb
index 8c1c0e02dda11940996d4c18f0e22708c47399e3..00290533a28e38b844e4abc8ee07b942d8eb99ab 100644
--- a/app/models/communication/website/permalink/program.rb
+++ b/app/models/communication/website/permalink/program.rb
@@ -33,7 +33,7 @@ class Communication::Website::Permalink::Program < Communication::Website::Perma
   end
 
   # /formations/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::EducationProgram).slug_with_ancestors}/:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::EducationProgram, language: language).slug_with_ancestors}/:slug/"
   end
 end
diff --git a/app/models/communication/website/permalink/researcher.rb b/app/models/communication/website/permalink/researcher.rb
index d9a85ca2e6ceac30a2bfd37cbcc414c28dfc45c9..c0b045b8294fd5bb9f25e1859bb87c580eb0deb6 100644
--- a/app/models/communication/website/permalink/researcher.rb
+++ b/app/models/communication/website/permalink/researcher.rb
@@ -32,9 +32,9 @@ class Communication::Website::Permalink::Researcher < Communication::Website::Pe
     :researchers
   end
 
-  # /equipe/:slug/papers/
+  # /equipe/:slug/publications/
   # FIXME
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Person).slug_with_ancestors}/:slug/papers/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Person, language: language).slug_with_ancestors}/:slug/papers/"
   end
 end
diff --git a/app/models/communication/website/permalink/teacher.rb b/app/models/communication/website/permalink/teacher.rb
index 6a75142aa196cd79dd88b2cac0285bd3fcb5c63f..de3dd68499f1dc443ac196c832170d1a4bfbe16e 100644
--- a/app/models/communication/website/permalink/teacher.rb
+++ b/app/models/communication/website/permalink/teacher.rb
@@ -34,7 +34,7 @@ class Communication::Website::Permalink::Teacher < Communication::Website::Perma
 
   # /equipe/:slug/programs/
   # FIXME
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::Person).slug_with_ancestors}/:slug/programs/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::Person, language: language).slug_with_ancestors}/:slug/programs/"
   end
 end
diff --git a/app/models/communication/website/permalink/volume.rb b/app/models/communication/website/permalink/volume.rb
index 96774e65de72512b292fee2ca322f3c8ae6790f6..1ceed05c79f00fcc80e1ffc613899998a68afeba 100644
--- a/app/models/communication/website/permalink/volume.rb
+++ b/app/models/communication/website/permalink/volume.rb
@@ -33,8 +33,8 @@ class Communication::Website::Permalink::Volume < Communication::Website::Permal
   end
 
   # /volumes/:slug/
-  def self.pattern_in_website(website)
-    "/#{website.special_page(Communication::Website::Page::ResearchVolume).slug_with_ancestors}/:year-:slug/"
+  def self.pattern_in_website(website, language)
+    "/#{website.special_page(Communication::Website::Page::ResearchVolume, language: language).slug_with_ancestors}/:year-:slug/"
   end
 
   protected
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 7cbf6a295f3d201d97e8b7fc850bfc4833cb01a5..8a94a8b759d167e677dbc4176ed814f88e0f264b 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -18,7 +18,8 @@
 #  updated_at               :datetime         not null
 #  author_id                :uuid             indexed
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
 # Indexes
@@ -26,11 +27,13 @@
 #  index_communication_website_posts_on_author_id                 (author_id)
 #  index_communication_website_posts_on_communication_website_id  (communication_website_id)
 #  index_communication_website_posts_on_language_id               (language_id)
+#  index_communication_website_posts_on_original_id               (original_id)
 #  index_communication_website_posts_on_university_id             (university_id)
 #
 # Foreign Keys
 #
 #  fk_rails_1e0d058a25  (university_id => universities.id)
+#  fk_rails_bbbef3b1e9  (original_id => communication_website_posts.id)
 #  fk_rails_d1c1a10946  (communication_website_id => communication_websites.id)
 #  fk_rails_e0eec447b0  (author_id => university_people.id)
 #
@@ -44,6 +47,7 @@ class Communication::Website::Post < ApplicationRecord
   include WithMenuItemTarget
   include WithPermalink
   include WithSlug # We override slug_unavailable? method
+  include WithTranslations
 
   has_one :imported_post,
           class_name: 'Communication::Website::Imported::Post',
@@ -54,7 +58,6 @@ class Communication::Website::Post < ApplicationRecord
   belongs_to :author,
              class_name: 'University::Person',
              optional: true
-  belongs_to :language, optional: true
   has_and_belongs_to_many :categories,
                           class_name: 'Communication::Website::Category',
                           join_table: 'communication_website_categories_posts',
@@ -121,8 +124,9 @@ class Communication::Website::Post < ApplicationRecord
     dependencies += git_block_dependencies
     dependencies += university.communication_blocks.where(template_kind: :posts).includes(:about).map(&:about).uniq
     if author.present?
-      dependencies += [author, author.author]
+      dependencies += [author, author.author, translated_author, translated_author.author]
       dependencies += author.active_storage_blobs
+      dependencies += translated_author.active_storage_blobs
     end
     dependencies
   end
@@ -139,6 +143,10 @@ class Communication::Website::Post < ApplicationRecord
     "#{Static.remove_trailing_slash website.url}#{Static.clean_path current_permalink_in_website(website).path}"
   end
 
+  def translated_author
+    @translated_author ||= author.find_or_translate!(language)
+  end
+
   def to_s
     "#{title}"
   end
@@ -147,7 +155,7 @@ class Communication::Website::Post < ApplicationRecord
 
   def slug_unavailable?(slug)
     self.class.unscoped
-              .where(communication_website_id: self.communication_website_id, slug: slug)
+              .where(communication_website_id: self.communication_website_id, language_id: language_id, slug: slug)
               .where.not(id: self.id)
               .exists?
   end
@@ -171,4 +179,12 @@ class Communication::Website::Post < ApplicationRecord
     end
     author.update_and_sync(is_author: true) if author_id
   end
+
+  def translate_additional_data!(translation)
+    categories.each do |category|
+      translated_category = category.find_or_translate!(translation.language)
+      translation.categories << translated_category
+    end
+    translation.update(author_id: author.find_or_translate!(translation.language).id) if author_id.present?
+  end
 end
diff --git a/app/models/communication/website/with_dependencies.rb b/app/models/communication/website/with_dependencies.rb
index 0f3d17760593c3c122fa653e602167d1a5cdf0c0..708ad848f3aade75ce49030ba0481abe7a591b33 100644
--- a/app/models/communication/website/with_dependencies.rb
+++ b/app/models/communication/website/with_dependencies.rb
@@ -84,6 +84,7 @@ module Communication::Website::WithDependencies
   end
 
   def people
+    # TODO: Scoper aux langues du website dans le cas où une personne serait traduite dans + de langues
     @people ||= begin
       people = []
       people += authors if has_authors?
@@ -96,6 +97,7 @@ module Communication::Website::WithDependencies
   end
 
   def people_with_facets
+    # TODO: Scoper aux langues du website dans le cas où une personne serait traduite dans + de langues
     @people_with_facets ||= begin
       people_with_facets = people
       people_with_facets += authors.compact.map(&:author) if has_authors?
diff --git a/app/models/communication/website/with_menus.rb b/app/models/communication/website/with_menus.rb
index 8ed45032fc4cdc2f4c721ab795b723444d17da9e..aa377e88a93ca2629adda552d43c160b5df6bf6c 100644
--- a/app/models/communication/website/with_menus.rb
+++ b/app/models/communication/website/with_menus.rb
@@ -66,33 +66,34 @@ module Communication::Website::WithMenus
   def initialize_menus
     find_or_create_menu 'primary'
     find_or_create_menu 'social'
-    menu = find_or_create_menu 'legal'
-    fill_legal_menu menu
+    find_or_create_menu('legal') do |menu|
+      # Only executed after menu creation
+      fill_legal_menu(menu)
+    end
+  end
+
+  def find_or_create_menu(identifier)
+    menu = menus.where(identifier: identifier, university: university, language: default_language).first_or_initialize do |menu|
+      menu.title = I18n.t("communication.menus.default_title.#{identifier}")
+    end
+    unless menu.persisted?
+      menu.save
+      yield(menu) if block_given?
+    end
+    menu
   end
 
   def fill_legal_menu(menu)
-    return if menu.items.any?
     [
       Communication::Website::Page::LegalTerm,
       Communication::Website::Page::PrivacyPolicy,
       Communication::Website::Page::Accessibility,
       Communication::Website::Page::Sitemap
     ].each do |page_class|
-      page = special_page(page_class)
-      menu.items.where( kind: 'page', 
-                        about: page,
-                        university: university,
-                        website: self)
-                .first_or_create do |item|
+      page = special_page(page_class, language: menu.language)
+      menu.items.where(kind: 'page', about: page, university: university, website: self).first_or_create do |item|
         item.title = page.title
       end
     end
   end
-
-  def find_or_create_menu(identifier)
-    title = Communication::Website::Menu.human_attribute_name(identifier)
-    menus.where(identifier: identifier, university: university).first_or_create do |menu|
-      menu.title = title
-    end
-  end
 end
diff --git a/app/models/communication/website/with_program_categories.rb b/app/models/communication/website/with_program_categories.rb
index 109e5096504ad858ea9f248efba9fd6c2f25a2a3..a2f9bd468a7298aad76962dd2c746e32946ec5b4 100644
--- a/app/models/communication/website/with_program_categories.rb
+++ b/app/models/communication/website/with_program_categories.rb
@@ -5,8 +5,10 @@ module Communication::Website::WithProgramCategories
     after_save_commit :set_programs_categories!, if: -> (website) { website.has_education_programs? }
   end
 
+  # TODO : I18n
+  # Actuellement, on ne crée que dans la langue par défaut du website, on ne gère pas les autres langues
   def set_programs_categories!
-    programs_root_category = categories.where(is_programs_root: true).first_or_create(
+    programs_root_category = categories.for_language_id(default_language_id).where(is_programs_root: true).first_or_create(
       name: 'Offre de formation',
       slug: 'offre-de-formation',
       is_programs_root: true,
@@ -20,7 +22,7 @@ module Communication::Website::WithProgramCategories
 
   def set_programs_categories_at_level!(parent_category, programs)
     programs.map.with_index do |program, index|
-      category = categories.where(program_id: program.id).first_or_initialize(
+      category = categories.for_language_id(default_language_id).where(program_id: program.id).first_or_initialize(
         name: program.name,
         slug: program.name.parameterize,
         university_id: university.id
diff --git a/app/models/communication/website/with_special_pages.rb b/app/models/communication/website/with_special_pages.rb
index aa82562110c39874a53aeb11705e9d0d3e243539..52e36e59acb75057090a8f3075b7d6672d384986 100644
--- a/app/models/communication/website/with_special_pages.rb
+++ b/app/models/communication/website/with_special_pages.rb
@@ -6,16 +6,28 @@ module Communication::Website::WithSpecialPages
     after_touch :create_missing_special_pages
   end
 
-  def special_page(type)
-    pages.where(type: type.to_s).first
+  def special_page(type, language: default_language)
+    find_special_page(type, language) || translate_special_page(type, language)
   end
 
   def create_missing_special_pages
     Communication::Website::Page::TYPES.each do |page_class|
-      page = page_class.where(website: self, university: university).first_or_initialize # Special pages have an before_validation (:on_create) callback to preset title, slug, ...
+      page = page_class.where(website: self, university: university, language_id: default_language_id).first_or_initialize # Special pages have an before_validation (:on_create) callback to preset title, slug, ...
       next if page.persisted? # No resave
       next unless page.is_necessary_for_website? # No useless pages
       page.save_and_sync
     end
   end
+
+  protected
+
+  def find_special_page(type, language)
+    pages.where(type: type.to_s, language_id: language.id).first
+  end
+
+  def translate_special_page(type, language)
+    # Not found for given language, we create it from the page in default_language
+    original_special_page = pages.where(type: type.to_s, language_id: default_language_id).first
+    original_special_page.translate!(language) if original_special_page.present?
+  end
 end
diff --git a/app/models/concerns/with_blocks.rb b/app/models/concerns/with_blocks.rb
index a710e06fbb736c612fb74cb2e607910f6cf877e3..ccf1e024f8c47811b2990cf26529470406f5ca17 100644
--- a/app/models/concerns/with_blocks.rb
+++ b/app/models/concerns/with_blocks.rb
@@ -11,7 +11,8 @@ module WithBlocks
 
   # Basic rule is: TOC if 2 titles or more
   def show_toc?
-    blocks.collect(&:title)
+    blocks.published
+          .collect(&:title)
           .reject(&:blank?)
           .many?
   end
diff --git a/app/models/concerns/with_featured_image.rb b/app/models/concerns/with_featured_image.rb
index 615a2e0ba03810fa32efafddb0585040351a10ad..d7f8102d2d1fa8bdffe9a164adc8598a1c6b8bde 100644
--- a/app/models/concerns/with_featured_image.rb
+++ b/app/models/concerns/with_featured_image.rb
@@ -33,23 +33,16 @@ module WithFeaturedImage
     photo = Unsplash::Photo.find id
     url = "#{photo['urls']['full']}&w=2048&fit=max"
     filename = "#{photo['id']}.jpg"
-    begin
-      file = URI.open url
-      featured_image.attach(io: file, filename: filename)
-      photo.track_download
-    rescue
-    end
+    file = URI.open url
+    featured_image.attach(io: file, filename: filename)
+    photo.track_download
   end
 
   def photo_import_pexels(id)
     photo = Pexels::Client.new.photos.find id
     url = "#{photo.src['original']}?auto=compress&cs=tinysrgb&w=2048"
     filename = "#{photo.id}.png"
-    begin
-      file = URI.open url
-      featured_image.attach(io: file, filename: filename)
-    rescue
-      byebug
-    end
+    file = URI.open url
+    featured_image.attach(io: file, filename: filename)
   end
 end
diff --git a/app/models/concerns/with_git.rb b/app/models/concerns/with_git.rb
index 6fec8601b9fbb866450d12192d19f6abd910f77a..e920fb7c867e2af41471c49998ac08d123c05109 100644
--- a/app/models/concerns/with_git.rb
+++ b/app/models/concerns/with_git.rb
@@ -13,12 +13,11 @@ module WithGit
   end
 
   def git_path_content_prefix(website)
-    # Handle legacy language-less websites
-    # TODO I18n: Right now, we use the language of the website. It HAS TO get the language from the object including this concern.
+    # Handle language-less objects
+    # TODO I18n: Right now, we use the language of the object, fallbacking on the language of the website. In the end, we'll only use the language of the object
     path = "content/"
-    if website.languages.any?
-      path += "#{website.default_language.iso_code}/"
-    end
+    path_language = respond_to?(:language_id) && language_id.present? ? language : website.default_language
+    path += "#{path_language.iso_code}/"
     path
   end
 
diff --git a/app/models/concerns/with_slug.rb b/app/models/concerns/with_slug.rb
index 26fbf3ab9f5a784aa76967808c5c2bd57c570426..7f3dc552cff3b16833bffc882a6d5c3dde7fae41 100644
--- a/app/models/concerns/with_slug.rb
+++ b/app/models/concerns/with_slug.rb
@@ -25,8 +25,11 @@ module WithSlug
     protected
 
     def slug_unavailable?(slug)
+      existence_params = { university_id: self.university_id, slug: slug }
+      existence_params[:language_id] = self.language_id if respond_to?(:language_id)
+
       self.class.unscoped
-                .where(university_id: self.university_id, slug: slug)
+                .where(**existence_params)
                 .where.not(id: self.id)
                 .exists?
     end
@@ -37,7 +40,7 @@ module WithSlug
     end
 
     def slug_must_be_unique
-      errors.add(:slug, ActiveRecord::Errors.default_error_messages[:taken]) if slug_unavailable?(slug)
+      errors.add(:slug, :taken) if slug_unavailable?(slug)
     end
   end
 end
diff --git a/app/models/concerns/with_translations.rb b/app/models/concerns/with_translations.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3d1771af782eeccbbe4ecb55004e9a3f356eef04
--- /dev/null
+++ b/app/models/concerns/with_translations.rb
@@ -0,0 +1,102 @@
+module WithTranslations
+  extend ActiveSupport::Concern
+
+  included do
+    attr_accessor :newly_translated
+
+    belongs_to  :language
+    belongs_to  :original, class_name: base_class.to_s, optional: true
+    has_many    :translations, class_name: base_class.to_s, foreign_key: :original_id, dependent: :nullify
+
+    scope :for_language, -> (language) { for_language_id(language.id) }
+    # The for_language_id scope can be used when you have the ID without needing to load the Language itself
+    scope :for_language_id, -> (language_id) { where(language_id: language_id) }
+
+  end
+
+  def available_languages
+    @available_languages ||= begin
+      languages = respond_to?(:website) ? website.languages : Language.all
+      languages.ordered
+    end
+  end
+
+  def find_or_translate!(language)
+    translation = translation_for(language)
+    translation ||= translate!(language)
+    translation
+  end
+
+  def translation_for(language)
+    # If the requested language is the object language, we return itself
+    return self if language_id == language.id
+    # All translations share the same original.
+    # If the current object is a translation, we call translation_for on the original.
+    # Else, if the current object is the original, we search the translation with the language.
+    original_id.present?  ? original.translation_for(language)
+                          : translations.find_by(language_id: language.id)
+  end
+
+  def original_object
+    @original_object ||= (self.original || self)
+  end
+
+  def original_with_translations
+    original_object.translations + [original_object]
+  end
+
+  # Used by Hugo to link translations with themselves
+  def static_translation_key
+    "#{self.class.polymorphic_name.parameterize}-#{self.original_object.id}"
+  end
+
+  def translate!(language)
+    translation = self.dup
+
+    # Inherits from original_id or set it to itself
+    translation.assign_attributes(
+      original_id: original_object.id,
+      language_id: language.id,
+      newly_translated: true
+    )
+
+    # Handle publication
+    translation.published = false if respond_to?(:published)
+    # Translate parent if needed
+    translation.parent_id = translate_parent!(language)&.id if respond_to?(:parent_id)
+    # Handle featured image if object has one
+    translate_attachment(translation, :featured_image) if respond_to?(:featured_image) && featured_image.attached?
+    translation.save
+    # Handle blocks if object has any
+    translate_blocks!(translation) if respond_to?(:blocks)
+    translate_additional_data!(translation)
+
+    translation
+  end
+
+  protected
+
+  def translate_parent!(language)
+    return nil if parent_id.nil?
+    parent.find_or_translate!(language)
+  end
+
+  def translate_blocks!(translation)
+    blocks.ordered.each do |block|
+      block.translate!(translation)
+    end
+  end
+
+  # Utility method to duplicate attachments
+  def translate_attachment(translation, attachment_name)
+    translation.public_send(attachment_name).attach(
+      io: URI.open(public_send(attachment_name).url),
+      filename: public_send(attachment_name).filename.to_s,
+      content_type: public_send(attachment_name).content_type
+    )
+  end
+
+  def translate_additional_data!(translation)
+    # Overridable method to handle custom cases
+  end
+end
\ No newline at end of file
diff --git a/app/models/education.rb b/app/models/education.rb
index e344ff6a4eb670acefb2ee9cf5b08b3edd9dc02d..e4aa5f201b27d3ed21ab0216d422495eb7bb77ec 100644
--- a/app/models/education.rb
+++ b/app/models/education.rb
@@ -5,4 +5,13 @@ module Education
   def self.table_name_prefix
     'education_'
   end
+
+  def self.parts
+    [
+      [University::Person::Teacher, :admin_education_teachers_path],
+      [Education::School, :admin_education_schools_path],
+      [Education::Diploma, :admin_education_diplomas_path],
+      [Education::Program, :admin_education_programs_path],
+    ]
+  end
 end
diff --git a/app/models/language.rb b/app/models/language.rb
index 047a01e1ac38ade22b87e265ec4989127079d4ca..36cf5338a0bc6d3f337c79dcac2fdaacb195158f 100644
--- a/app/models/language.rb
+++ b/app/models/language.rb
@@ -20,7 +20,7 @@ class Language < ApplicationRecord
   validates_presence_of :iso_code
   validates_uniqueness_of :iso_code
 
-  default_scope { order(name: :asc) }
+  scope :ordered, -> { order(name: :asc) }
 
   def to_s
     "#{name}"
diff --git a/app/models/research.rb b/app/models/research.rb
index ac5b622d13967b4ff83fd5d74e8559cf5948eec0..0c9050ee5598f8415c07587e3041291f8958a9fe 100644
--- a/app/models/research.rb
+++ b/app/models/research.rb
@@ -5,4 +5,14 @@ module Research
   def self.table_name_prefix
     'research_'
   end
+
+  def self.parts
+    [
+      [University::Person::Researcher, :admin_research_researchers_path],
+      [Research::Laboratory, :admin_research_laboratories_path],
+      [Research::Thesis, :admin_research_theses_path],
+      [Research::Journal, :admin_research_journals_path],
+      [Research::Publication, :admin_research_publications_path],
+    ]
+  end
 end
diff --git a/app/models/research/publication.rb b/app/models/research/publication.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3fd2eaa29a0b8c495040f8e428a20a62b17b40dd
--- /dev/null
+++ b/app/models/research/publication.rb
@@ -0,0 +1,81 @@
+# == Schema Information
+#
+# Table name: research_publications
+#
+#  id               :uuid             not null, primary key
+#  data             :jsonb
+#  docid            :string           indexed
+#  doi              :string
+#  hal_url          :string
+#  publication_date :date
+#  ref              :string
+#  slug             :string
+#  title            :string
+#  url              :string
+#  created_at       :datetime         not null
+#  updated_at       :datetime         not null
+#
+# Indexes
+#
+#  index_research_publications_on_docid  (docid)
+#
+class Research::Publication < ApplicationRecord
+  include WithGit
+  include WithSlug
+
+  DOI_PREFIX = 'http://dx.doi.org/'.freeze
+
+  has_and_belongs_to_many :research_people,
+                          class_name: 'University::Person', 
+                          foreign_key: 'university_person_id',
+                          association_foreign_key: 'research_publication_id'
+  alias :researchers :research_people
+
+  before_destroy { research_people.clear }
+
+  validates_presence_of :docid
+
+  scope :ordered, -> { order(publication_date: :desc)}
+
+  def self.create_from(doc)
+    publication = where(docid: doc.docid).first_or_create
+    puts "pub-- #{where(docid: doc.docid).count}"
+    publication.title = doc.title_s.first
+    publication.ref = doc.attributes['citationRef_s']
+    publication.hal_url = doc.attributes['uri_s']
+    publication.doi = doc.attributes['doiId_s']
+    publication.publication_date = doc.attributes['publicationDate_tdate']
+    publication.url = doc.attributes['linkExtUrl_s']
+    publication.save
+    publication
+  end
+
+  def self.update_from_hal
+    University::Person::Researcher.with_hal_identifier.find_each do |researcher|
+      puts "Loading publications for #{researcher} (#{researcher.university})"
+      researcher.import_research_publications_from_hal!
+    end
+  end
+
+  def template_static
+    "admin/research/publications/static"
+  end
+
+  def doi_url
+    return unless doi.present?
+    "#{DOI_PREFIX}#{doi}"
+  end
+
+  def to_s
+    "#{title}"
+  end
+
+  protected
+
+  def slug_unavailable?(slug)
+    self.class.unscoped
+              .where(slug: slug)
+              .where.not(id: self.id)
+              .exists?
+  end
+end
diff --git a/app/models/university.rb b/app/models/university.rb
index 96f44ec4a8cf892d7a063d72b354b6ab28550507..15691d83123a5909d84f87a8c0616201f32a9c23 100644
--- a/app/models/university.rb
+++ b/app/models/university.rb
@@ -25,6 +25,15 @@
 #  zipcode                    :string
 #  created_at                 :datetime         not null
 #  updated_at                 :datetime         not null
+#  default_language_id        :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_universities_on_default_language_id  (default_language_id)
+#
+# Foreign Keys
+#
+#  fk_rails_a8022b1c3f  (default_language_id => languages.id)
 #
 class University < ApplicationRecord
   self.filter_attributes += [:sso_cert]
@@ -43,8 +52,8 @@ class University < ApplicationRecord
   # Can't use dependent: :destroy because of attachments
   # We use after_destroy to let the attachment go first
   has_many :active_storage_blobs, class_name: 'ActiveStorage::Blob'
-
   has_many :imports, dependent: :destroy
+  belongs_to :default_language, class_name: "Language"
 
   validates_presence_of :name
   validates :sms_sender_name, presence: true, length: { maximum: 11 }
@@ -54,6 +63,15 @@ class University < ApplicationRecord
 
   scope :ordered, -> { order(:name) }
 
+  def self.parts
+    [
+      [University::Person, :admin_university_people_path],
+      [University::Organization, :admin_university_organizations_path],
+      [University::Person::Alumnus, :admin_university_alumni_path],
+      [User, :admin_users_path],
+    ]
+  end
+
   def to_s
     "#{name}"
   end
diff --git a/app/models/university/person.rb b/app/models/university/person.rb
index 538650c915ef4d9860d232dea8da1e85ba72ac87..79fa067b96e993e0dbdc0f4bdbd2c986d129f667 100644
--- a/app/models/university/person.rb
+++ b/app/models/university/person.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
@@ -58,6 +67,8 @@ class University::Person < ApplicationRecord
   include WithRoles
   include WithBlocks
   include WithPermalink
+  include WithResearch
+  include WithTranslations
 
   LIST_OF_ROLES = [
     :administration,
@@ -109,7 +120,7 @@ class University::Person < ApplicationRecord
 
   validates_presence_of   :first_name, :last_name
   validates_uniqueness_of :email,
-                          scope: :university_id,
+                          scope: [:university_id, :language_id],
                           allow_blank: true,
                           if: :will_save_change_to_email?
   validates_format_of     :email,
@@ -237,4 +248,8 @@ class University::Person < ApplicationRecord
   def prepare_name
     self.name = to_s
   end
+
+  def translate_additional_data!(translation)
+    translate_attachment(translation, :picture) if picture.attached?
+  end
 end
diff --git a/app/models/university/person/administrator.rb b/app/models/university/person/administrator.rb
index bac4deebe718a2416d90e51c40693d7e3c8c8339..c0978fc99478aea49b40d70e86cd82845c2c2dcc 100644
--- a/app/models/university/person/administrator.rb
+++ b/app/models/university/person/administrator.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
diff --git a/app/models/university/person/alumnus.rb b/app/models/university/person/alumnus.rb
index cecc421cd2f061798f2cfc03a20c9fa04c20ef6b..4bd99ef4673019367c3dca60ca436edc512faa85 100644
--- a/app/models/university/person/alumnus.rb
+++ b/app/models/university/person/alumnus.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
diff --git a/app/models/university/person/author.rb b/app/models/university/person/author.rb
index ce3bad531fb8019ade2136e103b17bdf299d4128..2abf6521682dbc795a30ef64c16fecc3f92b27f1 100644
--- a/app/models/university/person/author.rb
+++ b/app/models/university/person/author.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
diff --git a/app/models/university/person/researcher.rb b/app/models/university/person/researcher.rb
index aa2415f64931c64dab1857e259cff3b0d4e75ed1..ede0bf421f31f36a451762c44c1fcf5433759516 100644
--- a/app/models/university/person/researcher.rb
+++ b/app/models/university/person/researcher.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
diff --git a/app/models/university/person/teacher.rb b/app/models/university/person/teacher.rb
index 66d8f2af271b6524093d1648bd4710861269a039..515a4f47e697bd4c04a30b1f9a2aaae2abad1f46 100644
--- a/app/models/university/person/teacher.rb
+++ b/app/models/university/person/teacher.rb
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
diff --git a/app/models/university/person/with_research.rb b/app/models/university/person/with_research.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8292f37dc842d16751e6d9c6e79a6b953ed4fc40
--- /dev/null
+++ b/app/models/university/person/with_research.rb
@@ -0,0 +1,34 @@
+module University::Person::WithResearch
+  extend ActiveSupport::Concern
+
+  included do
+    has_and_belongs_to_many :research_publications,
+                            class_name: 'Research::Publication', 
+                            foreign_key: 'research_publication_id',
+                            association_foreign_key: 'university_person_id'
+    alias :publications :research_publications
+
+    scope :with_hal_identifier, -> { where.not(hal_form_identifier: [nil,'']) }
+  end
+
+  def hal_identity?
+    hal_form_identifier.present?
+  end
+
+  def import_research_publications_from_hal!
+    return unless hal_identity?
+    response = HalOpenscience::Document.search  "authIdForm_i:#{hal_form_identifier}",
+                                                fields: ["docid", "title_s", "citationRef_s", "uri_s", "*"],
+                                                limit: 1000
+    response.results.each do |doc|
+      publication = Research::Publication.create_from doc
+      research_publications << publication unless publication.in?(research_publications)
+    end
+  end
+  handle_asynchronously :import_research_publications_from_hal!
+
+  def possible_hal_authors
+    HalOpenscience::Author.search(to_s, fields: ['*']).results
+  end
+
+end
diff --git a/app/models/user/with_person.rb b/app/models/user/with_person.rb
index 0b6a4a000c386beb42461c34793b0375a121d29b..dbebb00057ef1745e05897dea070661a153d3ef4 100644
--- a/app/models/user/with_person.rb
+++ b/app/models/user/with_person.rb
@@ -2,7 +2,8 @@ module User::WithPerson
   extend ActiveSupport::Concern
 
   included do
-    has_one :person, class_name: 'University::Person', dependent: :nullify
+    # Original person
+    has_one :person, -> { where(original_id: nil) }, class_name: 'University::Person', dependent: :nullify
 
     delegate :experiences, to: :person
 
@@ -18,6 +19,7 @@ module User::WithPerson
     person.last_name = last_name
     person.slug = person.to_s.parameterize
     person.user = self
+    person.language_id ||= university.default_language_id
     person.save
   end
 
diff --git a/app/services/appstack/simple_navigation_renderer.rb b/app/services/appstack/simple_navigation_renderer.rb
index 65bb6925629ba9315633311bcc6a77c7deff6538..3e856e3e4c41ef6bc422af6cd6db7131141845a1 100644
--- a/app/services/appstack/simple_navigation_renderer.rb
+++ b/app/services/appstack/simple_navigation_renderer.rb
@@ -27,7 +27,7 @@ class Appstack::SimpleNavigationRenderer < SimpleNavigation::Renderer::Base
   def make_header(item)
     icon = item.send(:options)[:icon]
     header = '<li class="sidebar-header">'
-    header += "<i class=\"fas fa-#{ icon }\"></i>" if icon
+    header += "<i class=\"#{ icon }\"></i>" if icon
     header += item.name
     header += '</li>'
     header
@@ -38,7 +38,7 @@ class Appstack::SimpleNavigationRenderer < SimpleNavigation::Renderer::Base
     a = "<a href=\"#{ item.url }\" class=\"sidebar-link#{ item.selected? ? '' : ' collapsed' }\""
     a += " data-bs-target=\"##{ item.key }\" data-bs-toggle=\"collapse\"" if consider_sub_navigation?(item)
     a += ">"
-    a += "<i class=\"fas fa-#{ icon }\"></i>" if icon
+    a += "<i class=\"#{ icon }\"></i>" if icon
     a += "<span class=\"align-middle\">#{ item.name }</span></a>"
     a
   end
diff --git a/app/services/curator.rb b/app/services/curator.rb
index e00294534042c9eab0d457130569b7ca4a65b832..4f7c5042800995657d8cb46f6614626fb6e8a485 100644
--- a/app/services/curator.rb
+++ b/app/services/curator.rb
@@ -1,9 +1,10 @@
 class Curator
-  attr_reader :website, :user, :url, :post
+  attr_reader :website, :user, :language, :url, :post
 
-  def initialize(website, user, url)
+  def initialize(website, user, language, url)
     @website = website
     @user = user
+    @language = language
     @url = url
     create_post!
     attach_image! unless page.image.blank?
@@ -22,7 +23,8 @@ class Curator
       title: page.title,
       slug: page.title.parameterize,
       author: @user.person,
-      published_at: Time.now
+      published_at: Time.now,
+      language_id: @language.id
     )
     @chapter = @post.blocks.create(
       university: website.university,
diff --git a/app/services/filters/server/websites.rb b/app/services/filters/server/websites.rb
new file mode 100644
index 0000000000000000000000000000000000000000..120ed5e58546f251e463ab8e823da91c00b669ad
--- /dev/null
+++ b/app/services/filters/server/websites.rb
@@ -0,0 +1,11 @@
+module Filters
+  class Server::Websites < Filters::Base
+    def initialize(user)
+      super
+      add_search
+      add :for_theme_version,
+          ::Communication::Website.all.pluck(:theme_version).uniq.sort,
+          'Filtrer par version du thème'
+    end
+  end
+end
diff --git a/app/services/icon.rb b/app/services/icon.rb
index f67430b5860ec5d0f42f220593c05d7517d160bd..02c54be4f52491027e467ed55c5f3f7fea286210 100644
--- a/app/services/icon.rb
+++ b/app/services/icon.rb
@@ -1,31 +1,75 @@
 # used in menu items and in admin navigation
 class Icon
-  DASHBOARD = 'chart-line'
+  DASHBOARD = 'fas fa-chart-line'
 
-  COMMUNICATION_EXTRANET = 'project-diagram'
-  COMMUNICATION_WEBSITE = 'sitemap'
-  COMMUNICATION_WEBSITE_HOME = 'home'
-  COMMUNICATION_WEBSITE_POST = 'newspaper'
-  COMMUNICATION_WEBSITE_PAGE = 'file'
-  COMMUNICATION_WEBSITE_PAGES = 'sitemap'
-  COMMUNICATION_WEBSITE_MENUS = 'bars'
-  COMMUNICATION_WEBSITE_ANALYTICS = 'chart-pie'
-  COMMUNICATION_WEBSITE_PREVIEW_MOBILE = 'mobile-alt'
-  COMMUNICATION_WEBSITE_PREVIEW_TABLET = 'tablet-alt'
-  COMMUNICATION_WEBSITE_PREVIEW_DESKTOP = 'laptop'
+  COMMUNICATION_EXTRANET = 'fas fa-project-diagram'
+  COMMUNICATION_WEBSITE = 'fas fa-sitemap'
+  COMMUNICATION_WEBSITE_HOME = 'fas fa-home'
+  COMMUNICATION_WEBSITE_POST = 'fas fa-newspaper'
+  COMMUNICATION_WEBSITE_PAGE = 'fas fa-file'
+  COMMUNICATION_WEBSITE_PAGES = 'fas fa-sitemap'
+  COMMUNICATION_WEBSITE_MENUS = 'fas fa-bars'
+  COMMUNICATION_WEBSITE_ANALYTICS = 'fas fa-chart-pie'
+  COMMUNICATION_WEBSITE_PREVIEW_MOBILE = 'fas fa-mobile-alt'
+  COMMUNICATION_WEBSITE_PREVIEW_TABLET = 'fas fa-tablet-alt'
+  COMMUNICATION_WEBSITE_PREVIEW_DESKTOP = 'fas fa-laptop'
+  COMMUNICATION_WEBSITE_MENU_BLANK = 'fas fa-font'
+  COMMUNICATION_WEBSITE_MENU_URL = 'fas fa-globe'
+  COMMUNICATION_NEWSLETTERS = 'fas fa-envelope'
 
-  EDUCATION_DIPLOMA = 'graduation-cap'
-  EDUCATION_PROGRAM = 'chalkboard-teacher'
-  EDUCATION_SCHOOL = 'university'
-  EDUCATION_TEACHER = 'user-graduate'
+  EDUCATION_DIPLOMA = 'fas fa-graduation-cap'
+  EDUCATION_PROGRAM = 'fas fa-chalkboard-teacher'
+  EDUCATION_SCHOOL = 'fas fa-university'
+  EDUCATION_TEACHER = 'fas fa-user-graduate'
+  EDUCATION_RESOURCES = 'fas fa-laptop'
+  EDUCATION_FEEDBACKS = 'fas fa-comments'
 
-  RESEARCH_JOURNAL = 'newspaper'
-  RESEARCH_LABORATORY = 'flask'
-  RESEARCH_RESEARCHER = 'microscope'
-  RESEARCH_THESE = 'scroll'
+  RESEARCH_JOURNAL = 'fas fa-newspaper'
+  RESEARCH_LABORATORY = 'fas fa-flask'
+  RESEARCH_RESEARCHER = 'fas fa-microscope'
+  RESEARCH_PUBLICATION = 'fas fa-book'
+  RESEARCH_THESE = 'fas fa-scroll'
+  RESEARCH_WATCH = 'fas fa-eye'
+  UNIVERSITY_PERSON_RESEARCHER = RESEARCH_RESEARCHER
+  RESEARCH_THESIS = RESEARCH_THESE
 
-  UNIVERSITY_ORGANIZATION = 'building'
-  UNIVERSITY_PERSON = 'users'
-  UNIVERSITY_PERSON_ADMINISTRATORS = 'users-cog'
-  UNIVERSITY_PERSON_ALUMNUS = 'user-graduate'
+  ADMINISTRATION_CAMPUS = 'fas fa-map-marker-alt'
+  ADMINISTRATION_ADMISSIONS = 'fas fa-door-open'
+  ADMINISTRATION_INTERNSHIPS = 'fas fa-hands-helping'
+  ADMINISTRATION_STATISTICS = 'fas fa-chart-bar'
+  ADMINISTRATION_QUALITY = 'fas fa-tasks'
+  ADMINISTRATION_QUALIOPI = ADMINISTRATION_QUALITY
+
+  UNIVERSITY_ORGANIZATION = 'fas fa-building'
+  UNIVERSITY_PERSON = 'fas fa-users'
+  UNIVERSITY_PERSON_ADMINISTRATORS = 'fas fa-users-cog'
+  UNIVERSITY_PERSON_ALUMNUS = 'fas fa-user-graduate'
+  UNIVERSITY_PERSON_TEACHER = EDUCATION_TEACHER
+
+  OSUNY_USER = 'fas fa-user'
+  USER = OSUNY_USER
+  
+  ADD = 'fas fa-plus'
+  ARROW_RIGHT = 'fas fa-arrow-right'
+  A11Y = 'fas fa-universal-access'
+  CHECK_OK = 'fas fa-check'
+  CHECK_KO = 'fas fa-times'
+  FOLDER_CLOSED = 'far fa-folder'
+  FOLDER_OPENED = 'far fa-folder-open'
+  FOLDER_CLOSED_FULL = 'fas fa-folder'
+  FOLDER_OPENED_FULL = 'fas fa-folder-open'
+  DRAG = 'fas fa-bars'
+  DELETE = 'fas fa-times'
+  FILE = 'fas fa-file'
+  FILTERS = 'fas fa-filter'
+  MOVE = 'fas fa-arrows-alt'
+  SETTINGS = 'fas fa-gear'
+  SORT = 'fas fa-sort'
+  WARNING = 'fas fa-exclamation-circle'
+
+  def self.icon_for(class_name)
+    # University::Person::Teacher -> UNIVERSITY_PERSON_TEACHER
+    constant = class_name.to_s.remove('::').underscore.upcase
+    const_get constant
+  end
 end
diff --git a/app/services/osuny/simple_navigation_renderer.rb b/app/services/osuny/simple_navigation_renderer.rb
index 18d8d9238f79dd6a9bfe64b253061af9b27ef738..b6857b68e21279677696b68b500714ad00d18d76 100644
--- a/app/services/osuny/simple_navigation_renderer.rb
+++ b/app/services/osuny/simple_navigation_renderer.rb
@@ -20,14 +20,27 @@ class Osuny::SimpleNavigationRenderer < SimpleNavigation::Renderer::Base
 
   def build
     if @index.zero?
-      @content << "#{OPEN}<h2>#{item_name_and_link}</h2>"
+      @content << part
     elsif item_is_header?
-      @content << "</ul>#{CLOSE}#{OPEN}<h2>#{item_name_and_link}</h2><ul>"
+      @content << "</ul>#{CLOSE}#{part}"
     else
       @content << "<li>#{item_name_and_link}</li>"
     end
   end
 
+  def part
+    part = OPEN
+    if item.options.has_key? :image
+      image = item.options[:image]
+      part += "<a href=\"#{item.url}\">"
+      part += ActionController::Base.helpers.image_tag image, class: 'image', loading: :lazy
+      part += "</a>"
+    end
+    part += "<h2>#{item_name_and_link}</h2>"
+    part += "<ul>"
+    part
+  end
+
   def item_is_header?
     item.send(:options)[:kind] == :header
   end
diff --git a/app/views/admin/administration/qualiopi/evaluations/_list.html.erb b/app/views/admin/administration/qualiopi/evaluations/_list.html.erb
index 1d15f6796c7018ef9b52e8a7739ca05f3ec01cf6..376cd32fd783bfdbc8ed1c07f183bf4f717d1a51 100644
--- a/app/views/admin/administration/qualiopi/evaluations/_list.html.erb
+++ b/app/views/admin/administration/qualiopi/evaluations/_list.html.erb
@@ -25,9 +25,9 @@
             <% valid = !program.public_send("best_#{check}").blank? %>
             <td>
               <% if valid %>
-                <span class="fas fa-check text-success"></span>
+                <span class="<%= Icon::CHECK_OK %> text-success"></span>
               <% else %>
-                <span class="fas fa-times text-danger"></span>
+                <span class="<%= Icon::CHECK_KO %> text-danger"></span>
               <% end %>
             </td>
           <% end %>
diff --git a/app/views/admin/application/_dependencies.html.erb b/app/views/admin/application/_dependencies.html.erb
index b9aa06804d5bd5bd433980ac994ea4777059d4d9..8724d1fb9edcd9d8e533450c0557e59030f78c0a 100644
--- a/app/views/admin/application/_dependencies.html.erb
+++ b/app/views/admin/application/_dependencies.html.erb
@@ -2,7 +2,7 @@
 expanded ||= false
 %>
 <% if current_user.server_admin? %>
-<i  class="fas fa-gear text-muted"
+<i  class="<%= Icon::SETTINGS %> text-muted"
     data-bs-toggle="collapse"
     data-bs-target="#dependencies"
     aria-expanded="<%= expanded %>"
diff --git a/app/views/admin/application/_filters.html.erb b/app/views/admin/application/_filters.html.erb
index 5378f14976bac2f134b718abb4d9ac259dd67477..236a941117515b78741c93502e8b6303dafb5f3a 100644
--- a/app/views/admin/application/_filters.html.erb
+++ b/app/views/admin/application/_filters.html.erb
@@ -6,14 +6,14 @@ filters.each { |filter| should_be_open = true if params.has_key?(filter[:scope_n
 
 <div class="filters">
   <% if collapsable %>
-    <a  class="btn btn-outline-secondary btn-sm filters__button"
+    <a  class="btn btn-light btn-xs filters__button"
         data-bs-toggle="collapse"
         href="#collapseFilters"
         role="button"
         aria-expanded="false"
         aria-controls="collapseFilters">
-      <i class="fas fa-filter"></i>
       <%= t('filters.buttons.expand') %>
+      <i class="<%= Icon::FILTERS %>"></i>
     </a>
   <% end %>
   <div class="collapse filters__content <%= (!collapsable || should_be_open) ? 'show' : '' %>" id="collapseFilters">
diff --git a/app/views/admin/application/_preview.html.erb b/app/views/admin/application/_preview.html.erb
index 621ee83f372b1055cb0863c26b0e446afcdabdf3..25e4e28ba6fad24a33752846a0069c308f9f7b75 100644
--- a/app/views/admin/application/_preview.html.erb
+++ b/app/views/admin/application/_preview.html.erb
@@ -8,15 +8,15 @@
         <h5 class="modal-title h4"><%= t 'preview.title' %></h5>
         <div class="btn-group m-auto" role="group" aria-label="Basic example">
           <button type="button" class="btn btn-primary preview__button" data-mode="mobile">
-            <i class="fas fa-<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_MOBILE %>"></i>
+            <i class="<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_MOBILE %>"></i>
             <%= t 'preview.mobile' %>
           </button>
           <button type="button" class="btn btn-light preview__button" data-mode="tablet">
-            <i class="fas fa-<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_TABLET %>"></i>
+            <i class="<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_TABLET %>"></i>
             <%= t 'preview.tablet' %>
           </button>
           <button type="button" class="btn btn-light preview__button" data-mode="desktop">
-            <i class="fas fa-<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_DESKTOP %>"></i>
+            <i class="<%= Icon::COMMUNICATION_WEBSITE_PREVIEW_DESKTOP %>"></i>
             <%= t 'preview.desktop' %>
           </button>
         </div>
diff --git a/app/views/admin/application/a11y/_widget.html.erb b/app/views/admin/application/a11y/_widget.html.erb
index 6da09712b7044b74ed0fea3db2e4710d6b8e77aa..db26884e8fade959e33833d574f80b53d5ed1e35 100644
--- a/app/views/admin/application/a11y/_widget.html.erb
+++ b/app/views/admin/application/a11y/_widget.html.erb
@@ -1,6 +1,6 @@
 <%
 color = about.accessible? ? 'text-success' : 'text-danger'
-action = "<i class=\"fas fa-universal-access fa-2x float-end #{ color}\"></i>"
+action = "<i class=\"#{ Icon::A11Y } fa-2x float-end #{ color}\"></i>"
 %>
 <%= osuny_panel t('accessibility.label'), action: action do %>
   <% if about.accessibility_errors.any? %>
diff --git a/app/views/admin/application/i18n/_static.html.erb b/app/views/admin/application/i18n/_static.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..fa2ffb096321e9dcc5024e674a951095da44d952
--- /dev/null
+++ b/app/views/admin/application/i18n/_static.html.erb
@@ -0,0 +1 @@
+translation_key: <%= @about.static_translation_key %>
diff --git a/app/views/admin/application/i18n/_widget.html.erb b/app/views/admin/application/i18n/_widget.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..716cb26bd4dec9596b66ebe2b08cae08a2833487
--- /dev/null
+++ b/app/views/admin/application/i18n/_widget.html.erb
@@ -0,0 +1,17 @@
+<% if about.available_languages.many? %>
+  <%
+    route_args = about.respond_to?(:website)  ? [:admin, about.becomes(about.class.base_class)]
+                                              : [:show_in_language, :admin, about.becomes(about.class.base_class)]
+  %>
+  <%= osuny_panel t('internationalization.label') do %>
+    <ol class="list-unstyled">
+      <% about.available_languages.each do |language| %>
+        <%
+        label = t(language.iso_code, scope: :languages)
+        current = language.id == about.language_id
+        %>
+        <li><%= link_to_unless current, label, [*route_args, lang: language.iso_code] %></li>
+      <% end %>
+    </ol>
+  <% end %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/admin/application/property/_summernote_embeds.html.erb b/app/views/admin/application/property/_summernote_embeds.html.erb
index 22dac78fd23104c78bc46305abc352641ffac0a9..a714433bb7206bedbfd181746949d5b0a1852a95 100644
--- a/app/views/admin/application/property/_summernote_embeds.html.erb
+++ b/app/views/admin/application/property/_summernote_embeds.html.erb
@@ -7,7 +7,7 @@
           <% if embed.variable? %>
             <%= kamifusen_tag embed, class: 'img-fluid' %>
           <% else %>
-            <i class="fas fa-file p-3 fa-2x"></i>
+            <i class="<%= Icon::FILE %> p-3 fa-2x"></i>
           <% end %>
         </div>
       </div>
diff --git a/app/views/admin/application/property/_text.html.erb b/app/views/admin/application/property/_text.html.erb
index 9e05d1f266b8618588b8eb6c45059f7a93705b43..48fe15966b78b015fc890fd8cc27fa5eb18e6060 100644
--- a/app/views/admin/application/property/_text.html.erb
+++ b/app/views/admin/application/property/_text.html.erb
@@ -14,7 +14,7 @@ end
 <%= osuny_label title %>
 <p>
   <% if Static.blank?(value) %>
-    <i class="fa fa-exclamation-circle text-danger"></i>
+    <i class="<%= Icon::WARNING %> text-danger"></i>
     <%= t 'properties.text.missing' %>
   <% else %>
     <%= strip_tags(value).truncate(200).html_safe %>
diff --git a/app/views/admin/application/tree/_folder.html.erb b/app/views/admin/application/tree/_folder.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..6efc55efafa7695598897d07113e724dcfcd7773
--- /dev/null
+++ b/app/views/admin/application/tree/_folder.html.erb
@@ -0,0 +1,8 @@
+<span class="open_btn">
+  <i class="open_btn--without_children <%= Icon::FOLDER_CLOSED %>"></i>
+  <i class="open_btn--with_children <%= Icon::FOLDER_CLOSED_FULL %>"></i>
+</span>
+<span class="close_btn">
+  <i class="close_btn--without_children <%= Icon::FOLDER_OPENED %>"></i>
+  <i class="close_btn--with_children <%= Icon::FOLDER_OPENED_FULL %>"></i>
+</span>
\ No newline at end of file
diff --git a/app/views/admin/application/tree/_sort.html.erb b/app/views/admin/application/tree/_sort.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..0cb428a30bfa94937b08bbaceb7673dde0a7a7ab
--- /dev/null
+++ b/app/views/admin/application/tree/_sort.html.erb
@@ -0,0 +1,3 @@
+<span class="move_btn py-2 ps-2">
+  <i class="<%= Icon::SORT %>"></i>
+</span>
\ No newline at end of file
diff --git a/app/views/admin/communication/blocks/_list.html.erb b/app/views/admin/communication/blocks/_list.html.erb
index 856b5fdc9089a1da4942f664d80d35c5e4149908..346144498f2cd9fbbaf7b5115b575156020eda32 100644
--- a/app/views/admin/communication/blocks/_list.html.erb
+++ b/app/views/admin/communication/blocks/_list.html.erb
@@ -12,7 +12,7 @@ action += link_to t('admin.communication.blocks.add'),
           <% about.blocks.ordered.each do |block| %>
             <tr data-id="<%= block.id %>" class="<%= 'draft' unless block.published? %>">
               <% if can? :reorder, Communication::Block %>
-                <td class="ps-0 blocks__list__handle"><i class="fa fa-bars handle"></i></td>
+                <td class="ps-0 blocks__list__handle"><i class="<%= Icon::DRAG %> handle"></i></td>
               <% end %>
               <td class="blocks__list__name">
                 <%= block.to_s.truncate(50) %><br>
diff --git a/app/views/admin/communication/blocks/components/category/_edit.html.erb b/app/views/admin/communication/blocks/components/category/_edit.html.erb
index 48937b1750fa19448b8de5404f43570c3ae28db0..81468e51d217ba7c09c13fe351488a2cbd055ad3 100644
--- a/app/views/admin/communication/blocks/components/category/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/category/_edit.html.erb
@@ -1,6 +1,4 @@
-<%
-categories = collection_tree(@block.about&.website.categories)
-%>
+<% categories = collection_tree(@block.about&.website.categories.for_language(@block.language)) %>
 <label  class="form-label"
         :for="<%= dom_id.html_safe %>">
   <%= label %>
diff --git a/app/views/admin/communication/blocks/components/file/_edit.html.erb b/app/views/admin/communication/blocks/components/file/_edit.html.erb
index ad296973efa93cf54e6be4fd95c6ecc343d09035..1161795efd45f16a8dc6f776c79fcb8ddf87c665 100644
--- a/app/views/admin/communication/blocks/components/file/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/file/_edit.html.erb
@@ -19,7 +19,7 @@ remove = t 'admin.communication.blocks.components.file.input.remove'
     <p><b>{{ element.file.filename }}</b></p>
     <a  class="btn btn-sm text-danger"
         v-on:click="<%= model %>.<%= property %>={}">
-        <i class="fas fa-times"></i>
+        <i class="<%= Icon::DELETE %>"></i>
       <%= remove %>
     </a>
   </div>
diff --git a/app/views/admin/communication/blocks/components/image/_edit.html.erb b/app/views/admin/communication/blocks/components/image/_edit.html.erb
index 7a48179ec35d0ce7db0351289734be1fdcb09943..7691d20af29607b2f71806faa14b137f63fea9ef 100644
--- a/app/views/admin/communication/blocks/components/image/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/image/_edit.html.erb
@@ -20,7 +20,7 @@ remove = t 'admin.communication.blocks.components.image.input.remove'
   <a  class="btn btn-sm text-danger"
       v-on:click="<%= model %>.<%= property %>={}"
       v-if="<%= model %>.<%= property %>.id">
-      <i class="fas fa-times"></i>
+      <i class="<%= Icon::DELETE %>"></i>
     <%= remove %>
   </a>
 </div>
diff --git a/app/views/admin/communication/blocks/components/organization/_edit.html.erb b/app/views/admin/communication/blocks/components/organization/_edit.html.erb
index 5657ea94db25c75d1ed1dabb148f0328abbb6989..48fb8775666bb52de24429db995dcbdfaeca9622 100644
--- a/app/views/admin/communication/blocks/components/organization/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/organization/_edit.html.erb
@@ -1,6 +1,5 @@
-<%
-organizations = current_university.organizations.ordered
-%>
+<%# TODO: Traduire les organisations %>
+<% organizations = current_university.organizations.ordered %>
 <% unless label.blank? %>
   <label  class="form-label"
           :for="<%= dom_id.html_safe %>">
diff --git a/app/views/admin/communication/blocks/components/page/_edit.html.erb b/app/views/admin/communication/blocks/components/page/_edit.html.erb
index 3f922d8f45ae918c776f8142d5accd98e7945aff..fa13fccaeae883a19bc4c627ba95131c7eeee46e 100644
--- a/app/views/admin/communication/blocks/components/page/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/page/_edit.html.erb
@@ -1,5 +1,5 @@
 <%
-pages = collection_tree(@block.about&.website.pages)
+pages = collection_tree(@block.about&.website.pages.for_language(@block.language))
 %>
 <% unless label.blank? %>
   <label  class="form-label"
diff --git a/app/views/admin/communication/blocks/components/person/_edit.html.erb b/app/views/admin/communication/blocks/components/person/_edit.html.erb
index 33c7acb4adcb78e50925d78773f924057d5bbb95..ec05a677b040edbfae07cf6994270e53b44dab47 100644
--- a/app/views/admin/communication/blocks/components/person/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/person/_edit.html.erb
@@ -1,6 +1,4 @@
-<%
-people = current_university.people.ordered
-%>
+<% people = current_university.people.for_language(@block.language).ordered %>
 <% unless label.blank? %>
   <label  class="form-label"
           :for="<%= dom_id.html_safe %>">
diff --git a/app/views/admin/communication/blocks/components/post/_edit.html.erb b/app/views/admin/communication/blocks/components/post/_edit.html.erb
index e90073157dcdd06c29c5ac8e083e25f7adfe2809..594ad08b394a3748bfd3f4c81ccb19be12b60974 100644
--- a/app/views/admin/communication/blocks/components/post/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/post/_edit.html.erb
@@ -1,6 +1,4 @@
-<%
-posts = @block.about&.website.posts.ordered
-%>
+<% posts = @block.about&.website.posts.for_language(@block.language).ordered %>
 <label  class="form-label <%= 'visually-hidden' if label.blank? %>"
         :for="<%= dom_id.html_safe %>">
   <%= label %>
diff --git a/app/views/admin/communication/blocks/components/program/_edit.html.erb b/app/views/admin/communication/blocks/components/program/_edit.html.erb
index f3fcbd342401853547249cb3b97dd056318658e5..efb38295f9a51c4d5954f67722d33dd25c3c4ec9 100644
--- a/app/views/admin/communication/blocks/components/program/_edit.html.erb
+++ b/app/views/admin/communication/blocks/components/program/_edit.html.erb
@@ -1,6 +1,5 @@
-<%
-program = current_university.programs.ordered
-%>
+<%# TODO: Traduire les formations %>
+<% programs = current_university.programs.ordered %>
 <% if label.present? %>
 <label  class="form-label"
         :for="<%= dom_id.html_safe %>">
@@ -13,7 +12,7 @@ program = current_university.programs.ordered
   <% if placeholder %>
     <option value="" disabled><%= placeholder %></option>
   <% end %>
-  <% program.each do |program| %>
+  <% programs.each do |program| %>
     <option value="<%= program.id %>">
       <%= program %>
     </option>
diff --git a/app/views/admin/communication/blocks/templates/call_to_action/_edit.html.erb b/app/views/admin/communication/blocks/templates/call_to_action/_edit.html.erb
index ba5e9f19bba7a030b0b957c60759615011020c57..b97988ebbe1ce48196c1b787ea90e09449260c7b 100644
--- a/app/views/admin/communication/blocks/templates/call_to_action/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/call_to_action/_edit.html.erb
@@ -25,7 +25,7 @@
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 pt-0 dragHandle">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill">
@@ -45,7 +45,7 @@
     <div class="text-end">
       <a  class="btn btn-sm text-danger"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)">
-        <i class="fas fa-times"></i>
+        <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/blocks/templates/contact/_edit.html.erb b/app/views/admin/communication/blocks/templates/contact/_edit.html.erb
index 78408b9bf45f58ed50d11651e127a5591013c287..5619e739c9f045de7ba42e57cf56530e8d333ff4 100644
--- a/app/views/admin/communication/blocks/templates/contact/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/contact/_edit.html.erb
@@ -40,7 +40,7 @@
                     placeholder="<%= t '.phones.placeholder' %>"
                     v-model="data.phone_numbers[index]">
             <a class="btn text-danger" v-on:click="data.phone_numbers.splice(index, 1)">
-              <i class="fas fa-times"></i>
+              <i class="<%= Icon::DELETE %>"></i>
             </a>
           </div>
         </div>
@@ -61,7 +61,7 @@
                     placeholder="<%= t '.mails.placeholder' %>"
                     v-model="data.emails[index]">
             <a class="btn text-danger" v-on:click="data.emails.splice(index, 1)">
-              <i class="fas fa-times"></i>
+              <i class="<%= Icon::DELETE %>"></i>
             </a>
           </div>
         </div>
@@ -76,7 +76,7 @@
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 pt-0 dragHandle">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill">
@@ -95,7 +95,7 @@
     <div>
       <a  class="btn text-danger position-absolute top-0 end-0"
           v-on:click="data.elements.splice(index, 1)">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/blocks/templates/datatable/_edit.html.erb b/app/views/admin/communication/blocks/templates/datatable/_edit.html.erb
index 3656e86ffbeedd89b234d51454e802c17deee1fc..3c759cf3db758537c6b9aedcb20109e9041ac3d3 100644
--- a/app/views/admin/communication/blocks/templates/datatable/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/datatable/_edit.html.erb
@@ -19,14 +19,14 @@
                     v-model="data.columns[index]">
             <a  class="btn text-danger"
                 v-on:click="data.columns.splice(index, 1); data.elements.forEach(row => row.cells.splice(index, 1));">
-                <i class="fas fa-times"></i>
+                <i class="<%= Icon::DELETE %>"></i>
             </a>
           </div>
         </div>
         <div class="td">
           <a  class="btn btn-primary mt-n1"
               v-on:click="data.columns.push('')">
-              <i class="fas fa-plus"></i> colonne
+              <i class="<%= Icon::ADD %>"></i> colonne
           </a>
         </div>
       </div>
@@ -42,10 +42,10 @@
           <div class="d-flex">
             <a  class="btn text-danger"
                 v-on:click="data.elements.splice(index, 1)">
-                <i class="fas fa-times"></i>
+                <i class="<%= Icon::DELETE %>"></i>
             </a>
             <a class="btn dragHandle">
-              <i class="fa fa-bars handle"></i>
+              <i class="<%= Icon::DRAG %> handle"></i>
             </a>
           </div>
         </div>
@@ -54,7 +54,7 @@
   </div>
   <a  class="btn btn-primary"
       v-on:click="data.elements.push({cells: []})">
-      <i class="fas fa-plus"></i> ligne
+      <i class="<%= Icon::ADD %>"></i> ligne
   </a>
 </div>
 
diff --git a/app/views/admin/communication/blocks/templates/definitions/_edit.html.erb b/app/views/admin/communication/blocks/templates/definitions/_edit.html.erb
index 209859a3f6ffdfeea38d99fd5d555c0fb0dd18ce..577a6a16e063a1fa894d22e2f1f2650cc7ce5274 100644
--- a/app/views/admin/communication/blocks/templates/definitions/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/definitions/_edit.html.erb
@@ -8,7 +8,7 @@
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 pt-0 dragHandle">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill">
@@ -25,7 +25,7 @@
       <a  class="btn btn-sm text-danger ms-3"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
           title="<%= t '.remove_definition' %>">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/blocks/templates/files/_edit.html.erb b/app/views/admin/communication/blocks/templates/files/_edit.html.erb
index 918d8db735d04eb8caacb4d4053bfad6f081dee3..0fe565559132d3f320b5cc1b3f030e5d40cf687b 100644
--- a/app/views/admin/communication/blocks/templates/files/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/files/_edit.html.erb
@@ -11,13 +11,13 @@
     <div class="card">
       <div class="card-header border-bottom">
         <a class="btn ps-0 pt-0 dragHandle">
-          <i class="fa fa-bars handle"></i>
+          <i class="<%= Icon::DRAG %> handle"></i>
         </a>
         <div class="float-end">
           <a  class="btn btn-sm text-danger"
               v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
               title="<%= t '.remove_file' %>">
-              <i class="fas fa-times"></i>
+              <i class="<%= Icon::DELETE %>"></i>
           </a>
         </div>
       </div>
diff --git a/app/views/admin/communication/blocks/templates/gallery/_edit.html.erb b/app/views/admin/communication/blocks/templates/gallery/_edit.html.erb
index 20a8b508ac8c1e5cd25a10cbb5b7c57036977616..9e77ce4f5cc31ede8c7154a39bb48d2ae6f692b5 100644
--- a/app/views/admin/communication/blocks/templates/gallery/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/gallery/_edit.html.erb
@@ -11,7 +11,7 @@
   <div v-for="(element, index) in data.elements" class="col-xxl-1 col-lg-2 col-4">
     <div class="card">
       <div class="card-header p-1 text-center">
-        <i class="fas fa-arrows-alt"></i>
+        <i class="<%= Icon::MOVE %>"></i>
       </div>
       <div v-if="element.image.id">
         <img :src="getImageUrl(element.image)" class="img-fluid" />
@@ -30,7 +30,7 @@
       <a  class="btn btn-sm text-danger mt-n4"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
           title="<%= t 'admin.communication.blocks.templates.gallery.edit.remove_image' %>">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
     <div class="row pure__row--small">
diff --git a/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb b/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb
index 492cf2199e757e9970d327264bfc10d1778037fd..722deb0fc1a0c94bb0898be715251eae859a04bc 100644
--- a/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb
@@ -10,7 +10,7 @@
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 dragHandle">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill">
@@ -30,7 +30,7 @@
       <a  class="btn btn-sm text-danger ms-3"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
           title="<%= t '.remove_key' %>">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/blocks/templates/organization_chart/_edit.html.erb b/app/views/admin/communication/blocks/templates/organization_chart/_edit.html.erb
index e4ef15e319252aca51f10bb64abb1768588452bc..2262e66e71082619001c1e9e0c822ea8c2355de7 100644
--- a/app/views/admin/communication/blocks/templates/organization_chart/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/organization_chart/_edit.html.erb
@@ -16,7 +16,7 @@
     <div class="d-flex">
       <div>
         <a class="btn ps-0 pt-0 dragHandle" title="<%= t '.drag_title' %>">
-          <i class="fa fa-bars handle"></i>
+          <i class="<%= Icon::DRAG %> handle"></i>
         </a>
       </div>
       <div class="flex-fill">
@@ -33,7 +33,7 @@
         <a  class="btn btn-sm text-danger"
             v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
             title="<%= t '.delete_title' %>">
-            <i class="fas fa-times"></i>
+            <i class="<%= Icon::DELETE %>"></i>
         </a>
       </div>
     </div>
diff --git a/app/views/admin/communication/blocks/templates/pages/_edit.html.erb b/app/views/admin/communication/blocks/templates/pages/_edit.html.erb
index 5f305eb00677543b3134351492e0020f11ed1835..814d64830a317342fa6a93781fc9d9ecf1790de9 100644
--- a/app/views/admin/communication/blocks/templates/pages/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/pages/_edit.html.erb
@@ -1,5 +1,3 @@
-<% pages = collection_tree(@block.about&.website.pages) %>
-
 <%= block_component_edit :layout %>
 
 <div class="row pure__row--small">
@@ -21,7 +19,7 @@
           <div class="d-flex mb-n3">
             <div>
               <a class="btn ps-0 pt-0 dragHandle" title="Drag and drop">
-                <i class="fa fa-bars handle"></i>
+                <i class="<%= Icon::DRAG %> handle"></i>
               </a>
             </div>
             <div class="flex-fill">
@@ -31,7 +29,7 @@
               <a  class="btn btn-sm text-danger ms-3"
                   v-on:click="data.elements.splice(data.elements.indexOf(page), 1)"
                   title="Supprimer">
-                  <i class="fas fa-times"></i>
+                  <i class="<%= Icon::DELETE %>"></i>
               </a>
             </div>
           </div>
diff --git a/app/views/admin/communication/blocks/templates/partners/_edit.html.erb b/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
index f6385d0273d0c831f4c31bc6b76c11211427a998..0447550d1c475bdcda96dd9c51e6125811b57eff 100644
--- a/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
@@ -13,7 +13,7 @@
     <div class="d-flex mb-n3">
       <div>
         <a class="btn ps-0 pt-0 partnerHandle">
-          <i class="fa fa-bars handle"></i>
+          <i class="<%= Icon::DRAG %> handle"></i>
         </a>
       </div>
       <div class="flex-fill">
@@ -34,7 +34,7 @@
         <a  class="btn btn-sm text-danger ms-3"
             v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
             title="<%= t '.remove_partner' %>">
-            <i class="fas fa-times"></i>
+            <i class="<%= Icon::DELETE %>"></i>
         </a>
       </div>
     </div>
diff --git a/app/views/admin/communication/blocks/templates/posts/_edit.html.erb b/app/views/admin/communication/blocks/templates/posts/_edit.html.erb
index 471f3108d4188179f02696eb3d67593ad8823049..2f4fd1964e3913fcbe8f73bdd80e585c995db30e 100644
--- a/app/views/admin/communication/blocks/templates/posts/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/posts/_edit.html.erb
@@ -1,5 +1,3 @@
-<% categories = collection_tree(@block.about&.website.categories) %>
-
 <%= block_component_edit :layout %>
 
 <div class="mb-3">
@@ -18,7 +16,7 @@
   <draggable :list="data.elements" handle=".dragHandle" class="<%= if_appstack 'list-group' %>">
     <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
       <a class="btn ps-0 dragHandle" title="Drag and drop">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
       <div class="flex-fill">
         <%= block_component_edit :id, template: @element %>
@@ -26,7 +24,7 @@
       <a  class="btn text-danger ms-3"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
           title="Delete">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </draggable>
diff --git a/app/views/admin/communication/blocks/templates/programs/_edit.html.erb b/app/views/admin/communication/blocks/templates/programs/_edit.html.erb
index a5103398fe0553988fc0e12f918c1a6ffb596e8e..6ad4d0836ded138a48e50149a61920a387169e0e 100644
--- a/app/views/admin/communication/blocks/templates/programs/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/programs/_edit.html.erb
@@ -1,9 +1,8 @@
-<% pages = collection_tree(@block.university.programs) %>
 <draggable :list="data.elements" handle=".dragHandle" class="mb-3 <%= if_appstack 'list-group' %>">
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 pt-0 dragHandle" title="Drag and drop">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill mb-n3">
@@ -13,7 +12,7 @@
       <a  class="btn btn-sm text-danger ms-3"
           v-on:click="data.elements.splice(data.elements.indexOf(page), 1)"
           title="Supprimer">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/blocks/templates/testimonials/_edit.html.erb b/app/views/admin/communication/blocks/templates/testimonials/_edit.html.erb
index b5ab2cbd81b527f6f3799096a96f5135815d9ca6..60f9eff62ac7f31cbd1b9d21abe0d9ac3867a002 100644
--- a/app/views/admin/communication/blocks/templates/testimonials/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/testimonials/_edit.html.erb
@@ -7,7 +7,7 @@
     <div class="d-flex mb-5">
       <div>
         <a class="btn ps-0 pt-0 dragHandle">
-          <i class="fa fa-bars handle"></i>
+          <i class="<%= Icon::DRAG %> handle"></i>
         </a>
       </div>
       <div class="flex-fill">
@@ -28,7 +28,7 @@
         <a  class="btn btn-sm text-danger ms-3"
             v-on:click="data.elements.splice(data.elements.indexOf(testimonial), 1)"
             title="<%= t '.remove_testimonial' %>">
-            <i class="fas fa-times"></i>
+            <i class="<%= Icon::DELETE %>"></i>
         </a>
       </div>
     </div>
diff --git a/app/views/admin/communication/blocks/templates/timeline/_edit.html.erb b/app/views/admin/communication/blocks/templates/timeline/_edit.html.erb
index c5bbe37d4fe44b18a21db4f7c65cf86d106ea27e..b640e234beddebd013408a9f2a188c971c485006 100644
--- a/app/views/admin/communication/blocks/templates/timeline/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/timeline/_edit.html.erb
@@ -5,7 +5,7 @@
   <div v-for="(element, index) in data.elements" class="d-flex draggable-item <%= if_appstack 'list-group-item' %>">
     <div>
       <a class="btn ps-0 pt-0 dragHandle">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </a>
     </div>
     <div class="flex-fill">
@@ -22,7 +22,7 @@
       <a  class="btn btn-sm text-danger ms-3"
           v-on:click="data.elements.splice(data.elements.indexOf(element), 1)"
           title="<%= t '.remove_event' %>">
-          <i class="fas fa-times"></i>
+          <i class="<%= Icon::DELETE %>"></i>
       </a>
     </div>
   </div>
diff --git a/app/views/admin/communication/photo_imports/_selector.html.erb b/app/views/admin/communication/photo_imports/_selector.html.erb
index 5672edce072c7237eab9920602036369dda4c882..6486def70eaad4f95c67d350aa35791c68e60c8d 100644
--- a/app/views/admin/communication/photo_imports/_selector.html.erb
+++ b/app/views/admin/communication/photo_imports/_selector.html.erb
@@ -12,8 +12,8 @@ about_featured_image_credit = "##{about_identifier}_featured_image_credit"
 # fr, en...
 lang = about&.language&.iso_code if about.respond_to? :language
 # /admin/communication/photo_import.json?query=Page%20de%20test&per_page=12&page=1&lang=fr
-unsplash_path = admin_communication_unsplash_path(website_id: nil, format: :json)
-pexels_path = admin_communication_pexels_path(website_id: nil, format: :json)
+unsplash_path = admin_communication_unsplash_path(website_id: nil, lang: nil, format: :json)
+pexels_path = admin_communication_pexels_path(website_id: nil, lang: nil, format: :json)
 %>
 
 <div id="photo-import-app" v-cloak>
diff --git a/app/views/admin/communication/websites/_form.html.erb b/app/views/admin/communication/websites/_form.html.erb
index df4f1c7090df8f8986b1532e7c7f616c661ffb66..81f091f295b53880dff8aac3d8e12a80f99249a7 100644
--- a/app/views/admin/communication/websites/_form.html.erb
+++ b/app/views/admin/communication/websites/_form.html.erb
@@ -9,7 +9,7 @@
         <%= f.input :url %>
         <%= render 'admin/communication/abouts', f: f, i18n_key: 'activerecord.attributes.communication/website.about_' %>
         <%= f.association :languages, as: :check_boxes, required: true, wrapper_html: { class: "js-languages" } %>
-        <%= f.association :default_language, include_blank: t('simple_form.include_blanks.defaults.language'), input_html: { class: "js-default-language" } %>
+        <%= f.association :default_language, include_blank: t('simple_form.include_blanks.defaults.language'), input_html: (@website.persisted? ? { disabled: true } : { class: "js-default-language" }) %>
         <%= f.input :in_production %>
       <% end %>
     </div>
diff --git a/app/views/admin/communication/websites/_sidebar.html.erb b/app/views/admin/communication/websites/_sidebar.html.erb
index 0698c734baf612a77ad9a3b5ef49f1762dc809e9..e2205ef3eb35121a3d565933628ca3614643d482 100644
--- a/app/views/admin/communication/websites/_sidebar.html.erb
+++ b/app/views/admin/communication/websites/_sidebar.html.erb
@@ -1,6 +1,6 @@
 <div class="row mt-2 website__sidebar">
   <div class="col-lg-3 col-xl-2">
-    <div class="list-group list-group-flush" role="tablist">
+    <ul class="list-unstyled" role="tablist">
       <%
       navigation = [
         {
@@ -32,25 +32,38 @@
       navigation << {
         title: t('communication.website.analytics'),
         path: analytics_admin_communication_website_path(@website.id, website_id: nil),
-        icon:  Icon::COMMUNICATION_WEBSITE_ANALYTICS,
+        icon: Icon::COMMUNICATION_WEBSITE_ANALYTICS,
         ability: can?(:read, @website)
       } if @website.plausible_url.present?
 
       navigation.each_with_index do |object, index|
         next unless object[:ability]
-        active = index.zero?  ? object[:path] == request.path
+        active = index.zero?  ? controller_name == "websites" && action_name == "show"
                               : object[:path].in?(request.path)
       %>
-      <a class="list-group-item bg-transparent px-0 list-group-item-action<%= ' active' if active %>" href="<%= object[:path] %>">
-        <%= object[:title].html_safe %>
-        <span class="float-end">
-          <i class="fas fa-<%= object[:icon] %>"></i>
-        </span>
-      </a>
+        <li class="mb-3">
+          <a class="d-block py-1 <%= active ? 'text-black' : 'text-muted' %>" href="<%= object[:path] %>">
+            <i class="<%= object[:icon] %>" style="min-width: 30px"></i>
+            <%= object[:title].html_safe %>
+          </a>
+        </li>
       <% end %>
-    </div>
+    </ul>
+    <% if @website.languages.many? %>
+      <select class="form-control form-select mt-5"  onchange="if (this.value) window.location.href=this.value">
+        <% @website.languages.each do |language| %>
+          <%
+          label = I18n.t(language.iso_code, scope: :languages)
+          path = url_for request.params.merge(lang: language.iso_code)
+          selected = current_website_language == language
+          %>
+          <option value="<%= path %>"<% if selected %> selected="selected"<% end %>><%= label %></option>
+        <% end %>
+      </select>
+    <% end %>
   </div>
   <div class="col-lg-9 col-xl-10">
     <%= yield %>
   </div>
+
 </div>
diff --git a/app/views/admin/communication/websites/categories/_form.html.erb b/app/views/admin/communication/websites/categories/_form.html.erb
index ad011b1a673c7e86d5318712f76221a90320a2c2..0769ed9a26c14933cbdd34e5b2854e2cfb62e2e1 100644
--- a/app/views/admin/communication/websites/categories/_form.html.erb
+++ b/app/views/admin/communication/websites/categories/_form.html.erb
@@ -28,7 +28,7 @@
                         data: { source: '#communication_website_category_name' }
                       } %>
           <%= f.association :parent,
-                            collection: collection_tree(@website.categories, category),
+                            collection: collection_tree(@website.categories.for_language(current_website_language), category),
                             label_method: ->(p) { sanitize p[:label] },
                             value_method: ->(p) { p[:id] } %>
           <ul>
diff --git a/app/views/admin/communication/websites/categories/_treebranch.html.erb b/app/views/admin/communication/websites/categories/_treebranch.html.erb
index c8c9bcd3a736a80bdef143518fde4bd3d6efc081..b1a0cb7ef8b45f8b28add048009709af01ea671e 100644
--- a/app/views/admin/communication/websites/categories/_treebranch.html.erb
+++ b/app/views/admin/communication/websites/categories/_treebranch.html.erb
@@ -3,17 +3,10 @@
     <div class="d-flex align-items-center treeview__label border-bottom py-1">
       <%= link_to children_admin_communication_website_category_path(website_id: category.website.id, id: category.id),
                   class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %>
-        <span class="open_btn">
-          <i class="open_btn--with_children fas fa-folder"></i>
-          <i class="open_btn--without_children far fa-folder"></i>
-        </span>
-        <span class="close_btn">
-          <i class="close_btn--with_children fas fa-folder-open"></i>
-          <i class="close_btn--without_children far fa-folder-open"></i>
-        </span>
+        <%= render 'admin/application/tree/folder' %>
       <% end %>
       <%= link_to category, admin_communication_website_category_path(website_id: category.website.id, id: category.id) %>
-      <span class="move_btn py-2 ps-2"><i class="fas fa-sort"></i></span>
+      <%= render 'admin/application/tree/sort' %>
       <%= link_to children_admin_communication_website_category_path(website_id: category.website.id, id: category.id),
                   class: 'js-treeview-openzone small ps-2', remote: true do %>
         <span class="open_text"><%= t 'folder.open' %></span>
diff --git a/app/views/admin/communication/websites/categories/show.html.erb b/app/views/admin/communication/websites/categories/show.html.erb
index 001de20aeb3bac00bb1a4f3dd9ef15ad0bfce01e..7bf64735680b08f7492a14f7bd5f42a65a8b7489 100644
--- a/app/views/admin/communication/websites/categories/show.html.erb
+++ b/app/views/admin/communication/websites/categories/show.html.erb
@@ -7,6 +7,7 @@
       <%= render 'admin/communication/blocks/list', about: @category %>
     </div>
     <div class="col-md-4">
+      <%= render 'admin/application/i18n/widget', about: @category %>
       <%= osuny_panel t('metadata') do %>
         <%= osuny_label Communication::Website::Category.human_attribute_name('slug') %>
         <p><%= @category.slug %></p>
@@ -38,7 +39,7 @@
     </div>
   </div>
   <% if @posts.total_count > 0 %>
-    <%= osuny_panel Communication::Website::Post.model_name.human(count: 2), 
+    <%= osuny_panel Communication::Website::Post.model_name.human(count: 2),
                     subtitle: "#{@posts.total_count} #{Communication::Website::Post.model_name.human(count: @posts.total_count).downcase }" do %>
       <%= render 'admin/communication/websites/posts/list', posts: @posts, hide_category: true %>
       <%= paginate @posts, theme: 'bootstrap-5' %>
diff --git a/app/views/admin/communication/websites/categories/static.html.erb b/app/views/admin/communication/websites/categories/static.html.erb
index 01c2e54a0f63171fba4f35c1020590bbcd2fb866..708772076a594461fea18fe3983d93105f52ca1e 100644
--- a/app/views/admin/communication/websites/categories/static.html.erb
+++ b/app/views/admin/communication/websites/categories/static.html.erb
@@ -12,6 +12,7 @@ children:
 <% end %>
 <% end %>
 position: <%= @about.position %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/featured_image/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
diff --git a/app/views/admin/communication/websites/configs/default_languages/static.html.erb b/app/views/admin/communication/websites/configs/default_languages/static.html.erb
index 8657a91ea7bbfbd54c57a9aba19d5484276d8b9d..f221d66584ca48a27f353b934d42306431f08bc8 100644
--- a/app/views/admin/communication/websites/configs/default_languages/static.html.erb
+++ b/app/views/admin/communication/websites/configs/default_languages/static.html.erb
@@ -6,4 +6,8 @@
   contentDir: content/<%= language.iso_code %>
   languageCode: <%= language.iso_code %>
   languageName: <%= language.name %>
+  permalinks:
+    <% Communication::Website::Permalink.config_in_website(@website, language).each do |key, value| %>
+    <%= key %>: <%= value %>
+    <% end %>
 <% end %>
\ No newline at end of file
diff --git a/app/views/admin/communication/websites/configs/default_permalinks/static.html.erb b/app/views/admin/communication/websites/configs/default_permalinks/static.html.erb
index 27ed0728ff2dc7ab5e9a9d2cc748e0d2445768cc..ec8135a858f5574a2e1383055dba4c1326282df5 100644
--- a/app/views/admin/communication/websites/configs/default_permalinks/static.html.erb
+++ b/app/views/admin/communication/websites/configs/default_permalinks/static.html.erb
@@ -1,5 +1,2 @@
 # DO NOT EDIT THIS FILE BY HAND - IT WILL BE OVERWRITTEN BY OSUNY
-
-<% Communication::Website::Permalink.config_in_website(@website).each do |key, value| %>
-<%= key %>: <%= value %>
-<% end %>
\ No newline at end of file
+# Moved to languages.yml
diff --git a/app/views/admin/communication/websites/configs/development_config/static.html.erb b/app/views/admin/communication/websites/configs/development_config/static.html.erb
index 4482ef3003872df6c592679af77d3c5ef9ebc50b..5c6b2e4d55496aea0509fdc62052162cae18d92f 100644
--- a/app/views/admin/communication/websites/configs/development_config/static.html.erb
+++ b/app/views/admin/communication/websites/configs/development_config/static.html.erb
@@ -1,8 +1,4 @@
 # DO NOT EDIT THIS FILE BY HAND - IT WILL BE OVERWRITTEN BY OSUNY
 
-<% if @website.languages.any? %>
 defaultContentLanguage: <%= @website.default_language.iso_code %>
-<% else %>
-defaultContentLanguage: fr
-<% end %>
 defaultContentLanguageInSubdir: <%= @website.languages.many? %>
\ No newline at end of file
diff --git a/app/views/admin/communication/websites/configs/production_config/static.html.erb b/app/views/admin/communication/websites/configs/production_config/static.html.erb
index f08667878c33e5b548e62ada8967fe0ae3a1a8b2..4e86dabd96882e994b0e09592409f225d2fcf978 100644
--- a/app/views/admin/communication/websites/configs/production_config/static.html.erb
+++ b/app/views/admin/communication/websites/configs/production_config/static.html.erb
@@ -3,9 +3,5 @@
 baseURL: <%= @website.url %>
 
 ## LANGUAGE
-<% if @website.languages.any? %>
 defaultContentLanguage: <%= @website.default_language.iso_code %>
-<% else %>
-defaultContentLanguage: fr
-<% end %>
 defaultContentLanguageInSubdir: <%= @website.languages.many? %>
diff --git a/app/views/admin/communication/websites/menus/items/_form.html.erb b/app/views/admin/communication/websites/menus/items/_form.html.erb
index b54a740d557edeeab4cb644cfcec6c27bfefe013..ffeacc2c0e3d9baab8f76a64850dd40a106c01e2 100644
--- a/app/views/admin/communication/websites/menus/items/_form.html.erb
+++ b/app/views/admin/communication/websites/menus/items/_form.html.erb
@@ -44,15 +44,15 @@
         <%
           if item.has_about?
             if item.kind_page?
-              about_collection = collection_tree @website.pages
+              about_collection = collection_tree @website.pages.for_language(current_website_language)
             elsif item.kind_diploma?
               about_collection = collection @website.education_diplomas
             elsif item.kind_program?
               about_collection = collection_tree @website.education_programs
             elsif item.kind_category?
-              about_collection = collection_tree @website.categories
+              about_collection = collection_tree @website.categories.for_language(current_website_language)
             elsif item.kind_post?
-              about_collection = collection @website.posts
+              about_collection = collection @website.posts.for_language(current_website_language)
             elsif item.kind_volume?
               about_collection = collection @website.research_volumes
             elsif item.kind_paper?
diff --git a/app/views/admin/communication/websites/menus/items/_treebranch.html.erb b/app/views/admin/communication/websites/menus/items/_treebranch.html.erb
index d986dfb7a333b424c8712302e56161777edff9a0..cd2b795c0114cdfa1c13ac8229c5e1827e42fe7f 100644
--- a/app/views/admin/communication/websites/menus/items/_treebranch.html.erb
+++ b/app/views/admin/communication/websites/menus/items/_treebranch.html.erb
@@ -3,18 +3,10 @@
     <div class="d-flex align-items-center treeview__label border-bottom p-1">
       <%= link_to children_admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id),
                   class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %>
-        <% icon_style = item.has_children? ? 'fas' : 'far' %>
-        <span class="open_btn">
-          <i class="open_btn--with_children fas fa-folder"></i>
-          <i class="open_btn--without_children far fa-folder"></i>
-        </span>
-        <span class="close_btn">
-          <i class="close_btn--with_children fas fa-folder-open"></i>
-          <i class="close_btn--without_children far fa-folder-open"></i>
-        </span>
+        <%= render 'admin/application/tree/folder' %>
       <% end %>
       <%= link_to_if can?(:read, item), item, admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id) %>
-      <span class="move_btn py-2 ps-2"><i class="fas fa-sort"></i></span>
+      <%= render 'admin/application/tree/sort' %>
       <%= link_to children_admin_communication_website_menu_item_path(website_id: item.website.id, menu_id: item.menu.id, id: item.id),
                   class: 'js-treeview-openzone small ps-2', remote: true do %>
         <span class="open_text"><%= t 'folder.open' %></span>
diff --git a/app/views/admin/communication/websites/menus/items/kind_switch.js.erb b/app/views/admin/communication/websites/menus/items/kind_switch.js.erb
index 3e7d34011024a1dbf6e07ebd112f6ffa7e7f1971..b5db70accfe1ff1737a3865ca228f4ee16d158f1 100644
--- a/app/views/admin/communication/websites/menus/items/kind_switch.js.erb
+++ b/app/views/admin/communication/websites/menus/items/kind_switch.js.erb
@@ -15,7 +15,7 @@ function hideAbout() {
 <% elsif @kind == 'page' %>
     <%
     options = ['<option value="" label=" "></option>']
-    collection_tree(@website.pages).each do |page|
+    collection_tree(@website.pages.for_language(current_website_language)).each do |page|
         options << "<option value=\"#{page[:id]}\">#{page[:label]}</option>"
     end
     %>
@@ -40,7 +40,7 @@ function hideAbout() {
 <% elsif @kind == 'category' %>
     <%
         options = ['<option value="" label=" "></option>']
-        collection_tree(@website.categories).each do |category|
+        collection_tree(@website.categories.for_language(current_website_language)).each do |category|
             options << "<option value=\"#{category[:id]}\">#{category[:label]}</option>"
         end
     %>
@@ -48,7 +48,7 @@ function hideAbout() {
 <% elsif @kind == 'post' %>
     <%
     options = ['<option value="" label=" "></option>']
-    @website.posts.ordered.each do |post|
+    @website.posts.for_language(current_website_language).ordered.each do |post|
         options << "<option value=\"#{post.id}\">#{post.to_s}</option>"
     end
     %>
diff --git a/app/views/admin/communication/websites/menus/show.html.erb b/app/views/admin/communication/websites/menus/show.html.erb
index 0ac9ed5b1f63d9202130f675512eeb83abb03972..458f9088ac4e363cad0bbb4290ca1da564e29583 100644
--- a/app/views/admin/communication/websites/menus/show.html.erb
+++ b/app/views/admin/communication/websites/menus/show.html.erb
@@ -12,6 +12,7 @@
                   class: button_classes if can?(:create, Communication::Website::Menu::Item) %>
     </div>
     <div class="col-md-4">
+      <%= render 'admin/application/i18n/widget', about: @menu %>
       <%= osuny_panel t('metadata') do %>
         <%= osuny_label Communication::Website::Menu.human_attribute_name('identifier') %>
         <p><%= @menu.identifier %></p>
diff --git a/app/views/admin/communication/websites/pages/_form.html.erb b/app/views/admin/communication/websites/pages/_form.html.erb
index c9b287d2e7343350379e648cacb320c9b1d73ff1..bfc00a5c814e1fd9cc479e66980125431bd8b317 100644
--- a/app/views/admin/communication/websites/pages/_form.html.erb
+++ b/app/views/admin/communication/websites/pages/_form.html.erb
@@ -28,32 +28,14 @@ url = page.new_record?  ? admin_communication_website_pages_path
                         class: 'js-slug-input',
                         data: { source: '#communication_website_page_title' }
                       } unless page.is_home? %>
-          <% if @website.languages.many? %>
-            <%= f.input :language_id, collection: @website.languages, include_blank: false %>
-          <% elsif @website.languages.any? %>
-            <%= f.input :language_id, as: :hidden, input_html: { value: @website.languages.first.id }, wrapper: false %>
-          <% end %>
           <%= f.association :parent,
-                            collection: collection_tree(@website.pages, page),
+                            collection: collection_tree(@website.pages.for_language(current_website_language), page),
                             include_blank: false,
                             label_method: ->(p) { sanitize p[:label] },
                             value_method: ->(p) { p[:id] } unless page.is_home? %>
           <%= f.input :bodyclass if can?(:edit, @website) %>
           <%= f.input :full_width if page.editable_width? %>
         <% end %>
-      <% else %>
-        <% if @website.languages.many? %>
-          <div class="card flex-fill w-100">
-            <div class="card-header">
-              <h5 class="card-title mb-0"><%= t('metadata') %></h5>
-            </div>
-            <div class="card-body">
-              <%= f.input :language_id, collection: @website.languages, include_blank: false %>
-            </div>
-          </div>
-        <% elsif @website.languages.any? %>
-          <%= f.input :language_id, as: :hidden, input_html: { value: @website.languages.first.id }, wrapper: false %>
-        <% end %>
       <% end %>
       <%= render 'admin/application/featured_image/edit', about: @page, f: f %>
     </div>
diff --git a/app/views/admin/communication/websites/pages/_list.html.erb b/app/views/admin/communication/websites/pages/_list.html.erb
index 0134825491f823c2fc8039ab70e27ade5b1a12a5..b72267cf6e0fcac22eff405dc425b2272e81bb87 100644
--- a/app/views/admin/communication/websites/pages/_list.html.erb
+++ b/app/views/admin/communication/websites/pages/_list.html.erb
@@ -1,10 +1,16 @@
+<%
+  hide_buttons ||= false
+%>
 <div class="table-responsive">
   <table class="<%= table_classes %>">
     <thead>
       <tr>
-        <th class="ps-0"><%= Communication::Website::Page.human_attribute_name('title') %></th>
+        <th class="ps-0" width="60%"><%= Communication::Website::Page.human_attribute_name('title') %></th>
+        <th><%= Communication::Website::Page.human_attribute_name('featured_image') %></th>
         <th><%= Communication::Website::Page.human_attribute_name('parent') %></th>
-        <th width="150"></th>
+        <% unless hide_buttons %>
+          <th width="150"></th>
+        <% end %>
       </tr>
     </thead>
     <tbody>
@@ -15,22 +21,29 @@
                         admin_communication_website_page_path(website_id: page.website.id, id: page.id),
                         class: "#{'draft' unless page.published?}" %>
           </td>
+          <td>
+            <% if page.featured_image.attached? && page.featured_image.representable? %>
+              <%= image_tag page.featured_image.representation(resize: '200x'), width: 100 %>
+            <% end %>
+          </td>
           <td>
             <%= link_to page.parent,
                         admin_communication_website_page_path(website_id: page.website.id, id: page.id) if page.parent %>
           </td>
-          <td class="text-end pe-0">
-            <div class="btn-group" role="group">
-              <%= link_to t('edit'),
-                        edit_admin_communication_website_page_path(website_id: page.website.id, id: page.id),
-                        class: button_classes if can?(:update, page) %>
-              <%= link_to t('delete'),
-                        admin_communication_website_page_path(website_id: page.website.id, id: page.id),
-                        method: :delete,
-                        data: { confirm: page.children.any? ? t('please_confirm_with_children') : t('please_confirm') },
-                        class: button_classes_danger if can?(:destroy, page) && !page.is_special_page? %>
-            </div>
-          </td>
+          <% unless hide_buttons %>
+            <td class="text-end pe-0">
+              <div class="btn-group" role="group">
+                <%= link_to t('edit'),
+                          edit_admin_communication_website_page_path(website_id: page.website.id, id: page.id),
+                          class: button_classes if can?(:update, page) %>
+                <%= link_to t('delete'),
+                          admin_communication_website_page_path(website_id: page.website.id, id: page.id),
+                          method: :delete,
+                          data: { confirm: page.children.any? ? t('please_confirm_with_children') : t('please_confirm') },
+                          class: button_classes_danger if can?(:destroy, page) && !page.is_special_page? %>
+              </div>
+            </td>
+          <% end %>
         </tr>
       <% end %>
     </tbody>
diff --git a/app/views/admin/communication/websites/pages/_treebranch.html.erb b/app/views/admin/communication/websites/pages/_treebranch.html.erb
index e9df75c218279b0b40e15c268ab749205fb091fa..2a479388880de0b48d54d2cb20e0ec9ef16b91a8 100644
--- a/app/views/admin/communication/websites/pages/_treebranch.html.erb
+++ b/app/views/admin/communication/websites/pages/_treebranch.html.erb
@@ -3,21 +3,12 @@
     <div class="d-flex align-items-center treeview__label border-bottom p-1">
       <%= link_to children_admin_communication_website_page_path(website_id: page.website.id, id: page.id),
                   class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %>
-        <span class="open_btn">
-          <i class="open_btn--with_children fas fa-folder"></i>
-          <i class="open_btn--without_children far fa-folder"></i>
-        </span>
-        <span class="close_btn">
-          <i class="close_btn--with_children fas fa-folder-open"></i>
-          <i class="close_btn--without_children far fa-folder-open"></i>
-        </span>
+        <%= render 'admin/application/tree/folder' %>
       <% end %>
       <%= link_to page,
                   admin_communication_website_page_path(website_id: page.website.id, id: page.id),
                   class: "leaf-title" %>
-      <% unless page.is_home? %>
-        <span class="move_btn py-2 ps-2"><i class="fas fa-sort"></i></span>
-      <% end %>
+      <%= render 'admin/application/tree/sort' unless page.is_home? %>
       <%= link_to children_admin_communication_website_page_path(website_id: page.website.id, id: page.id),
                   class: 'js-treeview-openzone small ps-2', remote: true do %>
         <span class="open_text"><%= t 'folder.open' %></span>
diff --git a/app/views/admin/communication/websites/pages/index.html.erb b/app/views/admin/communication/websites/pages/index.html.erb
index 917dda57254cb38b4f9611d2334b4a0a504dc1d7..70de04929cdef98d39e9ca1713b6779a3bf4bfd7 100644
--- a/app/views/admin/communication/websites/pages/index.html.erb
+++ b/app/views/admin/communication/websites/pages/index.html.erb
@@ -1,8 +1,8 @@
 <% content_for :title, t('admin.communication.website.pages.structure') %>
 
 <% content_for :title_right do %>
-  <%= @website.pages.count %>
-  <%= Communication::Website::Page.model_name.human(count: @website.pages.count).downcase %>
+  <%= @pages.size %>
+  <%= Communication::Website::Page.model_name.human(count: @pages.size).downcase %>
 <% end %>
 
 <%= render 'admin/communication/websites/sidebar' do %>
@@ -11,7 +11,7 @@
       <div class="d-flex align-items-center treeview__label border-bottom p-1">
         <div class="d-inline-block p-2 ps-0" style="width: 22px">
           <span class="close_btn text-primary">
-            <i class="close_btn--with_children fas fa-folder-open"></i>
+            <i class="close_btn--with_children <%= Icon::FOLDER_OPENED_FULL %>"></i>
           </span>
         </div>
         <%= link_to @homepage,
diff --git a/app/views/admin/communication/websites/pages/show.html.erb b/app/views/admin/communication/websites/pages/show.html.erb
index 86cc6372c5d1fb195e60abcec5cd3cd49045e7b4..4f5b7bb22130a619635ed068a61cf3fabf6d2f89 100644
--- a/app/views/admin/communication/websites/pages/show.html.erb
+++ b/app/views/admin/communication/websites/pages/show.html.erb
@@ -12,6 +12,7 @@
     </div>
     <div class="col-md-4">
       <%= render 'admin/application/a11y/widget', about: @page %>
+      <%= render 'admin/application/i18n/widget', about: @page %>
       <%= render 'admin/communication/websites/pages/show/metadata' %>
       <%= render 'admin/application/featured_image/show', about: @page %>
       <%= render 'admin/application/meta_description/show', about: @page %>
diff --git a/app/views/admin/communication/websites/pages/static.html.erb b/app/views/admin/communication/websites/pages/static.html.erb
index 84092f13b66caa1dddcf1cf8e7d6910d68b2974b..cddc7e2f86999a9060a5ebd8f2e19d2327c7a43d 100644
--- a/app/views/admin/communication/websites/pages/static.html.erb
+++ b/app/views/admin/communication/websites/pages/static.html.erb
@@ -15,11 +15,12 @@ has:
   teachers: <%= @website.has_teachers? %>
 <% end %>
 position: <%= @about.position %>
+<%= render 'admin/application/i18n/static' %>
 bodyclass: <%= @about.best_bodyclass %>
 <%= render 'admin/application/featured_image/static' %>
 <% if @about.children.published.any? %>
 children:
-<% 
+<%
 @about.children.published.ordered.each do |child|
   next unless child.is_listed_among_children?
 %>
diff --git a/app/views/admin/communication/websites/posts/_form.html.erb b/app/views/admin/communication/websites/posts/_form.html.erb
index fbdcea1d787919b561a77bca600387c51d2ac6a2..929f6f3b56e184797f531734f6d21d04a711d1a1 100644
--- a/app/views/admin/communication/websites/posts/_form.html.erb
+++ b/app/views/admin/communication/websites/posts/_form.html.erb
@@ -10,13 +10,13 @@
         <%= f.input :text, as: :summernote if post.text&.to_plain_text.present? %>
       <% end %>
       <div class="row pure__row--small">
-        <% if @website.categories.any? %>
+        <% if @categories.any? %>
           <div class="col-md-6">
             <%= osuny_panel t('activerecord.attributes.communication/website/post.categories') do %>
               <%= f.association :categories,
                                 label_text: false,
                                 as: :check_boxes,
-                                collection: collection_tree_for_checkboxes(@website.categories) if @website.categories.any? %>
+                                collection: collection_tree_for_checkboxes(@categories) %>
             <% end %>
           </div>
         <% end %>
@@ -38,21 +38,9 @@
           </div>
           <%= f.input :published_at, html5: true, as: :date %>
         <% end %>
-        <% if @website.languages.many? %>
-          <%= f.input :language_id, collection: @website.languages, include_blank: false %>
-        <% elsif @website.languages.any? %>
-          <%= f.input :language_id, as: :hidden, input_html: { value: @website.languages.first.id }, wrapper: false %>
-        <% end %>
-        <% if current_user.author? || current_user.contributor? %>
-          <%= f.input :author_id,
-                      as: :hidden,
-                      input_html: { value: current_user.person&.id },
-                      wrapper: false %>
-        <% else %>
-          <%= f.association :author,
-                            collection: current_university.people.ordered,
+        <%= f.association :author,
+                            collection: current_university.people.for_language(current_website_language).ordered,
                             label_method: :to_s_alphabetical %>
-        <% end %>
         <%= f.input :slug,
                     as: :string,
                     input_html: post.persisted? ? {} : {
diff --git a/app/views/admin/communication/websites/posts/_list.html.erb b/app/views/admin/communication/websites/posts/_list.html.erb
index a0d4eaee12affb789ea19e4dda895258f714a9d1..0da0f7042829555e0fc90cab2d5a93edc6d7a9b8 100644
--- a/app/views/admin/communication/websites/posts/_list.html.erb
+++ b/app/views/admin/communication/websites/posts/_list.html.erb
@@ -1,7 +1,8 @@
 <%
-  hide_author |= false
-  hide_category |= false
-  selectable |= false
+  hide_author ||= false
+  hide_category ||= false
+  hide_buttons ||= false
+  selectable ||= false
 %>
 <% if selectable %>
   <input type="hidden" name="ids[]" value="">
@@ -15,9 +16,9 @@
             <%= check_box_tag nil, nil, false, data: { batch_selectable_role: "select-all" } %>
           </th>
         <% end %>
-        <th class="ps-0"><%= Communication::Website::Post.human_attribute_name('title') %></th>
+        <th class="ps-0" width="60%"><%= Communication::Website::Post.human_attribute_name('title') %></th>
         <th><%= Communication::Website::Post.human_attribute_name('featured_image') %></th>
-        <th colspan="2"><%= Communication::Website::Post.human_attribute_name('meta') %></th>
+        <th<% unless hide_buttons %> colspan="2"<% end %> class="ps-3"><%= Communication::Website::Post.human_attribute_name('meta') %></th>
       </tr>
     </thead>
     <tbody>
@@ -31,16 +32,12 @@
           <td class="ps-0"><%= link_to post,
                           admin_communication_website_post_path(website_id: post.website.id, id: post.id),
                           class: "#{'draft' unless post.published?}" %></td>
-          <td class="p-0"><%= image_tag post.featured_image.representation(resize: 'x100'),
-                                            height: 50 if post.featured_image.attached? && post.featured_image.representable? %></td>
-          <td>
-            <p class="small mb-0">
-              <%= l post.published_at, format: :date_with_explicit_month if post.published_at %>
-            </p>
+          <td><%= image_tag post.featured_image.representation(resize: '200x'),
+                                            width: 100 if post.featured_image.attached? && post.featured_image.representable? %></td>
+          <td class="ps-3 small">
+            <%= l post.published_at, format: :date_with_explicit_month if post.published_at %><br>
             <% if !hide_author && post.author %>
-              <p class="small mb-0">
-                <%= link_to post.author, admin_communication_website_author_path(website_id: post.website.id, id: post.author.id) %>
-              </p>
+              <%= link_to post.author, admin_communication_website_author_path(website_id: post.website.id, id: post.author.id) %><br>
             <% end %>
             <% unless hide_category %>
               <ul class="list-unstyled mb-0">
@@ -53,18 +50,20 @@
               <span class="badge bg-success"><%= Communication::Website::Post.human_attribute_name('pinned') %></span>
             <% end %>
           </td>
-          <td>
-            <div class="btn-group" role="group">
-              <%= link_to t('edit'),
-                          edit_admin_communication_website_post_path(website_id: post.website.id, id: post.id),
-                          class: button_classes if can?(:update, post) %>
-              <%= link_to t('delete'),
-                          admin_communication_website_post_path(website_id: post.website.id, id: post.id),
-                          method: :delete,
-                          data: { confirm: t('please_confirm') },
-                          class: button_classes_danger if can?(:destroy, post) %>
-            </div>
-          </td>
+          <% unless hide_buttons %>
+            <td>
+              <div class="btn-group" role="group">
+                <%= link_to t('edit'),
+                            edit_admin_communication_website_post_path(website_id: post.website.id, id: post.id),
+                            class: button_classes if can?(:update, post) %>
+                <%= link_to t('delete'),
+                            admin_communication_website_post_path(website_id: post.website.id, id: post.id),
+                            method: :delete,
+                            data: { confirm: t('please_confirm') },
+                            class: button_classes_danger if can?(:destroy, post) %>
+              </div>
+            </td>
+          <% end %>
         </tr>
       <% end %>
     </tbody>
diff --git a/app/views/admin/communication/websites/posts/index.html.erb b/app/views/admin/communication/websites/posts/index.html.erb
index 121bd4a01c1e99be71a9634fec90a94dbcee8d57..c440db38826dba9537c8454b6274d6614fd2bd27 100644
--- a/app/views/admin/communication/websites/posts/index.html.erb
+++ b/app/views/admin/communication/websites/posts/index.html.erb
@@ -31,30 +31,24 @@
       </div>
     <% end %>
   </div>
-  <div class="row">
-    <% if can?(:create, Communication::Website::Category) || (@root_categories.any? && can?(:edit, @root_categories.first))  %>
-      <div class="col-md-6">
-        <% action = create_link Communication::Website::Category %>
-        <%= osuny_panel Communication::Website::Category.model_name.human(count: 2), action: action do %>
-          <ul class="list-unstyled treeview treeview--sortable js-treeview js-treeview-sortable js-treeview-sortable-container"
-              data-id=""
-              data-sort-url="<%= reorder_admin_communication_website_categories_path %>">
-            <%= render 'admin/communication/websites/categories/treebranch', categories: @root_categories %>
-          </ul>
-        <% end %>
-      </div>
-    <% end %>
-    <% if @authors.any? %>
-      <div class="col-md-6">
-        <%= osuny_panel t('communication.authors', count: 2) do %>
-          <%= render 'admin/communication/websites/authors/list', authors: @authors %>
-          <% if @authors.total_pages > 1 %>
-            <%= paginate @authors, theme: 'bootstrap-5', param_name: :authors_page %>
-          <% end %>
-        <% end %>
-      </div>
+  <% if can?(:create, Communication::Website::Category) || (@root_categories.any? && can?(:edit, @root_categories.first))  %>
+      <% action = create_link Communication::Website::Category %>
+      <%= osuny_panel Communication::Website::Category.model_name.human(count: 2), action: action do %>
+        <ul class="list-unstyled treeview treeview--sortable js-treeview js-treeview-sortable js-treeview-sortable-container"
+            data-id=""
+            data-sort-url="<%= reorder_admin_communication_website_categories_path %>">
+          <%= render 'admin/communication/websites/categories/treebranch', categories: @root_categories %>
+        </ul>
+      <% end %>
+  <% end %>
+  <% if @authors.any? %>
+    <%= osuny_panel t('communication.authors', count: 2) do %>
+      <%= render 'admin/communication/websites/authors/list', authors: @authors %>
+      <% if @authors.total_pages > 1 %>
+        <%= paginate @authors, theme: 'bootstrap-5', param_name: :authors_page %>
+      <% end %>
     <% end %>
-  </div>
+  <% end %>
 
 <% end %>
 
diff --git a/app/views/admin/communication/websites/posts/show.html.erb b/app/views/admin/communication/websites/posts/show.html.erb
index fc2206f9ccc424b2061c25c429f5fa249b273afc..f1538493ae0a905a056cfa38baf380cb2ed78ab6 100644
--- a/app/views/admin/communication/websites/posts/show.html.erb
+++ b/app/views/admin/communication/websites/posts/show.html.erb
@@ -7,7 +7,8 @@
       <%= render 'admin/communication/blocks/list', about: @post %>
     </div>
     <div class="col-xl-4">
-      <% 
+      <%= render 'admin/application/i18n/widget', about: @post %>
+      <%
       action = ''
       action += link_to t('open'),
                         @post.url,
diff --git a/app/views/admin/communication/websites/posts/static.html.erb b/app/views/admin/communication/websites/posts/static.html.erb
index e89b9fd4cac31e15f5478a9a45f9680a84c91c29..4a3dd84b08f110417a3def554c4a6b007057a696 100644
--- a/app/views/admin/communication/websites/posts/static.html.erb
+++ b/app/views/admin/communication/websites/posts/static.html.erb
@@ -8,7 +8,7 @@ weight: 1
 <% end %>
 <% if @about.author %>
 authors:
-  - "<%= @about.author.slug %>"
+  - "<%= @about.translated_author.slug %>"
 <% end %>
 <% if @about.categories.any? %>
 categories:
@@ -16,6 +16,7 @@ categories:
   - "<%= category.slug_with_ancestors_slugs %>"
   <% end %>
 <% end %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/featured_image/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
diff --git a/app/views/admin/communication/websites/show/_pages.html.erb b/app/views/admin/communication/websites/show/_pages.html.erb
index fe28e0e4a8bdaeb31267d2c6d9b9dcf61337d2d2..1194a061bddafbb9f21a478a9035d0d4008f1ae7 100644
--- a/app/views/admin/communication/websites/show/_pages.html.erb
+++ b/app/views/admin/communication/websites/show/_pages.html.erb
@@ -3,7 +3,10 @@ action = ''
 action += link_to t('create'),
                   new_admin_communication_website_page_path(website_id: @website),
                   class: button_classes if can?(:create, Communication::Website::Page)
+subtitle = link_to t('communication.website.see_all', number: @all_pages.count), admin_communication_website_pages_path(website_id: @website)
 %>
-<%= osuny_panel t('communication.website.last_pages'), action: action do %>
-  <%= render 'admin/communication/websites/pages/list', pages: @pages %>
-<% end %>
\ No newline at end of file
+<%= osuny_panel t('communication.website.last_pages'),
+                subtitle: subtitle,
+                action: action do %>
+  <%= render 'admin/communication/websites/pages/list', pages: @pages, hide_buttons: true %>
+<% end %>
diff --git a/app/views/admin/communication/websites/show/_posts.html.erb b/app/views/admin/communication/websites/show/_posts.html.erb
index 17ce17ce71837926dd0dea018fdef41aa198f6de..6a58f65738b84b34f86beb9b9b45bde7993cb46e 100644
--- a/app/views/admin/communication/websites/show/_posts.html.erb
+++ b/app/views/admin/communication/websites/show/_posts.html.erb
@@ -6,10 +6,14 @@ action += link_to t('communication.website.posts.new_curation'),
 action += link_to t('create'),
                   new_admin_communication_website_post_path(website_id: @website),
                   class: button_classes('ms-1') if can?(:create, Communication::Website::Post)
+subtitle = link_to t('communication.website.see_all', number: @all_posts.size), admin_communication_website_posts_path(website_id: @website)
 %>
-<%= osuny_panel t('communication.website.last_posts'), action: action do %>
+<%= osuny_panel t('communication.website.last_posts'),
+                subtitle: subtitle,
+                action: action do %>
   <%= render 'admin/communication/websites/posts/list',
               posts: @posts,
               hide_author: true,
-              hide_category: true %>
-<% end %>
\ No newline at end of file
+              hide_category: true,
+              hide_buttons: true %>
+<% end %>
diff --git a/app/views/admin/dashboard/index.html.erb b/app/views/admin/dashboard/index.html.erb
index ccf96fe7257548ea536c91cd57d4849e12631d1b..2a52a293a7fbd0b0bfae56c4ac91840009f9f6b0 100644
--- a/app/views/admin/dashboard/index.html.erb
+++ b/app/views/admin/dashboard/index.html.erb
@@ -43,7 +43,7 @@
       <% next unless can?(:read, website) %>
       <div class="<%= classes %>">
         <%= osuny_panel website, 
-                  action: "<i class=\"fas fa-#{ Icon::COMMUNICATION_WEBSITE }\"></i>" do %>
+                  action: "<i class=\"#{ Icon::COMMUNICATION_WEBSITE }\"></i>" do %>
           <p class="small"><%= website.url %></p>
           <%= link_to t('show'), [:admin, website], class: button_classes('stretched-link') %>
         <% end %>
@@ -59,7 +59,7 @@
       <% next unless can?(:read, extranet) %>
       <div class="<%= classes %>">
         <%= osuny_panel extranet, 
-                  action: "<i class=\"fas fa-#{ Icon::COMMUNICATION_EXTRANET }\"></i>" do %>
+                  action: "<i class=\"#{ Icon::COMMUNICATION_EXTRANET }\"></i>" do %>
           <p class="small"><%= extranet.url %></p>
           <%= link_to t('show'), [:admin, extranet], class: button_classes('stretched-link') %>
         <% end %>
@@ -75,7 +75,7 @@
       <% next unless can?(:read, journal) %>
       <div class="<%= classes %>">
         <%= osuny_panel journal, 
-            action: "<i class=\"fas fa-#{ Icon::RESEARCH_JOURNAL }\"></i>" do %>
+            action: "<i class=\"#{ Icon::RESEARCH_JOURNAL }\"></i>" do %>
           <%= link_to t('show'), [:admin, journal], class: button_classes('stretched-link') %>
         <% end %>
       </div>
@@ -83,6 +83,21 @@
   </div>
 <% end %>
 
+<div class="row mt-5 pt-5">
+  <% @namespaces.each do |namespace| %>
+    <% 
+    path = send "admin_#{namespace.to_s.underscore}_root_path"
+    description = t "#{namespace.to_s.underscore}.description.text"
+    %>
+  <div class="col-lg-3">
+    <%= osuny_panel namespace.model_name.human, image: "admin/#{namespace.to_s.underscore}.jpg" do %>
+      <p><%= description.truncate 180 %></p>
+      <%= link_to t('show'), path, class: 'stretched-link' %>
+    <% end %>
+  </div>
+<% end %>
+</div>
+
 <% if current_admin_theme == 'appstack' %>
   <div class="small mt-5">
     <ul class="list-inline">
diff --git a/app/views/admin/dashboard/namespace.html.erb b/app/views/admin/dashboard/namespace.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..28069ead43796cfa701bd096beb96a36673ee555
--- /dev/null
+++ b/app/views/admin/dashboard/namespace.html.erb
@@ -0,0 +1,37 @@
+<% content_for :title, @namespace.model_name.human %>
+
+<div class="row">
+  <div class="col-lg-7">
+    <div>
+      <p class="lead"><i><%= t "#{@namespace.to_s.underscore}.description.text" %></i></p>
+      <p>— <%= t "#{@namespace.to_s.underscore}.description.source" %></p>
+    </div>
+    <div class="row pt-5 mt-5">
+      <% @namespace.parts.each do |part| %>
+        <%
+        class_name = part.first
+        path = send part.last
+        title = class_name.model_name.human(count: 2)
+        description = class_name.human_attribute_name('description')
+        # TODO
+        description = t 'administration.qualiopi.description' if class_name == Administration::Qualiopi
+        %>
+        <div class="col-lg-6 mt-5">
+          <%= osuny_panel title do %>
+            <p><%= description %></p>
+            <%= link_to t('show'), path, class: 'stretched-link' %>
+          <% end %>
+        </div>
+      <% end %>
+    </div>
+  </div>
+  <% if current_admin_theme == 'pure' %>
+    <div class="offset-lg-1 col-lg-4">
+      <%= image_tag "admin/#{@namespace.to_s.underscore}.jpg", class: 'img-fluid pure__chapter__image'%>
+      <p class="small text-lg-end mt-3">
+        Illustration de Virginia Frances Sterrett. 
+        Source : University of California Libraries, the Internet Archive.
+      </p>
+    </div>
+  <% end %>
+</div>
diff --git a/app/views/admin/education/diplomas/_programs.html.erb b/app/views/admin/education/diplomas/_programs.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..b7797ebc549728663f1489e58f4841180682a6e9
--- /dev/null
+++ b/app/views/admin/education/diplomas/_programs.html.erb
@@ -0,0 +1,14 @@
+<%
+indentation = ' ' * depth
+%>
+<% programs.each do |program| %>
+<%= indentation %>- label: >
+<%= indentation %>    <%= program.to_s %>
+<%= indentation %>  path: >
+<%= indentation %>    <%= program.current_permalink_in_website(@website)&.path %>
+<% children = program.children.ordered %>
+<% if children.any? %>
+<%= indentation %>  children: 
+<%= render 'programs', programs: program.children.ordered, depth: depth + 4 %>
+<% end %>
+<% end %>
diff --git a/app/views/admin/education/diplomas/static.html.erb b/app/views/admin/education/diplomas/static.html.erb
index a8bc3a230cb7088a33aeefb42c5bf39399454653..75b42d0fb92aed18ecb0a2aff1647a281231b229 100644
--- a/app/views/admin/education/diplomas/static.html.erb
+++ b/app/views/admin/education/diplomas/static.html.erb
@@ -3,6 +3,8 @@ title: >
   <%= prepare_text_for_static @about.name %>
 <%= render 'admin/application/static/permalink' %>
 <%= render 'admin/application/static/design', full_width: true, toc_offcanvas: true %>
+programs:
+<%= render 'programs', programs: @programs, depth: 2 %>
 short_name: >
   <%= prepare_text_for_static @about.short_name %>
 <%= render 'admin/application/summary/static' %>
diff --git a/app/views/admin/education/programs/_involvement_fields.html.erb b/app/views/admin/education/programs/_involvement_fields.html.erb
index a849fd7b4cab1eed4af5e7f4dbda5a2e1992e71c..53b196e684855cb3bfb5d9c76dc93fbf3c13edb3 100644
--- a/app/views/admin/education/programs/_involvement_fields.html.erb
+++ b/app/views/admin/education/programs/_involvement_fields.html.erb
@@ -16,7 +16,7 @@
                   wrapper: false %>
     </div>
     <div class="col-md-1 text-end">
-      <%= link_to_remove_association  '<i class="fas fa-times"></i>'.html_safe,
+      <%= link_to_remove_association  "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
                                       f,
                                       class: 'btn btn-sm btn-danger' %>
     </div>
diff --git a/app/views/admin/education/programs/_list.html.erb b/app/views/admin/education/programs/_list.html.erb
index f8aef89853ae5689182ba7f19e10c0c0e4f2d9da..2a3e43b8887dd78642a20276f5921a85dcd0ec8c 100644
--- a/app/views/admin/education/programs/_list.html.erb
+++ b/app/views/admin/education/programs/_list.html.erb
@@ -1,6 +1,6 @@
 <%
-  hide_diploma |= false
-  hide_parent |= false
+  hide_diploma ||= false
+  hide_parent ||= false
 %>
 <div class="table-responsive">
   <table class="<%= table_classes %>">
diff --git a/app/views/admin/education/programs/_treebranch.html.erb b/app/views/admin/education/programs/_treebranch.html.erb
index fa9062d6f734c8b5eea2d112e6f829456ae0b047..63f6b9de4be87704367bb43d1939f560fcfca98f 100644
--- a/app/views/admin/education/programs/_treebranch.html.erb
+++ b/app/views/admin/education/programs/_treebranch.html.erb
@@ -3,19 +3,12 @@
     <div class="d-flex align-items-center treeview__label border-bottom p-1">
       <%= link_to children_admin_education_program_path(id: program.id),
                   class: 'js-treeview-openzone d-inline-block p-2 ps-0', style: 'width: 22px', remote: true do %>
-        <span class="open_btn">
-          <i class="open_btn--with_children fas fa-folder"></i>
-          <i class="open_btn--without_children far fa-folder"></i>
-        </span>
-        <span class="close_btn">
-          <i class="close_btn--with_children fas fa-folder-open"></i>
-          <i class="close_btn--without_children far fa-folder-open"></i>
-        </span>
+        <%= render 'admin/application/tree/folder' %>
       <% end %>
       <%= link_to program,
                   admin_education_program_path(id: program.id),
                   class: 'leaf-title'  %>
-      <span class="move_btn py-2 ps-2"><i class="fas fa-sort"></i></span>
+      <%= render 'admin/application/tree/sort' %>
       <%= link_to children_admin_education_program_path(id: program.id),
                   class: 'js-treeview-openzone small ps-2', remote: true do %>
         <span class="open_text"><%= t 'folder.open' %></span>
diff --git a/app/views/admin/education/programs/roles/_involvement_fields.html.erb b/app/views/admin/education/programs/roles/_involvement_fields.html.erb
index 87b368af31776cb19491fafb7016abd173b4b051..cb51049ffb7ec1b79333563f0ff8ef16346c13b6 100644
--- a/app/views/admin/education/programs/roles/_involvement_fields.html.erb
+++ b/app/views/admin/education/programs/roles/_involvement_fields.html.erb
@@ -3,7 +3,7 @@
   <div class="card-body">
     <div class="row align-items-center">
       <div class="col-1">
-        <i class="fa fa-bars handle"></i>
+        <i class="<%= Icon::DRAG %> handle"></i>
       </div>
       <div class="col-9">
         <%= f.association :person,
@@ -14,7 +14,9 @@
                           required: true %>
       </div>
       <div class="col-2">
-        <%= link_to_remove_association '<i class="fas fa-times"></i>'.html_safe, f, class: 'btn btn-sm btn-danger' %>
+        <%= link_to_remove_association  "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
+                                        f,
+                                        class: 'btn btn-sm btn-danger' %>
       </div>
     </div>
   </div>
diff --git a/app/views/admin/education/programs/roles/_list.html.erb b/app/views/admin/education/programs/roles/_list.html.erb
index cbcffad6dd69c965bd9893bd4362c77e030f2f02..301353474b8db3f84c5e9dc1e4d33dc689c08c2b 100644
--- a/app/views/admin/education/programs/roles/_list.html.erb
+++ b/app/views/admin/education/programs/roles/_list.html.erb
@@ -15,7 +15,7 @@
         <% roles.each do |role| %>
           <tr data-id="<%= role.id %>">
             <% if can? :reorder, University::Role %>
-              <td><i class="fa fa-bars handle"></i></td>
+              <td><i class="<%= Icon::DRAG %> handle"></i></td>
             <% end %>
             <td class="ps-0">
               <%= link_to_if  can?(:read, role),
diff --git a/app/views/admin/education/programs/roles/show.html.erb b/app/views/admin/education/programs/roles/show.html.erb
index e19c7471b03bdedbcb7bafa164ca58fc0ab779cf..2214cfcdad476ffe268260cbb7addba160f4cc8c 100644
--- a/app/views/admin/education/programs/roles/show.html.erb
+++ b/app/views/admin/education/programs/roles/show.html.erb
@@ -16,7 +16,7 @@
         <% @involvements.each do |involvement| %>
           <tr data-id="<%= involvement.id %>">
             <% if can? :reorder, University::Role %>
-              <td><i class="fa fa-bars handle"></i></td>
+              <td><i class="<%= Icon::DRAG %> handle"></i></td>
             <% end %>
             <td class="ps-0">
               <%= link_to_if  can?(:read, involvement.person),
diff --git a/app/views/admin/education/schools/roles/_involvement_fields.html.erb b/app/views/admin/education/schools/roles/_involvement_fields.html.erb
index b90a7d1d0f57f1e0a2b60dcec2d5d7f4047ae590..b05e0c57c9c4cc3205a6ce7a2926ae0eaf6a4ef5 100644
--- a/app/views/admin/education/schools/roles/_involvement_fields.html.erb
+++ b/app/views/admin/education/schools/roles/_involvement_fields.html.erb
@@ -2,13 +2,15 @@
 <div class="nested-fields mb-2">
   <div class="row pure__row--small align-items-center">
     <div class="col-1">
-      <i class="fa fa-bars handle"></i>
+      <i class="<%= Icon::DRAG %> handle"></i>
     </div>
     <div class="col-9">
       <%= f.association :person, collection: @administration_people, label: false, include_blank: :translate, wrapper: false, required: true %>
     </div>
     <div class="col-2">
-      <%= link_to_remove_association '<i class="fas fa-times"></i>'.html_safe, f, class: 'btn btn-sm btn-danger' %>
+      <%= link_to_remove_association  "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
+                                      f,
+                                      class: 'btn btn-sm btn-danger' %>
     </div>
   </div>
   <%= f.hidden_field :position, data: { 'sortable-input': '' } %>
diff --git a/app/views/admin/education/schools/roles/_list.html.erb b/app/views/admin/education/schools/roles/_list.html.erb
index 142980c552c649022e773b436cde2524b6ab97b5..e4bf0ab0e8aa341696bab9011e862cc082e78692 100644
--- a/app/views/admin/education/schools/roles/_list.html.erb
+++ b/app/views/admin/education/schools/roles/_list.html.erb
@@ -15,7 +15,7 @@
         <% roles.each do |role| %>
           <tr data-id="<%= role.id %>">
             <% if can? :reorder, University::Role %>
-              <td><i class="fa fa-bars handle"></i></td>
+              <td><i class="<%= Icon::DRAG %> handle"></i></td>
             <% end %>
             <td class="ps-0">
               <%= link_to_if  can?(:read, role),
diff --git a/app/views/admin/education/schools/roles/show.html.erb b/app/views/admin/education/schools/roles/show.html.erb
index 9bf7f70942a59115fd2db2ce34c352361b87042a..5e7f3be9dbdd63dd19de6447e07ecd6138beea5d 100644
--- a/app/views/admin/education/schools/roles/show.html.erb
+++ b/app/views/admin/education/schools/roles/show.html.erb
@@ -16,7 +16,7 @@
         <% @involvements.each do |involvement| %>
           <tr data-id="<%= involvement.id %>">
             <% if can? :reorder, University::Person::Involvement %>
-              <td><i class="fa fa-bars handle"></i></td>
+              <td><i class="<%= Icon::DRAG %> handle"></i></td>
             <% end %>
             <td class="ps-0">
               <%= link_to_if  can?(:read, involvement.person),
diff --git a/app/views/admin/education/teachers/_involvement_fields.html.erb b/app/views/admin/education/teachers/_involvement_fields.html.erb
index 3cbb4f76aaeeb8f846aedfefc3f280373be52fd8..0419b3e64288d3b51438d89cf9c3c4df944ce251 100644
--- a/app/views/admin/education/teachers/_involvement_fields.html.erb
+++ b/app/views/admin/education/teachers/_involvement_fields.html.erb
@@ -22,9 +22,9 @@
                       wrapper: false %>
         </div>
         <div class="col-md-1 text-end">
-          <%= link_to_remove_association '<i class="fas fa-times"></i>'.html_safe,
-                                         f,
-                                         class: 'btn btn-sm btn-danger' %>
+          <%= link_to_remove_association  "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
+                                          f,
+                                          class: 'btn btn-sm btn-danger' %>
         </div>
       </div>
     </div>
diff --git a/app/views/admin/education/teachers/index.html.erb b/app/views/admin/education/teachers/index.html.erb
index 973534e4e14bca9f1d675fcebe13b0cd6136b2c4..090cba9b092fd436e816c1ecbac65f3b105b74eb 100644
--- a/app/views/admin/education/teachers/index.html.erb
+++ b/app/views/admin/education/teachers/index.html.erb
@@ -1,4 +1,4 @@
-<% content_for :title, "#{t('education.teachers', count: 2)} (#{@teachers.total_count})" %>
+<% content_for :title, University::Person::Teacher.model_name.human(count: 2) %>
 
 <%= render 'filters', current_path: admin_education_teachers_path, filters: @filters if @filters.any?  %>
 
diff --git a/app/views/admin/layouts/themes/pure/_nav.html.erb b/app/views/admin/layouts/themes/pure/_nav.html.erb
index c1cb7e5f387c137287adea20f0b1b62fc49aeebc..4e18def30d29207c87a930a3a8bddd84ffb88eac 100644
--- a/app/views/admin/layouts/themes/pure/_nav.html.erb
+++ b/app/views/admin/layouts/themes/pure/_nav.html.erb
@@ -43,14 +43,17 @@ context ||= :admin
       <div class="row">
         <%= render_navigation context: context, renderer: Osuny::SimpleNavigationRenderer %>
         <div class="col-md-4 col-lg-3">
-          <a class="float-end" href="#">
-            <% if current_user.picture.attached? && current_user.picture.variable? %>
-              <%= image_tag current_user.picture.variant(resize: '160x160'), class: 'avatar img-fluid rounded-circle' %>
-            <% else %>
-              <%= image_tag 'avatar.jpg', class: 'avatar img-fluid rounded-circle' %>
-            <% end %>
-          </a>
-          <h2><%= current_user.to_s %></h2>
+          <% 
+          if current_user.picture.attached? && current_user.picture.variable? 
+            image = current_user.picture.variant(resize: '200x200')
+          else
+            image = 'avatar.jpg'
+          end
+          %>
+          <%= link_to admin_user_path(current_user) do %>
+            <%= image_tag image, class: 'image', loading: :lazy %>
+          <% end %>
+          <h2><%= link_to current_user.to_s, admin_user_path(current_user) %></h2>
           <ul>
             <li><%= link_to t('menu.profile'), edit_user_registration_path %></li>
             <li><%= link_to t('menu.server_admin'), server_root_path if current_user.server_admin? %></li>
diff --git a/app/views/admin/layouts/themes/pure/_panel.html.erb b/app/views/admin/layouts/themes/pure/_panel.html.erb
index a119a06d2898d82b55ae92b0b864fb8715d99e4c..622f74dd953a269dad2b4628e7d9fa97a0885603 100644
--- a/app/views/admin/layouts/themes/pure/_panel.html.erb
+++ b/app/views/admin/layouts/themes/pure/_panel.html.erb
@@ -1,4 +1,5 @@
 <section class="pure__section flex-fill position-relative">
+  <%= image_tag image, class: 'img-fluid mb-3', loading: :lazy if image %>
   <% if action %>
     <div class="float-end"><%= raw action %></div>
   <% end %>
diff --git a/app/views/admin/research/journals/show.html.erb b/app/views/admin/research/journals/show.html.erb
index 2d80a449b8f1f02d0734bdbf893fab4a566abf20..2998a0a57c424965d093373e723f6eaa8dc012fa 100644
--- a/app/views/admin/research/journals/show.html.erb
+++ b/app/views/admin/research/journals/show.html.erb
@@ -3,7 +3,7 @@
 <% content_for :title_right do %>
   <% if @journal.websites.any? %>
     <%= Communication::Website.model_name.human(count: 2) %>
-    <i class="fas fa-arrow-right small"></i>
+    <i class="<%= Icon::ARROW_RIGHT %> small"></i>
     <% @journal.websites.each do |website| %>
       <%= link_to website, [:admin, website] %><br>
     <% end %>
diff --git a/app/views/admin/research/journals/volumes/show.html.erb b/app/views/admin/research/journals/volumes/show.html.erb
index e2852145b862ab64356aa2110b3be41ba3d5d177..2a46b266508a6f6df8c1512195a56487326b621b 100644
--- a/app/views/admin/research/journals/volumes/show.html.erb
+++ b/app/views/admin/research/journals/volumes/show.html.erb
@@ -21,7 +21,7 @@
               <% @papers.each do |paper| %>
                 <tr data-id="<%= paper.id %>">
                   <% if can? :reorder, Research::Journal::Paper %>
-                    <td><i class="fa fa-bars handle"></i></td>
+                    <td><i class="<%= Icon::DRAG %> handle"></i></td>
                   <% end %>
                   <td>
                     <%= link_to paper,
diff --git a/app/views/admin/research/laboratories/axes/_list.html.erb b/app/views/admin/research/laboratories/axes/_list.html.erb
index 62dec193111ca105a30deec9489b7ffd7399190d..63ee86865438c46fa272a28eb82624884b781412 100644
--- a/app/views/admin/research/laboratories/axes/_list.html.erb
+++ b/app/views/admin/research/laboratories/axes/_list.html.erb
@@ -14,7 +14,7 @@
       <% axes.each do |axis| %>
         <tr data-id="<%= axis.id %>">
           <% if can? :reorder, Research::Laboratory::Axis %>
-            <td><i class="fa fa-bars handle"></i></td>
+            <td><i class="<%= Icon::DRAG %> handle"></i></td>
           <% end %>
           <td>
             <%= link_to axis, admin_research_laboratory_axis_path(laboratory_id: axis.laboratory, id: axis) %>
diff --git a/app/views/admin/research/publications/_list.html.erb b/app/views/admin/research/publications/_list.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..b03ba32612477a128d8eacbfb6c8c99eecb23cb4
--- /dev/null
+++ b/app/views/admin/research/publications/_list.html.erb
@@ -0,0 +1,24 @@
+<div class="table-responsive">
+  <table class="<%= table_classes %>">
+    <thead>
+      <tr>
+        <th><%= Research::Publication.human_attribute_name('title') %></th>
+        <th><%= t('research.researchers', count: 2) %></th>
+      </tr>
+    </thead>
+    <tbody>
+      <% publications.each do |publication| %>
+        <tr>
+          <td><%= link_to publication, admin_research_publication_path(publication) %></td>
+          <td>
+            <% publication.researchers.each do |researcher| %>
+              <%= link_to_if  researcher.university == current_university, 
+                              researcher, 
+                              admin_research_researcher_path(researcher) %>
+            <% end %>
+          </td>
+        </tr>
+      <% end %>
+    </tbody>
+  </table>
+</div>
\ No newline at end of file
diff --git a/app/views/admin/research/publications/index.html.erb b/app/views/admin/research/publications/index.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..164e21085f11a8602afb7b338d85df671c9e0c7b
--- /dev/null
+++ b/app/views/admin/research/publications/index.html.erb
@@ -0,0 +1,5 @@
+<% content_for :title, Research::Publication.model_name.human(count: 2) %>
+
+<%= render 'admin/research/publications/list', publications: @publications %>
+
+<%= paginate @publications, theme: 'bootstrap-5' %>
diff --git a/app/views/admin/research/publications/show.html.erb b/app/views/admin/research/publications/show.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..9ca0010a81330855f533496fc4bb6cdb512a2724
--- /dev/null
+++ b/app/views/admin/research/publications/show.html.erb
@@ -0,0 +1,19 @@
+<% content_for :title, @publication %>
+
+<% @publication.research_people.each do |person| %>
+  <%= link_to person, admin_research_researcher_path(person) %>
+<% end %>
+
+<p><%= @publication.docid %></p>
+
+<div><%= sanitize @publication.ref %></div>
+
+<%= link_to 'url', @publication.url, target: :_blank if @publication.url %>
+<%= link_to 'HAL', @publication.hal_url, target: :_blank if @publication.hal_url %>
+<%= link_to 'DOI', @publication.doi_url, target: :_blank if @publication.doi_url %>
+
+<% content_for :action_bar_left do %>
+  <%= link_to t('static'),
+              static_admin_research_publication_path(@publication),
+              class: button_classes('btn-light') if current_user.server_admin? %>
+<% end %>
diff --git a/app/views/admin/research/publications/static.html.erb b/app/views/admin/research/publications/static.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..5910efe141522de01b82ee8447c1558390ce224e
--- /dev/null
+++ b/app/views/admin/research/publications/static.html.erb
@@ -0,0 +1,16 @@
+---
+title: "<%= @about.title %>"
+date: "<%= @about.publication_date&.iso8601 %>"
+slug: "<%= @about.slug %>"
+docid: "<%= @about.docid %>"
+ref: >
+  <%= sanitize @about.ref %>
+url:
+  hal: "<%= @about.hal_url %>"
+  doi: "<%= @about.doi_url %>"
+  raw: "<%= @about.url %>"
+researchers:
+<% @about.researchers.each do |researcher| %>
+  - <%= researcher.slug %>
+<% end %>
+---
diff --git a/app/views/admin/research/researchers/index.html.erb b/app/views/admin/research/researchers/index.html.erb
index 8dd753f09bf0841137a842ca90250c07d928aa80..6e6def800911a49aca69bc5b826ac3432eaa04d1 100644
--- a/app/views/admin/research/researchers/index.html.erb
+++ b/app/views/admin/research/researchers/index.html.erb
@@ -8,8 +8,10 @@
       <tr>
         <th><%= University::Person.human_attribute_name('name') %></th>
         <th><%= University::Person.human_attribute_name('first_name') %></th>
-        <th></th>
-        <th><%= t('research.number_of_papers') %></th>
+        <th><%= University::Person.human_attribute_name('picture') %></th>
+        <th><%= Research::Publication.model_name.human(count: 2) %></th>
+        <th><%= Research::Journal::Paper.model_name.human(count: 2) %></th>
+        <th width="160"></th>
       </tr>
     </thead>
 
@@ -18,11 +20,14 @@
         <tr>
           <td><%= link_to researcher.last_name, admin_research_researcher_path(researcher) %></td>
           <td><%= link_to researcher.first_name, admin_research_researcher_path(researcher) %></td>
-          <td class="p-0">
-            <%= kamifusen_tag researcher.best_picture,
-                              width: 40 if researcher.best_picture.attached? %>
+          <td>
+            <% if researcher.best_picture.attached? && researcher.best_picture.variable? %>
+              <%= kamifusen_tag researcher.best_picture, width: 60 %>
+            <% end %>
           </td>
+          <td><%= researcher.research_publications.count %></td>
           <td><%= researcher.research_journal_papers.count %></td>
+          <td></td>
         </tr>
       <% end %>
     </tbody>
@@ -31,7 +36,6 @@
 
 <%= paginate @researchers, theme: 'bootstrap-5' %>
 
-
 <% content_for :action_bar_right do %>
   <%= link_to t('research.manage_researchers'), admin_university_people_path, class: button_classes if can?(:read, University::Person) %>
 <% end %>
diff --git a/app/views/admin/research/researchers/show.html.erb b/app/views/admin/research/researchers/show.html.erb
index 63257c188fb3d295609c3128918307221423ba25..c4811e1bb07962219650f4ab2258f7387d33b9b0 100644
--- a/app/views/admin/research/researchers/show.html.erb
+++ b/app/views/admin/research/researchers/show.html.erb
@@ -3,17 +3,32 @@
 <%= render 'admin/university/people/main_infos', person: @researcher %>
 
 <% if @papers.total_count > 0 %>
-  <div class="card">
-    <div class="card-header">
-      <h2 class="card-title mb-0 h5"><%= "#{Research::Journal::Paper.model_name.human(count: 2)} (#{@papers.total_count})" %></h2>
-    </div>
+  <%= osuny_panel Research::Journal::Paper.model_name.human(count: 2) do %>
     <%= render 'admin/research/journals/papers/list', papers: @papers %>
-    <% if @papers.total_pages > 1 %>
-      <div class="card-footer">
-        <%= paginate @papers, theme: 'bootstrap-5' %>
-      </div>
-    <% end %>
-  </div>
+    <%= paginate @papers, theme: 'bootstrap-5' %>
+  <% end %>
+<% end %>
+
+<%= osuny_panel Research::Publication.model_name.human(count: 2), action: @researcher.research_publications.count do %>
+  <% if @researcher.hal_identity? %>
+    <div class="table-responsive">
+      <%= render 'admin/research/publications/list', publications: @researcher.research_publications.ordered %>
+    </div>
+  <% else %>
+    <p><%= t 'research.hal.select_identifier' %><p>
+    <ul class="list-unstyled">
+      <% @possible_hal_authors.each do |author| %>
+        <li>
+          <%= link_to admin_research_researcher_path( @researcher, 
+                                                      hal_doc_identifier: author.docid,
+                                                      hal_form_identifier: author.attributes['form_i'],
+                                                      hal_person_identifier: author.attributes['person_i']), method: :put do %>
+            <%= author.fullName_s %> (<%= author.docid %>)
+          <% end %>
+        </li>
+      <% end %>
+    </ul>
+  <% end %>
 <% end %>
 
 <% content_for :action_bar_right do %>
diff --git a/app/views/admin/university/alumni/cohorts/_cohort_fields.html.erb b/app/views/admin/university/alumni/cohorts/_cohort_fields.html.erb
index b66b73ca7f2bc0df238ae63e3524b2554432b9ce..a59c53d17cd15d985325efed82a58d2d9f6c7ee3 100644
--- a/app/views/admin/university/alumni/cohorts/_cohort_fields.html.erb
+++ b/app/views/admin/university/alumni/cohorts/_cohort_fields.html.erb
@@ -31,7 +31,7 @@
                             wrapper: false %>
         </div>
         <div class="col-md-1 text-end">
-          <%= link_to_remove_association '<i class="fas fa-times"></i>'.html_safe,
+          <%= link_to_remove_association "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
                                          f,
                                          class: 'btn btn-sm btn-danger' %>
         </div>
diff --git a/app/views/admin/university/alumni/experiences/_experience_fields.html.erb b/app/views/admin/university/alumni/experiences/_experience_fields.html.erb
index fc6a6e5c946a998956ae5cc0af91a397bd37cac3..820d47b06518502b08d69d3a148047b6e9d24450 100644
--- a/app/views/admin/university/alumni/experiences/_experience_fields.html.erb
+++ b/app/views/admin/university/alumni/experiences/_experience_fields.html.erb
@@ -35,9 +35,9 @@ hint = can?(:create, University::Organization) ?  t('university.person.experienc
           </div>
         </div>
         <div>
-          <%= link_to_remove_association '<i class="fas fa-times"></i>'.html_safe,
-                                        f,
-                                        class: 'btn btn-sm btn-danger' %>
+          <%= link_to_remove_association  "<i class=\"#{ Icon::DELETE }\"></i>".html_safe,
+                                          f,
+                                          class: 'btn btn-sm btn-danger' %>
         </div>
       </div>
     </div>
diff --git a/app/views/admin/university/people/_form.html.erb b/app/views/admin/university/people/_form.html.erb
index 655df3b1316a5bfc2e2d21f68f0afa06dc5391cf..8080b66f100e303d4053bd68849e063339a13179 100644
--- a/app/views/admin/university/people/_form.html.erb
+++ b/app/views/admin/university/people/_form.html.erb
@@ -3,7 +3,7 @@
   <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
 
   <div class="row">
-    <div class="col-md-8">
+    <div class="col-lg-8">
       <%= osuny_panel University::Person.human_attribute_name('essentials') do %>
         <div class="row pure__row--small">
           <div class="col-xxl-6">
@@ -74,6 +74,19 @@
           </div>
         </div>
       <% end %>
+      <%= osuny_panel t('research.hal.title') do %>
+        <div class="row">
+          <div class="col-xxl-6">
+            <%= f.input :hal_doc_identifier %>
+          </div>
+          <div class="col-xxl-6">
+            <%= f.input :hal_person_identifier %>
+          </div>
+          <div class="col-xxl-6">
+            <%= f.input :hal_form_identifier %>
+          </div>
+        </div>
+      <% end if person.is_researcher? %>
       <%= osuny_panel University::Person.human_attribute_name('abilities') do %>
         <div class="row pure__row--small">
           <div class="col-xxl-6">
@@ -89,7 +102,7 @@
         </div>
       <% end %>
     </div>
-    <div class="col-md-4">
+    <div class="col-lg-4">
       <%= osuny_panel t('metadata') do %>
           <%= f.input :slug,
                       as: :string,
diff --git a/app/views/admin/university/people/_main_infos.html.erb b/app/views/admin/university/people/_main_infos.html.erb
index 477cfae60f5b96433e45674daff4d32113f0d988..46d22c8d98cf1750982300950766d813f789e847 100644
--- a/app/views/admin/university/people/_main_infos.html.erb
+++ b/app/views/admin/university/people/_main_infos.html.erb
@@ -43,7 +43,7 @@
         <%= person.biography %>
       <% end %>
     <% end %>
-    
+
     <%= osuny_panel University::Person.human_attribute_name('socials') do %>
       <% unless person.url.blank? %>
         <%= osuny_label University::Person.human_attribute_name('url') %>
@@ -74,6 +74,7 @@
           <p><%= link_to_if can?(:read, person.user), person.user, admin_user_path(person.user) %></p>
         <% end %>
     <% end %>
+    <%= render 'admin/application/i18n/widget', about: person %>
     <%= osuny_panel t('activerecord.attributes.university/person.picture') do %>
       <% if person.best_picture_inherits_from_user? %>
         <p>
diff --git a/app/views/admin/university/people/administrators/static.html.erb b/app/views/admin/university/people/administrators/static.html.erb
index 5902a5d2070e642c75f59da2e8dde750634b3fe0..286718254a26cc80a23b5781399c066f0eed9c4d 100644
--- a/app/views/admin/university/people/administrators/static.html.erb
+++ b/app/views/admin/university/people/administrators/static.html.erb
@@ -9,6 +9,7 @@ first_name: >
   <%= @about.first_name %>
 last_name: >
   <%= @about.last_name %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
 ---
diff --git a/app/views/admin/university/people/authors/static.html.erb b/app/views/admin/university/people/authors/static.html.erb
index 5759db851d6dd42b4457ac640fd83fd71dc0decf..e44ee10cea02e1831dbb6bd7ae35b32ea5d56068 100644
--- a/app/views/admin/university/people/authors/static.html.erb
+++ b/app/views/admin/university/people/authors/static.html.erb
@@ -9,6 +9,7 @@ first_name: >
   <%= @about.first_name %>
 last_name: >
   <%= @about.last_name %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
 ---
diff --git a/app/views/admin/university/people/researchers/static.html.erb b/app/views/admin/university/people/researchers/static.html.erb
index 84b7176db352c054aef825fec92ad25d2524ebc6..17d3bdd271425c0c335fb816b77831079caba48f 100644
--- a/app/views/admin/university/people/researchers/static.html.erb
+++ b/app/views/admin/university/people/researchers/static.html.erb
@@ -9,6 +9,7 @@ first_name: >
   <%= @about.first_name %>
 last_name: >
   <%= @about.last_name %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
 ---
diff --git a/app/views/admin/university/people/static.html.erb b/app/views/admin/university/people/static.html.erb
index 5c3cb9a62b35b7277bcaae1a9817a1384050b6f0..48da801d9bdcca6973bde9478edb075dadd419f7 100644
--- a/app/views/admin/university/people/static.html.erb
+++ b/app/views/admin/university/people/static.html.erb
@@ -5,6 +5,7 @@ title: >
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
 <%= render 'admin/application/static/design', full_width: true, toc_offcanvas: true %>
+<%= render 'admin/application/i18n/static' %>
 first_name: >
   <%= @about.first_name %>
 last_name: >
@@ -73,6 +74,21 @@ administrative_missions:
         <%= target.current_permalink_in_website(@website)&.path if target.respond_to? :current_permalink_in_website %>
 <% end %>
 <% end %>
+<% if @about.publications.any? %>
+publications:
+<% @about.publications.each do |publication| %>
+  - title: >
+      <%= prepare_text_for_static publication.title %>
+    ref: >
+      <%= prepare_html_for_static publication.ref, @website.university %>
+    url: >
+      <%= prepare_text_for_static publication.url %>
+    hal_url: >
+      <%= prepare_text_for_static publication.hal_url %>
+    doi_url: >
+      <%= prepare_text_for_static publication.doi_url %>
+<% end %>
+<% end %>
 <%= render 'admin/communication/blocks/static', about: @about %>
 ---
 <%= prepare_html_for_static @about.biography, @about.university %>
diff --git a/app/views/admin/university/people/teachers/static.html.erb b/app/views/admin/university/people/teachers/static.html.erb
index b2d59e7b9ad73586918679effb5c26e0074e8fd4..1c684711d25b7cf619ba56fcc491ae61f4c07d57 100644
--- a/app/views/admin/university/people/teachers/static.html.erb
+++ b/app/views/admin/university/people/teachers/static.html.erb
@@ -9,6 +9,7 @@ first_name: >
   <%= @about.first_name %>
 last_name: >
   <%= @about.last_name %>
+<%= render 'admin/application/i18n/static' %>
 <%= render 'admin/application/meta_description/static' %>
 <%= render 'admin/application/summary/static' %>
 ---
diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb
index ce585ca206e8ceadc9041fd370f92e82e5fbc018..288e6602ceab46ef1e2c621fea2c4ff6dc6f58dc 100644
--- a/app/views/admin/users/index.html.erb
+++ b/app/views/admin/users/index.html.erb
@@ -1,8 +1,8 @@
 <% content_for :title, "#{User.model_name.human(count: 2)} (#{@users.total_count})" %>
 
-<%= render 'admin/application/filters',
-    current_path: admin_users_path,
-    filters: @filters if @filters.any? %>
+<%= render  'admin/application/filters',
+            current_path: admin_users_path,
+            filters: @filters if @filters.any? %>
 
 <div class="table-responsive">
   <table class="<%= table_classes %>">
diff --git a/app/views/server/universities/_form.html.erb b/app/views/server/universities/_form.html.erb
index f55c3a5bbd839f8e9efd9c5ff3fb8246a559234c..792181f1a8112d203de4dabd53eaeb9223404965 100644
--- a/app/views/server/universities/_form.html.erb
+++ b/app/views/server/universities/_form.html.erb
@@ -6,6 +6,7 @@
     <div class="col-md-4">
       <%= f.input :name %>
       <%= f.input :identifier %>
+      <%= f.association :default_language, include_blank: false %>
       <%= f.input :private %>
       <%= f.input :sms_sender_name,
                   maxlength: 11 %>
diff --git a/app/views/server/universities/_sso_mapping.html.erb b/app/views/server/universities/_sso_mapping.html.erb
index 19eee43d893cc54a8c7a160f55db7d0b0e955828..a353ec6e660120312bb8c5de09b2b39f9b13e98a 100644
--- a/app/views/server/universities/_sso_mapping.html.erb
+++ b/app/views/server/universities/_sso_mapping.html.erb
@@ -21,7 +21,7 @@ end
         <div class="card">
           <div class="card-header d-flex justify-content-between">
             <div>
-              <i class="fas fa-arrows-alt dragHandle"></i>
+              <i class="<%= Icon::SORT %> dragHandle"></i>
               &nbsp;
               <a data-bs-toggle="collapse" :href="'#sso_mapping_collapse_' + index ">
                 {{index + 1}}. {{ field.sso_key }} -> {{ keys[field.internal_key]}}
@@ -30,7 +30,7 @@ end
             <a
               v-on:click="fields.splice(fields.indexOf(field), 1)"
               title="Remove field">
-              <i class="far fa-trash-alt"></i>
+              <i class="<%= Icon::DELETE %>"></i>
             </a>
           </div>
           <div class="card-body collapse pt-0" :id="'sso_mapping_collapse_' + index ">
diff --git a/app/views/server/websites/_list.html.erb b/app/views/server/websites/_list.html.erb
index 061993597f07fcfbb886194a6a9e5f09f23b15b4..dab2389a5eebec82b2fec25d201cd130cc7ed60b 100644
--- a/app/views/server/websites/_list.html.erb
+++ b/app/views/server/websites/_list.html.erb
@@ -8,12 +8,12 @@
         <th><%= Communication::Website.human_attribute_name('theme_version') %></th>
         <th><%= University.model_name.human %></th>
         <th><%= Communication::Website.human_attribute_name('created_at') %></th>
-        <th></th>
+        <th width="160"></th>
       </tr>
     </thead>
     <tbody>
       <% websites.ordered.each do |website| %>
-        <tr>
+        <tr id="website-<%= website.id %>">
           <td><%= link_to website.name, admin_communication_website_url(website, host: website.university.url), target: :_blank %></td>
           <td><%= I18n.t("activerecord.attributes.communication/website.about_#{website.about_type}") %></td>
           <td>
@@ -22,12 +22,12 @@
               <span class="badge bg-success">Prod</span>
             <% end %>
           </td>
-          <td><%= link_to website.theme_version, website.theme_version_url, target: :_blank if website.theme_version_url.present? %></td>
+          <td class="js-version"><%= link_to website.theme_version, website.theme_version_url, target: :_blank if website.theme_version_url.present? %></td>
           <td><%= link_to website.university, [:server, website.university] %></td>
           <td><%= l website.created_at.to_date %></td>
-          <td><%= link_to "Sync version", refresh_server_website_path(website), method: :post, class: button_classes if website.url.present? %></td>
+          <td><%= link_to "Sync version", refresh_server_website_path(website), method: :post, remote: true, class: button_classes if website.url.present? %></td>
         </tr>
       <% end %>
     </tbody>
   </table>
-</div>
\ No newline at end of file
+</div>
diff --git a/app/views/server/websites/index.html.erb b/app/views/server/websites/index.html.erb
index b3d4a09cca19597789d636548966cadb4aeb2763..32fd7c7a742e28495c9436a523bc83b35cc7c9a4 100644
--- a/app/views/server/websites/index.html.erb
+++ b/app/views/server/websites/index.html.erb
@@ -2,4 +2,8 @@
 
 <p><%= Communication::Website.in_production.count %> en production</p>
 
-<%= render 'server/websites/list', websites: @websites %>
\ No newline at end of file
+<%= render  'admin/application/filters',
+            current_path: server_websites_path,
+            filters: @filters if @filters.any? %>
+
+<%= render 'server/websites/list', websites: @websites %>
diff --git a/app/views/server/websites/refresh.js.erb b/app/views/server/websites/refresh.js.erb
new file mode 100644
index 0000000000000000000000000000000000000000..5e4a1ebd8298c0d7c701ec736c224d555e1be6fb
--- /dev/null
+++ b/app/views/server/websites/refresh.js.erb
@@ -0,0 +1,2 @@
+var column = document.querySelector('#website-<%= @website.id %> .js-version');
+column.innerHTML = "<%= j link_to @website.theme_version, @website.theme_version_url, target: '_blank' if @website.theme_version_url.present? %>";
diff --git a/config/admin_navigation.rb b/config/admin_navigation.rb
index 9d1b22980fff7353f26f65be9f7553a62bb76a0f..f4e11299d9c6bcb52d99ce607a380cfa9a8ef7d6 100644
--- a/config/admin_navigation.rb
+++ b/config/admin_navigation.rb
@@ -3,138 +3,55 @@ SimpleNavigation::Configuration.run do |navigation|
   navigation.auto_highlight = true
   navigation.highlight_on_subpath = true
   navigation.selected_class = 'active'
-  navigation.items do |primary|
-    primary.item  :dashboard, t('admin.dashboard'),
-                  admin_root_path, 
-                  { icon: Icon::DASHBOARD, highlights_on: /admin$/ }
 
-    if can?(:read, University::Person) || can?(:read, University::Organization)
-      primary.item :university,
-                    University.model_name.human,
-                    nil,
-                    { kind: :header }
-      primary.item :university,
-                    University::Person.model_name.human(count: 2),
-                    admin_university_people_path,
-                    { icon: Icon::UNIVERSITY_PERSON } if can?(:read, University::Person)
-      primary.item :university,
-                    University::Organization.model_name.human(count: 2),
-                    admin_university_organizations_path,
-                    { icon: Icon::UNIVERSITY_ORGANIZATION } if can?(:read, University::Organization)
-      primary.item :communication_alumni,
-                    University::Person::Alumnus.model_name.human(count: 2),
-                    admin_university_alumni_path,
-                    { icon: Icon::UNIVERSITY_PERSON_ALUMNUS } if can?(:read, University::Person)
+  def load_from_parts class_name, primary
+    class_name.parts.each do |part|
+      class_name = part.first
+      identifier = class_name.to_s.to_sym
+      label = class_name.model_name.human(count: 2)
+      path = send part.last
+      icon = Icon.icon_for class_name
+      primary.item identifier, label, path, { icon: icon } if can?(:read, class_name)
+    end
+  end
+
+  navigation.items do |primary|
+    if current_admin_theme == 'appstack'
+      primary.item  :dashboard, t('admin.dashboard'), admin_root_path,  { icon: Icon::DASHBOARD, highlights_on: /admin$/ }
     end
 
     if can?(:read, Education::Program)
-      primary.item :education,
-                    Education.model_name.human,
-                    nil,
-                    { kind: :header }
-      primary.item :education_teachers,
-                    t('education.teachers', count: 2),
-                    admin_education_teachers_path,
-                    { icon: Icon::EDUCATION_TEACHER } if can?(:read, University::Person)
-      primary.item :education_schools,
-                    Education::School.model_name.human(count: 2), admin_education_schools_path,
-                    { icon: Icon::EDUCATION_SCHOOL } if can?(:read, Education::School)
-      primary.item :education_diplomas,
-                    Education::Diploma.model_name.human(count: 2), admin_education_diplomas_path,
-                    { icon: Icon::EDUCATION_DIPLOMA } if can?(:read, Education::Diploma)
-      primary.item :education_programs,
-                    Education::Program.model_name.human(count: 2), admin_education_programs_path,
-                    { icon: Icon::EDUCATION_PROGRAM } if can?(:read, Education::Program)
-      primary.item :education,
-                    'Ressources éducatives',
-                    nil,
-                    { icon: 'laptop' }
-      primary.item :education,
-                    'Feedbacks',
-                    nil,
-                    { icon: 'comments' }
+      primary.item :education, Education.model_name.human, admin_education_root_path, { kind: :header, image: 'admin/education-thumb.jpg' }
+      load_from_parts Education, primary
+      primary.item :education, 'Ressources éducatives', nil, { icon: Icon::EDUCATION_RESOURCES }
+      primary.item :education, 'Feedbacks', nil, { icon: Icon::EDUCATION_FEEDBACKS }
     end
 
-    if can?(:read, Research::Journal) || can?(:read, Research::Laboratory)
-      primary.item :research,
-                    Research.model_name.human,
-                    nil,
-                    { kind: :header }
-      primary.item :research_researchers,
-                    t('research.researchers', count: 2),
-                    admin_research_researchers_path(journal_id: nil),
-                    { icon: Icon::RESEARCH_RESEARCHER } if can?(:read, University::Person)
-      primary.item :research_laboratories,
-                    Research::Laboratory.model_name.human(count: 2), admin_research_laboratories_path,
-                    { icon: Icon::RESEARCH_LABORATORY } if can?(:read, Research::Laboratory)
-      primary.item :research_theses,
-                    Research::Thesis.model_name.human(count: 2),
-                    admin_research_theses_path,
-                    { icon: Icon::RESEARCH_THESE } if can?(:read, Research::Thesis)
-      primary.item :research_journals,
-                    Research::Journal.model_name.human(count: 2),
-                    admin_research_journals_path,
-                    { icon: Icon::RESEARCH_JOURNAL } if can?(:read, Research::Journal)
-      primary.item :research_watch,
-                    'Veille',
-                    nil,
-                    { icon: 'eye' }
+    if can?(:read, Research::Journal) || can?(:read, Research::Publication) || can?(:read, Research::Laboratory)
+      primary.item :research, Research.model_name.human, admin_research_root_path, { kind: :header, image: 'admin/research-thumb.jpg' }
+      load_from_parts Research, primary
+      primary.item :research_watch, 'Veille', nil, { icon: Icon::RESEARCH_WATCH }
     end
 
     if can?(:read, Communication::Website)
-      primary.item :communication,
-                    Communication.model_name.human,
-                    nil,
-                    { kind: :header }
-      primary.item :communication_websites,
-                    Communication::Website.model_name.human(count: 2),
-                    admin_communication_websites_path,
-                    { icon: Icon::COMMUNICATION_WEBSITE } if can?(:read, Communication::Website)
-      primary.item :communication_extranets,
-                    Communication::Extranet.model_name.human(count: 2), admin_communication_extranets_path,
-                    { icon: Icon::COMMUNICATION_EXTRANET } if can?(:read, Communication::Extranet)
-      primary.item :communication_newsletters,
-                    'Lettres d\'information',
-                    nil,
-                    { icon: 'envelope' }
+      primary.item :communication, Communication.model_name.human, admin_communication_root_path, { kind: :header, image: 'admin/communication-thumb.jpg' }
+      load_from_parts Communication, primary
+      primary.item :communication_newsletters, 'Lettres d\'information', nil, { icon: Icon::COMMUNICATION_NEWSLETTERS }
     end
 
     if can?(:read, Administration::Qualiopi::Criterion)
-      primary.item :administration,
-                    'Administration',
-                    nil,
-                    { kind: :header }
-      primary.item :administration_campus,
-                    'Campus',
-                    nil,
-                    { icon: 'map-marker-alt' }
-      primary.item :administration_admissions,
-                    'Admissions',
-                    nil,
-                    { icon: 'door-open' }
-      primary.item :administration_internship,
-                    'Stages',
-                    nil,
-                    { icon: 'hands-helping' }
-      primary.item :administration_statistics,
-                    'Statistiques',
-                    nil,
-                    { icon: 'chart-bar' }
-      primary.item :administration_qualiopi,
-                    'Qualité',
-                    admin_administration_qualiopi_criterions_path,
-                    { icon: 'tasks' } if can?(:read, Administration::Qualiopi::Criterion)
+      primary.item :administration, Administration.model_name.human, admin_administration_root_path, { kind: :header, image: 'admin/administration-thumb.jpg' }
+      load_from_parts Administration, primary
+      primary.item :administration_campus, 'Campus', nil, { icon: Icon::ADMINISTRATION_CAMPUS }
+      primary.item :administration_admissions, 'Admissions', nil, { icon: Icon::ADMINISTRATION_ADMISSIONS }
+      primary.item :administration_internship, 'Stages', nil, { icon: Icon::ADMINISTRATION_INTERNSHIPS }
+      primary.item :administration_statistics, 'Statistiques', nil, { icon: Icon::ADMINISTRATION_STATISTICS }
     end
 
-    if can?(:read, User)
-      primary.item :administration,
-                    'Osuny',
-                    nil,
-                    { kind: :header }
-      primary.item :administration_users,
-                    User.model_name.human(count: 2),
-                    admin_users_path,
-                    { icon: 'user' } if can?(:read, User)
+    if can?(:read, University::Person) || can?(:read, University::Organization)
+      primary.item :university, University.model_name.human, admin_university_root_path, { kind: :header, image: 'admin/university-thumb.jpg' }
+      load_from_parts University, primary
     end
+
   end
 end
diff --git a/config/locales/administration/en.yml b/config/locales/administration/en.yml
index ee9d57f1e169bd4891f7d13a738f1ff57ac26da9..ce23b4dc0ca7a26af92318a5d25a3b6b9ecb3ad8 100644
--- a/config/locales/administration/en.yml
+++ b/config/locales/administration/en.yml
@@ -25,3 +25,9 @@ en:
         requirement: Requirement
         non_conformity: Non-conformity
         glossary: Glossary
+  administration:
+    description:
+      text: L'administration, sous ses multiples formes, se définit principalement par ses activités au service de l'intérêt général. L'administration agit dans l'intérêt général et respecte le principe de légalité. Elle est tenue à l'obligation de neutralité et au respect du principe de laïcité. Elle se conforme au principe d'égalité et garantit à chacun un traitement impartial.
+      source: Code des relations entre le public et l'administration
+    qualiopi:
+      description: Aide à la vérification de la conformité de l'offre de formation avec la norme Qualiopi
\ No newline at end of file
diff --git a/config/locales/administration/fr.yml b/config/locales/administration/fr.yml
index e9d4fa0f992598683c0c90b3147be503e6d99c4a..3b955daa3605e95b9397bf31ec1a3858f676fc05 100644
--- a/config/locales/administration/fr.yml
+++ b/config/locales/administration/fr.yml
@@ -25,3 +25,9 @@ fr:
         requirement: Obligations spécifiques
         non_conformity: Non-conformité
         glossary: Glossaire
+  administration:
+    description:
+      text: L'administration, sous ses multiples formes, se définit principalement par ses activités au service de l'intérêt général. L'administration agit dans l'intérêt général et respecte le principe de légalité. Elle est tenue à l'obligation de neutralité et au respect du principe de laïcité. Elle se conforme au principe d'égalité et garantit à chacun un traitement impartial.
+      source: Code des relations entre le public et l'administration
+    qualiopi:
+      description: Aide à la vérification de la conformité de l'offre de formation avec la norme Qualiopi
\ No newline at end of file
diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml
index 5882e7ef89c8d4438d974a49406d52d7dec0b627..db55b72350b224452bfbc183c5e738891507d6bf 100644
--- a/config/locales/communication/en.yml
+++ b/config/locales/communication/en.yml
@@ -50,6 +50,7 @@ en:
         about_type: About
         color: Couleur
         cookies_policy: Cookies policy
+        description: Espaces d'échanges sécurisés dédiés aux personnes authentifiées
         favicon: Favicon (.png)
         has_sso: Has SSO?
         host: Domain
@@ -75,6 +76,7 @@ en:
         access_token: Access token
         created_at: Creation
         default_language: Default language
+        description: Espaces publics de diffusion d'information, sobre sur le plan écologique et accessible aux personnes en situation de handicap
         git_branch: Git branch
         git_endpoint: Git endpoint
         git_provider: Git provider
@@ -97,9 +99,6 @@ en:
       communication/website/menu:
         identifier: Identifier
         items: Items
-        legal: Legal
-        primary: Main menu
-        social: Social
         title: Title
       communication/website/menu/item:
         about: Target
@@ -148,6 +147,7 @@ en:
         communication/website:
           attributes:
             languages:
+              must_include_default: must include at least the default language
               too_short: must include at least one
   admin:
     communication:
@@ -291,6 +291,8 @@ en:
             edit:
               add_definition: Add definition
               remove_definition: Delete definition
+              description:
+                label: Description
               element:
                 title:
                   label: Title
@@ -549,6 +551,9 @@ en:
     block:
       choose_template: Choose the kind of block to add
       choose: Choose
+    description:
+      text: Communiquer, c'est mettre en commun; et mettre en commun, c'est l'acte qui nous constitue. Si l'on estime que cet acte est impossible, on refuse tout projet humain.
+      source: Albert Jacquard, Petite philosophie à l'usage des non-philosophes, 1997
     manage_authors: Manage authors
     number_of_posts: Nunber of posts
     website:
@@ -567,6 +572,11 @@ en:
         pending: Import in progress
       last_pages: Last pages
       last_posts: Last posts
+      menus:
+        default_title:
+          legal: Legal
+          primary: Main menu
+          social: Social
       pages:
         defaults:
           accessibility:
@@ -681,7 +691,10 @@ en:
       communication_website:
         git_branch: 'If blank, default branch will be used'
         git_endpoint: 'If blank, default will be used (https://github.com or https://gitlab.com/api/v4)'
-        languages: 'If you select at least one language the website will be considered as possibly multilingual, and therefore all urls will be prefixed with the language (/fr, /en)'
+        languages: 'If you select one language the website urls will not be prefixed. If you select more than one language the website will then be considered as multilingual, and therefore all urls will be prefixed with the language (/fr, /en)'
       communication_website_page:
         breadcrumb_title: If the field is empty, page title will be used in breadcrumbs.
         full_width: On large screens, a full width page uses all available space for the content. This is good for landing pages, or to make them spectacular. If the page is not full width, the content column will be smaller to make reading easier. The unused space might be used for a table of contents.
+        text: This field is deprecated, content will not be displayed on the website.
+      communication_website_post:
+        text: This field is deprecated, content will not be displayed on the website.
diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml
index 06742087e3317c21c41e4d2dd07babe81ad45f54..827b5f231f299cb081e470dc4055329de9e73113 100644
--- a/config/locales/communication/fr.yml
+++ b/config/locales/communication/fr.yml
@@ -50,6 +50,7 @@ fr:
         about_type: Type d'extranet
         color: Couleur
         cookies_policy: Politique de cookies
+        description: Espaces d'échanges sécurisés dédiés aux personnes authentifiées
         favicon: Favicon (.png)
         has_sso: A un SSO ?
         host: Domaine
@@ -75,6 +76,7 @@ fr:
         access_token: Access token
         created_at: Création
         default_language: Langue par défaut
+        description: Espaces publics de diffusion d'information, sobre sur le plan écologique et accessible aux personnes en situation de handicap
         git_branch: Branche
         git_endpoint: Point d'accès Git
         git_provider: Provider Git
@@ -97,9 +99,6 @@ fr:
       communication/website/menu:
         identifier: Identifiant
         items: Éléments
-        legal: Informations légales
-        primary: Menu principal
-        social: Liens sociaux
         title: Titre
       communication/website/menu/item:
         about: Cible
@@ -148,6 +147,7 @@ fr:
         communication/website:
           attributes:
             languages:
+              must_include_default: doivent contenir la langue par défaut
               too_short: doivent en comporter une minimum
   admin:
     communication:
@@ -551,6 +551,9 @@ fr:
     block:
       choose_template: Choisir le type de bloc à ajouter
       choose: Choisir
+    description:
+      text: Communiquer, c'est mettre en commun; et mettre en commun, c'est l'acte qui nous constitue. Si l'on estime que cet acte est impossible, on refuse tout projet humain.
+      source: Albert Jacquard, Petite philosophie à l'usage des non-philosophes, 1997
     manage_authors: Gérer les auteur·rice·s
     number_of_posts: Nombre d'actualités
     website:
@@ -569,6 +572,11 @@ fr:
         pending: Import en cours
       last_pages: Dernières pages
       last_posts: Dernières actualités
+      menus:
+        default_title:
+          legal: Informations légales
+          primary: Menu principal
+          social: Liens sociaux
       pages:
         defaults:
           accessibility:
@@ -683,7 +691,7 @@ fr:
       communication_website:
         git_branch: 'Laisser vide pour la branche par défaut'
         git_endpoint: 'Laisser vide pour les valeurs par défaut (https://github.com ou https://gitlab.com/api/v4)'
-        languages: 'Si vous sélectionnez au moins une langue le site sera considéré comme possiblement multilingue et donc toutes les urls seront préfixées avec la langue (/fr, /en)'
+        languages: 'Si vous sélectionnez une seule langue les urls ne seront pas préfixées. Si vous en sélectionnez plusieurs le site sera considéré comme multilingue et donc toutes les urls seront préfixées avec la langue (/fr, /en)'
       communication_website_page:
         breadcrumb_title: Si ce champ est vide le titre de la page sera utilisé dans le fil d'Ariane.
         full_width: Sur de grands écrans, la page en pleine largeur utilisera tout l'espace disponible, ce qui est pertinent pour événementialiser une page. Si la page n'est pas en pleine largeur, l'espace dédié au contenu sera réduit pour faciliter la lecture, et l'espace libre pourra être utilisé pour une table des matières facilitant la navigation.
diff --git a/config/locales/education/en.yml b/config/locales/education/en.yml
index ac13e8f926e31c23b40f80bfe0601a29cd7de7e2..16fd9aa73dc2bb0aca1e80c495d559bb7b42156e 100644
--- a/config/locales/education/en.yml
+++ b/config/locales/education/en.yml
@@ -4,6 +4,9 @@ en:
       education: Education
   activerecord:
     models:
+      university/person/teacher:
+        one: Teacher
+        other: Teachers
       education/academic_year:
         one: Year
         other: Years
@@ -87,6 +90,9 @@ en:
         tree:
           title: Programs treeview
   education:
+    description: 
+      text: L’éducation est l’ensemble des processus et des procédés qui permettent à tout enfant humain d’accéder progressivement à la culture, l’accès à la culture étant ce qui distingue l’homme de l’animal.
+      source: Olivier Reboul, La philosophie de l'éducation, 2018
     manage_programs: Manage programs
     manage_roles: Manage roles
     manage_teachers: Manage teachers
@@ -117,9 +123,6 @@ en:
       other: Roles
     schools:
       manage_roles: Manage the team
-    teachers:
-      one: Teacher
-      other: Teachers
   enums:
     education:
       diploma:
diff --git a/config/locales/education/fr.yml b/config/locales/education/fr.yml
index bc51c0384bbfbf77f7fa51eacd092bced4019b84..dcf3e47d01f945f5da95aaf87caa58aebe8cc7b8 100644
--- a/config/locales/education/fr.yml
+++ b/config/locales/education/fr.yml
@@ -4,6 +4,9 @@ fr:
       education: Enseignement
   activerecord:
     models:
+      university/person/teacher:
+        one: Enseignant·e
+        other: Enseignant·e·s
       education/academic_year:
         one: Année
         other: Années
@@ -28,6 +31,7 @@ fr:
         school: École
         year: Année
       education/diploma:
+        description: Présentation des diplômes et de leurs caractéristiques
         duration: Durée
         ects: Crédits ECTS
         level: Niveau
@@ -40,6 +44,7 @@ fr:
         capacity: Capacité
         contacts: Contacts
         continuing: Formation continue
+        description: Présentation exhaustive des formations, de leurs contenus, modalités pédagogiques et perspectives
         diploma: Diplôme
         duration: Durée
         downloadable_summary: Document de synthèse téléchargeable
@@ -63,7 +68,7 @@ fr:
         roles: Rôles
         schools: Écoles proposant cette formation
         short_name: Nom abrégé
-        teachers: Enseignants·es
+        teachers: Enseignant·e·s
         team: Équipe
         content: Contenus de la formation
         results: Indicateurs de résultats
@@ -72,12 +77,15 @@ fr:
         administrators: Équipe administrative
         city: Ville
         country: Pays
+        description: Présentation des écoles, de leurs coordonnées, enseignements, équipes et informations administratives
         name: Nom
         phone: Téléphone
         programs: Formations dispensées
         roles: Membres de l'équipe
         websites: Sites Web associés
         zipcode: Code postal
+      university/person/teacher:
+        description: Présentation des enseignants et enseignantes, avec leur biographie et leurs enseignements dans les différentes formations
   admin:
     education:
       programs:
@@ -87,6 +95,9 @@ fr:
         tree:
           title: Arborescence des formations
   education:
+    description: 
+      text: L’éducation est l’ensemble des processus et des procédés qui permettent à tout enfant humain d’accéder progressivement à la culture, l’accès à la culture étant ce qui distingue l’homme de l’animal.
+      source: Olivier Reboul, La philosophie de l'éducation, 2018
     manage_programs: Gérer les formations
     manage_roles: Gérer les rôles
     manage_teachers: Gérer les enseignants·es
@@ -117,9 +128,6 @@ fr:
       other: Rôles
     schools:
       manage_roles: Gérer l'équipe
-    teachers:
-      one: Enseignant·e
-      other: Enseignants·es
   enums:
     education:
       diploma:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 318ac19cf9f1b3422ccfe68abcec04bd4b6c31df..532844c10cdc8e5f195020193a84ec7ca872bc66 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -46,6 +46,7 @@ en:
         summernote_locale: Summernote locale code
       user:
         admin_theme: Admin Theme
+        description: Personne utilisant Osuny, dotée d'un compte authentifié
         email: Email
         first_name: First name
         language: Favourite language
@@ -208,6 +209,8 @@ en:
     still_pending: "Your import has not been processed yet. You will receive an email as soon as it's ready."
   import_btn: Import
   inactivity_alert: "It seems you have been away a little bit too long. Could you please retry?"
+  internationalization:
+    label: Internationalization
   languages:
     en: English
     fr: French
diff --git a/config/locales/extranet/en.yml b/config/locales/extranet/en.yml
index c56a2abc9b31c5e82bd65cf2ff1b10247656b099..f3766ca4dad4a61a8234be50bb186c114372bb09 100644
--- a/config/locales/extranet/en.yml
+++ b/config/locales/extranet/en.yml
@@ -12,6 +12,7 @@ en:
       email_not_allowed_with_contact: is not authorized to access this extranet. Contact %{contact} for more information.
     experiences:
       new: Add experience
+      search_organization: Search by name or SIREN
       title: Path
     home:
       recent_cohorts: Recent cohorts
@@ -22,5 +23,6 @@ en:
     osuny_html:
       <a href="https://www.osuny.org" target="_blank" rel="noreferer">Crafted with ♥ and with Osuny</a>
     personal_data:
+      edit: Edit
       title: My personal data
       updated: Your personal data has been updated!
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 28b2136d766f093d50d237587c102e1fea8fe7c6..ba028427c365e4174f854e6f32431cb116fc07e8 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -46,6 +46,7 @@ fr:
         summernote_locale: Nom de la locale Summernote
       user:
         admin_theme: Thème de l'administration
+        description: Personne utilisant Osuny, dotée d'un compte authentifié
         email: Email
         first_name: Prénom
         language: Langue préférée
@@ -208,6 +209,8 @@ fr:
     still_pending: "Votre import est toujours en cours de traitement. Vous recevrez un email dès qu'il est prêt."
   import_btn: Importer
   inactivity_alert: "Il semble que vous soyez resté sur la page un peu trop longtemps. Pouvez-vous ré-essayer ?"
+  internationalization:
+    label: Internationalisation
   languages:
     en: Anglais
     fr: Français
diff --git a/config/locales/research/en.yml b/config/locales/research/en.yml
index 4ac3f87f6e41abfd7ed54e47c57380af2400dcfe..1788650bb93ae6f41e6f8969055f29c7f074de09 100644
--- a/config/locales/research/en.yml
+++ b/config/locales/research/en.yml
@@ -4,6 +4,9 @@ en:
       research: Research
   activerecord:
     models:
+      university/person/researcher:
+        one: Researcher
+        other: Researchers
       research/journal:
         one: Journal
         other: Journals
@@ -22,11 +25,15 @@ en:
       research/laboratory/axis:
         one: Axis
         other: Axes
+      research/publication:
+        one: Publication
+        other: Publications
       research/thesis:
         one: Thesis
         other: Theses
     attributes:
       research/journal:
+        description: Journaux en accès ouvert (open access) permettant aux chercheur·e·s de contribuer à la recherche
         issn: ISSN
         title: Title
       research/journal/paper:
@@ -55,24 +62,34 @@ en:
         address: Address
         country: Country
         city: City
+        description: Structure de recherche hébergeant le travail des chercheur·e·s
         name: Name
         zipcode: Zipcode
       research/laboratory/axis:
         name: Name
         short_name: Short name
         text: Text
+      research/publication:
+        title: Title
+        description: Publications scientifiques importées automatiquement de HAL
       research/thesis:
         abstract: Abstract
         author: Author
         completed: Completed?
         completed_at: Completed at
+        description: Production scientifique permettant d'obtenir le titre de Docteur·e
         director: Director
         laboratory: Laboratory
         started_at: Started at
         title: Title
   research:
+    description:
+      text: La recherche scientifique est, à la fois, une démarche créatrice de connaissances motivée par la curiosité pure et une activité génératrice d’innovations qui augmentent les moyens d’action et de diagnostic sur la nature, l’homme et la société. Ces deux aspects de la recherche, le fondamental et l’appliqué, loin de s’opposer, sont complémentaires l’un de l’autre. La recherche fondamentale crée le socle de connaissances à partir duquel naissent les applications et, inversement, les avancées technologiques procurent les outils d’investigation de plus en plus perfectionnés qui conduisent à approfondir nos connaissances fondamentales.
+      source: Serge Haroche, Prix Nobel de physique 2012
+    hal:
+      title: HAL
+      select_identifier: You have no HAL identifier yet. Is it one of these possibilities? If there are several, please choose the most complete one (without -0 at the end).
     manage_researchers: Managege researchers
-    number_of_papers: Number of papers
     researchers:
       one: Researcher
       other: Researchers
diff --git a/config/locales/research/fr.yml b/config/locales/research/fr.yml
index baa9d39da0b2063d69f970cb75eb4c8ce6818ece..793af9b89289294f1c6aa38ddeab5e667d40fbdf 100644
--- a/config/locales/research/fr.yml
+++ b/config/locales/research/fr.yml
@@ -4,6 +4,9 @@ fr:
       research: Recherche
   activerecord:
     models:
+      university/person/researcher:
+        one: Chercheur·e
+        other: Chercheur·e·s
       research/journal:
         one: Revue scientifique
         other: Revues scientifiques
@@ -22,11 +25,15 @@ fr:
       research/laboratory/axis:
         one: Axe
         other: Axes
+      research/publication:
+        one: Publication
+        other: Publications
       research/thesis:
         one: Thèse
         other: Thèses
     attributes:
       research/journal:
+        description: Journaux en accès ouvert (open access) permettant aux chercheur·e·s de contribuer à la recherche
         issn: ISSN
         title: Titre
       research/journal/paper:
@@ -37,7 +44,7 @@ fr:
         published_at: Publié le
         references: Références
         kind: Type de papier
-        people: Auteu·rs·rices
+        people: Auteur·e·s
         text: Texte
         title: Titre
       research/journal/paper/kind:
@@ -55,27 +62,37 @@ fr:
         address: Adresse
         country: Pays
         city: Ville
+        description: Structure de recherche hébergeant le travail des chercheur·e·s
         name: Nom
         zipcode: Code postal
       research/laboratory/axis:
         name: Nom
         short_name: Nom court
         text: Texte
+      research/publication:
+        title: Titre
+        description: Publications scientifiques importées automatiquement de HAL
       research/thesis:
         abstract: Résumé
         author: Auteur·rice
         completed: Complétée ?
         completed_at: Complétée le
+        description: Production scientifique permettant d'obtenir le titre de Docteur·e
         director: Directeur·rice
         laboratory: Laboratoire
         started_at: Commencée le
         title: Titre
   research:
-    manage_researchers: Gérer les Chercheu·rs·ses
-    number_of_papers: Nombre de papiers
+    description:
+      text: La recherche scientifique est, à la fois, une démarche créatrice de connaissances motivée par la curiosité pure et une activité génératrice d’innovations qui augmentent les moyens d’action et de diagnostic sur la nature, l’homme et la société. Ces deux aspects de la recherche, le fondamental et l’appliqué, loin de s’opposer, sont complémentaires l’un de l’autre. La recherche fondamentale crée le socle de connaissances à partir duquel naissent les applications et, inversement, les avancées technologiques procurent les outils d’investigation de plus en plus perfectionnés qui conduisent à approfondir nos connaissances fondamentales.
+      source: Serge Haroche, Prix Nobel de physique 2012
+    hal:
+      title: HAL
+      select_identifier: Vous n'avez pas d'identifiant HAL. Est-ce l'une des possibilités suivantes ? S'il y a plusieurs possibilités, choisissez l'identifiant le plus complet (sans 0 à la fin).
+    manage_researchers: Gérer les chercheur·e·s
     researchers:
-      one: Chercheu·r·se
-      other: Chercheu·rs·ses
+      one: Chercheur·e
+      other: Chercheur·e·s
   simple_form:
     hints:
       research_journal_volume:
diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml
index 54a67b638b0ea7df16d0557d342d4cb94ec5987c..e379782d10e5dcad662ac08e502acabb48e37bbc 100644
--- a/config/locales/university/en.yml
+++ b/config/locales/university/en.yml
@@ -5,6 +5,7 @@ en:
         address: Address
         city: City
         country: Country
+        default_language: Default language
         has_sso: Has SSO?
         identifier: Identifier
         invoice_amount: Invoice amount
@@ -34,6 +35,7 @@ en:
         communication_website_posts: Posts
         contacts: Contact information
         country: Country
+        description: Personne physique liée à une université, une composante, un laboratoire, etc.
         education_programs: Programs
         email: Email
         essentials: Essentials
@@ -44,6 +46,9 @@ en:
           male: Male
           non_binary: Non binary
         habilitation: Can direct research?
+        hal_doc_identifier: Doc identifier
+        hal_form_identifier: Form identifier
+        hal_person_identifier: Person identifier
         is_administration: Administrative staff
         is_alumnus: Alumnus
         is_author: Author
@@ -84,6 +89,7 @@ en:
         contact: Contact information
         country: Country
         email: Email
+        description: Personne morale liée à une université, une composante, un laboratoire, etc.
         kind: Kind
         legal: Legal information
         linkedin: LinkedIn
@@ -175,6 +181,9 @@ en:
         import_btn: Import experiences
         import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @."
         title: Experiences imports
+    description:
+      text: Une université est une institution d'enseignement supérieur, d'étude et de recherche, constituée par la réunion de divers établissements nommés suivant les traditions “collèges”, “facultés”, “instituts”, “départements”, “centres”, “sections”, “unités” ou écoles spécifiques, mais aussi bibliothèque ou atelier, médiathèque ou musée, etc. formant un ensemble administratif cohérent avec un statut de droit défini, public, privé ou éventuellement mixte.
+      source: Wikipedia
     internal_key: Internal Key
     invoice_informations: Invoice informations
     manage_alumni: Manage alumni
diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml
index 5cc0997b8023cfd1f049992035d8caf9b54d68d3..e27af33f636acd2ce38a7bd662c4108628ab29a1 100644
--- a/config/locales/university/fr.yml
+++ b/config/locales/university/fr.yml
@@ -5,6 +5,7 @@ fr:
         address: Adresse
         city: Ville
         country: Pays
+        default_language: Langue par défaut
         has_sso: A un SSO ?
         identifier: Identifiant
         invoice_amount: Montant de facturation
@@ -34,6 +35,7 @@ fr:
         communication_website_posts: Actualités
         contacts: Coordonnées
         country: Pays
+        description: Personne physique liée à une université, une composante, un laboratoire, etc.
         education_programs: Formations
         email: Email
         essentials: Informations essentielles
@@ -44,10 +46,13 @@ fr:
           male: Masculin
           non_binary: Non binaire
         habilitation: Peut diriger des recherches ?
+        hal_doc_identifier: Identifiant doc
+        hal_form_identifier: Identifiant form
+        hal_person_identifier: Identifiant person
         is_administration: Personnel administratif
         is_alumnus: Alumnus
         is_author: Auteur·rice
-        is_researcher: Chercheur·se
+        is_researcher: Chercheur·e
         is_teacher: Enseignant·e
         last_name: Nom de famille
         linkedin: LinkedIn (URL)
@@ -57,7 +62,7 @@ fr:
         phone_professional: Téléphone professionnel
         picture: Photo de profil
         research_journal_papers: Papiers
-        researcher: Chercheur·se
+        researcher: Chercheur·e
         roles: Rôles
         slug: Slug
         socials: Réseaux sociaux
@@ -83,6 +88,7 @@ fr:
         city: Ville
         contact: Informations de contact
         country: Pays
+        description: Personne morale liée à une université, une composante, un laboratoire, etc.
         email: Email
         kind: Type
         legal: Informations légales
@@ -175,6 +181,9 @@ fr:
         import_btn: Importer des expériences
         import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@."
         title: Imports d'expériences
+    description:
+      text: Une université est une institution d'enseignement supérieur, d'étude et de recherche, constituée par la réunion de divers établissements nommés suivant les traditions “collèges”, “facultés”, “instituts”, “départements”, “centres”, “sections”, “unités” ou écoles spécifiques, mais aussi bibliothèque ou atelier, médiathèque ou musée, etc. formant un ensemble administratif cohérent avec un statut de droit défini, public, privé ou éventuellement mixte.
+      source: Wikipedia
     internal_key: Clé interne
     invoice_informations: Données de facturation
     manage_alumni: Gérer les alumni
diff --git a/config/routes/admin/administration.rb b/config/routes/admin/administration.rb
index f5b69fe50d8ccc61e2d3a2873a87271df524af51..1e2581e82cb84a7708069f067b5ef1fcb6dcbd03 100644
--- a/config/routes/admin/administration.rb
+++ b/config/routes/admin/administration.rb
@@ -3,4 +3,5 @@ namespace :administration do
     resources :criterions, only: [:index, :show]
     resources :indicators, only: [:index, :show]
   end
+  root to: 'dashboard#index'
 end
diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb
index 6e5ee1727dd78f239763d03da4c2c920ec243a43..4e0b0e0b7bdc1a3407dafc1a2aca0b6bf326a238 100644
--- a/config/routes/admin/communication.rb
+++ b/config/routes/admin/communication.rb
@@ -5,12 +5,14 @@ namespace :communication do
   end
   resources :websites do
     member do
-      get :import
-      post :import
-      get :style
-      get :analytics
+      scope '/:lang' do
+        get :import
+        post :import
+        get :style
+        get :analytics
+      end
     end
-    resources :pages, controller: 'websites/pages' do
+    resources :pages, controller: 'websites/pages', path: '/:lang/pages' do
       collection do
         post :reorder
       end
@@ -18,10 +20,11 @@ namespace :communication do
         get :children
         get :static
         get :preview
+        get "translate" => "websites/pages#translate", as: :translate
         post :duplicate
       end
     end
-    resources :categories, controller: 'websites/categories' do
+    resources :categories, controller: 'websites/categories', path: '/:lang/categories' do
       collection do
         post :reorder
       end
@@ -30,20 +33,18 @@ namespace :communication do
         get :static
       end
     end
-    resources :authors, controller: 'websites/authors', only: [:index, :show]
-    resources :posts, controller: 'websites/posts' do
-      post :publish, on: :collection
+    resources :authors, controller: 'websites/authors', path: '/:lang/authors', only: [:index, :show]
+    resources :posts, controller: 'websites/posts', path: '/:lang/posts' do
+      collection do
+        resources :curations, as: :post_curations, controller: 'websites/posts/curations', only: [:new, :create]
+        post :publish
+      end
       member do
         get :static
         get :preview
       end
     end
-    resources :curations,
-              path: 'posts/curations',
-              as: :post_curations,
-              controller: 'websites/posts/curations',
-              only: [:new, :create]
-    resources :menus, controller: 'websites/menus' do
+    resources :menus, controller: 'websites/menus', path: '/:lang/menus' do
       resources :items, controller: 'websites/menus/items', except: :index do
         collection do
           get :kind_switch
@@ -69,4 +70,5 @@ namespace :communication do
       resources :imports, only: [:index, :show, :new, :create]
     end
   end
+  root to: 'dashboard#index'
 end
diff --git a/config/routes/admin/education.rb b/config/routes/admin/education.rb
index e49cba17aa8ba69a18a8b36460a6545db4eb3b6c..e8faefb7445c069d1901386fe6c4060218f4cef8 100644
--- a/config/routes/admin/education.rb
+++ b/config/routes/admin/education.rb
@@ -41,4 +41,5 @@ namespace :education do
       get :static
     end
   end
+  root to: 'dashboard#index'
 end
diff --git a/config/routes/admin/research.rb b/config/routes/admin/research.rb
index 024239d0f6c7c1eca66573baa71689122ef27de3..521c188e84c99b471987b3fca4888931da4b623d 100644
--- a/config/routes/admin/research.rb
+++ b/config/routes/admin/research.rb
@@ -1,5 +1,10 @@
 namespace :research do
-  resources :researchers, only: [:index, :show]
+  resources :researchers, only: [:index, :show, :update]
+  resources :publications, only: [:index, :show] do
+    member do
+      get :static
+    end
+  end
   resources :journals do
     resources :volumes, controller: 'journals/volumes' do
       member do
@@ -28,4 +33,5 @@ namespace :research do
     end
   end
   resources :theses
+  root to: 'dashboard#index'
 end
diff --git a/config/routes/admin/university.rb b/config/routes/admin/university.rb
index 9f4701b020e53948e53488e8dc791f93254913a3..e7db269e913d25c0cb96d4403594b88023e81f4b 100644
--- a/config/routes/admin/university.rb
+++ b/config/routes/admin/university.rb
@@ -22,6 +22,7 @@ namespace :university do
   resources :people do
     member do
       get :static
+      get "/translations/:lang" => "people#in_language", as: :show_in_language
     end
   end
   resources :organizations do
@@ -29,4 +30,5 @@ namespace :university do
       get :static
     end
   end
+  root to: 'dashboard#index'
 end
diff --git a/db/migrate/20230113094502_add_hal_id_to_university_persons.rb b/db/migrate/20230113094502_add_hal_id_to_university_persons.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7f4762601759f93cd9a13f3c43ced00deb5fc70a
--- /dev/null
+++ b/db/migrate/20230113094502_add_hal_id_to_university_persons.rb
@@ -0,0 +1,5 @@
+class AddHalIdToUniversityPersons < ActiveRecord::Migration[7.0]
+  def change
+    add_column :university_people, :hal_person_identifier, :string
+  end
+end
diff --git a/db/migrate/20230113132451_create_research_documents.rb b/db/migrate/20230113132451_create_research_documents.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e085910c2e2951926b3d35c0953b5aefd1398952
--- /dev/null
+++ b/db/migrate/20230113132451_create_research_documents.rb
@@ -0,0 +1,15 @@
+class CreateResearchDocuments < ActiveRecord::Migration[7.0]
+  def change
+    create_table :research_documents, id: :uuid do |t|
+      t.references :university, null: false, foreign_key: true, type: :uuid
+      t.references :university_person, null: false, foreign_key: true, type: :uuid
+      t.string :docid
+      t.jsonb :data
+      t.string :title
+      t.string :url
+      t.string :ref
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20230113160749_add_i18n_infos_to_communication_pages.rb b/db/migrate/20230113160749_add_i18n_infos_to_communication_pages.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2315d1f17e0749496d4de5cdd99e133f00e8f7fd
--- /dev/null
+++ b/db/migrate/20230113160749_add_i18n_infos_to_communication_pages.rb
@@ -0,0 +1,13 @@
+class AddI18nInfosToCommunicationPages < ActiveRecord::Migration[7.0]
+  # communication_website_pages already have language_id
+  def up
+    add_reference :communication_website_pages, :original, foreign_key: {to_table: :communication_website_pages}, type: :uuid
+    Communication::Website::Page.where(language_id: nil).each do |page|
+      page.update_column(:language_id, page.website.default_language_id)
+    end
+  end
+
+  def down
+    remove_reference :communication_website_pages, :original
+  end
+end
diff --git a/db/migrate/20230113164208_add_null_false_to_communication_website_page_language_id.rb b/db/migrate/20230113164208_add_null_false_to_communication_website_page_language_id.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2562195795bd4c66abb2cdbaea56c92a4707307a
--- /dev/null
+++ b/db/migrate/20230113164208_add_null_false_to_communication_website_page_language_id.rb
@@ -0,0 +1,5 @@
+class AddNullFalseToCommunicationWebsitePageLanguageId < ActiveRecord::Migration[7.0]
+  def change
+    change_column :communication_website_pages, :language_id, :uuid, null: false
+  end
+end
diff --git a/db/migrate/20230113180753_add_docid_and_form_id_to_university_people.rb b/db/migrate/20230113180753_add_docid_and_form_id_to_university_people.rb
new file mode 100644
index 0000000000000000000000000000000000000000..be134eb4496463fb4173c100df088f3b9a8ee44b
--- /dev/null
+++ b/db/migrate/20230113180753_add_docid_and_form_id_to_university_people.rb
@@ -0,0 +1,6 @@
+class AddDocidAndFormIdToUniversityPeople < ActiveRecord::Migration[7.0]
+  def change
+    add_column :university_people, :hal_doc_identifier, :string
+    add_column :university_people, :hal_form_identifier, :string
+  end
+end
diff --git a/db/migrate/20230114123255_add_hal_url_to_research_documents.rb b/db/migrate/20230114123255_add_hal_url_to_research_documents.rb
new file mode 100644
index 0000000000000000000000000000000000000000..69fc66b82e6886d43883718900d0f3e78c5fa3b8
--- /dev/null
+++ b/db/migrate/20230114123255_add_hal_url_to_research_documents.rb
@@ -0,0 +1,5 @@
+class AddHalUrlToResearchDocuments < ActiveRecord::Migration[7.0]
+  def change
+    add_column :research_documents, :hal_url, :string
+  end
+end
diff --git a/db/migrate/20230114124148_add_hal_publication_date_to_research_documents.rb b/db/migrate/20230114124148_add_hal_publication_date_to_research_documents.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0a01bda4c5f2260b1ca41b36a87f370d2b7694b9
--- /dev/null
+++ b/db/migrate/20230114124148_add_hal_publication_date_to_research_documents.rb
@@ -0,0 +1,5 @@
+class AddHalPublicationDateToResearchDocuments < ActiveRecord::Migration[7.0]
+  def change
+    add_column :research_documents, :publication_date, :date
+  end
+end
diff --git a/db/migrate/20230114124308_add_doi_to_research_documents.rb b/db/migrate/20230114124308_add_doi_to_research_documents.rb
new file mode 100644
index 0000000000000000000000000000000000000000..52a184aa7d7698d03cdd353a2e48dba2e54d1164
--- /dev/null
+++ b/db/migrate/20230114124308_add_doi_to_research_documents.rb
@@ -0,0 +1,5 @@
+class AddDoiToResearchDocuments < ActiveRecord::Migration[7.0]
+  def change
+    add_column :research_documents, :doi, :string
+  end
+end
diff --git a/db/migrate/20230115092626_rename_document_to_publication.rb b/db/migrate/20230115092626_rename_document_to_publication.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b5e43f7a923be2a749ce4561abf63685d82beb86
--- /dev/null
+++ b/db/migrate/20230115092626_rename_document_to_publication.rb
@@ -0,0 +1,18 @@
+class RenameDocumentToPublication < ActiveRecord::Migration[7.0]
+  def change
+    rename_table :research_documents, :research_publications
+
+    remove_column :research_publications, :university_id, :uuid
+    remove_column :research_publications, :university_person_id, :uuid
+
+    create_join_table :research_publications, :university_people, column_options: {type: :uuid} do |t|
+      t.index [:research_publication_id, :university_person_id], name: 'index_publication_person'
+      t.index [:university_person_id, :research_publication_id], name: 'index_person_publication'
+    end
+
+    create_join_table :research_publications, :research_laboratories, column_options: {type: :uuid} do |t|
+      t.index [:research_publication_id, :research_laboratory_id], name: 'index_publication_laboratory'
+      t.index [:research_laboratory_id, :research_publication_id], name: 'index_laboratory_publication'
+    end
+  end
+end
diff --git a/db/migrate/20230115162644_add_slug_to_research_publications.rb b/db/migrate/20230115162644_add_slug_to_research_publications.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c9c4db47e9c5a4511fc631156c1231c6afc7a844
--- /dev/null
+++ b/db/migrate/20230115162644_add_slug_to_research_publications.rb
@@ -0,0 +1,5 @@
+class AddSlugToResearchPublications < ActiveRecord::Migration[7.0]
+  def change
+    add_column :research_publications, :slug, :string
+  end
+end
diff --git a/db/migrate/20230123150502_set_language_on_communication_website_posts.rb b/db/migrate/20230123150502_set_language_on_communication_website_posts.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ebee8b281180a0c6cf44da6a16590cef7b1082cf
--- /dev/null
+++ b/db/migrate/20230123150502_set_language_on_communication_website_posts.rb
@@ -0,0 +1,11 @@
+class SetLanguageOnCommunicationWebsitePosts < ActiveRecord::Migration[7.0]
+  def change
+    add_reference :communication_website_posts, :original, foreign_key: {to_table: :communication_website_posts}, type: :uuid
+
+    Communication::Website.find_each do |website|
+      website.posts.where(language_id: nil).update_all(language_id: website.default_language_id)
+    end
+
+    change_column_null :communication_website_posts, :language_id, false
+  end
+end
diff --git a/db/migrate/20230123162224_set_communication_website_categories_translatable.rb b/db/migrate/20230123162224_set_communication_website_categories_translatable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6d4b7bc7fa049ca3f6d61645fc404312816f4b8c
--- /dev/null
+++ b/db/migrate/20230123162224_set_communication_website_categories_translatable.rb
@@ -0,0 +1,12 @@
+class SetCommunicationWebsiteCategoriesTranslatable < ActiveRecord::Migration[7.0]
+  def change
+    add_reference :communication_website_categories, :original, foreign_key: {to_table: :communication_website_categories}, type: :uuid
+    add_reference :communication_website_categories, :language, foreign_key: true, type: :uuid
+
+    Communication::Website.find_each do |website|
+      website.categories.where(language_id: nil).update_all(language_id: website.default_language_id)
+    end
+
+    change_column_null :communication_website_categories, :language_id, false
+  end
+end
diff --git a/db/migrate/20230126163347_set_communication_website_menu_translatable.rb b/db/migrate/20230126163347_set_communication_website_menu_translatable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8096d244beaeb0023c6f163c485e8cffbf94820a
--- /dev/null
+++ b/db/migrate/20230126163347_set_communication_website_menu_translatable.rb
@@ -0,0 +1,12 @@
+class SetCommunicationWebsiteMenuTranslatable < ActiveRecord::Migration[7.0]
+  def change
+    add_reference :communication_website_menus, :original, foreign_key: {to_table: :communication_website_menus}, type: :uuid
+    add_reference :communication_website_menus, :language, foreign_key: true, type: :uuid
+
+    Communication::Website.find_each do |website|
+      website.menus.where(language_id: nil).update_all(language_id: website.default_language_id)
+    end
+
+    change_column_null :communication_website_menus, :language_id, false
+  end
+end
diff --git a/db/migrate/20230203134137_add_default_language_to_universities.rb b/db/migrate/20230203134137_add_default_language_to_universities.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2f0e8f9223322cd41e4bb032622a98258ad9863e
--- /dev/null
+++ b/db/migrate/20230203134137_add_default_language_to_universities.rb
@@ -0,0 +1,14 @@
+class AddDefaultLanguageToUniversities < ActiveRecord::Migration[7.0]
+  def change
+    add_reference :universities, :default_language, foreign_key: { to_table: :languages }, type: :uuid
+
+    University.reset_column_information
+    language = Language.find_by(iso_code: 'fr')
+    language ||= Language.find_by(iso_code: 'en')
+    language ||= Language.first
+
+    University.all.update_all(default_language_id: language.id)
+
+    change_column_null :universities, :default_language_id, false
+  end
+end
diff --git a/db/migrate/20230203135355_add_i18n_infos_to_university_people.rb b/db/migrate/20230203135355_add_i18n_infos_to_university_people.rb
new file mode 100644
index 0000000000000000000000000000000000000000..43785a9e4ab569c7a8cb22eec8b69e0f1d0a0b1c
--- /dev/null
+++ b/db/migrate/20230203135355_add_i18n_infos_to_university_people.rb
@@ -0,0 +1,13 @@
+class AddI18nInfosToUniversityPeople < ActiveRecord::Migration[7.0]
+  def change
+    add_reference :university_people, :language, foreign_key: true, type: :uuid
+
+    University::Person.reset_column_information
+    University.all.find_each do |university|
+      university.people.update_all(language_id: university.default_language_id)
+    end
+
+    change_column_null :university_people, :language_id, false
+    add_reference :university_people, :original, foreign_key: {to_table: :university_people}, type: :uuid
+  end
+end
diff --git a/db/migrate/20230210132818_add_default_value_to_website_theme_version.rb b/db/migrate/20230210132818_add_default_value_to_website_theme_version.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e66bdb6c341fdb4cf91712855cc64724b25513e8
--- /dev/null
+++ b/db/migrate/20230210132818_add_default_value_to_website_theme_version.rb
@@ -0,0 +1,6 @@
+class AddDefaultValueToWebsiteThemeVersion < ActiveRecord::Migration[7.0]
+  def change
+    change_column_default :communication_websites, :theme_version, 'NA'
+    Communication::Website.where(theme_version: nil).update_all(theme_version: 'NA')
+  end
+end
diff --git a/db/migrate/20230213083544_add_index_to_research_publications.rb b/db/migrate/20230213083544_add_index_to_research_publications.rb
new file mode 100644
index 0000000000000000000000000000000000000000..128ec9d30953d07f12bfada249e44f8b905b3bab
--- /dev/null
+++ b/db/migrate/20230213083544_add_index_to_research_publications.rb
@@ -0,0 +1,5 @@
+class AddIndexToResearchPublications < ActiveRecord::Migration[7.0]
+  def change
+    add_index :research_publications, :docid
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 50a9de2b78181c49e803e1a72980e5e803480f5a..2d9fa7c66d988518c61ea961863f4bb96ea96ab0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,13 +10,13 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
+ActiveRecord::Schema[7.0].define(version: 2023_02_13_083544) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
   enable_extension "unaccent"
 
-  create_table "action_text_rich_texts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "action_text_rich_texts", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name", null: false
     t.text "body"
     t.string "record_type", null: false
@@ -26,7 +26,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
   end
 
-  create_table "active_storage_attachments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "active_storage_attachments", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name", null: false
     t.string "record_type", null: false
     t.uuid "record_id", null: false
@@ -36,7 +36,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
   end
 
-  create_table "active_storage_blobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "active_storage_blobs", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "key", null: false
     t.string "filename", null: false
     t.string "content_type"
@@ -50,13 +50,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_active_storage_blobs_on_university_id"
   end
 
-  create_table "active_storage_variant_records", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "active_storage_variant_records", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "blob_id", null: false
     t.string "variation_digest", null: false
     t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
   end
 
-  create_table "administration_qualiopi_criterions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "administration_qualiopi_criterions", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.integer "number"
     t.text "name"
     t.text "description"
@@ -64,7 +64,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.datetime "updated_at", null: false
   end
 
-  create_table "administration_qualiopi_indicators", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "administration_qualiopi_indicators", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "criterion_id", null: false
     t.integer "number"
     t.text "name"
@@ -78,7 +78,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["criterion_id"], name: "index_administration_qualiopi_indicators_on_criterion_id"
   end
 
-  create_table "communication_blocks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_blocks", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "about_type"
     t.uuid "about_id"
@@ -93,7 +93,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_communication_blocks_on_university_id"
   end
 
-  create_table "communication_extranets", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_extranets", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name"
     t.uuid "university_id", null: false
     t.string "host"
@@ -117,7 +117,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_communication_extranets_on_university_id"
   end
 
-  create_table "communication_website_categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_categories", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "communication_website_id", null: false
     t.string "name"
@@ -134,7 +134,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.string "featured_image_alt"
     t.text "summary"
     t.text "featured_image_credit"
+    t.uuid "original_id"
+    t.uuid "language_id", null: false
     t.index ["communication_website_id"], name: "idx_communication_website_post_cats_on_communication_website_id"
+    t.index ["language_id"], name: "index_communication_website_categories_on_language_id"
+    t.index ["original_id"], name: "index_communication_website_categories_on_original_id"
     t.index ["parent_id"], name: "index_communication_website_categories_on_parent_id"
     t.index ["program_id"], name: "index_communication_website_categories_on_program_id"
     t.index ["university_id"], name: "index_communication_website_categories_on_university_id"
@@ -147,7 +151,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["communication_website_post_id", "communication_website_category_id"], name: "post_category"
   end
 
-  create_table "communication_website_git_files", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_git_files", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "previous_path"
     t.string "about_type", null: false
     t.uuid "about_id", null: false
@@ -159,7 +163,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_git_files_on_website_id"
   end
 
-  create_table "communication_website_imported_authors", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_authors", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.uuid "author_id"
@@ -175,7 +179,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "idx_communication_website_imported_auth_on_website"
   end
 
-  create_table "communication_website_imported_categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_categories", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.uuid "category_id"
@@ -193,7 +197,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "idx_communication_website_imported_cat_on_website"
   end
 
-  create_table "communication_website_imported_media", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_media", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "identifier"
     t.jsonb "data"
     t.text "file_url"
@@ -208,7 +212,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_imported_media_on_website_id"
   end
 
-  create_table "communication_website_imported_pages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_pages", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.uuid "page_id"
@@ -232,7 +236,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_imported_pages_on_website_id"
   end
 
-  create_table "communication_website_imported_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_posts", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.uuid "post_id"
@@ -257,7 +261,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_imported_posts_on_website_id"
   end
 
-  create_table "communication_website_imported_websites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_imported_websites", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.integer "status", default: 0
@@ -267,7 +271,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_imported_websites_on_website_id"
   end
 
-  create_table "communication_website_menu_items", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_menu_items", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.uuid "menu_id", null: false
@@ -287,7 +291,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_menu_items_on_website_id"
   end
 
-  create_table "communication_website_menus", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_menus", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "communication_website_id", null: false
     t.string "title"
@@ -295,11 +299,15 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.text "github_path"
+    t.uuid "original_id"
+    t.uuid "language_id", null: false
     t.index ["communication_website_id"], name: "idx_comm_website_menus_on_communication_website_id"
+    t.index ["language_id"], name: "index_communication_website_menus_on_language_id"
+    t.index ["original_id"], name: "index_communication_website_menus_on_original_id"
     t.index ["university_id"], name: "index_communication_website_menus_on_university_id"
   end
 
-  create_table "communication_website_pages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_pages", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "communication_website_id", null: false
     t.string "title"
@@ -314,17 +322,19 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.text "github_path"
     t.string "featured_image_alt"
     t.text "text"
+    t.text "summary"
     t.string "breadcrumb_title"
     t.text "header_text"
     t.integer "kind"
-    t.text "summary"
     t.string "bodyclass"
-    t.uuid "language_id"
+    t.uuid "language_id", null: false
     t.text "featured_image_credit"
     t.boolean "full_width", default: false
     t.string "type"
+    t.uuid "original_id"
     t.index ["communication_website_id"], name: "index_communication_website_pages_on_communication_website_id"
     t.index ["language_id"], name: "index_communication_website_pages_on_language_id"
+    t.index ["original_id"], name: "index_communication_website_pages_on_original_id"
     t.index ["parent_id"], name: "index_communication_website_pages_on_parent_id"
     t.index ["university_id"], name: "index_communication_website_pages_on_university_id"
   end
@@ -343,7 +353,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["website_id"], name: "index_communication_website_permalinks_on_website_id"
   end
 
-  create_table "communication_website_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_posts", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "communication_website_id", null: false
     t.string "title"
@@ -359,15 +369,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.string "featured_image_alt"
     t.text "text"
     t.text "summary"
-    t.uuid "language_id"
+    t.uuid "language_id", null: false
     t.text "featured_image_credit"
+    t.uuid "original_id"
     t.index ["author_id"], name: "index_communication_website_posts_on_author_id"
     t.index ["communication_website_id"], name: "index_communication_website_posts_on_communication_website_id"
     t.index ["language_id"], name: "index_communication_website_posts_on_language_id"
+    t.index ["original_id"], name: "index_communication_website_posts_on_original_id"
     t.index ["university_id"], name: "index_communication_website_posts_on_university_id"
   end
 
-  create_table "communication_websites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_websites", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
     t.string "url"
@@ -385,7 +397,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.string "git_branch"
     t.boolean "in_production", default: false
     t.uuid "default_language_id", null: false
-    t.string "theme_version"
+    t.string "theme_version", default: "NA"
     t.index ["about_type", "about_id"], name: "index_communication_websites_on_about"
     t.index ["default_language_id"], name: "index_communication_websites_on_default_language_id"
     t.index ["university_id"], name: "index_communication_websites_on_university_id"
@@ -419,7 +431,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["priority", "run_at"], name: "delayed_jobs_priority"
   end
 
-  create_table "education_academic_years", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "education_academic_years", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.integer "year"
     t.datetime "created_at", null: false
@@ -434,7 +446,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_person_id", "education_academic_year_id"], name: "index_person_academic_year"
   end
 
-  create_table "education_cohorts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "education_cohorts", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "program_id", null: false
     t.uuid "academic_year_id", null: false
@@ -455,7 +467,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_person_id", "education_cohort_id"], name: "index_person_cohort"
   end
 
-  create_table "education_diplomas", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "education_diplomas", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name"
     t.string "short_name"
     t.integer "level", default: 0
@@ -469,7 +481,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_education_diplomas_on_university_id"
   end
 
-  create_table "education_programs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "education_programs", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
     t.integer "capacity"
@@ -529,7 +541,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["education_program_id", "user_id"], name: "index_education_programs_users_on_program_id_and_user_id"
   end
 
-  create_table "education_schools", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "education_schools", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
     t.string "address"
@@ -544,7 +556,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_education_schools_on_university_id"
   end
 
-  create_table "imports", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "imports", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.integer "number_of_lines"
     t.jsonb "processing_errors"
     t.integer "kind"
@@ -557,7 +569,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["user_id"], name: "index_imports_on_user_id"
   end
 
-  create_table "languages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "languages", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name"
     t.string "iso_code"
     t.datetime "created_at", null: false
@@ -576,7 +588,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_journal_paper_kinds_on_university_id"
   end
 
-  create_table "research_journal_papers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_journal_papers", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "title"
     t.datetime "published_at", precision: nil
     t.uuid "university_id", null: false
@@ -609,7 +621,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["researcher_id"], name: "index_research_journal_papers_researchers_on_researcher_id"
   end
 
-  create_table "research_journal_volumes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_journal_volumes", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "research_journal_id", null: false
     t.string "title"
@@ -629,7 +641,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_journal_volumes_on_university_id"
   end
 
-  create_table "research_journals", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_journals", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "title"
     t.text "meta_description"
@@ -640,7 +652,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_journals_on_university_id"
   end
 
-  create_table "research_laboratories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_laboratories", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
     t.string "address"
@@ -652,7 +664,14 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_laboratories_on_university_id"
   end
 
-  create_table "research_laboratory_axes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_laboratories_publications", id: false, force: :cascade do |t|
+    t.uuid "research_publication_id", null: false
+    t.uuid "research_laboratory_id", null: false
+    t.index ["research_laboratory_id", "research_publication_id"], name: "index_laboratory_publication"
+    t.index ["research_publication_id", "research_laboratory_id"], name: "index_publication_laboratory"
+  end
+
+  create_table "research_laboratory_axes", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "research_laboratory_id", null: false
     t.string "name"
@@ -666,7 +685,29 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_laboratory_axes_on_university_id"
   end
 
-  create_table "research_theses", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "research_publications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.string "docid"
+    t.jsonb "data"
+    t.string "title"
+    t.string "url"
+    t.string "ref"
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.string "hal_url"
+    t.date "publication_date"
+    t.string "doi"
+    t.string "slug"
+    t.index ["docid"], name: "index_research_publications_on_docid"
+  end
+
+  create_table "research_publications_university_people", id: false, force: :cascade do |t|
+    t.uuid "research_publication_id", null: false
+    t.uuid "university_person_id", null: false
+    t.index ["research_publication_id", "university_person_id"], name: "index_publication_person"
+    t.index ["university_person_id", "research_publication_id"], name: "index_person_publication"
+  end
+
+  create_table "research_theses", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "research_laboratory_id", null: false
     t.uuid "author_id", null: false
@@ -684,7 +725,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_research_theses_on_university_id"
   end
 
-  create_table "universities", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "universities", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.string "name"
     t.string "identifier"
     t.string "address"
@@ -707,9 +748,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.string "sso_name_identifier_format"
     t.jsonb "sso_mapping"
     t.string "sso_button_label"
+    t.uuid "default_language_id", null: false
+    t.index ["default_language_id"], name: "index_universities_on_default_language_id"
   end
 
-  create_table "university_organizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "university_organizations", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "name"
     t.string "long_name"
@@ -736,7 +779,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_university_organizations_on_university_id"
   end
 
-  create_table "university_people", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "university_people", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "user_id"
     t.string "last_name"
@@ -768,12 +811,19 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.string "zipcode"
     t.string "city"
     t.string "country"
+    t.string "hal_person_identifier"
+    t.string "hal_doc_identifier"
+    t.string "hal_form_identifier"
     t.string "mastodon"
+    t.uuid "language_id", null: false
+    t.uuid "original_id"
+    t.index ["language_id"], name: "index_university_people_on_language_id"
+    t.index ["original_id"], name: "index_university_people_on_original_id"
     t.index ["university_id"], name: "index_university_people_on_university_id"
     t.index ["user_id"], name: "index_university_people_on_user_id"
   end
 
-  create_table "university_person_experiences", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "university_person_experiences", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "person_id", null: false
     t.uuid "organization_id", null: false
@@ -787,7 +837,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_university_person_experiences_on_university_id"
   end
 
-  create_table "university_person_involvements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "university_person_involvements", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "person_id", null: false
     t.integer "kind"
@@ -802,7 +852,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_university_person_involvements_on_university_id"
   end
 
-  create_table "university_roles", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "university_roles", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "target_type"
     t.uuid "target_id"
@@ -814,7 +864,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
     t.index ["university_id"], name: "index_university_roles_on_university_id"
   end
 
-  create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "users", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.string "first_name"
     t.string "last_name"
@@ -865,9 +915,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
   add_foreign_key "administration_qualiopi_indicators", "administration_qualiopi_criterions", column: "criterion_id"
   add_foreign_key "communication_blocks", "universities"
   add_foreign_key "communication_extranets", "universities"
+  add_foreign_key "communication_website_categories", "communication_website_categories", column: "original_id"
   add_foreign_key "communication_website_categories", "communication_website_categories", column: "parent_id"
   add_foreign_key "communication_website_categories", "communication_websites"
   add_foreign_key "communication_website_categories", "education_programs", column: "program_id"
+  add_foreign_key "communication_website_categories", "languages"
   add_foreign_key "communication_website_categories", "universities"
   add_foreign_key "communication_website_git_files", "communication_websites", column: "website_id"
   add_foreign_key "communication_website_imported_authors", "communication_website_imported_websites", column: "website_id"
@@ -892,13 +944,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
   add_foreign_key "communication_website_menu_items", "communication_website_menus", column: "menu_id"
   add_foreign_key "communication_website_menu_items", "communication_websites", column: "website_id"
   add_foreign_key "communication_website_menu_items", "universities"
+  add_foreign_key "communication_website_menus", "communication_website_menus", column: "original_id"
   add_foreign_key "communication_website_menus", "communication_websites"
+  add_foreign_key "communication_website_menus", "languages"
   add_foreign_key "communication_website_menus", "universities"
+  add_foreign_key "communication_website_pages", "communication_website_pages", column: "original_id"
   add_foreign_key "communication_website_pages", "communication_website_pages", column: "parent_id"
   add_foreign_key "communication_website_pages", "communication_websites"
   add_foreign_key "communication_website_pages", "universities"
   add_foreign_key "communication_website_permalinks", "communication_websites", column: "website_id"
   add_foreign_key "communication_website_permalinks", "universities"
+  add_foreign_key "communication_website_posts", "communication_website_posts", column: "original_id"
   add_foreign_key "communication_website_posts", "communication_websites"
   add_foreign_key "communication_website_posts", "universities"
   add_foreign_key "communication_website_posts", "university_people", column: "author_id"
@@ -934,8 +990,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_19_164205) do
   add_foreign_key "research_theses", "universities"
   add_foreign_key "research_theses", "university_people", column: "author_id"
   add_foreign_key "research_theses", "university_people", column: "director_id"
+  add_foreign_key "universities", "languages", column: "default_language_id"
   add_foreign_key "university_organizations", "universities"
+  add_foreign_key "university_people", "languages"
   add_foreign_key "university_people", "universities"
+  add_foreign_key "university_people", "university_people", column: "original_id"
   add_foreign_key "university_people", "users"
   add_foreign_key "university_person_experiences", "universities"
   add_foreign_key "university_person_experiences", "university_organizations", column: "organization_id"
diff --git a/lib/tasks/auto.rake b/lib/tasks/auto.rake
new file mode 100644
index 0000000000000000000000000000000000000000..0c8b23305caf5813d3bcf4624d79f1aa47257b73
--- /dev/null
+++ b/lib/tasks/auto.rake
@@ -0,0 +1,6 @@
+namespace :auto do
+  desc 'Update publications from HAL for all researchers'
+  task update_publications_from_hal: :environment do
+    Research::Publication.update_from_hal
+  end
+end
\ No newline at end of file
diff --git a/test/controllers/server/universities_controller_test.rb b/test/controllers/server/universities_controller_test.rb
index b68f98caf705d19e40061400faa38353b04c893e..b512593f49e9a760ee8d1730dd9bd975f04175e8 100644
--- a/test/controllers/server/universities_controller_test.rb
+++ b/test/controllers/server/universities_controller_test.rb
@@ -29,7 +29,8 @@ class Server::UniversitiesControllerTest < ActionDispatch::IntegrationTest
         university: {
           name: "Nouvelle université",
           identifier: "my-second-university",
-          sms_sender_name: "unitest2"
+          sms_sender_name: "unitest2",
+          default_language_id: languages(:fr).id
         }
       }
       university = University.find_by(identifier: "my-second-university")
diff --git a/test/controllers/server/websites_controller_test.rb b/test/controllers/server/websites_controller_test.rb
index aad867f2bf210edc879663d501dba29b97bbc4db..a05c068ebd584e2133d8dafdd5fe095a34569fde 100644
--- a/test/controllers/server/websites_controller_test.rb
+++ b/test/controllers/server/websites_controller_test.rb
@@ -9,7 +9,7 @@ class Server::WebsitesControllerTest < ActionDispatch::IntegrationTest
   end
 
   def test_refresh
-    post(refresh_server_website_path(communication_websites(:website_with_github)))
-    assert_redirected_to(server_websites_path)
+    post(refresh_server_website_path(communication_websites(:website_with_github)), xhr: true)
+    assert_response(:success)
   end
 end
diff --git a/test/fixtures/communication/website/posts.yml b/test/fixtures/communication/website/posts.yml
index 8a2cbd33b616566e8787a71c542a9dacb2e2fa01..55fd7a17790f2a24f5eeecd8b142bb48b63463fe 100644
--- a/test/fixtures/communication/website/posts.yml
+++ b/test/fixtures/communication/website/posts.yml
@@ -18,7 +18,8 @@
 #  updated_at               :datetime         not null
 #  author_id                :uuid             indexed
 #  communication_website_id :uuid             not null, indexed
-#  language_id              :uuid             indexed
+#  language_id              :uuid             not null, indexed
+#  original_id              :uuid             indexed
 #  university_id            :uuid             not null, indexed
 #
 # Indexes
@@ -26,11 +27,13 @@
 #  index_communication_website_posts_on_author_id                 (author_id)
 #  index_communication_website_posts_on_communication_website_id  (communication_website_id)
 #  index_communication_website_posts_on_language_id               (language_id)
+#  index_communication_website_posts_on_original_id               (original_id)
 #  index_communication_website_posts_on_university_id             (university_id)
 #
 # Foreign Keys
 #
 #  fk_rails_1e0d058a25  (university_id => universities.id)
+#  fk_rails_bbbef3b1e9  (original_id => communication_website_posts.id)
 #  fk_rails_d1c1a10946  (communication_website_id => communication_websites.id)
 #  fk_rails_e0eec447b0  (author_id => university_people.id)
 #
@@ -39,6 +42,7 @@ test_post:
   website: website_with_github
   title: Test
   slug: test
+  language: fr
   published: true
   published_at: 2010-11-28 00:00:00
 test_post_2:
@@ -46,5 +50,6 @@ test_post_2:
   website: website_with_github
   title: Test 2
   slug: test-2
+  language: fr
   published: true
   published_at: 2010-11-28 00:00:00
diff --git a/test/fixtures/communication/websites.yml b/test/fixtures/communication/websites.yml
index c88335243ca617b01c215a6c42c30c8a0f47c4c6..8f739d38af84415d173df302117170720604e07d 100644
--- a/test/fixtures/communication/websites.yml
+++ b/test/fixtures/communication/websites.yml
@@ -14,7 +14,7 @@
 #  repository          :string
 #  style               :text
 #  style_updated_at    :date
-#  theme_version       :string
+#  theme_version       :string           default("NA")
 #  url                 :string
 #  created_at          :datetime         not null
 #  updated_at          :datetime         not null
diff --git a/test/fixtures/research/publications.yml b/test/fixtures/research/publications.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2ccd47c2eaf77efc512b4bf3bfad8edabcd83838
--- /dev/null
+++ b/test/fixtures/research/publications.yml
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: research_publications
+#
+#  id               :uuid             not null, primary key
+#  data             :jsonb
+#  docid            :string           indexed
+#  doi              :string
+#  hal_url          :string
+#  publication_date :date
+#  ref              :string
+#  slug             :string
+#  title            :string
+#  url              :string
+#  created_at       :datetime         not null
+#  updated_at       :datetime         not null
+#
+# Indexes
+#
+#  index_research_publications_on_docid  (docid)
+#
+
+default_publication:
+  docid: MyString
+  data:
+  title: MyString
+  url: MyString
+  ref: MyString
diff --git a/test/fixtures/universities.yml b/test/fixtures/universities.yml
index a472c793d596ee8d5ebee66ac613a32d6c9ff02d..ecf1de669721a7a781d0118dcdc90a50f71960c9 100644
--- a/test/fixtures/universities.yml
+++ b/test/fixtures/universities.yml
@@ -25,13 +25,24 @@
 #  zipcode                    :string
 #  created_at                 :datetime         not null
 #  updated_at                 :datetime         not null
+#  default_language_id        :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_universities_on_default_language_id  (default_language_id)
+#
+# Foreign Keys
+#
+#  fk_rails_a8022b1c3f  (default_language_id => languages.id)
 #
 default_university:
   name: Université de test
   identifier: my-university
   sms_sender_name: "unitest"
+  default_language: fr
 
 stale_university:
   name: Université obsolète
   identifier: stale-university
-  sms_sender_name: "unistale"
\ No newline at end of file
+  sms_sender_name: "unistale"
+  default_language: fr
diff --git a/test/fixtures/university/people.yml b/test/fixtures/university/people.yml
index 49c568d5195415d1b2944fba5c22dc17997a8f7f..877859d4d94742760c90f50e7b90ccbbb02a6b27 100644
--- a/test/fixtures/university/people.yml
+++ b/test/fixtures/university/people.yml
@@ -2,47 +2,56 @@
 #
 # Table name: university_people
 #
-#  id                 :uuid             not null, primary key
-#  address            :string
-#  biography          :text
-#  birthdate          :date
-#  city               :string
-#  country            :string
-#  email              :string
-#  first_name         :string
-#  gender             :integer
-#  habilitation       :boolean          default(FALSE)
-#  is_administration  :boolean
-#  is_alumnus         :boolean          default(FALSE)
-#  is_author          :boolean
-#  is_researcher      :boolean
-#  is_teacher         :boolean
-#  last_name          :string
-#  linkedin           :string
-#  mastodon           :string
-#  meta_description   :text
-#  name               :string
-#  phone_mobile       :string
-#  phone_personal     :string
-#  phone_professional :string
-#  slug               :string
-#  summary            :text
-#  tenure             :boolean          default(FALSE)
-#  twitter            :string
-#  url                :string
-#  zipcode            :string
-#  created_at         :datetime         not null
-#  updated_at         :datetime         not null
-#  university_id      :uuid             not null, indexed
-#  user_id            :uuid             indexed
+#  id                    :uuid             not null, primary key
+#  address               :string
+#  biography             :text
+#  birthdate             :date
+#  city                  :string
+#  country               :string
+#  email                 :string
+#  first_name            :string
+#  gender                :integer
+#  habilitation          :boolean          default(FALSE)
+#  hal_doc_identifier    :string
+#  hal_form_identifier   :string
+#  hal_person_identifier :string
+#  is_administration     :boolean
+#  is_alumnus            :boolean          default(FALSE)
+#  is_author             :boolean
+#  is_researcher         :boolean
+#  is_teacher            :boolean
+#  last_name             :string
+#  linkedin              :string
+#  mastodon              :string
+#  meta_description      :text
+#  name                  :string
+#  phone_mobile          :string
+#  phone_personal        :string
+#  phone_professional    :string
+#  slug                  :string
+#  summary               :text
+#  tenure                :boolean          default(FALSE)
+#  twitter               :string
+#  url                   :string
+#  zipcode               :string
+#  created_at            :datetime         not null
+#  updated_at            :datetime         not null
+#  language_id           :uuid             not null, indexed
+#  original_id           :uuid             indexed
+#  university_id         :uuid             not null, indexed
+#  user_id               :uuid             indexed
 #
 # Indexes
 #
+#  index_university_people_on_language_id    (language_id)
+#  index_university_people_on_original_id    (original_id)
 #  index_university_people_on_university_id  (university_id)
 #  index_university_people_on_user_id        (user_id)
 #
 # Foreign Keys
 #
+#  fk_rails_08f468090d  (original_id => university_people.id)
+#  fk_rails_49a0628c42  (language_id => languages.id)
 #  fk_rails_b47a769440  (user_id => users.id)
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
@@ -57,3 +66,4 @@ alumnus:
     - default_cohort
   university: default_university
   user: alumnus
+  language: fr
diff --git a/test/models/communication/website/git_file_test.rb b/test/models/communication/website/git_file_test.rb
index 64e24c479b3d2b982d521c6e4903f8822e5f576f..82338ef8bbdddd952b0c8728e4cee628d181f954 100644
--- a/test/models/communication/website/git_file_test.rb
+++ b/test/models/communication/website/git_file_test.rb
@@ -38,7 +38,6 @@ class Communication::Website::GitFileTest < ActiveSupport::TestCase
       # file = communication_website_git_files(:git_file_2)
       # file.website.git_repository.add_git_file file
       # file.website.git_repository.sync!
-      # byebug
       # Then i got the sha and path, pasted it in the fixtures,
       # changed the text so the content would need an update.
       file = communication_website_git_files(:git_file_2)