-
Notifications
You must be signed in to change notification settings - Fork 779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rule): xml-lang-mismatch #999
feat(rule): xml-lang-mismatch #999
Conversation
Tidying up. Closing PR, will re-open when work on this rule is started again. |
Updated PR. Reviews welcome. |
lib/core/utils/get-base-lang.js
Outdated
* @param {String} value value specified as lang or xml:lang attribute | ||
* @return {String} | ||
*/ | ||
axe.utils.getBaseLang = function getBaseLang(lang) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be on axe.commons, not on axe.utils
. axe.utils
is reserved for things necessary in core.
lib/rules/xml-lang-mismatch.json
Outdated
@@ -0,0 +1,18 @@ | |||
{ | |||
"id": "xml-lang-mismatch", | |||
"matches": "xml-lang-mismatch-matches.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could simplify the matches by offloading some of the work to the selector: "selector": "html[lang][xml:lang]"
const langAndXmlLangAttrs = Array.from(node.attributes).filter(attr => { | ||
const attrName = attr.nodeName.toLowerCase(); | ||
const attrValue = attr.nodeValue; | ||
if (!attrValue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check that the subtag is valid here (I.e. its defined in the subtag registry). If not, it's inapplicable.
"impact": "moderate", | ||
"messages": { | ||
"pass": "Value of lang or xml:lang attribute match if both are specified and included in the list of valid languages", | ||
"fail": "Value of lang or xml:lang attribute either does not match or not included in the list of valid languages" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should simplify, something like "Lang and xml:lang attributes do not have the same base language"
const isValid = axe.utils.validLangs().includes(langSubTagsToValidate[0]); | ||
|
||
// return | ||
return isValid; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't look at valid langs. That's covered by another rule (see my comment on matches). Instead, all this should do is
const { getBaseLang } = axe.commons.text;
return getBaseLang(node.getAttribute('lang')) === getBaseLang(node.getAttribute('xml:lang'));
|
||
// unique the produced array, if identical primary subtag values were supplied, this would result in an array of length 1. | ||
// eg: if lang='en-GB' and xml:lang='en-US', the below will produce langSubTagsToValidate = ['en'] | ||
langSubTagsToValidate = axe.utils.uniqueArray(langSubTagsToValidate, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deduplicating an array is a very round-about way to check that two values are the same. Please just use two variables and do an equality comparison.
test/core/utils/get-base-lang.js
Outdated
|
||
it('returns false when expecting fr instead of en', function() { | ||
var actual = axe.utils.getBaseLang('en'); | ||
assert.notEqual(actual, 'fr'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessary. What you should check is case sensitivity though.
test/core/utils/get-base-lang.js
Outdated
@@ -0,0 +1,18 @@ | |||
describe('axe.utils.getBaseLang', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also check things with multiple dashes. What should this do 'foo-bar-baz'? It's clearly invalid, so maybe this needs to return empty or null?
var checkContext = axe.testUtils.MockCheckContext(); | ||
|
||
beforeEach(function() { | ||
node = document.createElement('html'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use a div instead, so you don't get into browser support trouble. The check is agnostic to what node its testing.
@@ -0,0 +1,11 @@ | |||
{ | |||
"id": "xml-lang-mismatch", |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorted!
const primaryLangValue = getBaseLang(node.getAttribute('lang') || ''); | ||
const primaryXmlLangValue = getBaseLang(node.getAttribute('xml:lang') || ''); | ||
|
||
return primaryLangValue === primaryXmlLangValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be the cleanest looking check we've got. Great job Jey.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of very minor points.
* @param {String} value value specified as lang or xml:lang attribute | ||
* @return {String} | ||
*/ | ||
axe.utils.getBaseLang = function getBaseLang(lang) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor: I'd suggest letting this function handle the null case, so that you don't have to do it separately a bunch of times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorted!
@@ -0,0 +1,16 @@ | |||
// Rule: xml-lang-mismatch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is wrong. I'd also rename this to xml-lang-mismatch-matches.js
. It's a fair bet we're going to reuse this for the non-HTML version.
], | ||
"metadata": { | ||
"description": "Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page", | ||
"help": "HTML elements with lang and xml:lang must have the same base language" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent spacing.
@WilcoFiers |
The rule checks that for the html element, there is no mismatch between the primary language in non-empty lang and xml:lang attributes, if both are used.
See also - https://auto-wcag.github.io/auto-wcag/rules/SC3-1-1-html-xml-lang-match.html for further details of the rule.
Closes issue:
Reviewer checks
Required fields, to be filled out by PR reviewer(s)