// 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);