globalize.currency.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*!
  2. * Globalize v1.0.0
  3. *
  4. * http://github.com/jquery/globalize
  5. *
  6. * Copyright jQuery Foundation and other contributors
  7. * Released under the MIT license
  8. * http://jquery.org/license
  9. *
  10. * Date: 2015-04-23T12:02Z
  11. */
  12. (function( root, factory ) {
  13. // UMD returnExports
  14. if ( typeof define === "function" && define.amd ) {
  15. // AMD
  16. define([
  17. "cldr",
  18. "../globalize",
  19. "./number",
  20. "cldr/event",
  21. "cldr/supplemental"
  22. ], factory );
  23. } else if ( typeof exports === "object" ) {
  24. // Node, CommonJS
  25. module.exports = factory( require( "cldrjs" ), require( "globalize" ) );
  26. } else {
  27. // Global
  28. factory( root.Cldr, root.Globalize );
  29. }
  30. }(this, function( Cldr, Globalize ) {
  31. var alwaysArray = Globalize._alwaysArray,
  32. formatMessage = Globalize._formatMessage,
  33. numberNumberingSystem = Globalize._numberNumberingSystem,
  34. numberPattern = Globalize._numberPattern,
  35. stringPad = Globalize._stringPad,
  36. validate = Globalize._validate,
  37. validateCldr = Globalize._validateCldr,
  38. validateDefaultLocale = Globalize._validateDefaultLocale,
  39. validateParameterPresence = Globalize._validateParameterPresence,
  40. validateParameterType = Globalize._validateParameterType,
  41. validateParameterTypeNumber = Globalize._validateParameterTypeNumber,
  42. validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
  43. var validateParameterTypeCurrency = function( value, name ) {
  44. validateParameterType(
  45. value,
  46. name,
  47. value === undefined || typeof value === "string" && ( /^[A-Za-z]{3}$/ ).test( value ),
  48. "3-letter currency code string as defined by ISO 4217"
  49. );
  50. };
  51. var validatePluralModulePresence = function() {
  52. validate( "E_MISSING_PLURAL_MODULE", "Plural module not loaded.",
  53. Globalize.plural !== undefined, {} );
  54. };
  55. /**
  56. * supplementalOverride( currency, pattern, cldr )
  57. *
  58. * Return pattern with fraction digits overriden by supplemental currency data.
  59. */
  60. var currencySupplementalOverride = function( currency, pattern, cldr ) {
  61. var digits,
  62. fraction = cldr.supplemental([ "currencyData/fractions", currency ]) ||
  63. cldr.supplemental( "currencyData/fractions/DEFAULT" );
  64. digits = +fraction._digits;
  65. if ( digits ) {
  66. fraction = "." + stringPad( "0", digits ).slice( 0, -1 ) + fraction._rounding;
  67. } else {
  68. fraction = "";
  69. }
  70. return pattern.replace( /\.(#+|0*[0-9]|0+[0-9]?)/g, fraction );
  71. };
  72. var objectFilter = function( object, testRe ) {
  73. var key,
  74. copy = {};
  75. for ( key in object ) {
  76. if ( testRe.test( key ) ) {
  77. copy[ key ] = object[ key ];
  78. }
  79. }
  80. return copy;
  81. };
  82. var currencyUnitPatterns = function( cldr ) {
  83. return objectFilter( cldr.main([
  84. "numbers",
  85. "currencyFormats-numberSystem-" + numberNumberingSystem( cldr )
  86. ]), /^unitPattern/ );
  87. };
  88. /**
  89. * codeProperties( currency, cldr )
  90. *
  91. * Return number pattern with the appropriate currency code in as literal.
  92. */
  93. var currencyCodeProperties = function( currency, cldr ) {
  94. var pattern = numberPattern( "decimal", cldr );
  95. // The number of decimal places and the rounding for each currency is not locale-specific. Those
  96. // values overridden by Supplemental Currency Data.
  97. pattern = currencySupplementalOverride( currency, pattern, cldr );
  98. return {
  99. currency: currency,
  100. pattern: pattern,
  101. unitPatterns: currencyUnitPatterns( cldr )
  102. };
  103. };
  104. /**
  105. * nameFormat( formattedNumber, pluralForm, properties )
  106. *
  107. * Return the appropriate name form currency format.
  108. */
  109. var currencyNameFormat = function( formattedNumber, pluralForm, properties ) {
  110. var displayName, unitPattern,
  111. displayNames = properties.displayNames || {},
  112. unitPatterns = properties.unitPatterns;
  113. displayName = displayNames[ "displayName-count-" + pluralForm ] ||
  114. displayNames[ "displayName-count-other" ] ||
  115. displayNames.displayName ||
  116. properties.currency;
  117. unitPattern = unitPatterns[ "unitPattern-count-" + pluralForm ] ||
  118. unitPatterns[ "unitPattern-count-other" ];
  119. return formatMessage( unitPattern, [ formattedNumber, displayName ]);
  120. };
  121. /**
  122. * nameProperties( currency, cldr )
  123. *
  124. * Return number pattern with the appropriate currency code in as literal.
  125. */
  126. var currencyNameProperties = function( currency, cldr ) {
  127. var properties = currencyCodeProperties( currency, cldr );
  128. properties.displayNames = objectFilter( cldr.main([
  129. "numbers/currencies",
  130. currency
  131. ]), /^displayName/ );
  132. return properties;
  133. };
  134. /**
  135. * Unicode regular expression for: everything except math symbols, currency signs, dingbats, and
  136. * box-drawing characters.
  137. *
  138. * Generated by:
  139. *
  140. * regenerate()
  141. * .addRange( 0x0, 0x10FFFF )
  142. * .remove( require( "unicode-7.0.0/categories/S/symbols" ) ).toString();
  143. *
  144. * https://github.com/mathiasbynens/regenerate
  145. * https://github.com/mathiasbynens/unicode-7.0.0
  146. */
  147. var regexpNotS = /[\0-#%-\*,-;\?-\]_a-\{\}\x7F-\xA1\xA7\xAA\xAB\xAD\xB2\xB3\xB5-\xB7\xB9-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376-\u0383\u0386-\u03F5\u03F7-\u0481\u0483-\u058C\u0590-\u0605\u0609\u060A\u060C\u060D\u0610-\u06DD\u06DF-\u06E8\u06EA-\u06FC\u06FF-\u07F5\u07F7-\u09F1\u09F4-\u09F9\u09FC-\u0AF0\u0AF2-\u0B6F\u0B71-\u0BF2\u0BFB-\u0C7E\u0C80-\u0D78\u0D7A-\u0E3E\u0E40-\u0F00\u0F04-\u0F12\u0F14\u0F18\u0F19\u0F20-\u0F33\u0F35\u0F37\u0F39-\u0FBD\u0FC6\u0FCD\u0FD0-\u0FD4\u0FD9-\u109D\u10A0-\u138F\u139A-\u17DA\u17DC-\u193F\u1941-\u19DD\u1A00-\u1B60\u1B6B-\u1B73\u1B7D-\u1FBC\u1FBE\u1FC2-\u1FCC\u1FD0-\u1FDC\u1FE0-\u1FEC\u1FF0-\u1FFC\u1FFF-\u2043\u2045-\u2051\u2053-\u2079\u207D-\u2089\u208D-\u209F\u20BE-\u20FF\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u218F\u2308-\u230B\u2329\u232A\u23FB-\u23FF\u2427-\u243F\u244B-\u249B\u24EA-\u24FF\u2768-\u2793\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2B74\u2B75\u2B96\u2B97\u2BBA-\u2BBC\u2BC9\u2BD2-\u2CE4\u2CEB-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u3003\u3005-\u3011\u3014-\u301F\u3021-\u3035\u3038-\u303D\u3040-\u309A\u309D-\u318F\u3192-\u3195\u31A0-\u31BF\u31E4-\u31FF\u321F-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u32FF\u3400-\u4DBF\u4E00-\uA48F\uA4C7-\uA6FF\uA717-\uA71F\uA722-\uA788\uA78B-\uA827\uA82C-\uA835\uA83A-\uAA76\uAA7A-\uAB5A\uAB5C-\uD7FF\uDC00-\uFB28\uFB2A-\uFBB1\uFBC2-\uFDFB\uFDFE-\uFE61\uFE63\uFE67\uFE68\uFE6A-\uFF03\uFF05-\uFF0A\uFF0C-\uFF1B\uFF1F-\uFF3D\uFF3F\uFF41-\uFF5B\uFF5D\uFF5F-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]|\uD800[\uDC00-\uDD36\uDD40-\uDD78\uDD8A\uDD8B\uDD8D-\uDD8F\uDD9C-\uDD9F\uDDA1-\uDDCF\uDDFD-\uDFFF]|[\uD801\uD803-\uD819\uD81B-\uD82E\uD830-\uD833\uD836-\uD83A\uD83F-\uDBFF][\uDC00-\uDFFF]|\uD802[\uDC00-\uDC76\uDC79-\uDEC7\uDEC9-\uDFFF]|\uD81A[\uDC00-\uDF3B\uDF40-\uDF44\uDF46-\uDFFF]|\uD82F[\uDC00-\uDC9B\uDC9D-\uDFFF]|\uD834[\uDCF6-\uDCFF\uDD27\uDD28\uDD65-\uDD69\uDD6D-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDDDE-\uDDFF\uDE42-\uDE44\uDE46-\uDEFF\uDF57-\uDFFF]|\uD835[\uDC00-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFFF]|\uD83B[\uDC00-\uDEEF\uDEF2-\uDFFF]|\uD83C[\uDC2C-\uDC2F\uDC94-\uDC9F\uDCAF\uDCB0\uDCC0\uDCD0\uDCF6-\uDD0F\uDD2F\uDD6C-\uDD6F\uDD9B-\uDDE5\uDE03-\uDE0F\uDE3B-\uDE3F\uDE49-\uDE4F\uDE52-\uDEFF\uDF2D-\uDF2F\uDF7E\uDF7F\uDFCF-\uDFD3\uDFF8-\uDFFF]|\uD83D[\uDCFF\uDD4B-\uDD4F\uDD7A\uDDA4\uDE43\uDE44\uDED0-\uDEDF\uDEED-\uDEEF\uDEF4-\uDEFF\uDF74-\uDF7F\uDFD5-\uDFFF]|\uD83E[\uDC0C-\uDC0F\uDC48-\uDC4F\uDC5A-\uDC5F\uDC88-\uDC8F\uDCAE-\uDFFF]|[\uD800-\uDBFF]/;
  148. /**
  149. * symbolProperties( currency, cldr )
  150. *
  151. * Return pattern replacing `¤` with the appropriate currency symbol literal.
  152. */
  153. var currencySymbolProperties = function( currency, cldr, options ) {
  154. var currencySpacing, pattern,
  155. regexp = {
  156. "[:digit:]": /\d/,
  157. "[:^S:]": regexpNotS
  158. },
  159. symbol = cldr.main([
  160. "numbers/currencies",
  161. currency,
  162. "symbol"
  163. ]);
  164. currencySpacing = [ "beforeCurrency", "afterCurrency" ].map(function( position ) {
  165. return cldr.main([
  166. "numbers",
  167. "currencyFormats-numberSystem-" + numberNumberingSystem( cldr ),
  168. "currencySpacing",
  169. position
  170. ]);
  171. });
  172. pattern = cldr.main([
  173. "numbers",
  174. "currencyFormats-numberSystem-" + numberNumberingSystem( cldr ),
  175. options.style === "accounting" ? "accounting" : "standard"
  176. ]);
  177. pattern =
  178. // The number of decimal places and the rounding for each currency is not locale-specific.
  179. // Those values are overridden by Supplemental Currency Data.
  180. currencySupplementalOverride( currency, pattern, cldr )
  181. // Replace "¤" (\u00A4) with the appropriate symbol literal.
  182. .split( ";" ).map(function( pattern ) {
  183. return pattern.split( "\u00A4" ).map(function( part, i ) {
  184. var currencyMatch = regexp[ currencySpacing[ i ].currencyMatch ],
  185. surroundingMatch = regexp[ currencySpacing[ i ].surroundingMatch ],
  186. insertBetween = "";
  187. // For currencyMatch and surroundingMatch definitions, read [1].
  188. // When i === 0, beforeCurrency is being handled. Otherwise, afterCurrency.
  189. // 1: http://www.unicode.org/reports/tr35/tr35-numbers.html#Currencies
  190. currencyMatch = currencyMatch.test( symbol.charAt( i ? symbol.length - 1 : 0 ) );
  191. surroundingMatch = surroundingMatch.test(
  192. part.charAt( i ? 0 : part.length - 1 ).replace( /[#@,.]/g, "0" )
  193. );
  194. if ( currencyMatch && part && surroundingMatch ) {
  195. insertBetween = currencySpacing[ i ].insertBetween;
  196. }
  197. return ( i ? insertBetween : "" ) + part + ( i ? "" : insertBetween );
  198. }).join( "'" + symbol + "'" );
  199. }).join( ";" );
  200. return {
  201. pattern: pattern
  202. };
  203. };
  204. /**
  205. * objectOmit( object, keys )
  206. *
  207. * Return a copy of the object, filtered to omit the blacklisted key or array of keys.
  208. */
  209. var objectOmit = function( object, keys ) {
  210. var key,
  211. copy = {};
  212. keys = alwaysArray( keys );
  213. for ( key in object ) {
  214. if ( keys.indexOf( key ) === -1 ) {
  215. copy[ key ] = object[ key ];
  216. }
  217. }
  218. return copy;
  219. };
  220. function validateRequiredCldr( path, value ) {
  221. validateCldr( path, value, {
  222. skip: [ /supplemental\/currencyData\/fractions\/[A-Za-z]{3}$/ ]
  223. });
  224. }
  225. /**
  226. * .currencyFormatter( currency [, options] )
  227. *
  228. * @currency [String] 3-letter currency code as defined by ISO 4217.
  229. *
  230. * @options [Object]:
  231. * - style: [String] "symbol" (default), "accounting", "code" or "name".
  232. * - see also number/format options.
  233. *
  234. * Return a function that formats a currency according to the given options and default/instance
  235. * locale.
  236. */
  237. Globalize.currencyFormatter =
  238. Globalize.prototype.currencyFormatter = function( currency, options ) {
  239. var cldr, numberFormatter, plural, properties, style;
  240. validateParameterPresence( currency, "currency" );
  241. validateParameterTypeCurrency( currency, "currency" );
  242. validateParameterTypePlainObject( options, "options" );
  243. options = options || {};
  244. style = options.style || "symbol";
  245. cldr = this.cldr;
  246. validateDefaultLocale( cldr );
  247. // Get properties given style ("symbol" default, "code" or "name").
  248. cldr.on( "get", validateRequiredCldr );
  249. properties = ({
  250. accounting: currencySymbolProperties,
  251. code: currencyCodeProperties,
  252. name: currencyNameProperties,
  253. symbol: currencySymbolProperties
  254. }[ style ] )( currency, cldr, options );
  255. cldr.off( "get", validateRequiredCldr );
  256. // options = options minus style, plus raw pattern.
  257. options = objectOmit( options, "style" );
  258. options.raw = properties.pattern;
  259. // Return formatter when style is "symbol" or "accounting".
  260. if ( style === "symbol" || style === "accounting" ) {
  261. return this.numberFormatter( options );
  262. }
  263. // Return formatter when style is "code" or "name".
  264. validatePluralModulePresence();
  265. numberFormatter = this.numberFormatter( options );
  266. plural = this.pluralGenerator();
  267. return function( value ) {
  268. validateParameterPresence( value, "value" );
  269. validateParameterTypeNumber( value, "value" );
  270. return currencyNameFormat( numberFormatter( value ), plural( value ), properties );
  271. };
  272. };
  273. /**
  274. * .currencyParser( currency [, options] )
  275. *
  276. * @currency [String] 3-letter currency code as defined by ISO 4217.
  277. *
  278. * @options [Object] see currencyFormatter.
  279. *
  280. * Return the currency parser according to the given options and the default/instance locale.
  281. */
  282. Globalize.currencyParser =
  283. Globalize.prototype.currencyParser = function( /* currency, options */ ) {
  284. // TODO implement parser.
  285. };
  286. /**
  287. * .formatCurrency( value, currency [, options] )
  288. *
  289. * @value [Number] number to be formatted.
  290. *
  291. * @currency [String] 3-letter currency code as defined by ISO 4217.
  292. *
  293. * @options [Object] see currencyFormatter.
  294. *
  295. * Format a currency according to the given options and the default/instance locale.
  296. */
  297. Globalize.formatCurrency =
  298. Globalize.prototype.formatCurrency = function( value, currency, options ) {
  299. return this.currencyFormatter( currency, options )( value );
  300. };
  301. /**
  302. * .parseCurrency( value, currency [, options] )
  303. *
  304. * @value [String]
  305. *
  306. * @currency [String] 3-letter currency code as defined by ISO 4217.
  307. *
  308. * @options [Object]: See currencyFormatter.
  309. *
  310. * Return the parsed currency or NaN when value is invalid.
  311. */
  312. Globalize.parseCurrency =
  313. Globalize.prototype.parseCurrency = function( /* value, currency, options */ ) {
  314. };
  315. return Globalize;
  316. }));