{"record":{"id":"5e9cd2bf67d848e7","repo":"symfony/css-selector","slug":"expected-a-single-string-or-identifier-for-lang-got-5e9cd2","errorCode":null,"errorMessage":"Expected a single string or identifier for :lang(), got ","messagePattern":"Expected a single string or identifier for :lang\\(\\), got ","errorType":"exception","errorClass":"ExpressionErrorException","httpStatus":null,"severity":"error","filePath":"XPath/Extension/HtmlExtension.php","lineNumber":148,"sourceCode":"                .')'\n                .' and not(@disabled or '.self::DISABLING_FIELDSET.')'\n            .') or ('\n                .\"name(.) = 'option' and not(\"\n                    .'@disabled or ancestor::optgroup[@disabled]'\n                .')'\n            .')'\n        );\n    }\n\n    /**\n     * @throws ExpressionErrorException\n     */\n    public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr\n    {\n        $arguments = $function->getArguments();\n        foreach ($arguments as $token) {\n            if (!($token->isString() || $token->isIdentifier())) {\n                throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));\n            }\n        }\n\n        return $xpath->addCondition(\\sprintf(\n            'ancestor-or-self::*[@lang][1][starts-with(concat('\n            .\"translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')\"\n            .', %s)]',\n            'lang',\n            Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')\n        ));\n    }\n\n    public function translateSelected(XPathExpr $xpath): XPathExpr\n    {\n        return $xpath->addCondition(\"(@selected and name(.) = 'option')\");\n    }\n\n    public function translateInvalid(XPathExpr $xpath): XPathExpr","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/symfony/css-selector/blob/08e2905152a39cf3fd1745d83f8c483e258887d9/XPath/Extension/HtmlExtension.php#L130-L166","documentation":"ExpressionErrorException thrown by HtmlExtension::translateLang (HTML-aware translator) when any argument token of :lang() is neither a string nor an identifier token. The HTML variant emits an XPath condition matching case-insensitive lang/xml:lang attributes with prefix matching, which still requires a literal string/identifier value.","triggerScenarios":"Using Translator with HtmlExtension enabled and translating ':lang(42)', ':lang(\"a\" \"b\")', or any selector whose :lang() token list contains a non-string/non-identifier token.","commonSituations":"Same as the base :lang() error but in HTML documents: unquoted numeric or malformed language codes, programmatically generated selectors with wrong token types, CSS4-style wildcard arguments like ':lang(\"*-Latn\")' typed in a way that mis-tokenizes.","solutions":["Quote the argument: ':lang(\"en-us\")'.","Use a simple identifier: ':lang(en)'.","Match only one language tag per :lang(); combine selectors for several.","Catch ExpressionErrorException around the translation call."],"exampleFix":"// before\n':lang(01)'\n// after\n':lang(\"en\")'","handlingStrategy":"validation","validationCode":"function isValidLangArg(?string $arg): bool {\n    return null !== $arg && (bool) preg_match('/^(\"[^\"]*\"|\\'[A-Za-z-]+\\'|[A-Za-z][\\w-]*)$/', $arg);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $xpath = $translator->cssToXPath($css); // with HtmlExtension registered\n} catch (ExpressionErrorException $e) {\n    if (str_contains($e->getMessage(), ':lang()')) {\n        // reject selector\n    }\n}","preventionTips":["Quote :lang() values when they contain digits or odd characters.","One language tag per :lang() selector.","Prefer identifier-shaped language codes (en, en-us).","Wrap HTML selector translation in try-catch for user input."],"tags":["css-selector","lang","html","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"08e2905152a39cf3fd1745d83f8c483e258887d9","analyzedAt":"2026-09-14T11:41:28.509Z","contentChangedAt":"2026-09-14T11:41:28.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}