-
-
Save gregoriopellegrino/c94c46933d660a3db233e7a1c9c6f5e6 to your computer and use it in GitHub Desktop.
// main lang | |
if ($("html").get(0).hasAttribute("lang")) { | |
var main_lang = $("html").attr("lang"); | |
} else { | |
var main_lang = $("body").attr("lang"); | |
} | |
console.log("Main language is "+main_lang); | |
// children lang | |
var langs = []; | |
$("*[lang]").each(function() { | |
var lang = $(this).attr("lang"); | |
if ($.inArray(lang, langs) == -1) { | |
langs.push(lang) | |
} | |
}); | |
console.log("Other languages found: "+langs); |
Here you go, this one will check if language tag is valid, and whether values of xml:lang
and lang
match.
I refrained from refactoring too much so that the process be kinda clearer/commented but turned it into functions so that it can be refactored into a JS module more easily – so anyone please feel free to do that if re-using the logic (npm, etc.) and share it.
// UTILS
// Strips leading or trailing spaces from string
const trimmer = (string) => {
return string.trim();
}
// Checks if lang is specified
const langIsSpecified = (string) => {
string = trimmer(string);
if (string.length > 1) {
return true;
} else {
return false;
}
}
// Checks if string contains leading or trailing spaces
const hasWhitespace = (string) => {
return string.length > trimmer(string).length;
}
// Find and checks validity of the lang for the given element
const findLangForEl = (el) => {
const langValue = el.lang;
if (langIsSpecified(langValue)) {
// If lang is specified
if (!hasWhitespace(langValue)) {
// If value is valid, return value
return langValue;
} else {
// If lang specified for el have a space, then it’s invalid BCP47 so we throw an error
console.error(`There is a space in '${langValue}' therefore it isn’t a valid BCP47 language tag for element:`, el);
}
}
return undefined;
}
// FUNCTIONS/METHODS
// Handle XHTML (xml namespace)
const handleXMLLang = () => {
// Query all elements in the DOM
const domEls = document.querySelectorAll("*");
// For each, check if there is an xml:lang
for (let i = 0; i < domEls.length; i++) {
const el = domEls[i];
if (el.hasAttribute("xml:lang") && el.hasAttribute("lang")) {
// if there is, and there’s also a lang, make sure their values match:
const xmlValue = el.getAttribute("xml:lang");
const langValue = el.getAttribute("lang");
if (xmlValue !== langValue) {
// If value is different then it’s an error
console.error(`Langs don’t match for element:`, el);
}
} else if (el.hasAttribute("xml:lang") && !el.hasAttribute("lang")) {
// if there is xml:lang but not lang, then add it
// Note: this function must be called first so that code below takes over
const langValue = el.getAttribute("xml:lang");
el.setAttribute("lang", langValue);
}
}
};
const checkMainLang = () => {
// Checking if lang specified for html and body
const docLang = findLangForEl(document.documentElement);
const bodyLang = findLangForEl(document.body);
if (docLang && bodyLang) {
// If both HTML and BODY langs are specified
if (docLang !== bodyLang) {
// We check if they match, and warn if they don’t
console.warn(
`HTML and BODY langs don’t match. HTML is '${docLang}' while BODY is '${bodyLang}'. Main lang will be '${bodyLang}'.`
);
} else {
// Else we use html’s
console.log(`Main lang is '${docLang}'.`);
}
} else if (docLang && !bodyLang) {
// If it’s specified for html
console.log(`Main lang is '${docLang}'.`);
} else if (bodyLang && !docLang) {
// If it’s specified for body
console.warn(`Main lang is '${bodyLang}' but only set on BODY. Elements such as <title> consequently don’t inherit a specified lang and could inherit the navigator’s default.`);
} else {
// Else we warn no lang is set and the navigator’s default will be used
console.warn(`No lang is set, it will default to the navigator’s: ${navigator.language}.`)
}
};
const checkOtherLangs = () => {
// Other languages start here, with an empty array
let langs = [];
// We check all elements in body with a lang attribute
const els = document.body.querySelectorAll(`*[lang]`);
// For each, we check if we must add the lang to the array
for (let i = 0; i < els.length; i++) {
const el = els[i];
const langToAdd = findLangForEl(el);
// If there’s a lang and it isn’t in the array yet, we add it
if (langToAdd && langs.indexOf(langToAdd) === -1) {
langs.push(langToAdd);
}
}
// Finally we log all the other languages found.
console.log(`Other languages found: ${langs.toString().replace(/,/g, ", ")}`);
};
handleXMLLang();
checkMainLang();
checkOtherLangs();
Also, if you want to check the validity of the BCP47 language tag (pattern) → https://github.com/SafetyCulture/bcp47
This has gone so far that I’m wondering whether it shouldn’t be a module (with a GitHub repo). I could even imagine having/finding some use-cases in the future.
My idea was simply to save a code that I use from time to time to check the accessibility of EPUB and PDF :) , but the work it's becoming interesting...
I’ve just pushed an invite – started working on completing this a little bit in a private repo – so it’s fair to enable access for you :-)
No problem.
That said, trying to handle errors kinda opens a can of worms:
I’ll try updating the code above at some point.