Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoload locale from browser language #732

Open
mjau-mjau opened this issue Nov 14, 2019 · 3 comments
Open

Autoload locale from browser language #732

mjau-mjau opened this issue Nov 14, 2019 · 3 comments

Comments

@mjau-mjau
Copy link

mjau-mjau commented Nov 14, 2019

Hi. I'm looking into a solution to automatically load and set default locale based on the browsers language. I already did some searching, but could not find any existing info on the topic. Surely this is a useful feature that others have done before?

I know I can get browser language from JS navigator.language or $_SERVER['HTTP_ACCEPT_LANGUAGE'] from PHP (which might be more reliable). However, the challenge is to map the browser language with dayjs supported locales naming, because they do not all match automagically. Anyone have any experience with this?

For example, my browser is norwegian and outputs no (norwegian), although it is named nb (norsk bokmål) in dayjs for the default variation. Furthermore, some languages have several variations fr fr-be fr-ca fr-lu, whereas dayjs supports only some of them (which makes sense) ... If I detect fr-ch (French swiss) from browser, I would first need to check if there is a unique dayjs locale, and if not, I would chop it down to fr and see if that exists. Seems I may need to add all locales to an array and do some mapping.

@iamkun
Copy link
Owner

iamkun commented Nov 14, 2019

1 We use ISO_639-2 country code. #171
2 A custom locale helper would be helped. #682

@mjau-mjau
Copy link
Author

mjau-mjau commented Nov 15, 2019

I whipped up some code that automatically loads and sets locale based on visitors browser language. Below is the unedited code, just for reference.

  • Uses navigator.languages to detect browser language(s) in order of language array.
  • Checks for sub language xx-XX with fallback to primary language xx. For example, fr-ch (French Swiss) will load, while fr-be (French Belgian, does not exist) will fallback to fr.
  • A few fixes to catch and convert no (Norwegian) and zn (Chinese).
  • Does not load if lang resolves to en or en-us.
  • Stores resolved language in localStorage.
(function() {

	// load locale
	var nav_langs = navigator.languages || (navigator.language ? [navigator.language] : false);
	if(!nav_langs || !nav_langs.length) return;

	// load locale
	function load_locale(locale){
		if(!locale) return;
		_f.load_plugin('dayjs_locale', function(){
			dayjs.locale(locale);
		}, {
			src: ['dayjs@1.8.17/locale/' + locale + '.js']
		});
		local_storage('files:options:dayjs_locale', locale);
		return true;
	}

	// localStorage
	if(load_locale(local_storage('files:options:dayjs_locale'))) return;

	// dayjs locales
	var dayjs_locales = ['af','ar','ar-dz','ar-kw','ar-ly','ar-ma','ar-sa','ar-tn','az','be','bg','bm','bn','bo','br','bs','ca','cs','cv','cy','da','de','de-at','de-ch','dv','el','en','en-au','en-ca','en-gb','en-ie','en-il','en-nz','en-SG','eo','es','es-do','es-us','et','eu','fa','fi','fo','fr','fr-ca','fr-ch','fy','ga','gd','gl','gom-latn','gu','he','hi','hr','hu','hy-am','id','is','it','it-ch','ja','jv','ka','kk','km','kn','ko','ku','ky','lb','lo','lt','lv','me','mi','mk','ml','mn','mr','ms','ms-my','mt','my','nb','ne','nl','nl-be','nn','oc-lnc','pa-in','pl','pt','pt-br','ro','ru','sd','se','si','sk','sl','sq','sr','sr-cyrl','ss','sv','sw','ta','te','tet','tg','th','tl-ph','tlh','tr','tzl','tzm','tzm-latn','ug-cn','uk','ur','uz','uz-latn','vi','x-pseudo','yo','zh-cn','zh-hk','zh-tw'];

	// check locale
	function check_locale(locale){
		if(['en', 'en-us'].includes(locale)) return true;
		if(locale === 'zn') return load_locale('zh-cn');
		if(locale === 'no') return load_locale('nb');
		if(dayjs_locales.includes(locale)) return load_locale(locale);
	}

	// loop nav_langs array
	nav_langs.some(function(lang){
		lang = lang.toLowerCase();
		return check_locale(lang) || (lang.includes('-') && check_locale(lang.split('-')[0]));
	});
})();

@kd496
Copy link

kd496 commented Apr 25, 2023

1 We use ISO_639-2 country code. #171 2 A custom locale helper would be helped. #682

Correct me if I'm wrong but from what I see Dayjs uses <language_tag>-<country_code> format. ISO 639-2 is only used whenever the first format cannot be established.

Here's what I got:

const dayjs = require("dayjs");
const locales = require("dayjs/locale");

const dayjsLocales = locales.map((l) => l.key);

const mapper = new Map([
  ["en-us", "en"],
  ["no", "nb"],
]);

const fix = (l: string): string => (mapper.has(l) ? mapper.get(l)! : l);

const contains = (l: string): Boolean => dayjsLocales.includes(l);

async function load(locale: string) {
  if (locale === "en") return;

  await import(`dayjs/locale/${locale}` + ".js");
  dayjs.locale(locale);
}

function main() {
  const myLocales = navigator.languages;

  myLocales.some((locale) => {
    locale = locale.toLowerCase();
    locale = fix(locale);

    if (contains(locale)) {
      load(locale);
      return true;
    } else {
      const [langTag, countryCode] = locale.split("-");

      if (contains(langTag)) {
        const l = fix(langTag);
        load(l);
        return true;
      }
    }

    return false;
  });
}

main();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants