Translate links and buttons in hardcoded french
This commit is contained in:
82
app/helpers/lucide_helper.rb
Normal file
82
app/helpers/lucide_helper.rb
Normal file
@@ -0,0 +1,82 @@
|
||||
module LucideHelper
|
||||
# Create a Lucide icon element
|
||||
#
|
||||
# @param name [String] The name of the Lucide icon
|
||||
# @param options [Hash] Additional options
|
||||
# @option options [String] :class Additional CSS classes
|
||||
# @option options [String] :size Size class (e.g., 'w-4 h-4', 'w-6 h-6')
|
||||
# @option options [Hash] :data Additional data attributes
|
||||
#
|
||||
# @return [String] HTML string for the icon
|
||||
#
|
||||
# Usage:
|
||||
# lucide_icon('user')
|
||||
# lucide_icon('check-circle', class: 'text-green-500', size: 'w-5 h-5')
|
||||
# lucide_icon('menu', data: { action: 'click->header#toggleMenu' })
|
||||
def lucide_icon(name, options = {})
|
||||
css_classes = ["lucide-icon"]
|
||||
css_classes << options[:size] if options[:size]
|
||||
css_classes << options[:class] if options[:class]
|
||||
|
||||
data_attributes = { lucide: name }
|
||||
data_attributes.merge!(options[:data]) if options[:data]
|
||||
|
||||
content_tag :i, "",
|
||||
class: css_classes.join(" "),
|
||||
data: data_attributes,
|
||||
**options.except(:class, :size, :data)
|
||||
end
|
||||
|
||||
# Create a button with a Lucide icon
|
||||
#
|
||||
# @param name [String] The name of the Lucide icon
|
||||
# @param options [Hash] Button options
|
||||
# @option options [String] :text Button text (optional)
|
||||
# @option options [String] :class Additional CSS classes for button
|
||||
# @option options [String] :icon_class Additional CSS classes for icon
|
||||
# @option options [String] :icon_size Size class for icon
|
||||
#
|
||||
# Usage:
|
||||
# lucide_button('plus', text: 'Add Item', class: 'btn btn-primary')
|
||||
# lucide_button('trash-2', class: 'btn-danger', data: { confirm: 'Are you sure?' })
|
||||
def lucide_button(name, options = {})
|
||||
text = options.delete(:text)
|
||||
icon_class = options.delete(:icon_class)
|
||||
icon_size = options.delete(:icon_size) || 'w-4 h-4'
|
||||
|
||||
icon = lucide_icon(name, class: icon_class, size: icon_size)
|
||||
|
||||
content = if text.present?
|
||||
safe_join([icon, " ", text])
|
||||
else
|
||||
icon
|
||||
end
|
||||
|
||||
content_tag :button, content, options
|
||||
end
|
||||
|
||||
# Create a link with a Lucide icon
|
||||
#
|
||||
# @param name [String] The name of the Lucide icon
|
||||
# @param url [String] The URL for the link
|
||||
# @param options [Hash] Link options
|
||||
#
|
||||
# Usage:
|
||||
# lucide_link('edit', edit_user_path(user), text: 'Edit')
|
||||
# lucide_link('external-link', 'https://example.com', text: 'Visit', target: '_blank')
|
||||
def lucide_link(name, url, options = {})
|
||||
text = options.delete(:text)
|
||||
icon_class = options.delete(:icon_class)
|
||||
icon_size = options.delete(:icon_size) || 'w-4 h-4'
|
||||
|
||||
icon = lucide_icon(name, class: icon_class, size: icon_size)
|
||||
|
||||
content = if text.present?
|
||||
safe_join([icon, " ", text])
|
||||
else
|
||||
icon
|
||||
end
|
||||
|
||||
link_to content, url, options
|
||||
end
|
||||
end
|
||||
68
app/javascript/controllers/lucide_controller.js
Normal file
68
app/javascript/controllers/lucide_controller.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
// Connects to data-controller="lucide"
|
||||
export default class extends Controller {
|
||||
static targets = ["icon"]
|
||||
|
||||
connect() {
|
||||
this.initializeIcons()
|
||||
|
||||
// Listen for Turbo navigation events to reinitialize icons
|
||||
document.addEventListener('turbo:render', this.handleTurboRender.bind(this))
|
||||
document.addEventListener('turbo:frame-render', this.handleTurboFrameRender.bind(this))
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
// Clean up event listeners
|
||||
document.removeEventListener('turbo:render', this.handleTurboRender.bind(this))
|
||||
document.removeEventListener('turbo:frame-render', this.handleTurboFrameRender.bind(this))
|
||||
}
|
||||
|
||||
// Initialize all Lucide icons in the controller scope
|
||||
initializeIcons() {
|
||||
if (typeof lucide !== 'undefined') {
|
||||
// Initialize icons within this controller's element
|
||||
lucide.createIcons({
|
||||
element: this.element
|
||||
})
|
||||
} else {
|
||||
console.warn('Lucide not loaded yet, retrying...')
|
||||
// Retry after a short delay if Lucide hasn't loaded yet
|
||||
setTimeout(() => this.initializeIcons(), 100)
|
||||
}
|
||||
}
|
||||
|
||||
// Method to reinitialize icons after dynamic content changes
|
||||
reinitialize() {
|
||||
this.initializeIcons()
|
||||
}
|
||||
|
||||
// Method to create a specific icon programmatically
|
||||
createIcon(iconName, element = null) {
|
||||
if (typeof lucide !== 'undefined') {
|
||||
const targetElement = element || this.element
|
||||
lucide.createIcons({
|
||||
element: targetElement,
|
||||
icons: {
|
||||
[iconName]: lucide[iconName]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Turbo page renders
|
||||
handleTurboRender() {
|
||||
// Small delay to ensure DOM is fully updated
|
||||
setTimeout(() => this.initializeIcons(), 10)
|
||||
}
|
||||
|
||||
// Handle Turbo frame renders
|
||||
handleTurboFrameRender(event) {
|
||||
// Initialize icons within the specific frame that was rendered
|
||||
if (event.detail && event.detail.newFrame) {
|
||||
lucide.createIcons({
|
||||
element: event.detail.newFrame
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,17 @@
|
||||
<img class="mx-auto h-12 w-auto" src="/icon.svg" alt="Aperonight" />
|
||||
<% end %>
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-neutral-900">
|
||||
<%= t('devise.passwords.new.title') %>
|
||||
Mot de passe oublié ?
|
||||
</h2>
|
||||
<p class="mt-2 text-center text-sm text-neutral-600">
|
||||
<%= t('devise.passwords.new.description') %>
|
||||
Entrez votre adresse email ci-dessous et nous vous enverrons un lien pour réinitialiser votre mot de passe.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: "mt-8 space-y-6" }) do |f| %>
|
||||
|
||||
<div>
|
||||
<%= f.label :email, class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.label :email, "Adresse Email", class: "block text-sm font-medium text-neutral-700" %>
|
||||
<div class="mt-1">
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email",
|
||||
class: "appearance-none block w-full px-3 py-2 border border-neutral-300 rounded-md shadow-sm placeholder-neutral-400 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm",
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.submit t('devise.passwords.new.submit'),
|
||||
<%= f.submit "Envoyer le lien de réinitialisation",
|
||||
class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-50 focus:ring-purple-500" %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="w-full border-t border-neutral-300"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600"> <%= t('devise.sessions.new.continue_with') %> </span>
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600">Continuer avec</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,14 +4,9 @@
|
||||
<%= link_to "/" do %>
|
||||
<img class="mx-auto h-12 w-auto" src="/icon.svg" alt="Aperonight" />
|
||||
<% end %>
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-neutral-900">
|
||||
<%= t('devise.registrations.new.title') %>
|
||||
</h2>
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-neutral-900">Créer un compte</h2>
|
||||
<p class="mt-2 text-center text-sm text-neutral-600">
|
||||
<%= t('devise.registrations.new.or') %>
|
||||
<a href="<%= new_user_session_path %>" class="font-medium text-purple-600 hover:text-purple-500">
|
||||
<%= t('devise.registrations.new.sign_in_link') %>
|
||||
</a>
|
||||
ou <a href="<%= new_user_session_path %>" class="font-medium text-purple-600 hover:text-purple-500">se connecter à votre compte</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -19,13 +14,13 @@
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<%= f.label :email, class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.label :email, "Adresse email", class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email",
|
||||
class: "mt-1 block w-full px-3 py-2 border border-neutral-300 rounded-md shadow-sm placeholder-neutral-500 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm" %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.label :password, class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.label :password, "Mot de passe", class: "block text-sm font-medium text-neutral-700" %>
|
||||
<% if @minimum_password_length %>
|
||||
<em class="text-sm text-neutral-500">(<%= t('devise.registrations.new.minimum_password_length', count: @minimum_password_length) %>)</em>
|
||||
<% end %>
|
||||
@@ -34,14 +29,14 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.label :password_confirmation, class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.label :password_confirmation, "Confirmation du mot de passe", class: "block text-sm font-medium text-neutral-700" %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password",
|
||||
class: "mt-1 block w-full px-3 py-2 border border-neutral-300 rounded-md shadow-sm placeholder-neutral-500 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit t('devise.registrations.new.sign_up'), class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-50 focus:ring-purple-500" %>
|
||||
<div class="acthons">
|
||||
<%= f.submit "Créer un compte", class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-50 focus:ring-purple-500" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -51,7 +46,7 @@
|
||||
<div class="w-full border-t border-neutral-300"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600"> <%= t('devise.registrations.new.continue_with') %> </span>
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600">Continuer avec</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
<img class="mx-auto h-12 w-auto" src="/icon.svg" alt="Aperonight" />
|
||||
<% end %>
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-neutral-900">
|
||||
<%= t('devise.sessions.new.title') %>
|
||||
Se connecter à votre compte
|
||||
</h2>
|
||||
<p class="mt-2 text-center text-sm text-neutral-600">
|
||||
<%= t('devise.sessions.new.or') %>
|
||||
ou
|
||||
<a href="<%= new_user_registration_path %>" class="font-medium text-purple-600 hover:text-purple-500">
|
||||
<%= t('devise.sessions.new.sign_up_link') %>
|
||||
créer un compte
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -19,17 +19,17 @@
|
||||
|
||||
<div class="rounded-md shadow-sm -space-y-px">
|
||||
<div class="field">
|
||||
<%= f.label :email, class: "sr-only" %>
|
||||
<%= f.label :email, "Email", class: "sr-only" %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email",
|
||||
class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-neutral-300 placeholder-neutral-500 text-neutral-900 bg-white rounded-t-md focus:outline-none focus:ring-purple-500 focus:border-purple-500 focus:z-10 sm:text-sm",
|
||||
placeholder: t('devise.sessions.new.email_placeholder') %>
|
||||
placeholder: "Adresse email" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password, class: "sr-only" %>
|
||||
<%= f.label :password, "Mot de passe", class: "sr-only" %>
|
||||
<%= f.password_field :password, autocomplete: "current-password",
|
||||
class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-neutral-300 placeholder-neutral-500 text-neutral-900 bg-white rounded-b-md focus:outline-none focus:ring-purple-500 focus:border-purple-500 focus:z-10 sm:text-sm",
|
||||
placeholder: t('devise.sessions.new.password_placeholder') %>
|
||||
placeholder: "Mot de passe" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<%= f.check_box :remember_me, class: "h-4 w-4 text-purple-600 focus:ring-purple-500 border-neutral-300 rounded bg-white" %>
|
||||
<label for="user_remember_me" class="ml-2 block text-sm text-neutral-700"> <%= t('devise.sessions.new.remember_me') %> </label>
|
||||
<label for="user_remember_me" class="ml-2 block text-sm text-neutral-700"> Se souvenir de moi </label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit t('devise.sessions.new.sign_in'), class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-50 focus:ring-purple-500" %>
|
||||
<%= f.submit "Se connecter", class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-50 focus:ring-purple-500" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="w-full border-t border-neutral-300"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600"> <%= t('devise.sessions.new.continue_with') %> </span>
|
||||
<span class="px-2 bg-neutral-50 text-neutral-600">Continuer avec</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
<div class="mt-4 space-y-4">
|
||||
<%- if controller_name != "sessions" %>
|
||||
<div class="w-full flex justify-center py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= link_to t('devise.shared.links.sign_in'), new_session_path(resource_name), class: "block" %>
|
||||
<%= link_to "Se connecter", new_session_path(resource_name), class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != "registrations" %>
|
||||
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= link_to t('devise.shared.links.sign_up'), new_registration_path(resource_name), class: "block" %>
|
||||
<%= link_to "Créer un compte", new_registration_path(resource_name), class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != "passwords" && controller_name != "registrations" %>
|
||||
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= link_to t('devise.shared.links.forgot_password'), new_password_path(resource_name), class: "block" %>
|
||||
<%= link_to "Mot de passe oublié ?", new_password_path(resource_name), class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != "confirmations" %>
|
||||
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= link_to t('devise.shared.links.confirmation_instructions'), new_confirmation_path(resource_name), class: "block" %>
|
||||
<%= link_to "Renvoyer le lien de confirmation", new_confirmation_path(resource_name), class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != "unlocks" %>
|
||||
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= link_to t('devise.shared.links.unlock_instructions'), new_unlock_path(resource_name), class: "block" %>
|
||||
<%= link_to "Renvoyer le lien de déblocage", new_unlock_path(resource_name), class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-neutral-300 rounded-md shadow-sm text-sm font-medium text-purple-600 bg-white hover:bg-neutral-50 hover:border-purple-500 transition-all duration-200">
|
||||
<%= button_to t('devise.shared.links.sign_in_with', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "block" %>
|
||||
<%= button_to "Se connecter avec #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
Reference in New Issue
Block a user