locale-utils.ts 2.1 KB

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