locale-utils.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import type { IncomingHttpHeaders } from 'http';
  2. import { Lang } from '@growi/core/dist/interfaces';
  3. import * as i18nextConfig from '^/config/i18next.config';
  4. const ACCEPT_LANG_MAP = {
  5. en: Lang.en_US,
  6. ja: Lang.ja_JP,
  7. zh: Lang.zh_CN,
  8. fr: Lang.fr_FR,
  9. };
  10. /**
  11. * It return the first language that matches ACCEPT_LANG_MAP keys from sorted accept languages array
  12. * @param sortedAcceptLanguagesArray
  13. */
  14. const getPreferredLanguage = (sortedAcceptLanguagesArray: string[]): Lang => {
  15. for (const lang of sortedAcceptLanguagesArray) {
  16. const matchingLang = Object.keys(ACCEPT_LANG_MAP).find(key => lang.includes(key));
  17. if (matchingLang) return ACCEPT_LANG_MAP[matchingLang];
  18. }
  19. return i18nextConfig.defaultLang;
  20. };
  21. /**
  22. * Detect locale from browser accept language
  23. * @param headers
  24. */
  25. export const detectLocaleFromBrowserAcceptLanguage = (headers: IncomingHttpHeaders): Lang => {
  26. // 1. get the header accept-language
  27. // ex. "ja,ar-SA;q=0.8,en;q=0.6,en-CA;q=0.4,en-US;q=0.2"
  28. const acceptLanguages = headers['accept-language'];
  29. if (acceptLanguages == null) {
  30. return i18nextConfig.defaultLang;
  31. }
  32. // 1. trim blank spaces.
  33. // 2. separate by ,.
  34. // 3. if "lang;q=x", then { 'x', 'lang' } to add to the associative array.
  35. // if "lang" has no weight x (";q=x"), add it with key = 1.
  36. // ex. {'1': 'ja','0.8': 'ar-SA','0.6': 'en','0.4': 'en-CA','0.2': 'en-US'}
  37. const acceptLanguagesDict = acceptLanguages
  38. .replace(/\s+/g, '')
  39. .split(',')
  40. .map(item => item.split(/\s*;\s*q\s*=\s*/))
  41. .reduce((acc, [key, value = '1']) => {
  42. acc[value] = key;
  43. return acc;
  44. }, {});
  45. // 1. create an array of sorted languages in descending order.
  46. // ex. [ 'ja', 'ar-SA', 'en', 'en-CA', 'en-US' ]
  47. const sortedAcceptLanguagesArray = Object.keys(acceptLanguagesDict)
  48. .sort((x, y) => y.localeCompare(x))
  49. .map(item => acceptLanguagesDict[item]);
  50. return getPreferredLanguage(sortedAcceptLanguagesArray);
  51. };