locale-utils.ts 2.2 KB

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