diff options
| author | Armand Philippot <git@armandphilippot.com> | 2021-10-26 21:54:36 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2021-10-26 21:54:36 +0200 |
| commit | ed9f269a78062f0d9a805b91b95fff5f479098ac (patch) | |
| tree | a6794933b3994ded3dcc8992b353ec9e9c07532f /htdocs | |
| parent | 1d272eac38ebb310e360891a3a717447a1d0547a (diff) | |
feat: translate the app - two locales available: fr and en
Diffstat (limited to 'htdocs')
| -rw-r--r-- | htdocs/index.html | 45 | ||||
| -rw-r--r-- | htdocs/src/js/app.js | 27 | ||||
| -rw-r--r-- | htdocs/src/js/config/projects.js | 34 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/i18n.js | 42 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/locales/en.js | 24 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/locales/fr.js | 24 |
6 files changed, 160 insertions, 36 deletions
diff --git a/htdocs/index.html b/htdocs/index.html index e7aaace..47e41fd 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -1,19 +1,16 @@ <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Armand Philippot</title> - <link rel="stylesheet" href="assets/css/style.css"> + <link rel="stylesheet" href="assets/css/style.css" /> </head> <body class="body"> <div class="toolbar"> - <button type="button" class="toolbar__options btn btn--menu"> - Menu - </button> + <button type="button" class="toolbar__options btn btn--menu">Menu</button> <button type="button" class="toolbar__options btn btn--details"> About app </button> @@ -22,37 +19,43 @@ <div class="branding"> <div class="branding__logo logo"> <a href="/" rel="home" class="logo__link"> - <img src="./assets/images/armand-philippot.jpg" alt="Back to homepage" - class="logo__image logo__image--front"> - <img src="./assets/images/armand-philippot-logo.svg" alt="Back to homepage" - class="logo__image logo__image--back"> + <img + src="./assets/images/armand-philippot.jpg" + alt="Back to homepage" + class="logo__image logo__image--front" + /> + <img + src="./assets/images/armand-philippot-logo.svg" + alt="Back to homepage" + class="logo__image logo__image--back" + /> </a> </div> <h1 class="branding__title"> <a href="/" rel="home" class="branding__link">Armand Philippot</a> </h1> - <p class="branding__description"> - Front-end developer - </p> + <p class="branding__description">Front-end developer</p> </div> <nav class="nav"> <p class="nav__label">App list:</p> - <ul class="nav__list"> - </ul> + <ul class="nav__list"></ul> </nav> </header> <main class="main"> - <div class="instructions">Select an app inside menu to see a live preview and app details.</div> + <div class="instructions"> + Select an app inside menu to see a live preview and app details. + </div> </main> <footer class="footer"> <div class="copyright"> - <span class="copyright__license">MIT</span> + <span class="copyright__license" title="License MIT">MIT</span> <span class="copyright__date">2021.</span> - <a href="https://www.armandphilippot.com/" class="copyright__author">Armand Philippot.</a> + <a href="https://www.armandphilippot.com/" class="copyright__author" + >Armand Philippot.</a + > </div> </footer> <script src="./assets/js/runtime.js"></script> <script src="./assets/js/app.js"></script> </body> - </html> diff --git a/htdocs/src/js/app.js b/htdocs/src/js/app.js index b605583..2837621 100644 --- a/htdocs/src/js/app.js +++ b/htdocs/src/js/app.js @@ -1,4 +1,5 @@ import projects from './config/projects'; +import { translate, setLocale, currentLocale } from './i18n/i18n'; import { hideToBottom, hideToLeft, @@ -134,7 +135,7 @@ function getRepos(repos) { const list = document.createElement('ul'); const items = repos.map((repo) => getRepoItem(repo.name, repo.url)); title.classList.add('project-details__title'); - title.textContent = 'Repositories:'; + title.textContent = translate('main.project.details.repo'); list.classList.add('list', 'list--repos'); list.append(...items); wrapper.append(title, list); @@ -151,7 +152,7 @@ function getTechs(technologies) { const title = document.createElement('h3'); title.classList.add('project-details__title'); - title.textContent = 'Technologies:'; + title.textContent = translate('main.project.details.tech'); const list = document.createElement('ul'); const items = technologies.map((technology) => { const item = document.createElement('li'); @@ -173,17 +174,20 @@ function getProjectDetails(project) { const title = document.createElement('h2'); const techList = project?.technologies ? getTechs(project.technologies) : []; const reposList = getRepos(project.repo); + const locale = currentLocale(); let description; if (project.description) { description = document.createElement('p'); - description.textContent = project.description; + description.textContent = project.description[locale] || ''; } else { description = ''; } title.classList.add('project-details__title'); - title.textContent = `About ${project.name}`; + title.textContent = translate('main.project.details.about', { + name: project.name, + }); details.classList.add('project-details'); if (!isSmallVw()) details.classList.add('fade-in'); details.replaceChildren(title, description, ...techList, ...reposList); @@ -228,7 +232,9 @@ function showProject(id) { if (isSmallVw()) details.classList.add('hide'); - detailsBtn.textContent = `About ${currentProject.name}`; + detailsBtn.textContent = translate('main.project.details.about', { + name: currentProject.name, + }); detailsBtn.addEventListener('click', toggleProjectDetails); window.history.pushState({}, currentProject.name, `#${id}`); main.replaceChildren(preview, details); @@ -311,10 +317,21 @@ function printRequestedPage() { } } +function translateHTMLContent() { + const brandingDesc = document.querySelector('.branding__description'); + const navLabel = document.querySelector('.nav__label'); + const license = document.querySelector('.copyright__license'); + brandingDesc.textContent = translate('branding.description'); + navLabel.textContent = translate('nav.title'); + license.title = translate('footer.license'); +} + /** * Initialize the website with the projects list. */ function init() { + setLocale('en'); + translateHTMLContent(); loadWebpackStyles(); printProjectsNav(); updateView(); diff --git a/htdocs/src/js/config/projects.js b/htdocs/src/js/config/projects.js index bb239db..f22fa9b 100644 --- a/htdocs/src/js/config/projects.js +++ b/htdocs/src/js/config/projects.js @@ -2,7 +2,10 @@ const projects = [ { id: 'bin2dec', name: 'Bin2Dec', - description: 'Convert a binary string to a decimal number.', + description: { + en: 'Convert a binary string to a decimal number.', + fr: 'Convertit un nombre binaire en un nombre décimal.', + }, path: './projects/js-small-apps/bin2dec/index.html', repo: [ { @@ -19,8 +22,10 @@ const projects = [ { id: 'budget-app', name: 'Budget App', - description: - 'By selecting a language in the initialization form, only the currency is converted (the app is not translated). Also, no data is saved on reload.', + description: { + en: 'By selecting a language in the initialization form, only the currency is converted (the app is not translated). Also, no data is saved on page reload.', + fr: "En sélectionnant une langue dans le formulaire d'initialisation, seul le format des nombres change (l'application n'est pas traduite). Aucune donnée n'est conservée après rechargement de la page.", + }, path: './projects/js-small-apps/budget-app/index.html', repo: [ { @@ -37,7 +42,10 @@ const projects = [ { id: 'calculator', name: 'Calculator', - description: 'A basic calculator.', + description: { + en: 'A basic calculator.', + fr: 'Une simple calculette.', + }, path: './projects/js-small-apps/calculator/index.html', repo: [ { @@ -54,8 +62,10 @@ const projects = [ { id: 'clock', name: 'Clock', - description: - 'What time is it? You can have the current hour in three formats: an analogic clock, a numeric display or a text.', + description: { + en: 'What time is it? You can have the current hour in three formats: an analogic clock, a numeric display or a text.', + fr: "Quelle heure est-il ? Vous pouvez voir l'heure actuelle dans trois formats : une horloge analogique, un affichage numérique et sous forme de texte.", + }, path: './projects/js-small-apps/clock/index.html', repo: [ { @@ -72,8 +82,10 @@ const projects = [ { id: 'css-border-previewer', name: 'CSS Border Previewer', - description: - 'Play with CSS borders (style, width, border-radius). Then, you can copy the generated code if the preview suits you.', + description: { + en: 'Play with CSS borders (style, width, radius). Then, you can copy the generated code if the preview suits you.', + fr: "Jouez avec les bordures CSS (style, largeur, radius). Puis, vous pouvez copier le code généré si l'aperçu vous satisfait.", + }, path: './projects/js-small-apps/css-border-previewer/index.html', repo: [ { @@ -90,8 +102,10 @@ const projects = [ { id: 'rps-game', name: 'Rock Paper Scissors', - description: - 'A basic implementation of the game. Try to beat your friend or the computer.', + description: { + en: 'A basic implementation of the game. Try to beat your friend or the computer.', + fr: "Une implémentation du jeu. Essayez de battre votre ami ou l'ordinateur.", + }, path: './projects/js-small-apps/rock-paper-scissors/index.html', repo: [ { diff --git a/htdocs/src/js/i18n/i18n.js b/htdocs/src/js/i18n/i18n.js new file mode 100644 index 0000000..6bdc7cd --- /dev/null +++ b/htdocs/src/js/i18n/i18n.js @@ -0,0 +1,42 @@ +import I18n from 'i18n-js'; +import en from './locales/en'; +import fr from './locales/fr'; + +const supportedLanguages = [ + { + code: 'en', + label: 'English', + translations: en, + }, + { + code: 'fr', + label: 'Français', + translations: fr, + }, +]; + +supportedLanguages.forEach((locale) => { + I18n.translations[locale.code] = locale.translations; +}); + +function setLocale(locale) { + I18n.locale = locale; +} + +function currentLocale() { + return I18n.currentLocale(); +} + +function translate(name, params = {}) { + return I18n.t(name, params); +} + +const { defaultLocale } = I18n; + +export { + supportedLanguages, + setLocale, + translate, + defaultLocale, + currentLocale, +}; diff --git a/htdocs/src/js/i18n/locales/en.js b/htdocs/src/js/i18n/locales/en.js new file mode 100644 index 0000000..d8fea40 --- /dev/null +++ b/htdocs/src/js/i18n/locales/en.js @@ -0,0 +1,24 @@ +const en = { + branding: { + description: 'Front-end developer', + }, + nav: { + title: 'Apps list:', + }, + main: { + instructions: + 'Select an app inside menu to see a live preview and app details.', + project: { + details: { + about: 'About {{name}}', + repo: 'Repositories:', + tech: 'Technologies:', + }, + }, + }, + footer: { + license: 'License MIT', + }, +}; + +export default en; diff --git a/htdocs/src/js/i18n/locales/fr.js b/htdocs/src/js/i18n/locales/fr.js new file mode 100644 index 0000000..f44d459 --- /dev/null +++ b/htdocs/src/js/i18n/locales/fr.js @@ -0,0 +1,24 @@ +const fr = { + branding: { + description: 'Intégrateur web', + }, + nav: { + title: 'Liste des applications :', + }, + main: { + instructions: + "Sélectionnez une application dans le menu pour afficher un aperçu en direct et les informations sur l'application.", + project: { + details: { + about: 'À propos de {{name}}', + repo: 'Dépôts :', + tech: 'Technologies :', + }, + }, + }, + footer: { + license: 'Licence MIT', + }, +}; + +export default fr; |
