prism-icu-message-format.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // https://unicode-org.github.io/icu/userguide/format_parse/messages/
  2. // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/MessageFormat.html
  3. (function (Prism) {
  4. /**
  5. * @param {string} source
  6. * @param {number} level
  7. * @returns {string}
  8. */
  9. function nested(source, level) {
  10. if (level <= 0) {
  11. return /[]/.source;
  12. } else {
  13. return source.replace(/<SELF>/g, function () { return nested(source, level - 1); });
  14. }
  15. }
  16. var stringPattern = /'[{}:=,](?:[^']|'')*'(?!')/;
  17. var escape = {
  18. pattern: /''/,
  19. greedy: true,
  20. alias: 'operator'
  21. };
  22. var string = {
  23. pattern: stringPattern,
  24. greedy: true,
  25. inside: {
  26. 'escape': escape
  27. }
  28. };
  29. var argumentSource = nested(
  30. /\{(?:[^{}']|'(?![{},'])|''|<STR>|<SELF>)*\}/.source
  31. .replace(/<STR>/g, function () { return stringPattern.source; }),
  32. 8
  33. );
  34. var nestedMessage = {
  35. pattern: RegExp(argumentSource),
  36. inside: {
  37. 'message': {
  38. pattern: /^(\{)[\s\S]+(?=\}$)/,
  39. lookbehind: true,
  40. inside: null // see below
  41. },
  42. 'message-delimiter': {
  43. pattern: /./,
  44. alias: 'punctuation'
  45. }
  46. }
  47. };
  48. Prism.languages['icu-message-format'] = {
  49. 'argument': {
  50. pattern: RegExp(argumentSource),
  51. greedy: true,
  52. inside: {
  53. 'content': {
  54. pattern: /^(\{)[\s\S]+(?=\}$)/,
  55. lookbehind: true,
  56. inside: {
  57. 'argument-name': {
  58. pattern: /^(\s*)[^{}:=,\s]+/,
  59. lookbehind: true
  60. },
  61. 'choice-style': {
  62. // https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1ChoiceFormat.html#details
  63. pattern: /^(\s*,\s*choice\s*,\s*)\S(?:[\s\S]*\S)?/,
  64. lookbehind: true,
  65. inside: {
  66. 'punctuation': /\|/,
  67. 'range': {
  68. pattern: /^(\s*)[+-]?(?:\d+(?:\.\d*)?|\u221e)\s*[<#\u2264]/,
  69. lookbehind: true,
  70. inside: {
  71. 'operator': /[<#\u2264]/,
  72. 'number': /\S+/
  73. }
  74. },
  75. rest: null // see below
  76. }
  77. },
  78. 'plural-style': {
  79. // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/PluralFormat.html#:~:text=Patterns%20and%20Their%20Interpretation
  80. pattern: /^(\s*,\s*(?:plural|selectordinal)\s*,\s*)\S(?:[\s\S]*\S)?/,
  81. lookbehind: true,
  82. inside: {
  83. 'offset': /^offset:\s*\d+/,
  84. 'nested-message': nestedMessage,
  85. 'selector': {
  86. pattern: /=\d+|[^{}:=,\s]+/,
  87. inside: {
  88. 'keyword': /^(?:few|many|one|other|two|zero)$/
  89. }
  90. }
  91. }
  92. },
  93. 'select-style': {
  94. // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/SelectFormat.html#:~:text=Patterns%20and%20Their%20Interpretation
  95. pattern: /^(\s*,\s*select\s*,\s*)\S(?:[\s\S]*\S)?/,
  96. lookbehind: true,
  97. inside: {
  98. 'nested-message': nestedMessage,
  99. 'selector': {
  100. pattern: /[^{}:=,\s]+/,
  101. inside: {
  102. 'keyword': /^other$/
  103. }
  104. }
  105. }
  106. },
  107. 'keyword': /\b(?:choice|plural|select|selectordinal)\b/,
  108. 'arg-type': {
  109. pattern: /\b(?:date|duration|number|ordinal|spellout|time)\b/,
  110. alias: 'keyword'
  111. },
  112. 'arg-skeleton': {
  113. pattern: /(,\s*)::[^{}:=,\s]+/,
  114. lookbehind: true
  115. },
  116. 'arg-style': {
  117. pattern: /(,\s*)(?:currency|full|integer|long|medium|percent|short)(?=\s*$)/,
  118. lookbehind: true
  119. },
  120. 'arg-style-text': {
  121. pattern: RegExp(/(^\s*,\s*(?=\S))/.source + nested(/(?:[^{}']|'[^']*'|\{(?:<SELF>)?\})+/.source, 8) + '$'),
  122. lookbehind: true,
  123. alias: 'string'
  124. },
  125. 'punctuation': /,/
  126. }
  127. },
  128. 'argument-delimiter': {
  129. pattern: /./,
  130. alias: 'operator'
  131. }
  132. }
  133. },
  134. 'escape': escape,
  135. 'string': string
  136. };
  137. nestedMessage.inside.message.inside = Prism.languages['icu-message-format'];
  138. Prism.languages['icu-message-format'].argument.inside.content.inside['choice-style'].inside.rest = Prism.languages['icu-message-format'];
  139. }(Prism));