2
0

locale-utils.ts 2.0 KB

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