Add i18n selector

This commit is contained in:
Samuel Ortion 2024-01-17 12:13:08 +01:00
parent 3e28cb35e9
commit f6bfa6bce5
7 changed files with 73 additions and 27 deletions

View File

@ -1 +1,17 @@
{} {
"Game": "Game",
"About": "About",
"It was a": "It was a",
"Language": "Language",
"Submit": "Submit",
"Geolocalize yourself on the map": "Geolocalize yourself on the map",
"Start the game": "Start the game",
"Start a new quizz": "Start a new quizz",
"Return to the map": "Return to the map",
"Wrong!": "Wrong!",
"About SoundBirder": "About SoundBirder",
"SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.": "SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.",
"Author": "Author",
"The project is made with ♥ by Samuel Ortion.": "The project is made with ♥ by Samuel Ortion.",
"Correct!": "Correct!"
}

View File

@ -1,12 +1,18 @@
{ {
"Game": "Jeu", "Game": "Jeu",
"About": "À propos", "About": "À propos",
"Contact": "Contact", "Contact": "Contact",
"Author": "Auteur", "Author": "Auteur",
"The project is made with ♥ by Samuel Ortion": "Ce projet est fait avec ♥ par Samuel Ortion", "The project is made with ♥ by Samuel Ortion": "Ce projet est fait avec ♥ par Samuel Ortion",
"Correct!": "Correct !", "Correct!": "Correct !",
"Wrong!": "Incorrect !", "Wrong!": "Incorrect !",
"It was a": "C'était un", "It was a": "C'était un",
"SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.": "SoundBirder est une application open-source pour apprendre les chant d'oiseaux. Elle est basée sur les enregistrements de Xeno-Canto et sur les données d'eBird", "SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.": "SoundBirder est une application open-source pour apprendre les chant d'oiseaux. Elle est basée sur les enregistrements de Xeno-Canto et sur les données d'eBird",
"The project is made with ♥ by Samuel Ortion.": "Ce projet est fait avec ♥ par Samuel Ortion." "The project is made with ♥ by Samuel Ortion.": "Ce projet est fait avec ♥ par Samuel Ortion.",
"Language": "Language",
"Submit": "Submit",
"Geolocalize yourself on the map": "Geolocalize yourself on the map",
"Start the game": "Start the game",
"Start a new quizz": "Start a new quizz",
"Return to the map": "Return to the map"
} }

View File

