diff --git a/app/controllers/admin/communication/websites/menus_controller.rb b/app/controllers/admin/communication/websites/menus_controller.rb
index 7f32950f9effbbd7f214922455716ae1f502a46b..439c06d61e0fccb71235b4f7b31f069b404543da 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.where(language_id: current_website_language.id).ordered.page(params[:page])
     breadcrumb
   end
 
@@ -57,8 +59,6 @@ class Admin::Communication::Websites::MenusController < Admin::Communication::We
   end
 
   def menu_params
-    params.require(:communication_website_menu)
-          .permit(:website_id, :title, :identifier)
-          .merge(university_id: current_university.id)
+    translatable_params(:communication_website_menu, [:title, :identifier])
   end
 end
diff --git a/app/models/communication/website/menu.rb b/app/models/communication/website/menu.rb
index 44f048cbdcf5f61678fc528192bd0b50d5ccbae5..29bb82bfa363041167fe0f2f6ba3cbc20e48f328 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) }
 
@@ -48,4 +55,38 @@ class Communication::Website::Menu < ApplicationRecord
   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
+
+    case item_translation.kind
+    when 'blank', 'url'
+      # Nothing to do
+    when 'program', 'diploma', 'volume', 'paper'
+      # TODO: Translate Education & Research Models
+    when 'page', 'category', 'post'
+      translated_about = item.about.translation_for(menu_translation.language)
+      if translated_about.present?
+        item_translation.about = translated_about
+      elsif item.children.any?
+        # Convert to a blank menu item to translate children correctly
+        item_translation.kind = 'blank'
+        item_translation.about = nil
+      else
+        # Skip menu item if no translation and no children to translate
+        return
+      end
+    end
+
+    item_translation.save
+    item.children.ordered.each do |child|
+      translate_menu_item!(child, menu_translation, item_translation)
+    end
+  end
 end
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 fd977e794c0002efccc44992949e1f295bc0d0ad..fd79a74073f214ecaaa20cd702564c6b5a759de2 100644
--- a/app/views/admin/communication/websites/menus/items/_form.html.erb
+++ b/app/views/admin/communication/websites/menus/items/_form.html.erb
@@ -18,15 +18,15 @@
             <%
               if item.has_about?
                 if item.kind_page?
-                  about_collection = collection_tree @website.pages
+                  about_collection = collection_tree @website.pages.where(language_id: current_website_language.id)
                 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.where(language_id: current_website_language.id)
                 elsif item.kind_post?
-                  about_collection = collection @website.posts
+                  about_collection = collection @website.posts.where(language_id: current_website_language.id)
                 elsif item.kind_volume?
                   about_collection = collection @website.research_volumes
                 elsif item.kind_paper?
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..2a8e26abd148b78fbdc3a2cd137f0b0ee0e8774b 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.where(language_id: current_website_language.id)).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.where(language_id: current_website_language.id)).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.where(language_id: current_website_language.id).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 b504928cbfa47a88a83b140d43af5eadd79a271c..af8e2ef7d071f40e925ce08a2cce450c17e8381f 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 %>
       <h2 class="h3"><%= t('metadata') %></h2>
       <h3 class="h5"><%= Communication::Website::Menu.human_attribute_name('identifier') %></h3>
       <p><%= @menu.identifier %></p>
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/schema.rb b/db/schema.rb
index 88a4f98999aa27b96e83167e045bddec1f59a4d6..a7e8d904def6137fb6f6dc1e729d941870ce891d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) do
+ActiveRecord::Schema[7.0].define(version: 2023_01_26_163347) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
@@ -299,7 +299,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) 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
 
@@ -573,6 +577,20 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) do
     t.string "summernote_locale"
   end
 
+  create_table "research_documents", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.uuid "university_id", null: false
+    t.uuid "university_person_id", null: false
+    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.index ["university_id"], name: "index_research_documents_on_university_id"
+    t.index ["university_person_id"], name: "index_research_documents_on_university_person_id"
+  end
+
   create_table "research_journal_paper_kinds", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "journal_id", null: false
@@ -776,6 +794,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) do
     t.string "zipcode"
     t.string "city"
     t.string "country"
+    t.string "hal_person_identifier"
     t.string "mastodon"
     t.index ["university_id"], name: "index_university_people_on_university_id"
     t.index ["user_id"], name: "index_university_people_on_user_id"
@@ -902,7 +921,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) 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"
@@ -927,6 +948,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_23_162224) do
   add_foreign_key "education_schools", "universities"
   add_foreign_key "imports", "universities"
   add_foreign_key "imports", "users"
+  add_foreign_key "research_documents", "universities"
+  add_foreign_key "research_documents", "university_people"
   add_foreign_key "research_journal_paper_kinds", "research_journals", column: "journal_id"
   add_foreign_key "research_journal_paper_kinds", "universities"
   add_foreign_key "research_journal_papers", "research_journal_paper_kinds", column: "kind_id"