javascripthtmlcsstogglebutton

Toggling between languages with JS


I am trying to create a website that can switch languages from English to French by clicking on the toggle button. I tried a few ways without Javascript because I don't know much, and only with CSS but never found the result I wanted.

Only The <h2 class="title">welcome!</h2>changes to "yoohoo les nazes", but the rest does not change.

Can anyone help?

document.querySelector('#togBtn').addEventListener('input', (event) => {
  document.querySelector('.title', '.1', '.2', '.3', '.4', '.5').textContent = data[event.currentTarget.checked ? 'francais' : 'english'].title;
  .1;
});
var data = {
  "english": {
    "title": "welcome!",
    "1": "My work is primarily inspired by nature.",
    "2": "Each creation is unique.",
    "3": "The white porcelain I use",
    "4": "I studied and graduated",
    "5": "I wish to thank"
  },
  "francais": {
    "title": "yoohoo les nazes",
    "1": "Mon travail est d'abord inspiré sur la nature.",
    "2": "chaque création est unique.",
    "3": "La porcelaine blanche que j'utilise",
    "4": "j'ai étudiée et sui diplômée",
    "5": "j'aimerai remercier"
  }
}
.switch {
  position: relative;
  display: inline-block;
  width: 80px;
  height: 34px;
}

.switch input {
  display: none;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: brown;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked+.slider {
  background-color: burlywood;
}

input:focus+.slider {
  box-shadow: 0 0 1px #2196F3;
}

input:checked+.slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(45px);
}

.slider {
  border-radius: 34px;
}

.slider:before {
  border-radius: 50%;
}

.on {
  display: none;
}

.on,
.off {
  color: white;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  font-size: 10px;
  font-family: Verdana, sans-serif;
}

input:checked+.slider .on {
  display: block;
}

input:checked+.slider .off {
  display: none;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Whisper&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>

<label class="switch">       
  <input type="checkbox" id="togBtn">       
  <div class="slider round">         
    <span language='english' class="on">EN</span>         
    <span language='francais' class="off">FR</span>       
  </div>     
</label>
<ul class="nav-items">
  <div class="content">
    <h2 class="title">welcome!</h2>
    <p class="1">My work is primarily inspired by nature.</p>
    <p class="2">Each creation is unique.</p>
    <p class="3">The white porcelain I use</p>
    <p class="4">I studied and graduated </p>
    <p class="5">I wish to thank</p>
  </div>
</ul>


Solution

  • The first issue you have is that document.querySelector() can only select a single element. To select multiple elements you should use querySelectorAll() instead. However the syntax you used is incorrect. You need to provide a single string selector, not multiple arguments, eg:

    document.querySelector('.title, .element1, .element2, .element3, .element4, .element5');
    

    To improve the code quality you can use a single common class which you put on all elements to be translated, I used .translate in the following example. From there you can loop over all of those elements and use a data attribute to provide the 'key' of the translation to use for that specific element.

    In addition, note that the EN and FR labels in the toggle were inverted for the actual language being shown.

    Finally, as noted by @CBroe in the comments, browsers are tolerant of class and id values which are numeric, however it's outside of the spec and not good practice. I've converted these to alpha-numeric values instead.

    Here's a working example with the above changes made:

    document.querySelector('#togBtn').addEventListener('change', e => {
      document.querySelectorAll('.translate').forEach(el => {
        el.textContent = data[e.target.checked ? 'francais' : 'english'][el.dataset['tkey']];
      });
    });
    
    var data = {
      "english": {
        "title": "welcome!",
        "para-01": "My work is primarily inspired by nature.",
        "para-02": "Each creation is unique.",
        "para-03": "The white porcelain I use",
        "para-04": "I studied and graduated",
        "para-05": "I wish to thank"
      },
      "francais": {
        "title": "yoohoo les nazes",
        "para-01": "Mon travail est d'abord inspiré sur la nature.",
        "para-02": "chaque création est unique.",
        "para-03": "La porcelaine blanche que j'utilise",
        "para-04": "j'ai étudiée et sui diplômée",
        "para-05": "j'aimerai remercier"
      }
    }
    .switch {
      position: relative;
      display: inline-block;
      width: 80px;
      height: 34px;
    }
    
    .switch input {
      display: none;
    }
    
    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: brown;
      -webkit-transition: .4s;
      transition: .4s;
    }
    
    .slider:before {
      position: absolute;
      content: "";
      height: 26px;
      width: 26px;
      left: 4px;
      bottom: 4px;
      background-color: white;
      -webkit-transition: .4s;
      transition: .4s;
    }
    
    input:checked+.slider {
      background-color: burlywood;
    }
    
    input:focus+.slider {
      box-shadow: 0 0 1px #2196F3;
    }
    
    input:checked+.slider:before {
      -webkit-transform: translateX(26px);
      -ms-transform: translateX(26px);
      transform: translateX(45px);
    }
    
    .slider {
      border-radius: 34px;
    }
    
    .slider:before {
      border-radius: 50%;
    }
    
    .on {
      display: none;
    }
    
    .on,
    .off {
      color: white;
      position: absolute;
      transform: translate(-50%, -50%);
      top: 50%;
      left: 50%;
      font-size: 10px;
      font-family: Verdana, sans-serif;
    }
    
    input:checked+.slider .on {
      display: block;
    }
    
    input:checked+.slider .off {
      display: none;
    }
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Whisper&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer"
    />
    
    <label class="switch">       
      <input type="checkbox" id="togBtn">       
      <div class="slider round">         
        <span class="on">FR</span>         
        <span class="off">EN</span>       
      </div>     
    </label>
    <ul class="nav-items">
      <div class="content">
        <h2 class="translate" data-tkey="title">welcome!</h2>
        <p class="translate" data-tkey="para-01">My work is primarily inspired by nature.</p>
        <p class="translate" data-tkey="para-02">Each creation is unique.</p>
        <p class="translate" data-tkey="para-03">The white porcelain I use</p>
        <p class="translate" data-tkey="para-04">I studied and graduated </p>
        <p class="translate" data-tkey="para-05">I wish to thank</p>
      </div>
    </ul>