@ -8,7 +8,7 @@ let gameQuizzStep = document.querySelector('.game-quizz-step');
let gameQuizz = document.querySelector('.game-quizz'); let gameQuizz = document.querySelector('.game-quizz');
let gameResultStep = document.querySelector('.game-results-step'); let gameResultStep = document.querySelector('.game-results-step');
let gameLoading = document.querySelector('.game-loading'); let gameLoading = document.querySelector('.game-loading');
let audio = document.querySelector('.game-quizz-step audio'); let audio = document.querySelector('.game-audio audio');
let proposals = document.querySelector('.game-quizz-step .proposals'); let proposals = document.querySelector('.game-quizz-step .proposals');
let result = document.querySelector('.game-results-step .message'); let result = document.querySelector('.game-results-step .message');
let restartButton = document.querySelector('.game-quizz .restart-button'); let restartButton = document.querySelector('.game-quizz .restart-button');
@ -45,6 +45,7 @@ function regionCoder() {
function quizzStep() { function quizzStep() {
gameQuizz.classList.remove("none"); gameQuizz.classList.remove("none");
gameLoading.classList.remove("none"); gameLoading.classList.remove("none");
audio.classList.add("none");
client.getQuizz(region) client.getQuizz(region)
.then(quizz => { .then(quizz => {
gameLoading.classList.add("none"); gameLoading.classList.add("none");
@ -66,6 +67,10 @@ function displayQuizz(quizz) {
audio.play(); audio.play();
proposals.innerHTML = ""; proposals.innerHTML = "";
quizz.species.forEach(sp => { quizz.species.forEach(sp => {
if (sp.speciesCode == undefined) {
quizzStep();
return
}
let proposal = document.createElement('li'); let proposal = document.createElement('li');
proposal.classList.add('proposal'); proposal.classList.add('proposal');
let button = document.createElement('button'); let button = document.createElement('button');
@ -81,6 +86,7 @@ function displayQuizz(quizz) {
function verifyAnswer(event) { function verifyAnswer(event) {
let answer = event.target.value; let answer = event.target.value;
console.log(answer);
audio.pause(); audio.pause();
client.checkAnswer(answer) client.checkAnswer(answer)
.then(data => { .then(data => {
@ -99,7 +105,6 @@ mapButton.addEventListener('click', returnToMap);
function displayResult(message_class, message, species) { function displayResult(message_class, message, species) {
gameQuizzStep.classList.toggle('none'); gameQuizzStep.classList.toggle('none');
audio.classList.add("none");
result.classList.remove('success', 'error'); result.classList.remove('success', 'error');
result.classList.add(message_class); result.classList.add(message_class);
result.innerText = message; result.innerText = message;

6
public/javascripts/lang.js Executable file
View File

@ -0,0 +1,6 @@
let languageSelectorButton = document.getElementById('language-selector-button');
let languageSelector = document.getElementById('language-selector');
languageSelectorButton.addEventListener('click', function () {
let code = languageSelector.value;
window.location = '/' + code;
});

View File

@ -1,27 +1,28 @@
.game .game
.game-map-step .game-map-step
#map.h-100 #map.h-100
button.button.geolocation-button button.button.geolocation-button(aria-label=__('Geolocalize yourself on the map'))
i(data-feather="map-pin") i(data-feather="map-pin")
button.button.start-button button.button.start-button(aria-label=__('Start the game'))
i(data-feather="play") i(data-feather="play")
.game-quizz.none .game-quizz.none
.game-loading .game-loading
<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg"> <svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle> <circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
</svg> </svg>
.game-quizz-step.none .game-audio
ul.proposals .game-quizz-step.none
ul.proposals
.game-results-step.none
p.message
.species.answer
p #{ __('It was a') }
span.com
span.sci
audio(controls).none audio(controls).none
.game-results-step.none button.button.restart-button(aria-label=__('Start a new quizz'))
p.message
.species.answer
p #{ __('It was a') }
span.com
span.sci
button.button.restart-button
i(data-feather="repeat") i(data-feather="repeat")
button.button.map-button button.button.map-button(aria-label=__('Return to the map'))
i(data-feather="map") i(data-feather="map")
link(rel="stylesheet" href="/dist/leaflet/leaflet.css") link(rel="stylesheet" href="/dist/leaflet/leaflet.css")
link(rel="stylesheet" href="/stylesheets/spinner.css") link(rel="stylesheet" href="/stylesheets/spinner.css")

10
views/lang.pug Normal file
View File

@ -0,0 +1,10 @@
- var languages = {en: "English", fr: "Français"} // , de: "Deutsch", es: "Español"}
.flex.flex-row
.relative.h-10.w-10(class='min-w-[100px]')
select#language-selector.peer.h-full.w-full.border.border-blue-gray-200.border-t-transparent.bg-transparent.px-3.font-sans.text-sm.font-normal.text-blue-gray-700.outline.outline-0.transition-all(class='rounded-[7px] py-2.5 placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 empty:!bg-gray-900 focus:border-2 focus:border-gray-900 focus:border-t-transparent focus:outline-0 disabled:border-0 disabled:bg-blue-gray-50')
each language, code in languages
option.pointer-events-none.absolute.left-0.flex.h-full.w-full.select-none.font-normal.leading-tight.text-blue-gray-400.transition-all(class="before:content[' '] after:content[' '] -top-1.5 text-[11px] before:pointer-events-none before:mt-[6.5px] before:mr-1 before:box-border before:block before:h-1.5 before:w-2.5 before:rounded-tl-md before:border-t before:border-l before:border-blue-gray-200 before:transition-all after:pointer-events-none after:mt-[6.5px] after:ml-1 after:box-border after:block after:h-1.5 after:w-2.5 after:flex-grow after:rounded-tr-md after:border-t after:border-r after:border-blue-gray-200 after:transition-all peer-placeholder-shown:text-sm peer-placeholder-shown:leading-[3.75] peer-placeholder-shown:text-blue-gray-500 peer-placeholder-shown:before:border-transparent peer-placeholder-shown:after:border-transparent peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-gray-900 peer-focus:before:border-t-2 peer-focus:before:border-l-2 peer-focus:before:border-gray-900 peer-focus:after:border-t-2 peer-focus:after:border-r-2 peer-focus:after:border-gray-900 peer-disabled:text-transparent peer-disabled:before:border-transparent peer-disabled:after:border-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500" value=code) #{ language }
label.pointer-events-none.absolute.left-0.flex.h-full.w-full.select-none.font-normal.leading-tight.text-blue-gray-400.transition-all(class="before:content[' '] after:content[' '] -top-1.5 text-[11px] before:pointer-events-none before:mt-[6.5px] before:mr-1 before:box-border before:block before:h-1.5 before:w-2.5 before:rounded-tl-md before:border-t before:border-l before:border-blue-gray-200 before:transition-all after:pointer-events-none after:mt-[6.5px] after:ml-1 after:box-border after:block after:h-1.5 after:w-2.5 after:flex-grow after:rounded-tr-md after:border-t after:border-r after:border-blue-gray-200 after:transition-all peer-placeholder-shown:text-sm peer-placeholder-shown:leading-[3.75] peer-placeholder-shown:text-blue-gray-500 peer-placeholder-shown:before:border-transparent peer-placeholder-shown:after:border-transparent peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-gray-900 peer-focus:before:border-t-2 peer-focus:before:border-l-2 peer-focus:before:border-gray-900 peer-focus:after:border-t-2 peer-focus:after:border-r-2 peer-focus:after:border-gray-900 peer-disabled:text-transparent peer-disabled:before:border-transparent peer-disabled:after:border-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500")
| #{ __('Language') }
button#language-selector-button.p-1.btn #{ __('Submit') }

View File

@ -10,13 +10,14 @@ html
body body
.flex.flex-col.min-h-screen .flex.flex-col.min-h-screen
.flex-1.p-5 .flex-1.p-5
nav nav(role="navigation")
- var i18n_prefix = locale ? '/' + locale : '' - var i18n_prefix = locale ? '/' + locale : ''
ul.flex.flex-row.text-center.justify-evenly ul.flex.flex-row.text-center.justify-evenly
li li
a(href=`${i18n_prefix}/`) #{ __('Game') } a(href=`${i18n_prefix}/`) #{ __('Game') }
li li
a(href=`${i18n_prefix}/about`) #{ __('About') } a(href=`${i18n_prefix}/about`) #{ __('About') }
include lang.pug
header header
h1= title h1= title
main main
@ -29,4 +30,5 @@ html
span.author span.author
a(href="https://samuel.ortion.fr" class="link") Samuel Ortion a(href="https://samuel.ortion.fr" class="link") Samuel Ortion
script(src="/javascripts/app.js" type="module") script(src="/javascripts/app.js" type="module")
script(src="/dist/feather/feather.min.js") script(src="/dist/feather/feather.min.js")
script(src="/javascripts/lang.js")