Is there any method for me to create translations of pages with Javascript or Typescript?

Asked

Viewed 950 times

0

I wonder if there is any method for me to create my own translations of static pages with Javascript.

  • 1

    Want to implement your own translations or want something to do yourself?

  • Make my own translations. No use of automatic tools... Like Google Transfer...

  • 1

    No, there is nothing "purely" with JS or Typescript. Just using libs for this. I edited the answer to make more sense and avoid confusion, the effort of my answer that took a -1, was within what the question seemed to cover, unfortunately the question did not specify anything and so the answer was not in the wrong logic, but instead of returning the downvote I edited your question, because the purpose is to help.

  • just need to create a callback with the parameters that will be changed, and a changeon to change the language

  • @Hudsonph Is there any practical example?

  • there are several examples that combined can make your solution, but it is necessary to have a very broad knowledge of js...

Show 1 more comment

2 answers

3


See, just create one object containing the string.

let TRANSLATIONS = {
  'en': {
    'Homepage': 'Homepage',
    ...
  },
  'pt-br': {
    'Homepage': 'Pagina inicial',
    ...
  }
}

For the elements, define a dataset as data-lang-str example:

<a class="nav-link" href="#" data-lang-str="Features"></a>
...

For language selection elements, set a dataset as data-lang, example:

<button class="btn btn-primary" name="btn-translate" data-lang="pt-br">Português</button>
<button class="btn btn-dark" name="btn-translate" data-lang="en">Inglês</button>
...

Method to translate:

const translate = (lang = null) => {
  if (lang === null) {
    lang = DEFAULT_LANG;
  }
  let DEFAULT_LANG_LENGTH = Object.keys(TRANSLATIONS[DEFAULT_LANG]).length;
  // Verifica se o idioma selecionado existe.
  if (TRANSLATIONS[lang]) {
    // Existe... Agora verifica se a tradução selecionada está completa
    // Se não estiver exibe a mensagem.
    ALERT_TRANSLATION_UNAVAILABLE.style.display = 'none';
    let LANG_LENGTH = Object.keys(TRANSLATIONS[lang]).length;
    if (LANG_LENGTH < DEFAULT_LANG_LENGTH) {
      ALERT_TRANSLATION_INCOMPLETE.style.display = 'block';
    } else {
      ALERT_TRANSLATION_INCOMPLETE.style.display = 'none';
    }
    DATA_LANG_ELEMENTS.forEach((el) => {
      let STR = el.getAttribute('data-lang-str');
      if (TRANSLATIONS[lang][STR]) {
        el.innerText = (TRANSLATIONS[lang][STR]);
      }
    });
  } else {
    // Não existe, então exibe a mensagem
    ALERT_TRANSLATION_INCOMPLETE.style.display = 'none';
    ALERT_TRANSLATION_UNAVAILABLE.style.display = 'block';
  }
}

Working example

let DEFAULT_LANG = 'en';
let ALERT_TRANSLATION_INCOMPLETE = document.querySelector('#translatoin-incomplete');
let ALERT_TRANSLATION_UNAVAILABLE = document.querySelector('#translatoin-unavailable');
let DATA_LANG_ELEMENTS = document.querySelectorAll('[data-lang-str]');
let TRANSLATIONS = {
  'en': {
    'Homepage': 'Homepage',
    'Features': 'Features',
    'Pricing': 'Pricing',
    'Disabled': 'Disabled',
    'Email': 'Email',
    'Password': 'Password',
    'Address': 'Address',
    'City': 'City',
    'State': 'State',
    'Zip': 'Zip',
    'SendMeNewsletters': 'Send me newsletters'
  },
  'pt-br': {
    'Homepage': 'Pagina inicial',
    'Features': 'Características',
    'Pricing': 'Preços',
    'Disabled': 'Desativado',
    'Email': 'Email',
    'Password': 'Senha',
    'Address': 'Endereço',
    'City': 'Cidade',
    'State': 'Estado',
    'Zip': 'CEP',
    'SendMeNewsletters': 'Envie-me boletins informativos'
  },
  'es': {
    'Homepage': 'Página principal',
    'Features': 'Caracteristicas',
    'Pricing': 'Precio',
    'Disabled': 'Discapacitado',
    'Email': 'Email',
    'Password': 'Contraseña',
    'Address': 'Dirección'
  },
  'ru': {
    'Homepage': 'домашняя страница',
    'Features': 'Особенности',
    'Pricing': 'ценообразование',
    'Disabled': 'Отключено',
    'Email': 'Адрес электронной почты',
    'Password': 'пароль',
    'Address': 'Адрес'
  },
  'ja': {
    'Homepage': 'ホームページ',
    'Features': '特徴',
    'Pricing': '価格設定',
    'Disabled': '無効',
    'Password': 'Password',
    'Address': 'Address'
  }
};


