isLocale.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import assertString from './util/assertString';
  2. /*
  3. = 3ALPHA ; selected ISO 639 codes
  4. *2("-" 3ALPHA) ; permanently reserved
  5. */
  6. var extlang = '([A-Za-z]{3}(-[A-Za-z]{3}){0,2})';
  7. /*
  8. = 2*3ALPHA ; shortest ISO 639 code
  9. ["-" extlang] ; sometimes followed by
  10. ; extended language subtags
  11. / 4ALPHA ; or reserved for future use
  12. / 5*8ALPHA ; or registered language subtag
  13. */
  14. var language = "(([a-zA-Z]{2,3}(-".concat(extlang, ")?)|([a-zA-Z]{5,8}))");
  15. /*
  16. = 4ALPHA ; ISO 15924 code
  17. */
  18. var script = '([A-Za-z]{4})';
  19. /*
  20. = 2ALPHA ; ISO 3166-1 code
  21. / 3DIGIT ; UN M.49 code
  22. */
  23. var region = '([A-Za-z]{2}|\\d{3})';
  24. /*
  25. = 5*8alphanum ; registered variants
  26. / (DIGIT 3alphanum)
  27. */
  28. var variant = '([A-Za-z0-9]{5,8}|(\\d[A-Z-a-z0-9]{3}))';
  29. /*
  30. = DIGIT ; 0 - 9
  31. / %x41-57 ; A - W
  32. / %x59-5A ; Y - Z
  33. / %x61-77 ; a - w
  34. / %x79-7A ; y - z
  35. */
  36. var singleton = '(\\d|[A-W]|[Y-Z]|[a-w]|[y-z])';
  37. /*
  38. = singleton 1*("-" (2*8alphanum))
  39. ; Single alphanumerics
  40. ; "x" reserved for private use
  41. */
  42. var extension = "(".concat(singleton, "(-[A-Za-z0-9]{2,8})+)");
  43. /*
  44. = "x" 1*("-" (1*8alphanum))
  45. */
  46. var privateuse = '(x(-[A-Za-z0-9]{1,8})+)'; // irregular tags do not match the 'langtag' production and would not
  47. // otherwise be considered 'well-formed'. These tags are all valid, but
  48. // most are deprecated in favor of more modern subtags or subtag combination
  49. var irregular = '((en-GB-oed)|(i-ami)|(i-bnn)|(i-default)|(i-enochian)|' + '(i-hak)|(i-klingon)|(i-lux)|(i-mingo)|(i-navajo)|(i-pwn)|(i-tao)|' + '(i-tay)|(i-tsu)|(sgn-BE-FR)|(sgn-BE-NL)|(sgn-CH-DE))'; // regular tags match the 'langtag' production, but their subtags are not
  50. // extended language or variant subtags: their meaning is defined by
  51. // their registration and all of these are deprecated in favor of a more
  52. // modern subtag or sequence of subtags
  53. var regular = '((art-lojban)|(cel-gaulish)|(no-bok)|(no-nyn)|(zh-guoyu)|' + '(zh-hakka)|(zh-min)|(zh-min-nan)|(zh-xiang))';
  54. /*
  55. = irregular ; non-redundant tags registered
  56. / regular ; during the RFC 3066 era
  57. */
  58. var grandfathered = "(".concat(irregular, "|").concat(regular, ")");
  59. /*
  60. RFC 5646 defines delimitation of subtags via a hyphen:
  61. "Subtag" refers to a specific section of a tag, delimited by a
  62. hyphen, such as the subtags 'zh', 'Hant', and 'CN' in the tag "zh-
  63. Hant-CN". Examples of subtags in this document are enclosed in
  64. single quotes ('Hant')
  65. However, we need to add "_" to maintain the existing behaviour.
  66. */
  67. var delimiter = '(-|_)';
  68. /*
  69. = language
  70. ["-" script]
  71. ["-" region]
  72. *("-" variant)
  73. *("-" extension)
  74. ["-" privateuse]
  75. */
  76. var langtag = "".concat(language, "(").concat(delimiter).concat(script, ")?(").concat(delimiter).concat(region, ")?(").concat(delimiter).concat(variant, ")*(").concat(delimiter).concat(extension, ")*(").concat(delimiter).concat(privateuse, ")?");
  77. /*
  78. Regex implementation based on BCP RFC 5646
  79. Tags for Identifying Languages
  80. https://www.rfc-editor.org/rfc/rfc5646.html
  81. */
  82. var languageTagRegex = new RegExp("(^".concat(privateuse, "$)|(^").concat(grandfathered, "$)|(^").concat(langtag, "$)"));
  83. export default function isLocale(str) {
  84. assertString(str);
  85. return languageTagRegex.test(str);
  86. }