Skip to content

Commit

Permalink
Refactor AndroidString classes to be able to apply proper and consist…
Browse files Browse the repository at this point in the history
…ent escaping.

This also greatly simplify the logic
  • Loading branch information
ja-openai committed Sep 27, 2024
1 parent 603fa41 commit 24e9421
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ public String execute(String xmlContent) {

if (xmlContent == null
|| xmlContent.isBlank()
|| (!shouldApplyPostProcessingRemoveUntranslatedExcluded && !removeTranslatableFalse)) {
|| (!shouldApplyPostProcessingRemoveUntranslatedExcluded && !hasRemoveUntranslated())) {
return xmlContent;
}

Expand Down Expand Up @@ -553,6 +553,11 @@ public String execute(String xmlContent) {
StreamResult streamResult = new StreamResult(new StringWriter());
transformer.transform(domSource, streamResult);
String processedXmlContent = streamResult.getWriter().toString();

if (!hasStandalone) {
processedXmlContent = processedXmlContent.replace(" standalone=\"no\"", "");
}

return processedXmlContent;

} catch (ParserConfigurationException | SAXException | IOException | TransformerException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void testPostProcessingKeepDescription() {
String output = androidFilePostProcessor.execute(input);
String expected =
"""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string description="a description" name="pinterest2">somestring to keep</string>
<!--testing plural-->
Expand Down Expand Up @@ -182,7 +182,7 @@ public void testPostProcessingRemoveDescription() {
String output = androidFilePostProcessor.execute(input);
String expected =
"""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="pinterest2">somestring to keep</string>
<!--testing plural-->
Expand Down Expand Up @@ -257,7 +257,7 @@ public void testPostProcessingRemoveTranslatableFalse() {
String output = androidFilePostProcessor.execute(input);
String expected =
"""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<!--testing plural-->
<plurals name="pins2">
Expand All @@ -267,4 +267,82 @@ public void testPostProcessingRemoveTranslatableFalse() {
""";
assertEquals(expected, output);
}

@Test
public void testPostProcessingStandaloneNo() {
AndroidFilter.AndroidFilePostProcessor androidFilePostProcessor =
new AndroidFilter.AndroidFilePostProcessor(true, true, 2, true, false);
String input =
"""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<resources>
<string name="pinterest2" description="a description" translatable="false">somestring to keep</string>
<string name="pinterest">@#$untranslated$#@</string>
<!--testing plural-->
<plurals name="pins">
<item quantity="one">@#$untranslated$#@</item>
<item quantity="other">@#$untranslated$#@</item>
</plurals>
<plurals description="testing plural attr" name="pins2">
<item quantity="one">translated</item>
<item quantity="other">@#$untranslated$#@</item>
</plurals>
<plurals name="pins3" translatable="false">
<item quantity="one">pin fr</item>
<item quantity="other">pins fr</item>
</plurals>
</resources>
""";
String output = androidFilePostProcessor.execute(input);
String expected =
"""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<resources>
<!--testing plural-->
<plurals name="pins2">
<item quantity="one">translated</item>
</plurals>
</resources>
""";
assertEquals(expected, output);
}

@Test
public void testPostProcessingStandaloneYes() {
AndroidFilter.AndroidFilePostProcessor androidFilePostProcessor =
new AndroidFilter.AndroidFilePostProcessor(true, true, 2, true, false);
String input =
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources>
<string name="pinterest2" description="a description" translatable="false">somestring to keep</string>
<string name="pinterest">@#$untranslated$#@</string>
<!--testing plural-->
<plurals name="pins">
<item quantity="one">@#$untranslated$#@</item>
<item quantity="other">@#$untranslated$#@</item>
</plurals>
<plurals description="testing plural attr" name="pins2">
<item quantity="one">translated</item>
<item quantity="other">@#$untranslated$#@</item>
</plurals>
<plurals name="pins3" translatable="false">
<item quantity="one">pin fr</item>
<item quantity="other">pins fr</item>
</plurals>
</resources>
""";
String output = androidFilePostProcessor.execute(input);
String expected =
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources>
<!--testing plural-->
<plurals name="pins2">
<item quantity="one">translated</item>
</plurals>
</resources>
""";
assertEquals(expected, output);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.box.l10n.mojito.android.strings;

import static com.google.common.base.Preconditions.checkArgument;

import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Node;

public class AndroidStringDocument {

Expand All @@ -29,46 +26,8 @@ public void addSingular(AndroidSingular string) {
strings.add(string);
}

public void addSingular(AndroidStringElement element, Node comment) {

checkArgument(element.isSingular(), "element should be singular");

addSingular(
new AndroidSingular(
element.getIdAttribute(),
element.getNameAttribute(),
element.getUnescapedContent(),
comment != null ? comment.getTextContent() : null));
}

public void addPlural(AndroidPlural plural) {
plurals.add(plural);
strings.add(plural);
}

public void addPlural(AndroidStringElement element, Node comment) {

checkArgument(element.isPlural(), "element should be plural");

AndroidPlural.AndroidPluralBuilder builder = AndroidPlural.builder();
builder.setName(element.getNameAttribute());
if (comment != null) {
builder.setComment(comment.getTextContent());
}

element.forEachPluralItem(builder::addItem);

addPlural(builder.build());
}

public void addElement(Node node, Node comment) {

AndroidStringElement element = new AndroidStringElement(node);

if (element.isSingular()) {
addSingular(element, comment);
} else if (element.isPlural()) {
addPlural(element, comment);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -202,7 +201,7 @@ Stream<TextUnitDTO> singularToTextUnit(AndroidSingular singular) {
textUnit.setName(singular.getName());
textUnit.setComment(singular.getComment());
textUnit.setTmTextUnitId(singular.getId());
textUnit.setTarget(unescape(singular.getContent()));
textUnit.setTarget(singular.getContent());
addTextUnitDTOAttributes(textUnit);

return Stream.of(textUnit);
Expand All @@ -226,7 +225,7 @@ Stream<TextUnitDTO> pluralToTextUnits(AndroidPlural plural) {
textUnit.setTmTextUnitId(item.getId());
textUnit.setPluralForm(quantity);
textUnit.setPluralFormOther(pluralFormOther);
textUnit.setTarget(unescape(item.getContent()));
textUnit.setTarget(item.getContent());
addTextUnitDTOAttributes(textUnit);

return textUnit;
Expand Down Expand Up @@ -286,23 +285,4 @@ static String removeInvalidControlCharacter(String str) {

return withoutControlCharacters;
}

/** should use {@link com.box.l10n.mojito.okapi.filters.AndroidFilter#unescape(String)} */
static String unescape(String str) {

String unescape = str;

if (StringUtils.startsWith(unescape, "\"") && StringUtils.endsWith(unescape, "\"")) {
unescape = unescape.substring(1, unescape.length() - 1);
}

unescape =
Strings.nullToEmpty(unescape)
.replaceAll("\\\\'", "'")
.replaceAll("\\\\\"", "\"")
.replaceAll("\\\\@", "@")
.replaceAll("\\\\n", "\n");

return unescape;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.Optional;
import java.util.Queue;
import javax.xml.parsers.ParserConfigurationException;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class AndroidStringDocumentReader {

public static AndroidStringDocument fromFile(String fileName)
throws ParserConfigurationException, IOException, SAXException {
public static AndroidStringDocument fromFile(String fileName) throws IOException, SAXException {
return buildFromDocument(documentBuilder().parse(new File(fileName)));
}

Expand All @@ -44,10 +47,90 @@ private static AndroidStringDocument buildFromDocument(Document source) {
commentNodes.offer(node);

} else if (Node.ELEMENT_NODE == node.getNodeType()) {
document.addElement(node, commentNodes.poll());
Element nodeAsElement = (Element) node;
Node comment = commentNodes.poll();

if (nodeAsElement.getTagName().equals(AndroidStringElement.SINGULAR_ELEMENT_NAME)) {
document.addSingular(
new AndroidSingular(
getAttributeAs(
nodeAsElement, AndroidStringElement.ID_ATTRIBUTE_NAME, Long::valueOf),
getNameAttribute(nodeAsElement),
unescape(nodeAsElement.getTextContent()),
comment != null ? comment.getTextContent() : null));
} else if (nodeAsElement.getTagName().equals(AndroidStringElement.PLURAL_ELEMENT_NAME)) {

AndroidPlural.AndroidPluralBuilder builder = AndroidPlural.builder();

builder.setName(nodeAsElement.getAttribute(AndroidStringElement.NAME_ATTRIBUTE_NAME));
if (comment != null) {
builder.setComment(comment.getTextContent());
}

NodeList nodeList =
nodeAsElement.getElementsByTagName(AndroidStringElement.PLURAL_ITEM_ELEMENT_NAME);

for (int j = 0; j < nodeList.getLength(); j++) {
Element item = (Element) nodeList.item(j);

builder.addItem(
new AndroidPluralItem(
getAttribute(item, AndroidStringElement.QUANTITY_ATTRIBUTE_NAME),
getAttributeAs(item, AndroidStringElement.ID_ATTRIBUTE_NAME, Long::valueOf),
unescape(getTextContent(item))));
}

document.addPlural(builder.build());
}
}
}

return document;
}

public static String getAttribute(Element element, String name) {
// looks like ofNullable is useless and then the orElse
return Optional.ofNullable(element.getAttribute(name)).orElse("");
}

public static <T> T getAttributeAs(
Element element, String attributeName, Function<String, T> converter) {

T result = null;

if (element.hasAttribute(attributeName)) {
result = converter.apply(element.getAttribute(attributeName));
}

return result;
}

public static String getTextContent(Element element) {
return Optional.ofNullable(element).map(Element::getTextContent).orElse("");
}

public static String getNameAttribute(Element element) {
return element.getAttribute(AndroidStringElement.NAME_ATTRIBUTE_NAME);
}

/** should use {@link com.box.l10n.mojito.okapi.filters.AndroidFilter#unescape(String)} */
static String unescape(String str) {

String unescape = str;

if (!Strings.isNullOrEmpty(str)) {

if (StringUtils.startsWith(unescape, "\"") && StringUtils.endsWith(unescape, "\"")) {
unescape = unescape.substring(1, unescape.length() - 1);
}

unescape =
Strings.nullToEmpty(unescape)
.replaceAll("\\\\'", "'")
.replaceAll("\\\\\"", "\"")
.replaceAll("\\\\@", "@")
.replaceAll("\\\\n", "\n");
}
return unescape;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private Element addChild(Node node, String name) {

private void setContent(Element element, String content) {
if (!Strings.isNullOrEmpty(content)) {
element.setTextContent(escapeQuotes(content));
element.setTextContent(escapeQuotes(content, escapeType));
}
}

Expand All @@ -159,7 +159,7 @@ private void setAttribute(Element element, String name, String value) {
}
}

String escapeQuotes(String str) {
static String escapeQuotes(String str, EscapeType escapeType) {
String escaped = str;
if (!Strings.isNullOrEmpty(str)) {
escaped =
Expand Down
Loading

0 comments on commit 24e9421

Please sign in to comment.