locale.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import exponent from "./exponent.js";
  2. import formatGroup from "./formatGroup.js";
  3. import formatNumerals from "./formatNumerals.js";
  4. import formatSpecifier from "./formatSpecifier.js";
  5. import formatTrim from "./formatTrim.js";
  6. import formatTypes from "./formatTypes.js";
  7. import {prefixExponent} from "./formatPrefixAuto.js";
  8. import identity from "./identity.js";
  9. var map = Array.prototype.map,
  10. prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
  11. export default function(locale) {
  12. var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
  13. currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
  14. currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
  15. decimal = locale.decimal === undefined ? "." : locale.decimal + "",
  16. numerals = locale.numerals === undefined ? identity : formatNumerals(map.call(locale.numerals, String)),
  17. percent = locale.percent === undefined ? "%" : locale.percent + "",
  18. minus = locale.minus === undefined ? "−" : locale.minus + "",
  19. nan = locale.nan === undefined ? "NaN" : locale.nan + "";
  20. function newFormat(specifier) {
  21. specifier = formatSpecifier(specifier);
  22. var fill = specifier.fill,
  23. align = specifier.align,
  24. sign = specifier.sign,
  25. symbol = specifier.symbol,
  26. zero = specifier.zero,
  27. width = specifier.width,
  28. comma = specifier.comma,
  29. precision = specifier.precision,
  30. trim = specifier.trim,
  31. type = specifier.type;
  32. // The "n" type is an alias for ",g".
  33. if (type === "n") comma = true, type = "g";
  34. // The "" type, and any invalid type, is an alias for ".12~g".
  35. else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g";
  36. // If zero fill is specified, padding goes after sign and before digits.
  37. if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
  38. // Compute the prefix and suffix.
  39. // For SI-prefix, the suffix is lazily computed.
  40. var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
  41. suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : "";
  42. // What format function should we use?
  43. // Is this an integer type?
  44. // Can this type generate exponential notation?
  45. var formatType = formatTypes[type],
  46. maybeSuffix = /[defgprs%]/.test(type);
  47. // Set the default precision if not specified,
  48. // or clamp the specified precision to the supported range.
  49. // For significant precision, it must be in [1, 21].
  50. // For fixed precision, it must be in [0, 20].
  51. precision = precision === undefined ? 6
  52. : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
  53. : Math.max(0, Math.min(20, precision));
  54. function format(value) {
  55. var valuePrefix = prefix,
  56. valueSuffix = suffix,
  57. i, n, c;
  58. if (type === "c") {
  59. valueSuffix = formatType(value) + valueSuffix;
  60. value = "";
  61. } else {
  62. value = +value;
  63. // Determine the sign. -0 is not less than 0, but 1 / -0 is!
  64. var valueNegative = value < 0 || 1 / value < 0;
  65. // Perform the initial formatting.
  66. value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
  67. // Trim insignificant zeros.
  68. if (trim) value = formatTrim(value);
  69. // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
  70. if (valueNegative && +value === 0 && sign !== "+") valueNegative = false;
  71. // Compute the prefix and suffix.
  72. valuePrefix = (valueNegative ? (sign === "(" ? sign : minus) : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
  73. valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
  74. // Break the formatted value into the integer “value” part that can be
  75. // grouped, and fractional or exponential “suffix” part that is not.
  76. if (maybeSuffix) {
  77. i = -1, n = value.length;
  78. while (++i < n) {
  79. if (c = value.charCodeAt(i), 48 > c || c > 57) {
  80. valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
  81. value = value.slice(0, i);
  82. break;
  83. }
  84. }
  85. }
  86. }
  87. // If the fill character is not "0", grouping is applied before padding.
  88. if (comma && !zero) value = group(value, Infinity);
  89. // Compute the padding.
  90. var length = valuePrefix.length + value.length + valueSuffix.length,
  91. padding = length < width ? new Array(width - length + 1).join(fill) : "";
  92. // If the fill character is "0", grouping is applied after padding.
  93. if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
  94. // Reconstruct the final output based on the desired alignment.
  95. switch (align) {
  96. case "<": value = valuePrefix + value + valueSuffix + padding; break;
  97. case "=": value = valuePrefix + padding + value + valueSuffix; break;
  98. case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
  99. default: value = padding + valuePrefix + value + valueSuffix; break;
  100. }
  101. return numerals(value);
  102. }
  103. format.toString = function() {
  104. return specifier + "";
  105. };
  106. return format;
  107. }
  108. function formatPrefix(specifier, value) {
  109. var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
  110. e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
  111. k = Math.pow(10, -e),
  112. prefix = prefixes[8 + e / 3];
  113. return function(value) {
  114. return f(k * value) + prefix;
  115. };
  116. }
  117. return {
  118. format: newFormat,
  119. formatPrefix: formatPrefix
  120. };
  121. }