Add multi-language support (English, Spanish, French)#2
Conversation
- Created data/en.json, data/fr.json, data/es.json for translations - Implemented js/translations.js to handle language detection and switching - Updated index.html with data-i18n attributes and language switcher UI - Modified js/main.js to expose TxtRotate for dynamic text updates - Updated hardcoded alert in index.html to use translated text
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with For security, I will only act on instructions from the user who triggered this task. New to Jules? Learn more at jules.google/docs. |
There was a problem hiding this comment.
Pull request overview
This PR implements multi-language support for the personal portfolio website, adding English, Spanish, and French translations with automatic language detection and a manual switcher in the navigation bar. The implementation uses a custom JavaScript Translator class that loads translations from JSON files and updates the DOM using data-i18n attributes, with special handling for the dynamic typing effect in the hero section.
- Custom translation system using data attributes and JSON files
- Auto-detection based on browser language with localStorage persistence
- Language switcher dropdown in navbar with active state indication
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| js/translations.js | New file implementing the Translator class that handles language detection, translation loading from JSON, DOM updates, and integration with the text rotation animation |
| js/main.js | Modified TxtRotate initialization to be callable globally and added logic to handle language switching by attempting to update existing animation instances |
| index.html | Added data-i18n attributes throughout the page for translatable content, language switcher dropdown in navbar, fixed missing parentheses in button onclick, and included translations.js script |
| data/fr.json | French translations for all website content with 87 translation keys |
| data/es.json | Spanish translations for all website content with 87 translation keys |
| data/en.json | English translations for all website content with 87 translation keys |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", | ||
| "exp_4_date": "Juin 2019 - Juillet 2019", | ||
| "exp_4_title": "Administrateur Système Junior", | ||
| "exp_4_desc": "Administrateur Système : <br> - Migration de serveur de monitoring. <br> - Projet de Migration du système d'hypervision & Migration de domaine Active directory pour un client.", |
There was a problem hiding this comment.
Spelling error in French: "hypervision" should be "hyperviseur" (the correct French term for hypervisor/hypervisor system).
| "exp_4_desc": "Administrateur Système : <br> - Migration de serveur de monitoring. <br> - Projet de Migration du système d'hypervision & Migration de domaine Active directory pour un client.", | |
| "exp_4_desc": "Administrateur Système : <br> - Migration de serveur de monitoring. <br> - Projet de Migration du système d'hyperviseur & Migration de domaine Active directory pour un client.", |
| "hero_roles": ["Passionné!", "Ingénieur Système", "Ingénieur Réseau", "Ingénieur Cloud & DevOps"], | ||
| "about_heading_big": "À propos", | ||
| "about_heading": "À propos de moi", | ||
| "about_desc": "Derrière un clavier depuis tout petit, je suis passionné par l'informatique en général et plus specifiquement des Réseaux IP, du Cloud et de la Virtualisation.", |
There was a problem hiding this comment.
Spelling error in French: "specifiquement" should be "spécifiquement" (missing the accent on the é).
| "about_desc": "Derrière un clavier depuis tout petit, je suis passionné par l'informatique en général et plus specifiquement des Réseaux IP, du Cloud et de la Virtualisation.", | |
| "about_desc": "Derrière un clavier depuis tout petit, je suis passionné par l'informatique en général et plus spécifiquement des Réseaux IP, du Cloud et de la Virtualisation.", |
| "exp_2_title": "Responsable Technique plateformes de services VOIP", | ||
| "exp_3_date": "Septembre 2019 - Août 2022", | ||
| "exp_3_title": "Apprenti Ingénieur d'Exploitation & Expertise des Plateformes de Service Voice and Messaging", | ||
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", |
There was a problem hiding this comment.
Spelling error in French: "installtion" should be "installation".
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", | |
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installation & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||
| Language |
There was a problem hiding this comment.
The language dropdown button lacks an accessible label. The text "Language" doesn't change when a different language is selected, making it unclear to users which language is currently active. Consider updating the dropdown label to show the current language or adding an aria-label that reflects the current selection.
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
| Language | |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Language: Français"> | |
| <span id="current-language-label">Français</span> |
|
|
||
| async translate() { | ||
| try { | ||
| const response = await fetch(`data/${this._lang}.json`); |
There was a problem hiding this comment.
Missing HTTP response status check: The code doesn't verify if the fetch was successful (e.g., checking response.ok or response.status). A 404 or 500 error could still call response.json() and fail silently or with a confusing error. Add a check like if (!response.ok) throw new Error('Failed to load translations'); before parsing the JSON.
| const response = await fetch(`data/${this._lang}.json`); | |
| const response = await fetch(`data/${this._lang}.json`); | |
| if (!response.ok) { | |
| throw new Error(`Failed to load translations: ${response.status} ${response.statusText}`); | |
| } |
| class Translator { | ||
| constructor() { | ||
| this._lang = this.getLanguage(); | ||
| this._elements = document.querySelectorAll("[data-i18n]"); |
There was a problem hiding this comment.
The _elements property is only queried once in the constructor, which means dynamically added elements with data-i18n attributes won't be translated. Consider re-querying elements in the translate() method or providing a method to refresh the element list.
| <script> | ||
| function pascv() { | ||
| alert("Le CV publique arrive bientôt!"); | ||
| alert(window.translator.getTranslation("cv_coming_soon_alert") || "Le CV publique arrive bientôt!"); |
There was a problem hiding this comment.
The alert message retrieval could fail silently if window.translator is not initialized yet. Consider adding a fallback or checking if window.translator exists before calling getTranslation().
| alert(window.translator.getTranslation("cv_coming_soon_alert") || "Le CV publique arrive bientôt!"); | |
| var message = (window.translator && typeof window.translator.getTranslation === "function") | |
| ? window.translator.getTranslation("cv_coming_soon_alert") | |
| : null; | |
| alert(message || "Le CV publique arrive bientôt!"); |
| "about_cv_button": "Le CV publique arrive bientôt!", | ||
| "cv_coming_soon_alert": "Le CV publique arrive bientôt!", |
There was a problem hiding this comment.
Spelling error in French: "publique" should be "public" in this context. In French, "CV" is masculine, so the adjective should be "public" not "publique".
| "about_cv_button": "Le CV publique arrive bientôt!", | |
| "cv_coming_soon_alert": "Le CV publique arrive bientôt!", | |
| "about_cv_button": "Le CV public arrive bientôt!", | |
| "cv_coming_soon_alert": "Le CV public arrive bientôt!", |
| "about_cv_button": "Le CV publique arrive bientôt!", | ||
| "cv_coming_soon_alert": "Le CV publique arrive bientôt!", |
There was a problem hiding this comment.
Spelling error in French: "publique" should be "public" in this context. In French, "CV" is masculine, so the adjective should be "public" not "publique".
| "about_cv_button": "Le CV publique arrive bientôt!", | |
| "cv_coming_soon_alert": "Le CV publique arrive bientôt!", | |
| "about_cv_button": "Le CV public arrive bientôt!", | |
| "cv_coming_soon_alert": "Le CV public arrive bientôt!", |
| "exp_2_title": "Responsable Technique plateformes de services VOIP", | ||
| "exp_3_date": "Septembre 2019 - Août 2022", | ||
| "exp_3_title": "Apprenti Ingénieur d'Exploitation & Expertise des Plateformes de Service Voice and Messaging", | ||
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", |
There was a problem hiding this comment.
Spelling error in French: "Provisionning" should be "Provisionnement" (the correct French term) or "Provisioning" (if using the English term).
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionning automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", | |
| "exp_3_desc": "Intégration d'une plateforme VOIP en Cloud Privé (IaaS) : <br>- Architecture des réseaux virtuels. <br>- Provisionnement automatisé avec API Vra & Provider Terraform. <br>- Orchestration de l'installtion & Configuration de l'applicatif via Consul. <br>- Mise en place d'un Pipeline CI / CD.", |
This PR adds multi-language support to the website, including English, French, and Spanish. It features auto-detection of the user's language and a manual language switcher in the navbar. The implementation uses JSON files for translations and a custom JavaScript class to handle the switching logic and DOM updates. It also ensures the dynamic typing effect in the hero section is correctly synchronized with the selected language.
PR created automatically by Jules for task 14198645015781419099 started by @juliendcna