{"record":{"id":"21fdbe1061f09a47","repo":"GoogleChrome/lighthouse","slug":"content-cannot-appear-outside-plural-or-select-icu","errorCode":null,"errorMessage":"Content cannot appear outside plural or select ICU messages. Instead, repeat that content in each option (message: '${lhlMessage}')","messagePattern":"Content cannot appear outside plural or select ICU messages\\. Instead, repeat that content in each option \\(message: '(.+?)'\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/scripts/i18n/collect-strings.js","lineNumber":213,"sourceCode":"  let parsedMessageElements;\n  try {\n    parsedMessageElements = MessageParser.parse(escapeIcuMessage(lhlMessage), {ignoreTag: true});\n  } catch (err) {\n    if (err.name !== 'SyntaxError') throw err;\n    throw new Error(`[${err.message}] Did not find the expected syntax in message: ${err.originalMessage}`);\n  }\n\n  /**\n   * @param {MessageParser.MessageFormatElement[]} elements\n   */\n  function validate(elements) {\n    for (const element of elements) {\n      if (element.type === MessageParser.TYPE.plural || element.type === MessageParser.TYPE.select) {\n        // `plural`/`select` arguments can't have content before or after them.\n        // See http://userguide.icu-project.org/formatparse/messages#TOC-Complex-Argument-Types\n        // e.g. https://github.com/GoogleChrome/lighthouse/pull/11068#discussion_r451682796\n        if (elements.length > 1) {\n          throw new Error(`Content cannot appear outside plural or select ICU messages. Instead, repeat that content in each option (message: '${lhlMessage}')`);\n        }\n\n        for (const option of Object.values(element.options)) {\n          validate(option.value);\n        }\n      }\n    }\n  }\n\n  validate(parsedMessageElements);\n}\n\n/**\n * Convert code spans into placeholders with examples.\n *\n * @param {IncrementalCtc} icu\n */\nfunction _processPlaceholderMarkdownCode(icu) {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/core/scripts/i18n/collect-strings.js#L195-L231","documentation":"Thrown by _lhlValidityChecks().validate() when a plural or select ICU argument shares its message with sibling content (elements.length > 1). Per ICU rules, complex argument types (plural/select) cannot have text before or after them — all surrounding content must be repeated inside each option.","triggerScenarios":"Writing a message like `You have {itemCount, plural, =1 {1 item} other {# items}} remaining` where text ('You have', 'remaining') appears outside the plural argument.","commonSituations":"Translating natural-language sentences that embed a plural mid-sentence; refactoring messages that previously used separate concatenation.","solutions":["Restructure so the entire message is inside the plural/select, e.g. `{itemCount, plural, =1 {You have 1 item remaining.} other {You have # items remaining.}}`.","Repeat the surrounding content verbatim in every plural/select option.","If two independent clauses are needed, split into two separate message keys instead."],"exampleFix":"// before\nmessage: 'You have {itemCount, plural, =1 {1 item} other {# items}} remaining.'\n// after\nmessage: '{itemCount, plural, =1 {You have 1 item remaining.} other {You have # items remaining.}}'","handlingStrategy":"validation","validationCode":"const {parse, TYPE} = require('intl-messageformat');\nfunction hasContentOutsideComplexArg(msg) {\n  const els = parse(msg, {ignoreTag: true});\n  return els.some(el =>\n    (el.type === TYPE.plural || el.type === TYPE.select) && els.length > 1\n  );\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When using plural/select, put the entire sentence inside the argument.","Repeat fixed text in every plural/select option.","Split multi-clause sentences into separate message keys."],"tags":["i18n","icu","plural","select","collect-strings","message-format"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}