0

The original and ugly code:

const lang = navigator.language || navigator.userLanguage;

if (lang.indexOf("de") == 0)
{
  window.location.href = 'https://gusbemacbe.github.io/suru-plus-folders/de/';
}

# ...

else if (lang.indexOf("es") == 0) 
{
  window.location.href = 'https://gusbemacbe.github.io/suru-plus-folders/es/';
}

else 
{
  window.location.href = 'https://gusbemacbe.github.io/suru-plus-folders/en/';
}

I simplified into an elegant condition-based operation:

const lang = navigator.language || navigator.userLanguage;
const url = 'https://gusbemacbe.github.io/suru-plus-folders/'

function detection(lang) 
{
  let languages =
  {
    'de': () => window.location.href = url+'de',
    'es': () => window.location.href = url+'es',
    'fr': () => window.location.href = url+'fr',
    'it': () => window.location.href = url+'it',
    'nl': () => window.location.href = url+'nl',
    'pt-BR': () => window.location.href = url+'pt-br',
    'pt-PT': () => window.location.href = url+'pt-pt'
  }

  return languages(lang);
}

detection(lang);

The problem is else, that is for needing to trigger to English if there is not another language into which I didn't translate the website. I checked that I could return languages(lang) ? 'en': () => window.location.href = url+'en', but I am not sure that it is right. I also thought of adding en': () => window.location.href = url+'en' to let languages, but it needs to be an "else".

Oo'-
  • 203
  • 6
  • 22
  • Pretty sure it should be `languages[lang]()`? (Otherwise your code won't work even without considering the else) – SuperStormer Apr 03 '21 at 19:36
  • Ah, yes, is `languages[lang]()` already an "`else`"? – Oo'- Apr 03 '21 at 19:37
  • 2
    Does this answer your question? [How to get value from Object, with default value](https://stackoverflow.com/questions/9003999/how-to-get-value-from-object-with-default-value). Something like `return (languages[lang] || languages["en"])()`, assuming you add "en" to the object. – SuperStormer Apr 03 '21 at 19:37
  • Do you mean `const lang = navigator.language || navigator.userLanguage || 'en': () => window.location.href = url+'en'`? – Oo'- Apr 03 '21 at 19:40
  • Lang code seems to be the same than URLs. Factorize in an array? `url + ([ 'de', 'es', 'fr', 'it', 'nl', 'pt-BR', 'pt-PT' ].includes(lang) ? lang : 'en')` – Cid Apr 03 '21 at 19:42
  • @Cid, observe `pt-BR` and `pt-PT` will trigger `pt-br` and `pt-pt`, the window and page regional language codes have different cases (upper and lower). – Oo'- Apr 03 '21 at 19:46
  • @GustavoReis `.toLowerCase()`? – Cid Apr 03 '21 at 19:50

3 Answers3

4

Just de, fr etc in the list is not enough, because navigator.language can, and in most cases, will return a full locale code like de-DE, fr-FR etc. Therefore, you have to check both the full code and then the language id.

You can have a list of supported languages/locales and write a small function like this:

const supportedLanguages = new Set([
    'en',
    'de',
    'es',
    'fr',
    'it',
    'nl',
    'pt-br',
    'pt-pt',
]);

function getLanguage() {
    let lang = (navigator.language || navigator.userLanguage).toLowerCase();

    // full locale matches?
    if (supportedLanguages.has(lang))
        return lang;
    
    // language matches?
    lang = lang.split('-')[0];
    if (supportedLanguages.has(lang))
        return lang;

    // no match, return the default
    return 'en';
}

The rest is easy:

const url = '...'
window.location.href = url + getLanguage()
georg
  • 211,518
  • 52
  • 313
  • 390
2

Don't Repeat Yourself.

This has a name in programmation: it's the DRY principle. So let's repeat ourselves a bit less here. Click Run code snippet to test the function by yourself.

function detectLang(lang) {

  // Let's lowerCase that string to normalize it, so we can compare it with others
  lang = lang.toLowerCase()
  const firstHalf = lang.split('-')[0]

  // A new supported language ? Just add it here.
  const supportedLanguages = ['en', 'de', 'es', 'fr', 'it', 'nl', 'pt-br', 'pt-pt']

  // If supportedLanguages contains your language, select it
  const finalLang = supportedLanguages.includes(lang) ? lang
    // Else, check just for the first half
    : supportedLanguages.includes(firstHalf) ? firstHalf
    // Otherwise, fallback to English
    : 'en'

  // Set the URL (uncomment that, that's for the snippet)
  // window.location.href = url + finalLang

  // Return the final lang
  return finalLang
}

console.log("en =>", detectLang("en"))
console.log("fr =>", detectLang("fr"))
console.log("de-DE =>", detectLang("de-DE"))
console.log("pt-PT =>", detectLang("pt-PT"))
console.log("sw =>", detectLang("sw"))

This tricky thing, a ? b : c, is a ternary conditional operator, which is basically a one-liner for if / else. If supportedLanguages has lang, it'll execute the corresponding value. If not, it'll try with the first half, or set the language to English. The input is normalized so that the capitalized letters are ignored.

deb
  • 6,671
  • 2
  • 11
  • 27
  • There is a small problem. I set Germany German as the default language in the browser. The browser detected `de-DE` and triggered to `/en/` instead of `/de/`. Check @georg's comment. – Oo'- Apr 03 '21 at 20:41
  • You're right! Here you go, fixed. – deb Apr 03 '21 at 20:50
1

Try not to repete the code, check out this example..

 let lng = {'de':'de',
    'es':'es',
    'fr':'fr',
    'it':'it',
    'nl':'nl',
    'pt-BR':'pt-br'}

function lang(prop){
 let lang = lng.hasOwnProperty(prop) ? lng[prop] : lng['default'];
  console.log(lang)
  window.location.href = url + lang
}
 
lang('es');
Stefan Avramovic
  • 1,365
  • 2
  • 11
  • 20