+
+
{domains.map((domain) => renderDomainCard(domain))}
diff --git a/src/components/data/about.js b/src/components/data/about.js
new file mode 100644
index 0000000..bcd999c
--- /dev/null
+++ b/src/components/data/about.js
@@ -0,0 +1,26 @@
+import resumePdf from '../../assets/resume.pdf'
+import profileImg from '../../assets/images/cropped-profile.jpg'
+
+export const aboutData = {
+ name: "Luan Tran", // Name doesn't need translation
+ description1: {
+ en: "I'm a Master's student in Applied Computer Science with industry experience in automation and web development " +
+ "at Broadsign, Ericsson, and Matrox. My projects include deploying automated CI/CD workflows," +
+ " multimodal medical imaging applications, and automated language proficiency assessment systems.",
+ fr: "Je suis étudiant en maîtrise en informatique appliquée avec une expérience industrielle en automatisation et développement web " +
+ "chez Broadsign, Ericsson et Matrox. Mes projets incluent le déploiement de workflows CI/CD automatisés," +
+ " des applications d'imagerie médicale multimodale et des systèmes d'évaluation automatique de compétence linguistique."
+ },
+ description2: {
+ en: "I'm currently researching LLM-based agents for linguistic education and seeking opportunities in " +
+ "software development and machine learning.",
+ fr: "Je fais actuellement de la recherche sur les agents basés sur les LLM pour l'enseignement linguistique et je recherche des opportunités en " +
+ "développement logiciel et apprentissage automatique."
+ },
+ downloadCV: {
+ en: "Download CV",
+ fr: "Télécharger CV"
+ },
+ resume: resumePdf,
+ image: profileImg
+}
\ No newline at end of file
diff --git a/src/components/data/education.js b/src/components/data/education.js
index 97dc0ff..020afd6 100644
--- a/src/components/data/education.js
+++ b/src/components/data/education.js
@@ -1,18 +1,43 @@
// Import logos
import mcgillLogo from '../../assets/images/mcgill_logo.png'
import concordiaLogo from '../../assets/images/concordia_logo.png'
+import cimfLogo from '../../assets/images/cimf_logo.png'
export const educationData = [
{
- university: 'Concordia University',
+ university: {
+ en: 'Concordia University',
+ fr: 'Université Concordia'
+ },
date: '2025 - 2027',
logo: concordiaLogo,
- degree: 'Master\'s of Applied Computer Science'
+ degree: {
+ en: "Master's of Applied Computer Science",
+ fr: "Maîtrise en informatique appliquée"
+ }
},
{
- university: 'McGill University',
+ university: {
+ en: 'McGill University',
+ fr: 'Université McGill'
+ },
date: '2014 - 2019',
logo: mcgillLogo,
- degree: 'Bachelors\'s of Computer Engineering'
+ degree: {
+ en: "Bachelor's of Computer Engineering",
+ fr: "Baccalauréat en génie informatique"
+ }
+ },
+ {
+ university: {
+ en: 'Collège Marie de France',
+ fr: 'Collège Marie de France'
+ },
+ date: '2012-2014',
+ logo: cimfLogo,
+ degree: {
+ en: 'French Baccalaureate - Highest Honors',
+ fr: 'Baccalauréat français - Mention très bien'
+ }
}
]
\ No newline at end of file
diff --git a/src/components/data/experience.js b/src/components/data/experience.js
index 69e453a..66df1a4 100644
--- a/src/components/data/experience.js
+++ b/src/components/data/experience.js
@@ -1,56 +1,81 @@
export const experienceData = [
{
- hash: "a3f52b9", // or auto-generate
- title: "Web Automation Developer Intern",
- company: "Broadsign",
- period: "Jan - May 2019",
- // description: "Brief overview...",
- achievements: [
- "Designed a new automation framework that accurately reproduce a live environment against which integration\n" +
- "and system tests can be run",
- "Automated the clean deployment and database population of a web server using Docker and Bitbucket Pipelines",
- "Developed a Python REST tool library which developers could use to write their unit and integration tests"
- ],
- // projects: [ // optional array
- // { name: "Dashboard Redesign", link: "..." }
- // ],
- // impact: "40% increase in engagement", // optional
+ hash: "a3f52b9",
+ title: {
+ en: "Web Automation Developer Intern",
+ fr: "Stagiaire développeur en automatisation web"
+ },
+ company: "Broadsign", // Company name stays the same
+ period: {
+ en: "Jan - May 2019",
+ fr: "Jan - Mai 2019"
+ },
+ achievements: {
+ en: [
+ "Designed a new automation framework that accurately reproduce a live environment against which integration and system tests can be run",
+ "Automated the clean deployment and database population of a web server using Docker and Bitbucket Pipelines",
+ "Developed a Python REST tool library which developers could use to write their unit and integration tests"
+ ],
+ fr: [
+ "Conçu un nouveau framework d'automatisation qui reproduit fidèlement un environnement réel pour exécuter des tests d'intégration et système",
+ "Automatisé le déploiement propre et le peuplement de base de données d'un serveur web avec Docker et Bitbucket Pipelines",
+ "Développé une bibliothèque d'outils REST en Python que les développeurs peuvent utiliser pour écrire leurs tests unitaires et d'intégration"
+ ]
+ },
tech: ["Python", "Docker", "Bitbucket"],
},
{
- hash: "7c2d81e", // or auto-generate
- title: "Software Developer Intern",
+ hash: "7c2d81e",
+ title: {
+ en: "Software Developer Intern",
+ fr: "Stagiaire développeur logiciel"
+ },
company: "Ericsson",
- period: "May - Dec 2018",
- // description: "Brief overview...",
- achievements: [
- "Automated software installation processes to decrease runtime by 15% using Ansible",
- "Implemented a build certification process in custom Concourse to improve testing team’s efficiency by 75%",
- "Developed automated Oracle backup and restore solution to decrease Concourse jobs’ runtime by 20%",
- "Proposed and implemented new dispatch process for CI infrastructure by integrating Mantis API to Concourse"
- ],
- // projects: [ // optional array
- // { name: "Dashboard Redesign", link: "..." }
- // ],
- // impact: "40% increase in engagement", // optional
+ period: {
+ en: "May - Dec 2018",
+ fr: "Mai - Déc 2018"
+ },
+ achievements: {
+ en: [
+ "Automated software installation processes to decrease runtime by 15% using Ansible",
+ "Implemented a build certification process in custom Concourse to improve testing team's efficiency by 75%",
+ "Developed automated Oracle backup and restore solution to decrease Concourse jobs' runtime by 20%",
+ "Proposed and implemented new dispatch process for CI infrastructure by integrating Mantis API to Concourse"
+ ],
+ fr: [
+ "Automatisé les processus d'installation logicielle pour réduire le temps d'exécution de 15% avec Ansible",
+ "Implémenté un processus de certification de build dans Concourse personnalisé pour améliorer l'efficacité de l'équipe de test de 75%",
+ "Développé une solution automatisée de sauvegarde et restauration Oracle pour réduire le temps d'exécution des jobs Concourse de 20%",
+ "Proposé et implémenté un nouveau processus de dispatch pour l'infrastructure CI en intégrant l'API Mantis à Concourse"
+ ]
+ },
tech: ["Python", "Mantis", "Concourse", "Ansible"],
},
{
- hash: "1f9a3bc", // or auto-generate
- title: "Automation SQA Intern",
+ hash: "1f9a3bc",
+ title: {
+ en: "Automation SQA Intern",
+ fr: "Stagiaire SQA en automatisation"
+ },
company: "Matrox",
- period: "Jan - Aug 2017",
- // description: "Brief overview...",
- achievements: [
- "Created a new automated testing workflow to improve reduce weekly manual testing by 10 hours",
- "Integrated Silktest, Jenkins and Testrail API using Python scripts to 100% automate log parsing, reporting and archiving",
- "Set up, configured and managed Jenkins servers and slaves",
- "Developed Python and 4Test test suites to perform functional and performance tests"
- ],
- // projects: [ // optional array
- // { name: "Dashboard Redesign", link: "..." }
- // ],
- // impact: "40% increase in engagement", // optional
+ period: {
+ en: "Jan - Aug 2017",
+ fr: "Jan - Août 2017"
+ },
+ achievements: {
+ en: [
+ "Created a new automated testing workflow to improve reduce weekly manual testing by 10 hours",
+ "Integrated Silktest, Jenkins and Testrail API using Python scripts to 100% automate log parsing, reporting and archiving",
+ "Set up, configured and managed Jenkins servers and slaves",
+ "Developed Python and 4Test test suites to perform functional and performance tests"
+ ],
+ fr: [
+ "Créé un nouveau workflow de tests automatisés pour réduire les tests manuels hebdomadaires de 10 heures",
+ "Intégré Silktest, Jenkins et l'API Testrail avec des scripts Python pour automatiser à 100% l'analyse de logs, les rapports et l'archivage",
+ "Configuré et géré des serveurs Jenkins et leurs agents",
+ "Développé des suites de tests Python et 4Test pour effectuer des tests fonctionnels et de performance"
+ ]
+ },
tech: ["Python", "Bash", "Silktest", "Jenkins", "Testrail"],
}
]
\ No newline at end of file
diff --git a/src/components/data/skills.js b/src/components/data/skills.js
index c219102..08fcb80 100644
--- a/src/components/data/skills.js
+++ b/src/components/data/skills.js
@@ -1,204 +1,98 @@
export const skillsData = {
+ // These don't need translation - they're universal
languages: [
- {
- name: "Python",
- icon: "FaPython"
- },
- {
- name: "Java",
- icon: "FaJava"
- },
- {
- name: "Bash",
- icon: "FaTerminal"
- },
- {
- name: "JavaScript",
- icon: "FaJs"
- }
+ { name: "Python", icon: "FaPython" },
+ { name: "Java", icon: "FaJava" },
+ { name: "Bash", icon: "FaTerminal" },
+ { name: "JavaScript", icon: "FaJs" }
],
environments: [
- {
- name: "Windows",
- icon: "FaWindows"
- },
- {
- name: "Linux",
- icon: "FaLinux"
- },
- {
- name: "Ubuntu",
- icon: "FaUbuntu"
- }
+ { name: "Windows", icon: "FaWindows" },
+ { name: "Linux", icon: "FaLinux" },
+ { name: "Ubuntu", icon: "FaUbuntu" }
],
virtualization: [
- {
- name: "VirtualBox",
- icon: "SiVirtualbox"
- },
- {
- name: "Docker",
- icon: "FaDocker"
- },
- {
- name: "Hyper-V",
- icon: "FaTerminal"
- }
+ { name: "VirtualBox", icon: "SiVirtualbox" },
+ { name: "Docker", icon: "FaDocker" },
+ { name: "Hyper-V", icon: "FaTerminal" }
],
frameworks: [
- {
- name: "Flask",
- icon: "SiFlask"
- },
- {
- name: "Node.js",
- icon: "FaNode"
- },
- {
- name: "WordPress",
- icon: "FaWordpress"
- },
- {
- name: "React",
- icon: "FaReact"
- },
- {
- name: "Google Cloud",
- icon: "FaGoogle"
- },
- {
- name: "Play",
- icon: "FaPlay"
- }
+ { name: "Flask", icon: "SiFlask" },
+ { name: "Node.js", icon: "FaNode" },
+ { name: "WordPress", icon: "FaWordpress" },
+ { name: "React", icon: "FaReact" },
+ { name: "Google Cloud", icon: "FaGoogle" },
+ { name: "Play", icon: "FaPlay" }
],
"CI/CD": [
- {
- name: "Git",
- icon: "FaGitAlt"
- },
- {
- name: "Github",
- icon: "FaGithub"
- },
- {
- name: "Jenkins",
- icon: "FaJenkins"
- },
- {
- name: "Bitbucket",
- icon: "FaBitbucket"
- },
- {
- name: "JIRA",
- icon: "FaJira"
- },
- {
- name: "Concourse",
- icon: "SiConcourse"
- }
+ { name: "Git", icon: "FaGitAlt" },
+ { name: "Github", icon: "FaGithub" },
+ { name: "Jenkins", icon: "FaJenkins" },
+ { name: "Bitbucket", icon: "FaBitbucket" },
+ { name: "JIRA", icon: "FaJira" },
+ { name: "Concourse", icon: "SiConcourse" }
],
"Machine Learning": [
- {
- name: "PyTorch",
- icon: "SiPytorch"
- },
- {
- name: "Scikit-learn",
- icon: "SiScikitlearn"
- },
- {
- name: "Pandas",
- icon: "SiPandas"
- },
- {
- name: "NumPy",
- icon: "SiNumpy"
- },
- {
- name: "Jupyter",
- icon: "SiJupyter"
- }
+ { name: "PyTorch", icon: "SiPytorch" },
+ { name: "Scikit-learn", icon: "SiScikitlearn" },
+ { name: "Pandas", icon: "SiPandas" },
+ { name: "NumPy", icon: "SiNumpy" },
+ { name: "Jupyter", icon: "SiJupyter" }
],
+ // Domain sections need translation
domains: [
{
- name: "Web Development",
- description: "Full-stack applications with modern frameworks and RESTful APIs",
+ name: {
+ en: "Web Development",
+ fr: "Développement Web"
+ },
+ description: {
+ en: "Full-stack applications with modern frameworks and RESTful APIs",
+ fr: "Applications full-stack avec des frameworks modernes et des API RESTful"
+ },
icon: "FaCode",
relatedSkills: [
- {
- icon: "FaReact",
- displayName: "React"
- },
- {
- icon: "FaNode",
- displayName: "Node.js"
- },
- {
- icon: "SiFlask",
- displayName: "Flask"
- },
- {
- icon: "FaJs",
- displayName: "JavaScript"
- },
- {
- icon: "FaPython",
- displayName: "Python"
- }
+ { icon: "FaReact", displayName: "React" },
+ { icon: "FaNode", displayName: "Node.js" },
+ { icon: "SiFlask", displayName: "Flask" },
+ { icon: "FaJs", displayName: "JavaScript" },
+ { icon: "FaPython", displayName: "Python" }
]
},
{
- name: "Machine Learning",
- description: "ML models, data analysis, and NLP solutions",
+ name: {
+ en: "Machine Learning",
+ fr: "Apprentissage Automatique"
+ },
+ description: {
+ en: "ML models, data analysis, and NLP solutions",
+ fr: "Modèles ML, analyse de données et solutions NLP"
+ },
icon: "FaBrain",
relatedSkills: [
- {
- icon: "SiPytorch",
- displayName: "PyTorch"
- },
- {
- icon: "SiScikitlearn",
- displayName: "Scikit-learn"
- },
- {
- icon: "SiPandas",
- displayName: "Pandas"
- },
- {
- icon: "SiNumpy",
- displayName: "NumPy"
- },
- {
- icon: "SiJupyter",
- displayName: "Jupyter"
- }
+ { icon: "SiPytorch", displayName: "PyTorch" },
+ { icon: "SiScikitlearn", displayName: "Scikit-learn" },
+ { icon: "SiPandas", displayName: "Pandas" },
+ { icon: "SiNumpy", displayName: "NumPy" },
+ { icon: "SiJupyter", displayName: "Jupyter" }
]
},
{
- name: "DevOps & Cloud",
- description: "CI/CD pipelines, containerization, and cloud infrastructure",
+ name: {
+ en: "DevOps & Cloud",
+ fr: "DevOps et Cloud"
+ },
+ description: {
+ en: "CI/CD pipelines, containerization, and cloud infrastructure",
+ fr: "Pipelines CI/CD, conteneurisation et infrastructure cloud"
+ },
icon: "FaCloud",
relatedSkills: [
- {
- icon: "FaDocker",
- displayName: "Docker"
- },
- {
- icon: "FaGitAlt",
- displayName: "Git"
- },
- {
- icon: "FaJenkins",
- displayName: "Jenkins"
- },
- {
- icon: "FaGoogle",
- displayName: "Google Cloud"
- },
- {
- icon: "SiConcourse",
- displayName: "Concourse"
- }
+ { icon: "FaDocker", displayName: "Docker" },
+ { icon: "FaGitAlt", displayName: "Git" },
+ { icon: "FaJenkins", displayName: "Jenkins" },
+ { icon: "FaGoogle", displayName: "Google Cloud" },
+ { icon: "SiConcourse", displayName: "Concourse" }
]
}
]
diff --git a/src/contexts/LanguageContext.js b/src/contexts/LanguageContext.js
new file mode 100644
index 0000000..6fd746b
--- /dev/null
+++ b/src/contexts/LanguageContext.js
@@ -0,0 +1,3 @@
+import { createContext } from 'react';
+
+export const LanguageContext = createContext(null);
diff --git a/src/contexts/LanguageProvider.jsx b/src/contexts/LanguageProvider.jsx
new file mode 100644
index 0000000..85745cf
--- /dev/null
+++ b/src/contexts/LanguageProvider.jsx
@@ -0,0 +1,31 @@
+import React, { useState, useEffect } from 'react';
+import { LanguageContext } from './LanguageContext';
+
+export const LanguageProvider = ({ children }) => {
+ const [language, setLanguage] = useState(() => {
+ const savedLang = localStorage.getItem('preferred-language');
+ return savedLang || 'en';
+ });
+
+ useEffect(() => {
+ localStorage.setItem('preferred-language', language);
+ }, [language]);
+
+ const toggleLanguage = () => {
+ setLanguage(prev => (prev === 'en' ? 'fr' : 'en'));
+ };
+
+ const value = {
+ language,
+ setLanguage,
+ toggleLanguage,
+ isEnglish: language === 'en',
+ isFrench: language === 'fr',
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/contexts/useLanguage.js b/src/contexts/useLanguage.js
new file mode 100644
index 0000000..2bb3aa3
--- /dev/null
+++ b/src/contexts/useLanguage.js
@@ -0,0 +1,10 @@
+import {useContext} from "react";
+import {LanguageContext} from "./LanguageContext.js";
+
+export const useLanguage = () => {
+ const context = useContext(LanguageContext);
+ if (!context) {
+ throw new Error('useLanguage must be used within a LanguageProvider');
+ }
+ return context;
+};
\ No newline at end of file
diff --git a/src/utils/translationHelpers.js b/src/utils/translationHelpers.js
new file mode 100644
index 0000000..a5fd8b5
--- /dev/null
+++ b/src/utils/translationHelpers.js
@@ -0,0 +1,39 @@
+/**
+ * Helper function to get translated text from bilingual data
+ * @param {string|object} value - Either a string or an object with 'en' and 'fr' keys
+ * @param {string} language - Current language ('en' or 'fr')
+ * @returns {string} - The translated text
+ */
+export const getText = (value, language = 'en') => {
+ // If it's already a string (not translated), return as is
+ if (typeof value === 'string') {
+ return value;
+ }
+
+ // If it's an object with language keys, return the appropriate one
+ if (value && typeof value === 'object') {
+ return value[language] || value.en || '';
+ }
+
+ return '';
+};
+
+/**
+ * Helper function to get translated array from bilingual data
+ * @param {array|object} value - Either an array or an object with 'en' and 'fr' keys containing arrays
+ * @param {string} language - Current language ('en' or 'fr')
+ * @returns {array} - The translated array
+ */
+export const getArray = (value, language = 'en') => {
+ // If it's already an array (not translated), return as is
+ if (Array.isArray(value)) {
+ return value;
+ }
+
+ // If it's an object with language keys, return the appropriate array
+ if (value && typeof value === 'object') {
+ return value[language] || value.en || [];
+ }
+
+ return [];
+};
\ No newline at end of file