const translate = (lang = null) => {
  if (lang === null) {
    lang = DEFAULT_LANG;
  }
  let DEFAULT_LANG_LENGTH = Object.keys(TRANSLATIONS[DEFAULT_LANG]).length;
  // Verifica se o idioma selecionado existe.
  if (TRANSLATIONS[lang]) {
    // Existe... Agora verifica se a tradução selecionada está completa
    // Se não estiver exibe a mensagem.
    ALERT_TRANSLATION_UNAVAILABLE.style.display = 'none';
    let LANG_LENGTH = Object.keys(TRANSLATIONS[lang]).length;
    if (LANG_LENGTH < DEFAULT_LANG_LENGTH) {
      ALERT_TRANSLATION_INCOMPLETE.style.display = 'block';
    } else {
      ALERT_TRANSLATION_INCOMPLETE.style.display = 'none';
    }
    DATA_LANG_ELEMENTS.forEach((el) => {
      let STR = el.getAttribute('data-lang-str');
      if (TRANSLATIONS[lang][STR]) {
        el.innerText = (TRANSLATIONS[lang][STR]);
      }
    });
  } else {
    // Não existe, então exibe a mensagem
    ALERT_TRANSLATION_INCOMPLETE.style.display = 'none';
    ALERT_TRANSLATION_UNAVAILABLE.style.display = 'block';
  }
}

let BTNS_TRANSLATE = document.querySelectorAll('[name=btn-translate]');
BTNS_TRANSLATE.forEach((btn) => {
  btn.addEventListener('click', (ev) => {
    translate(btn.getAttribute('data-lang'));
  });
});

translate();
* {
  border-radius: 0px !important;
}
body {
  margin-top: 60px !important;
}
.btn {
  cursor: pointer;
  margin-bottom: 14px;
  text-transform: uppercase;
}
#idioma-indisponivel,
#traducao-incompleta {
  display: none;
}
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">

<nav class="navbar navbar-expand-md navbar-light bg-light fixed-top">
  <div class="container">
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav">
        <li class="nav-item active">
          <a class="nav-link" href="#" data-lang-str="Homepage"></a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#" data-lang-str="Features"></a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#" data-lang-str="Pricing"></a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled" href="#" data-lang-str="Disabled">Disabled</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

<div class="container">
  <div class="row">
    <div class="col-md-12">
      <div class="alert alert-info" role="alert" id="translatoin-incomplete">
        Incomplete translation
      </div>
      <div class="alert alert-danger" role="alert" id="translatoin-unavailable">
        Language unavailable
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-md-12">
      <button class="btn btn-primary" name="btn-translate" data-lang="pt-br">Português</button>
      <button class="btn btn-dark" name="btn-translate" data-lang="en">Inglês</button>
      <button class="btn btn-danger" name="btn-translate" data-lang="es">Espanhol</button>
      <button class="btn btn-info" name="btn-translate" data-lang="ru">Russo</button>
      <button class="btn btn-success" name="btn-translate" data-lang="ja">Japonês</button>
      <button class="btn btn-secondary" name="btn-translate" data-lang="ko">Coreano</button>
    </div>
  </div>
</div>

<div class="container">
    <form>
      <div class="form-row">
        <div class="form-group col-md-6">
          <label for="inputEmail4" class="col-form-label" data-lang-str="Email"></label>
          <input type="email" class="form-control" id="inputEmail4">
        </div>
        <div class="form-group col-md-6">
          <label for="inputPassword4" class="col-form-label" data-lang-str="Password"></label>
          <input type="password" class="form-control" id="inputPassword4">
        </div>
      </div>
      <div class="form-group">
        <label for="inputAddress" class="col-form-label" data-lang-str="Address"></label>
        <input type="text" class="form-control" id="inputAddress">
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          <label for="inputCity" class="col-form-label" data-lang-str="City"></label>
          <input type="text" class="form-control" id="inputCity">
        </div>
        <div class="form-group col-md-4">
          <label for="inputState" class="col-form-label" data-lang-str="State"></label>
          <select id="inputState" class="form-control">Choose</select>
        </div>
        <div class="form-group col-md-2">
          <label for="inputZip" class="col-form-label" data-lang-str="Zip"></label>
          <input type="text" class="form-control" id="inputZip">
        </div>
      </div>
      <div class="form-group">
        <div class="form-check">
          <label class="form-check-label">
            <input class="form-check-input" type="checkbox"> <span data-lang-str="SendMeNewsletters"></span>
          </label>
        </div>
      </div>
      <button type="submit" class="btn btn-primary">Sign in</button>
    </form>
</div>

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>

  • Man...Too perfect...I believe it will solve my problem! I could understand... now... it’s time for the community to develop a framework to meet this need!

0

If you want something automatic you can use the Google Translator, example:

<!DOCTYPE html>
<html>
<head>

</head>
<body>
    <div id="google_translate_element"></div>

    <p>Olá, mundo!</p>

    <!-- O Javascript deve vir depois -->
    <script type="text/javascript">
    //Disparado como callback para ?cb=googleTranslateElementInit
    function googleTranslateElementInit()
    {
        new google.translate.TranslateElement({
            pageLanguage: 'pt', //Idioma principal da página
            includedLanguages: 'en,es', //Idiomas que pode traduzir
            layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL
        }, 'google_translate_element'); //google_translate_element é o elemento no div
    }
    </script>

    <!-- Adiciona o script do tradutor -->
    <script type="text/javascript" src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
</body>
</html>

Example in jsfiddle


Customizing the Google translator

With CSS it is possible to change some things and to remove that top menu you can use this:

#google_translate_element {
    display: none;
}
.goog-te-banner-frame {
    display: none !important;
}
body {
    position: static !important;
    top: 0 !important;
}

For more customizations see this: /a/82760/3635

Browser other questions tagged

You are not signed in. Login or sign up in order to post.