diff --git a/apps/web/next-i18next.config.ts b/apps/web/next-i18next.config.ts new file mode 100644 index 0000000..f4fbb50 --- /dev/null +++ b/apps/web/next-i18next.config.ts @@ -0,0 +1,24 @@ +import { Config } from 'next-i18next'; +import path from 'path'; + +const config: Config = { + i18n: { + defaultLocale: 'fr', + locales: ['fr', 'en'], + }, + localePath: path.resolve('./public/locales'), + ns: ['common'], + defaultNS: 'common', + backend: { + loadPath: './public/locales/{{lng}}/{{ns}}.json', + }, + detection: { + order: ['cookie', 'localStorage', 'navigator'], + caches: ['localStorage', 'cookie'], + }, + react: { + useSuspense: false, + }, +}; + +export default config; diff --git a/apps/web/package.json b/apps/web/package.json index 50b6536..4514379 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -26,10 +26,14 @@ "@trpc/react-query": "^11.0.0", "@uiw/react-md-editor": "^4.0.11", "firebase": "^10.14.1", + "i18next": "^25.8.0", + "i18next-browser-languagedetector": "^8.2.0", "lucide-react": "^0.417.0", "next": "^14.2.25", + "next-i18next": "^15.4.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "^16.5.3", "react-markdown": "^9.1.0", "remark-gfm": "^4.0.1", "superjson": "^2.2.2" diff --git a/apps/web/public/locales/en/common.json b/apps/web/public/locales/en/common.json new file mode 100644 index 0000000..f45a14e --- /dev/null +++ b/apps/web/public/locales/en/common.json @@ -0,0 +1,400 @@ +{ + "common": { + "home": "Home", + "login": "Sign in", + "register": "Sign up", + "logout": "Sign out", + "dashboard": "Dashboard" + }, + "header": { + "login_button": "Sign in", + "register_button": "Sign up", + "dashboard_button": "Go to dashboard", + "logout_button": "Sign out" + }, + "landing": { + "title": "Manage your projects with clarity, speed and peace of mind.", + "description": "Taskly centralizes your tasks, teams and decisions in simple and visual boards. Go from idea to execution without friction.", + "features_title": "Everything you need to deliver better, together.", + "features": [ + { + "title": "Clear and fast boards", + "description": "Organize your tasks in columns and keep an overview." + }, + { + "title": "Real-time collaboration", + "description": "Invite your teammates, assign tasks and track progress." + }, + { + "title": "Useful notifications", + "description": "Get important updates without being overwhelmed." + }, + { + "title": "Multi-workspace management", + "description": "Separate your personal, client or team projects with one click." + } + ], + "steps_title": "A simple 3-step workflow", + "steps_description": "Taskly adapts to your pace. Start small, scale fast.", + "steps": [ + { + "title": "Create a workspace", + "description": "Start a project in seconds." + }, + { + "title": "Invite your team", + "description": "Add members and set roles." + }, + { + "title": "Launch your board", + "description": "Organize, prioritize and deliver faster." + } + ], + "cta_title": "Ready to make your teams more fluid?", + "cta_description": "Get started now and invite your team in minutes.", + "cta_button": "Create account", + "start_free": "Start free", + "have_account": "Already have an account", + "resume_work": "Resume my work", + "view_workspaces": "View my workspaces", + "new_feature": "New: Google and GitHub integrations", + "tagline": "No commitment", + "tagline_security": "Firebase security", + "tagline_collab": "Smooth collaboration", + "footer_copyright": "© {{year}} Taskly. All rights reserved.", + "footer_links": [ + { + "label": "Sign in", + "href": "/login" + }, + { + "label": "Sign up", + "href": "/register" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ], + "example_board_title": "Marketing Board", + "example_board_status": "In progress", + "example_tasks_ready": "3 tasks ready to be delivered", + "why_taskly": "Why Taskly" + }, + "auth": { + "login_title": "Sign in", + "login_description": "Sign in with your email and password.", + "register_title": "Create account", + "register_description": "Create an account to access Taskly.", + "email_label": "Email", + "password_label": "Password", + "password_confirm_label": "Confirm password", + "email_placeholder": "you@example.com", + "continue_google": "Continue with Google", + "continue_github": "Continue with GitHub", + "continue_google_loading": "Google sign in…", + "continue_github_loading": "GitHub sign in…", + "sign_in": "Sign in", + "sign_in_loading": "Signing in…", + "no_account": "Don't have an account?", + "create_account": "Create account", + "have_account": "Already have an account?", + "sign_up": "Sign up", + "sign_up_loading": "Signing up…", + "or": "or", + "error_title": "Sign in failed", + "error_default": "An error occurred.", + "login_link": "Sign in", + "register_link": "Sign up" + }, + "navbar": { + "workspaces": "Workspaces", + "archived": "Archived", + "create": "Create", + "create_workspace": "Create workspace", + "create_board": "Create board", + "workspace_title_placeholder": "Workspace title", + "description_optional": "Description (optional)", + "board_title_placeholder": "Board title", + "search_placeholder": "Search", + "mark_all_as_read": "Mark all as read", + "notifications": "Notifications", + "loading": "Loading…", + "no_notifications": "No notifications at the moment.", + "see_more": "See more", + "account": "Account", + "profile": "Profile", + "logout": "Sign out", + "delete_account": "Delete account", + "change_avatar": "Change avatar", + "update_avatar": "Update avatar", + "upload_photo": "Upload photo", + "display_name": "Display name", + "username": "Username", + "first_name": "First name", + "last_name": "Last name", + "description": "Description", + "about_you": "About you…", + "reset": "Reset", + "save": "Save", + "cancel": "Cancel", + "delete": "Delete", + "profile_photo": "Profile photo", + "account_info": "Account", + "email": "Email", + "id": "ID", + "delete_account_confirmation": "Delete account", + "delete_confirmation_text": "This action is irreversible. To confirm, type", + "delete_confirmation_keyword": "DELETE", + "uploading": "Uploading…", + "upload_failed": "Upload failed", + "no_background_found": "No background found.", + "loading_backgrounds": "Loading backgrounds…", + "load_more": "Load more", + "upload_square_image": "Upload a square image (we'll store it in GCS).", + "gcs_credentials_not_configured": "GCS credentials not configured" + }, + "dashboard": { + "loading_boards": "Loading boards…", + "no_board_in_workspace": "No board in this workspace.", + "open": "Open →", + "previous": "Previous", + "next": "Next", + "no_archived_workspace": "No archived workspace.", + "no_workspace_yet": "There is no workspace yet.", + "archived_workspaces": "Archived workspaces.", + "all_workspaces": "All your workspaces, and a preview of their boards.", + "remove_from_archives": "Remove from archives", + "loading": "Loading…", + "workspace_not_found": "Workspace not found.", + "create_board": "Create board", + "no_board": "No board. Create the first one.", + "open_board": "Open →" + }, + "members": { + "select_workspace": "Select a workspace to manage its members.", + "impossible": "Impossible", + "cannot_remove_last_admin": "You cannot remove the last admin.", + "cannot_delete_last_member": "You cannot delete the last member of the workspace.", + "cannot_delete_last_admin": "You cannot delete the last admin." + }, + "settings": { + "select_workspace": "Select a workspace to modify its settings.", + "archive_description": "Archiving a workspace makes it inaccessible (the data remains in the database but it no longer appears)." + }, + "notifications": { + "unread": "unread.", + "all_up_to_date": "Everything is up to date.", + "mark_all_as_read": "Mark all as read", + "loading": "Loading…", + "no_notifications": "No notifications at the moment.", + "mark_as_read": "Mark as read", + "open": "Open", + "see_more": "See more" + }, + "invite": { + "missing_token": "Missing token.", + "about_to_join": "You are about to join a workspace." + }, + "actions": { + "create": "Create", + "save": "Save", + "cancel": "Cancel", + "delete": "Delete", + "edit": "Edit", + "close": "Close", + "open": "Open", + "confirm": "Confirm", + "yes": "Yes", + "no": "No" + }, + "toast": { + "action_failed": "Action failed", + "invalid_date": "Invalid date", + "invalid_mention": "Invalid mention", + "invalid_mention_desc": "One or more mentioned users are not members of this workspace.", + "update_failed": "Update failed", + "comment_added": "Comment added", + "failed_to_add_comment": "Failed to add comment", + "member_added": "Member added", + "failed_to_add_member": "Failed to add member", + "member_removed": "Member removed", + "label_added": "Label added", + "label_removed": "Label removed", + "failed_to_create_label": "Failed to create label", + "label_updated": "Label updated", + "failed_to_update_label": "Failed to update label", + "label_deleted": "Label deleted", + "failed_to_delete_label": "Failed to delete label", + "checklist_created": "Checklist created", + "checklist_deleted": "Checklist deleted", + "file_uploaded": "File uploaded", + "attachment_deleted": "Attachment deleted", + "reminder_created": "Reminder created", + "failed_to_create_reminder": "Failed to create reminder", + "reminder_removed": "Reminder removed", + "failed_to_remove_reminder": "Failed to remove reminder", + "watching_ticket": "Watching this ticket", + "failed_to_watch": "Failed to watch ticket", + "unwatched_ticket": "Unwatched this ticket", + "failed_to_unwatch": "Failed to unwatch ticket", + "download_failed": "Download failed", + "photo_updated": "Photo updated", + "uploading": "Uploading…", + "upload_failed": "Upload failed", + "copied": "Copied", + "cannot_copy": "Cannot copy", + "clipboard_not_available": "Clipboard not available", + "workspace_updated": "Workspace updated", + "cannot_update": "Cannot update", + "workspace_archived": "Workspace archived", + "cannot_archive": "Cannot archive", + "member_role_updated": "Role updated", + "cannot_update_role": "Cannot update role", + "cannot_remove_member": "Cannot remove member", + "invitation_created": "Invitation created", + "cannot_create_invitation": "Cannot create invitation", + "invitation_cancelled": "Invitation cancelled", + "cannot_cancel_invitation": "Cannot cancel invitation", + "invitation_accepted": "Invitation accepted", + "cannot_accept": "Cannot accept", + "invitation_declined": "Invitation declined", + "cannot_decline": "Cannot decline", + "password_mismatch": "Passwords do not match.", + "registration_failed": "Registration failed" + }, + "board": { + "loading_ticket": "Loading ticket…", + "not_found": "Board not found.", + "column_settings": "Column settings", + "column_title_label": "Title", + "column_title_placeholder": "Column title", + "delete_column": "Delete column", + "add_a_card": "Add a card", + "add_card_dialog": "Add card", + "card_title_placeholder": "Card title", + "description_placeholder": "Description (optional)", + "background": "Background", + "board_background": "Board background", + "images": "Images", + "gradients": "Gradients", + "colors": "Colors", + "remove": "Remove", + "activity": "Activity", + "board_activity": "Board activity", + "no_activity_yet": "No activity yet.", + "open_ticket": "Open ticket", + "add_column": "Add column", + "create_column_dialog": "Create column", + "column_placeholder": "Column", + "ticket_placeholder": "Ticket", + "board_created": "Board created", + "column_created": "Column created", + "card_created": "Card created", + "comment_added": "Comment added", + "description_updated": "Description updated", + "label_added": "Label added", + "due_date_set": "Due date set", + "member_assigned": "Member assigned", + "card_moved": "Card moved", + "ticket_updated": "Ticket updated" + }, + "ticket": { + "labels": "Labels", + "description": "Description", + "edit": "Edit", + "save": "Save", + "cancel": "Cancel", + "add_detailed_description": "Add a more detailed description…", + "checklists": "Checklists", + "completed": "completed", + "delete_checklist_title": "Delete checklist", + "delete_checklist_confirm": "Are you sure you want to delete \"{{name}}\"?", + "add_item_placeholder": "Add an item…", + "attachments": "Attachments", + "pending": "Pending", + "download": "Download", + "delete_attachment_title": "Delete attachment", + "delete_attachment_confirm": "Delete \"{{filename}}\"?", + "activity_tab": "Activity", + "comments_tab": "Comments", + "history_tab": "History", + "write_comment_placeholder": "Write a comment…", + "no_activity": "No activity yet.", + "system": "System", + "ticket_created": "Ticket created", + "due_date": "Due date", + "overdue": "Overdue", + "due": "Due", + "no_due_date": "No due date.", + "set_due_date": "Set due date", + "change_due_date": "Change due date", + "notifications_section": "Notifications", + "unwatch": "Unwatch", + "watch": "Watch", + "reminders_section": "Reminders", + "no_reminders": "No reminders yet.", + "add_reminder_btn": "Add reminder", + "add_to_card": "Add to card", + "members_button": "Members", + "labels_button": "Labels", + "create_checklist_dialog": "Create checklist", + "checklist_title_placeholder": "Checklist title", + "checklist_button": "Checklist", + "attachment_button": "Attachment", + "members_section": "Members", + "invalid_reminder_date": "Invalid reminder date", + "presets": "Presets", + "one_hour_before": "1h before due", + "one_day_before": "1d before due", + "set_due_date_for_presets": "Set a due date to use presets." + }, + "members": { + "page_title": "Members", + "members_count": "Members ({{count}})", + "loading": "Loading…", + "no_members": "No members.", + "add_member_btn": "Add member", + "add_member_dialog": "Add member", + "search_user_placeholder": "Search user (min 2 chars)", + "searching": "Searching…", + "no_results": "No results.", + "role_label": "Role", + "role_placeholder": "Role", + "admin": "Admin", + "maintainer": "Maintainer", + "editor": "Editor", + "viewer": "Viewer", + "add_button": "Add", + "create_invite_btn": "Create invite", + "create_invitation_dialog": "Create invitation", + "expires_in_days": "Expires in (days)", + "token_label": "Token", + "invitation_link": "Invitation link", + "copy_link_btn": "Copy link", + "open_button": "Open", + "create_button": "Create", + "pending_invitations": "Pending invitations", + "no_pending": "No pending invitations.", + "role_colon": "Role:", + "expires_colon": "Expires:", + "token_colon": "Token:", + "link_colon": "Link:", + "cancel_button": "Cancel", + "remove_confirm": "Remove {{label}}?", + "remove_button": "Remove", + "role_updated_msg": "Role updated" + }, + "settings": { + "page_title": "Settings", + "workspace_profile": "Workspace profile", + "title_label": "Title", + "workspace_title_placeholder": "Workspace title", + "description_label": "Description", + "description_placeholder": "Description", + "reset_button": "Reset", + "danger_zone": "Danger zone", + "archive_confirm": "Archive this workspace?", + "archive_button": "Archive workspace" + } +} diff --git a/apps/web/public/locales/fr/common.json b/apps/web/public/locales/fr/common.json new file mode 100644 index 0000000..f196ca9 --- /dev/null +++ b/apps/web/public/locales/fr/common.json @@ -0,0 +1,400 @@ +{ + "common": { + "home": "Accueil", + "login": "Connexion", + "register": "Créer un compte", + "logout": "Se déconnecter", + "dashboard": "Dashboard" + }, + "header": { + "login_button": "Se connecter", + "register_button": "Créer un compte", + "dashboard_button": "Aller au dashboard", + "logout_button": "Se déconnecter" + }, + "landing": { + "title": "Gérez vos projets avec clarté, vitesse et sérénité.", + "description": "Taskly centralise vos tâches, vos équipes et vos décisions dans des boards simples et visuels. Passez de l'idée à l'exécution sans friction.", + "features_title": "Tout ce qu'il faut pour livrer mieux, ensemble.", + "features": [ + { + "title": "Tableaux clairs et rapides", + "description": "Organisez vos tâches en colonnes et gardez une vue d'ensemble." + }, + { + "title": "Collaboration en temps réel", + "description": "Invitez vos coéquipiers, assignez des tâches et suivez l'avancement." + }, + { + "title": "Notifications utiles", + "description": "Recevez les mises à jour importantes sans être submergé." + }, + { + "title": "Gestion multi‑workspaces", + "description": "Séparez vos projets perso, clients ou équipes en un clic." + } + ], + "steps_title": "Un flux simple en 3 étapes", + "steps_description": "Taskly s'adapte à votre rythme. Commencez petit, évoluez vite.", + "steps": [ + { + "title": "Créez un workspace", + "description": "Démarrez un projet en quelques secondes." + }, + { + "title": "Invitez votre équipe", + "description": "Ajoutez des membres et définissez les rôles." + }, + { + "title": "Lancez votre board", + "description": "Organisez, priorisez et livrez plus vite." + } + ], + "cta_title": "Prêt à rendre vos équipes plus fluides ?", + "cta_description": "Commencez maintenant et invitez votre équipe en quelques minutes.", + "cta_button": "Créer un compte", + "start_free": "Démarrer gratuitement", + "have_account": "J'ai déjà un compte", + "resume_work": "Reprendre mon travail", + "view_workspaces": "Voir mes workspaces", + "new_feature": "Nouveau: intégrations Google et GitHub", + "tagline": "Aucun engagement", + "tagline_security": "Sécurité Firebase", + "tagline_collab": "Collaboration fluide", + "footer_copyright": "© {{year}} Taskly. Tous droits réservés.", + "footer_links": [ + { + "label": "Se connecter", + "href": "/login" + }, + { + "label": "S'inscrire", + "href": "/register" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ], + "example_board_title": "Board Marketing", + "example_board_status": "En cours", + "example_tasks_ready": "3 tâches prêtes à être livrées", + "why_taskly": "Pourquoi Taskly" + }, + "auth": { + "login_title": "Connexion", + "login_description": "Connecte-toi avec ton email et ton mot de passe.", + "register_title": "Créer un compte", + "register_description": "Crée un compte pour accéder à Taskly.", + "email_label": "Email", + "password_label": "Mot de passe", + "password_confirm_label": "Confirmer le mot de passe", + "email_placeholder": "you@example.com", + "continue_google": "Continuer avec Google", + "continue_github": "Continuer avec GitHub", + "continue_google_loading": "Connexion Google…", + "continue_github_loading": "Connexion GitHub…", + "sign_in": "Se connecter", + "sign_in_loading": "Connexion…", + "no_account": "Pas de compte ?", + "create_account": "Créer un compte", + "have_account": "Tu as déjà un compte ?", + "sign_up": "S'inscrire", + "sign_up_loading": "Inscription…", + "or": "ou", + "error_title": "Connexion impossible", + "error_default": "Une erreur est survenue.", + "login_link": "Se connecter", + "register_link": "S'inscrire" + }, + "navbar": { + "workspaces": "Workspaces", + "archived": "Archivé", + "create": "Créer", + "create_workspace": "Créer un workspace", + "create_board": "Créer un board", + "workspace_title_placeholder": "Titre du workspace", + "description_optional": "Description (optionnelle)", + "board_title_placeholder": "Titre du board", + "search_placeholder": "Rechercher", + "mark_all_as_read": "Tout marquer comme lu", + "notifications": "Notifications", + "loading": "Chargement…", + "no_notifications": "Aucune notification pour le moment.", + "see_more": "Voir plus", + "account": "Compte", + "profile": "Profil", + "logout": "Se déconnecter", + "delete_account": "Supprimer le compte", + "change_avatar": "Modifier l'avatar", + "update_avatar": "Mettre à jour l'avatar", + "upload_photo": "Télécharger une photo", + "display_name": "Nom d'affichage", + "username": "Nom d'utilisateur", + "first_name": "Prénom", + "last_name": "Nom de famille", + "description": "Description", + "about_you": "À propos de toi…", + "reset": "Réinitialiser", + "save": "Enregistrer", + "cancel": "Annuler", + "delete": "Supprimer", + "profile_photo": "Photo de profil", + "account_info": "Compte", + "email": "Email", + "id": "ID", + "delete_account_confirmation": "Supprimer le compte", + "delete_confirmation_text": "Cette action est irréversible. Pour confirmer, tapez", + "delete_confirmation_keyword": "DELETE", + "uploading": "Téléchargement…", + "upload_failed": "Téléchargement échoué", + "no_background_found": "Aucun arrière-plan trouvé.", + "loading_backgrounds": "Chargement des arrière-plans…", + "load_more": "Charger plus", + "upload_square_image": "Télécharger une image carrée (nous la stockerons dans GCS).", + "gcs_credentials_not_configured": "Les identifiants GCS ne sont pas configurés" + }, + "dashboard": { + "loading_boards": "Chargement des boards…", + "no_board_in_workspace": "Aucun board dans ce workspace.", + "open": "Ouvrir →", + "previous": "Précédent", + "next": "Suivant", + "no_archived_workspace": "Aucun workspace archivé.", + "no_workspace_yet": "Il n'y a pas encore de workspace.", + "archived_workspaces": "Workspaces archivés.", + "all_workspaces": "Tous tes workspaces, et un aperçu de leurs boards.", + "remove_from_archives": "Retirer des archives", + "loading": "Chargement…", + "workspace_not_found": "Workspace introuvable.", + "create_board": "Créer un board", + "no_board": "Aucun board. Crée le premier.", + "open_board": "Ouvrir →" + }, + "members": { + "select_workspace": "Sélectionne un workspace pour gérer ses membres.", + "impossible": "Impossible", + "cannot_remove_last_admin": "Tu ne peux pas retirer le dernier admin.", + "cannot_delete_last_member": "Tu ne peux pas supprimer le dernier membre du workspace.", + "cannot_delete_last_admin": "Tu ne peux pas supprimer le dernier admin." + }, + "settings": { + "select_workspace": "Sélectionne un workspace pour modifier ses paramètres.", + "archive_description": "Archiver un workspace le rend inaccessible (les données restent dans la base mais il n'apparaît plus)." + }, + "notifications": { + "unread": "non lue(s).", + "all_up_to_date": "Tout est à jour.", + "mark_all_as_read": "Tout marquer comme lu", + "loading": "Chargement…", + "no_notifications": "Aucune notification pour le moment.", + "mark_as_read": "Marquer comme lu", + "open": "Ouvrir", + "see_more": "Voir plus" + }, + "invite": { + "missing_token": "Token manquant.", + "about_to_join": "Tu es sur le point de rejoindre un workspace." + }, + "actions": { + "create": "Créer", + "save": "Enregistrer", + "cancel": "Annuler", + "delete": "Supprimer", + "edit": "Modifier", + "close": "Fermer", + "open": "Ouvrir", + "confirm": "Confirmer", + "yes": "Oui", + "no": "Non" + }, + "toast": { + "action_failed": "L'action a échoué", + "invalid_date": "Date invalide", + "invalid_mention": "Mention invalide", + "invalid_mention_desc": "Un ou plusieurs utilisateurs mentionnés ne sont pas membres de ce workspace.", + "update_failed": "La mise à jour a échoué", + "comment_added": "Commentaire ajouté", + "failed_to_add_comment": "Impossible d'ajouter le commentaire", + "member_added": "Membre ajouté", + "failed_to_add_member": "Impossible d'ajouter le membre", + "member_removed": "Membre supprimé", + "label_added": "Libellé ajouté", + "label_removed": "Libellé supprimé", + "failed_to_create_label": "Impossible de créer le libellé", + "label_updated": "Libellé mis à jour", + "failed_to_update_label": "Impossible de mettre à jour le libellé", + "label_deleted": "Libellé supprimé", + "failed_to_delete_label": "Impossible de supprimer le libellé", + "checklist_created": "Checklist créée", + "checklist_deleted": "Checklist supprimée", + "file_uploaded": "Fichier téléchargé", + "attachment_deleted": "Pièce jointe supprimée", + "reminder_created": "Rappel créé", + "failed_to_create_reminder": "Impossible de créer le rappel", + "reminder_removed": "Rappel supprimé", + "failed_to_remove_reminder": "Impossible de supprimer le rappel", + "watching_ticket": "Vous regardez cette tâche", + "failed_to_watch": "Impossible de regarder la tâche", + "unwatched_ticket": "Vous ne regardez plus cette tâche", + "failed_to_unwatch": "Impossible d'arrêter de regarder la tâche", + "download_failed": "Le téléchargement a échoué", + "photo_updated": "Photo mise à jour", + "uploading": "Téléchargement…", + "upload_failed": "Le téléchargement a échoué", + "copied": "Copié", + "cannot_copy": "Impossible de copier", + "clipboard_not_available": "Le presse-papiers n'est pas disponible", + "workspace_updated": "Workspace mis à jour", + "cannot_update": "Impossible de mettre à jour", + "workspace_archived": "Workspace archivé", + "cannot_archive": "Impossible d'archiver", + "member_role_updated": "Rôle mis à jour", + "cannot_update_role": "Impossible de mettre à jour le rôle", + "cannot_remove_member": "Impossible de supprimer le membre", + "invitation_created": "Invitation créée", + "cannot_create_invitation": "Impossible de créer l'invitation", + "invitation_cancelled": "Invitation annulée", + "cannot_cancel_invitation": "Impossible d'annuler l'invitation", + "invitation_accepted": "Invitation acceptée", + "cannot_accept": "Impossible d'accepter", + "invitation_declined": "Invitation déclinée", + "cannot_decline": "Impossible de décliner", + "password_mismatch": "Les mots de passe ne correspondent pas.", + "registration_failed": "L'inscription a échoué" + }, + "board": { + "loading_ticket": "Chargement de la tâche…", + "not_found": "Board introuvable.", + "column_settings": "Paramètres de la colonne", + "column_title_label": "Titre", + "column_title_placeholder": "Titre de la colonne", + "delete_column": "Supprimer la colonne", + "add_a_card": "Ajouter une carte", + "add_card_dialog": "Ajouter une carte", + "card_title_placeholder": "Titre de la carte", + "description_placeholder": "Description (optionnelle)", + "background": "Arrière-plan", + "board_background": "Arrière-plan du board", + "images": "Images", + "gradients": "Dégradés", + "colors": "Couleurs", + "remove": "Supprimer", + "activity": "Activité", + "board_activity": "Activité du board", + "no_activity_yet": "Aucune activité pour le moment.", + "open_ticket": "Ouvrir la tâche", + "add_column": "Ajouter une colonne", + "create_column_dialog": "Créer une colonne", + "column_placeholder": "Colonne", + "ticket_placeholder": "Tâche", + "board_created": "Board créé", + "column_created": "Colonne créée", + "card_created": "Carte créée", + "comment_added": "Commentaire ajouté", + "description_updated": "Description mise à jour", + "label_added": "Libellé ajouté", + "due_date_set": "Date d'échéance définie", + "member_assigned": "Membre assigné", + "card_moved": "Carte déplacée", + "ticket_updated": "Tâche mise à jour" + }, + "ticket": { + "labels": "Libellés", + "description": "Description", + "edit": "Modifier", + "save": "Enregistrer", + "cancel": "Annuler", + "add_detailed_description": "Ajouter une description plus détaillée…", + "checklists": "Checklists", + "completed": "complétées", + "delete_checklist_title": "Supprimer la checklist", + "delete_checklist_confirm": "Êtes-vous sûr de vouloir supprimer \"{{name}}\"?", + "add_item_placeholder": "Ajouter un élément…", + "attachments": "Pièces jointes", + "pending": "En attente", + "download": "Télécharger", + "delete_attachment_title": "Supprimer la pièce jointe", + "delete_attachment_confirm": "Supprimer \"{{filename}}\"?", + "activity_tab": "Activité", + "comments_tab": "Commentaires", + "history_tab": "Historique", + "write_comment_placeholder": "Écrire un commentaire…", + "no_activity": "Aucune activité pour le moment.", + "system": "Système", + "ticket_created": "Tâche créée", + "due_date": "Date d'échéance", + "overdue": "En retard", + "due": "À échéance", + "no_due_date": "Pas de date d'échéance.", + "set_due_date": "Définir la date d'échéance", + "change_due_date": "Modifier la date d'échéance", + "notifications_section": "Notifications", + "unwatch": "Ne plus regarder", + "watch": "Regarder", + "reminders_section": "Rappels", + "no_reminders": "Aucun rappel pour le moment.", + "add_reminder_btn": "Ajouter un rappel", + "add_to_card": "Ajouter à la carte", + "members_button": "Membres", + "labels_button": "Libellés", + "create_checklist_dialog": "Créer une checklist", + "checklist_title_placeholder": "Titre de la checklist", + "checklist_button": "Checklist", + "attachment_button": "Pièce jointe", + "members_section": "Membres", + "invalid_reminder_date": "Date de rappel invalide", + "presets": "Présets", + "one_hour_before": "1h avant l'échéance", + "one_day_before": "1j avant l'échéance", + "set_due_date_for_presets": "Définir une date d'échéance pour utiliser les présets." + }, + "members": { + "page_title": "Membres", + "members_count": "Membres ({{count}})", + "loading": "Chargement…", + "no_members": "Aucun membre.", + "add_member_btn": "Ajouter un membre", + "add_member_dialog": "Ajouter un membre", + "search_user_placeholder": "Chercher un utilisateur (min 2 caractères)", + "searching": "Recherche…", + "no_results": "Aucun résultat.", + "role_label": "Rôle", + "role_placeholder": "Rôle", + "admin": "Admin", + "maintainer": "Responsable", + "editor": "Éditeur", + "viewer": "Lecteur", + "add_button": "Ajouter", + "create_invite_btn": "Créer une invitation", + "create_invitation_dialog": "Créer une invitation", + "expires_in_days": "Expire dans (jours)", + "token_label": "Token", + "invitation_link": "Lien d'invitation", + "copy_link_btn": "Copier le lien", + "open_button": "Ouvrir", + "create_button": "Créer", + "pending_invitations": "Invitations en attente", + "no_pending": "Aucune invitation en attente.", + "role_colon": "Rôle:", + "expires_colon": "Expire:", + "token_colon": "Token:", + "link_colon": "Lien:", + "cancel_button": "Annuler", + "remove_confirm": "Retirer {{label}}?", + "remove_button": "Retirer", + "role_updated_msg": "Rôle mis à jour" + }, + "settings": { + "page_title": "Paramètres", + "workspace_profile": "Profil du workspace", + "title_label": "Titre", + "workspace_title_placeholder": "Titre du workspace", + "description_label": "Description", + "description_placeholder": "Description", + "reset_button": "Réinitialiser", + "danger_zone": "Zone de danger", + "archive_confirm": "Archiver ce workspace?", + "archive_button": "Archiver le workspace" + } +} diff --git a/apps/web/src/app/(app)/dashboard/boards/[boardId]/board-client.tsx b/apps/web/src/app/(app)/dashboard/boards/[boardId]/board-client.tsx index 21e500f..364515c 100644 --- a/apps/web/src/app/(app)/dashboard/boards/[boardId]/board-client.tsx +++ b/apps/web/src/app/(app)/dashboard/boards/[boardId]/board-client.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { api } from '@/app/trpc'; +import { useTranslation } from '@/lib/i18n'; import type { BoardBackground } from '@taskly/trpc'; import { getBoardBackgroundStyle } from '@/components/board/board-background'; import { @@ -370,6 +371,7 @@ function SortableBoardColumn({ initialsForUser: (userId: string) => string; userById: Map; }) { + const { t } = useTranslation(); const { setNodeRef: setDropRef } = useDroppable({ id: dndColumnDropId(col.id), data: { type: 'column-drop' satisfies DndItemType, columnId: col.id }, @@ -450,21 +452,21 @@ function SortableBoardColumn({ - Column settings + {t('board.column_settings')}
-
Title
- setSettingsTitleDraft(e.target.value)} placeholder="Column title" /> +
{t('board.column_title_label')}
+ setSettingsTitleDraft(e.target.value)} placeholder={t('board.column_title_placeholder')} />
@@ -473,11 +475,11 @@ function SortableBoardColumn({
- dndTicketId(t.id))} strategy={verticalListSortingStrategy}> - {colTickets.map((t) => ( + dndTicketId(ticket.id))} strategy={verticalListSortingStrategy}> + {colTickets.map((ticket) => ( - Add a card + {t('board.add_a_card')} - Add card + {t('board.add_card_dialog')}
- onChangeNewTitle(e.target.value)} placeholder="Card title" /> -