index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // @flow
  2. 'use strict'
  3. var interpret = require('format-message-interpret')
  4. var parse = require('format-message-parse')
  5. var plurals = require('format-message-interpret/plurals')
  6. var supportedExp = new RegExp(
  7. '^(' + Object.keys(plurals).join('|') + ')\\b'
  8. )
  9. /*::
  10. import type { Types } from 'format-message-interpret'
  11. import type { AST } from 'format-message-parse'
  12. type Options = {
  13. types: Types
  14. }
  15. type Internals = {
  16. ast: AST,
  17. format: (args?: Object) => string,
  18. locale: string,
  19. locales?: string | string[],
  20. toParts?: (args?: Object) => any[],
  21. options?: Options
  22. }
  23. */
  24. var internals/*: WeakMap<Object, Internals> */ = new WeakMap()
  25. /*!
  26. * Intl.MessageFormat prollyfill
  27. * Copyright(c) 2015 Andy VanWagoner
  28. * MIT licensed
  29. **/
  30. function MessageFormat (
  31. pattern/*: string */,
  32. locales/*:: ?: string | string[] */,
  33. options/*:: ?: Options */
  34. ) {
  35. if (!(this instanceof MessageFormat) || internals.has(this)) {
  36. throw new TypeError('calling MessageFormat constructor without new is invalid')
  37. }
  38. var ast = parse(pattern)
  39. internals.set(this, {
  40. ast: ast,
  41. format: interpret(ast, locales, options && options.types),
  42. locale: MessageFormat.supportedLocalesOf(locales)[0] || 'en',
  43. locales: locales,
  44. options: options
  45. })
  46. }
  47. module.exports = MessageFormat
  48. // $FlowFixMe It thinks `value` needs to be defined for format
  49. Object.defineProperties(MessageFormat.prototype, {
  50. format: {
  51. configurable: true,
  52. get: function format () {
  53. var values = internals.get(this)
  54. if (!values) throw new TypeError('MessageFormat.prototype.format called on value that\'s not an object initialized as a MessageFormat')
  55. return values.format
  56. }
  57. },
  58. formatToParts: {
  59. configurable: true,
  60. writable: true,
  61. value: function formatToParts (args/*:: ?: Object */) {
  62. var values = internals.get(this)
  63. if (!values) throw new TypeError('MessageFormat.prototype.formatToParts called on value that\'s not an object initialized as a MessageFormat')
  64. var frmt = values.toParts || (values.toParts = interpret.toParts(
  65. values.ast,
  66. values.locales,
  67. values.options && values.options.types
  68. ))
  69. return frmt(args)
  70. }
  71. },
  72. resolvedOptions: {
  73. configurable: true,
  74. writable: true,
  75. value: function resolvedOptions () {
  76. var values = internals.get(this)
  77. if (!values) throw new TypeError('MessageFormat.prototype.resolvedOptions called on value that\'s not an object initialized as a MessageFormat')
  78. return {
  79. locale: values.locale
  80. }
  81. }
  82. }
  83. })
  84. /* istanbul ignore else */
  85. if (typeof Symbol !== 'undefined') {
  86. Object.defineProperty(MessageFormat.prototype, Symbol.toStringTag, { value: 'Object' })
  87. }
  88. Object.defineProperties(MessageFormat, {
  89. supportedLocalesOf: {
  90. configurable: true,
  91. writable: true,
  92. value: function supportedLocalesOf (requestedLocales/*:: ?: string | string[] */) {
  93. return [].concat(
  94. Intl.NumberFormat.supportedLocalesOf(requestedLocales),
  95. Intl.DateTimeFormat.supportedLocalesOf(requestedLocales),
  96. Intl.PluralRules ? Intl.PluralRules.supportedLocalesOf(requestedLocales) : [],
  97. [].concat(requestedLocales || []).filter(function (locale) {
  98. return supportedExp.test(locale)
  99. })
  100. ).filter(function (v, i, a) { return a.indexOf(v) === i })
  101. }
  102. }
  103. })