Last active
April 26, 2024 22:10
-
-
Save freaktechnik/4a72bc0711d9bc82cf3b075bcc292953 to your computer and use it in GitHub Desktop.
Drop-in script to localize HTML sites in WebExtensions like it was the Add-on SDK.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Translates a HTMl page in the web l10n style from the Add-on SDK with | |
* WebExtensions strings. | |
* Large parts of the logic are very similar to the SDK implmentation. | |
* All you have to do to use this in a document is load it. | |
* | |
* It supports some additional attributes: | |
* - The "translate" attribute is fully respected (see | |
* https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/translate) | |
* - "data-l10n-nocontent" means that the text content of the element | |
* will not be attempted to be translated. | |
* | |
* @author Martin Giger | |
* @license MPL-2.0 | |
*/ | |
function translateElementAttributes(element) { | |
const attrList = [ 'title', 'accesskey', 'alt', 'label', 'placeholder', 'abbr', 'content', 'download', 'srcdoc', 'value' ]; | |
const ariaAttrMap = { | |
'aria-label': 'ariaLabel', | |
'aria-value-text': 'ariaValueText', | |
'aria-moz-hint': 'ariaMozHint' | |
}; | |
const attrSeparator = '.'; | |
const presentAttributes = element.dataset.l10nAttrs.split(","); | |
// Translate allowed attributes. | |
for(let attribute of presentAttributes) { | |
let data; | |
if(attrList.includes(attribute)) { | |
data = browser.i18n.getMessage(element.dataset.l10nId + attrSeparator + attribute); | |
} | |
// Translate ARIA attributes | |
else if(attribute in ariaAttrMap) { | |
data = browser.i18n.getMessage(element.dataset.l10nId + attrSeparator + ariaAttrMap[attribute]); | |
} | |
if(data && data != "??") { | |
element.setAttribute(attribute, data); | |
} | |
} | |
} | |
const C_TRANSLATE_VALUES = [ | |
'yes', | |
'no' | |
]; | |
function getTranslateState(element) { | |
if(element.hasAttribute("translate") && C_TRANSLATE_VALUES.includes(element.getAttribute("translate"))) { | |
return element.getAttribute("translate"); | |
} | |
const closestTranslate = element.closest('[translate]:not([translate="inherit"])'); | |
if(closestTranslate) { | |
return closestTranslate.getAttribute("translate"); | |
} | |
return "yes"; | |
} | |
function translateElement(element = document) { | |
// Set the language attribute of the document. | |
if(element === document) { | |
document.documentElement.setAttribute("lang", browser.i18n.getUILanguage().replace("_", "-")); | |
} | |
// Get all children that are marked as being translateable. | |
const children = element.querySelectorAll('*[data-l10n-id]:not([translate="no"])'); | |
for(const child of children) { | |
if(getTranslateState(child) !== "no") { | |
if(!child.dataset.l10nNocontent) { | |
const data = browser.i18n.getMessage(child.dataset.l10nId); | |
if(data && data != "??") { | |
child.textContent = data; | |
} | |
} | |
if(child.dataset.l10nAttrs) { | |
translateElementAttributes(child); | |
} | |
} | |
} | |
} | |
document.addEventListener("DOMContentLoaded", () => translateElement(), { | |
capture: false, | |
passive: true, | |
once: true | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment