/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.ui.shared; import java.util.HashMap; import java.util.Map; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Visits the dom and finds elements that need translating. */ public class TemplateVisitor implements DomVisitor { private String i18nPrefix; private final Map<String, String> i18nValues = new HashMap<String, String>(); public TemplateVisitor(String i18nPrefix) { this.i18nPrefix = i18nPrefix; } @Override public boolean visit(Element element) { // Developers can mark entire sections of the template as "do not translate" if ("dummy".equals(element.getAttribute("data-role"))) { return false; } // If the element either explicitly enables i18n (via an i18n key) or is a text-only // node, record it. if (hasAttribute(element, "data-i18n-key") || isTextOnly(element)) { visitElement(i18nPrefix, element); return false; } if (hasAttribute(element, "title")) { visitAttribute(i18nPrefix, element, "title"); } if (hasAttribute(element, "placeholder")) { visitAttribute(i18nPrefix, element, "placeholder"); } return true; } /** * Records the translation key/value for an element. * * @param i18nKeyPrefix * @param element */ protected void visitElement(String i18nKeyPrefix, Element element) { String translationKey = i18nKeyPrefix + getOrGenerateTranslationKey(element); String translationValue = getTextContent(element); i18nValues.put(translationKey, translationValue); } /** * Records the translation key/value for an attribute. * * @param i18nKeyPrefix * @param element * @param attributeName */ protected void visitAttribute(String i18nKeyPrefix, Element element, String attributeName) { String elementKey = getElementKey(element); // If we couldn't figure out a key for this thing, then just bail. if (elementKey == null || elementKey.trim().length() == 0) { return; } String translationKey = i18nKeyPrefix + elementKey; translationKey += "-" + attributeName; String translationValue = element.getAttribute(attributeName); i18nValues.put(translationKey, translationValue); } protected String getElementKey(Element element) { String elementKey; if (hasAttribute(element, "data-field")) { elementKey = element.getAttribute("data-field"); } else if (hasAttribute(element, "id")) { elementKey = element.getAttribute("id"); } else if (hasAttribute(element, "name")) { elementKey = element.getAttribute("name"); } else { elementKey = getOrGenerateTranslationKey(element); } return elementKey; } /** * Gets a translation key associated with the given element. If no key attribute exists in this * element, generate and assign one. * * @param element */ protected String getOrGenerateTranslationKey(Element element) { String translationKey = null; String currentText = getTextContent(element); if (hasAttribute(element, "data-i18n-key")) { translationKey = element.getAttribute("data-i18n-key"); } else { translationKey = currentText.replaceAll("[:\\s'\"]+", "_"); if (translationKey.length() > 128) { translationKey = translationKey.substring(0, 128) + translationKey.hashCode(); } element.setAttribute("data-i18n-key", translationKey); } return translationKey; } /** * Returns true if the given element has some text and no element children. * * @param element */ public boolean isTextOnly(Element element) { NodeList childNodes = element.getChildNodes(); for (int idx = 0; idx < childNodes.getLength(); idx++) { Node item = childNodes.item(idx); // As soon as we hit an element, we can return false if (item.getNodeType() == Node.ELEMENT_NODE) { return false; } } String textContent = getTextContent(element); return (textContent != null) && (textContent.trim().length() > 0); } /** * Called to determine if an element has an attribute defined. * * @param element * @param attributeName */ public boolean hasAttribute(Element element, String attributeName) { String attribute = element.getAttribute(attributeName); return (attribute != null && attribute.trim().length() > 0); } /** * Gets the text content for the given element. * * @param element */ private String getTextContent(Element element) { StringBuilder text = new StringBuilder(); NodeList childNodes = element.getChildNodes(); boolean first = true; for (int idx = 0; idx < childNodes.getLength(); idx++) { Node item = childNodes.item(idx); if (item.getNodeType() == Node.TEXT_NODE) { if (first) { first = false; } else { text.append(" "); } text.append(item.getNodeValue()); } } return text.toString(); } public void setI18nPrefix(String i18nPrefix) { this.i18nPrefix = i18nPrefix; } public Map<String, String> getI18nValues() { return i18nValues; } }