// https://unicode-org.github.io/icu/userguide/format_parse/messages/ // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/MessageFormat.html (function (Prism) { /** * @param {string} source * @param {number} level * @returns {string} */ function nested(source, level) { if (level <= 0) { return /[]/.source; } else { return source.replace(//g, function () { return nested(source, level - 1); }); } } var stringPattern = /'[{}:=,](?:[^']|'')*'(?!')/; var escape = { pattern: /''/, greedy: true, alias: 'operator' }; var string = { pattern: stringPattern, greedy: true, inside: { 'escape': escape } }; var argumentSource = nested( /\{(?:[^{}']|'(?![{},'])|''||)*\}/.source .replace(//g, function () { return stringPattern.source; }), 8 ); var nestedMessage = { pattern: RegExp(argumentSource), inside: { 'message': { pattern: /^(\{)[\s\S]+(?=\}$)/, lookbehind: true, inside: null // see below }, 'message-delimiter': { pattern: /./, alias: 'punctuation' } } }; Prism.languages['icu-message-format'] = { 'argument': { pattern: RegExp(argumentSource), greedy: true, inside: { 'content': { pattern: /^(\{)[\s\S]+(?=\}$)/, lookbehind: true, inside: { 'argument-name': { pattern: /^(\s*)[^{}:=,\s]+/, lookbehind: true }, 'choice-style': { // https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1ChoiceFormat.html#details pattern: /^(\s*,\s*choice\s*,\s*)\S(?:[\s\S]*\S)?/, lookbehind: true, inside: { 'punctuation': /\|/, 'range': { pattern: /^(\s*)[+-]?(?:\d+(?:\.\d*)?|\u221e)\s*[<#\u2264]/, lookbehind: true, inside: { 'operator': /[<#\u2264]/, 'number': /\S+/ } }, rest: null // see below } }, 'plural-style': { // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/PluralFormat.html#:~:text=Patterns%20and%20Their%20Interpretation pattern: /^(\s*,\s*(?:plural|selectordinal)\s*,\s*)\S(?:[\s\S]*\S)?/, lookbehind: true, inside: { 'offset': /^offset:\s*\d+/, 'nested-message': nestedMessage, 'selector': { pattern: /=\d+|[^{}:=,\s]+/, inside: { 'keyword': /^(?:few|many|one|other|two|zero)$/ } } } }, 'select-style': { // https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/text/SelectFormat.html#:~:text=Patterns%20and%20Their%20Interpretation pattern: /^(\s*,\s*select\s*,\s*)\S(?:[\s\S]*\S)?/, lookbehind: true, inside: { 'nested-message': nestedMessage, 'selector': { pattern: /[^{}:=,\s]+/, inside: { 'keyword': /^other$/ } } } }, 'keyword': /\b(?:choice|plural|select|selectordinal)\b/, 'arg-type': { pattern: /\b(?:date|duration|number|ordinal|spellout|time)\b/, alias: 'keyword' }, 'arg-skeleton': { pattern: /(,\s*)::[^{}:=,\s]+/, lookbehind: true }, 'arg-style': { pattern: /(,\s*)(?:currency|full|integer|long|medium|percent|short)(?=\s*$)/, lookbehind: true }, 'arg-style-text': { pattern: RegExp(/(^\s*,\s*(?=\S))/.source + nested(/(?:[^{}']|'[^']*'|\{(?:)?\})+/.source, 8) + '$'), lookbehind: true, alias: 'string' }, 'punctuation': /,/ } }, 'argument-delimiter': { pattern: /./, alias: 'operator' } } }, 'escape': escape, 'string': string }; nestedMessage.inside.message.inside = Prism.languages['icu-message-format']; Prism.languages['icu-message-format'].argument.inside.content.inside['choice-style'].inside.rest = Prism.languages['icu-message-format']; }(Prism));