From afc3b1d6439436f318240e5458c0ae9b5da0d47b Mon Sep 17 00:00:00 2001 From: Jean Aurambault Date: Fri, 27 Sep 2024 00:39:15 -0700 Subject: [PATCH] Refactor AndroidString classes to be able to apply proper and consistent escaping. This also greatly simplify the logic --- .../res/values-fr-rCA/strings.xml | 2 +- .../res/values-fr-rFR/strings.xml | 2 +- .../res/values-ja-rJP/strings.xml | 2 +- .../res/values-ru-rRU/strings.xml | 2 +- .../res/values-fr-rCA/strings.xml | 2 +- .../res/values-fr-rFR/strings.xml | 2 +- .../res/values-ja-rJP/strings.xml | 2 +- .../res/values-ru-rRU/strings.xml | 2 +- .../res/values-fr-rCA/strings.xml | 2 +- .../res/values-fr-rFR/strings.xml | 2 +- .../res/values-ja-rJP/strings.xml | 2 +- .../res/values-ru-rRU/strings.xml | 2 +- .../mojito/okapi/filters/AndroidFilter.java | 7 +- .../okapi/filters/AndroidFilterTest.java | 84 ++++++++++++++++- .../strings/AndroidStringDocument.java | 41 --------- .../strings/AndroidStringDocumentMapper.java | 24 +---- .../strings/AndroidStringDocumentReader.java | 91 +++++++++++++++++- .../strings/AndroidStringDocumentWriter.java | 4 +- .../android/strings/AndroidStringElement.java | 92 ------------------- .../AndroidStringDocumentWriterTest.java | 15 +-- .../android/strings/test_resources_file.xml | 6 +- 21 files changed, 203 insertions(+), 185 deletions(-) diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rCA/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rCA/strings.xml index 626d7f70a2..06d4ae0878 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rCA/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rCA/strings.xml @@ -1,4 +1,4 @@ - + %1$,d heure à cuisiner diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rFR/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rFR/strings.xml index 626d7f70a2..06d4ae0878 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rFR/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-fr-rFR/strings.xml @@ -1,4 +1,4 @@ - + %1$,d heure à cuisiner diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ja-rJP/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ja-rJP/strings.xml index f6d60b9ef8..fdec8b186e 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ja-rJP/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ja-rJP/strings.xml @@ -1,4 +1,4 @@ - + 所要時間:%1$,d 時間 diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ru-rRU/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ru-rRU/strings.xml index 9ea8e22ee0..db73c90d99 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ru-rRU/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeDescription/res/values-ru-rRU/strings.xml @@ -1,4 +1,4 @@ - + Приготовление: %1$,d час diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rCA/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rCA/strings.xml index 7f8da59742..57d77bf1f7 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rCA/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rCA/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rFR/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rFR/strings.xml index ae2676f2b4..dd671274a9 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rFR/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-fr-rFR/strings.xml @@ -1,4 +1,4 @@ - + %1$,d heure à cuisiner diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ja-rJP/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ja-rJP/strings.xml index bfc2d7d33f..b6dc7ce899 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ja-rJP/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ja-rJP/strings.xml @@ -1,4 +1,4 @@ - + 所要時間:%1$,d 時間 diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ru-rRU/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ru-rRU/strings.xml index 4185c07f6e..4c831f9553 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ru-rRU/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslated/res/values-ru-rRU/strings.xml @@ -1,4 +1,4 @@ - + Приготовление: %1$,d час diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rCA/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rCA/strings.xml index 7f8da59742..57d77bf1f7 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rCA/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rCA/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rFR/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rFR/strings.xml index 26960ff3f8..aaddcd25e0 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rFR/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-fr-rFR/strings.xml @@ -1,4 +1,4 @@ - + %1$,d heure à cuisiner diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ja-rJP/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ja-rJP/strings.xml index 8f5a230089..e95e22548c 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ja-rJP/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ja-rJP/strings.xml @@ -1,4 +1,4 @@ - + 所要時間:%1$,d 時間 diff --git a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ru-rRU/strings.xml b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ru-rRU/strings.xml index 487445f368..a08ef21339 100644 --- a/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ru-rRU/strings.xml +++ b/cli/src/test/resources/com/box/l10n/mojito/cli/command/ImportLocalizedAssetCommandTest_IO/importAndroidStringsPostProcessing/expected/removeUntranslatedAndDescription/res/values-ru-rRU/strings.xml @@ -1,4 +1,4 @@ - + Приготовление: %1$,d час diff --git a/common/src/main/java/com/box/l10n/mojito/okapi/filters/AndroidFilter.java b/common/src/main/java/com/box/l10n/mojito/okapi/filters/AndroidFilter.java index e3de012438..349e21a3e1 100644 --- a/common/src/main/java/com/box/l10n/mojito/okapi/filters/AndroidFilter.java +++ b/common/src/main/java/com/box/l10n/mojito/okapi/filters/AndroidFilter.java @@ -466,7 +466,7 @@ public String execute(String xmlContent) { if (xmlContent == null || xmlContent.isBlank() - || (!shouldApplyPostProcessingRemoveUntranslatedExcluded && !removeTranslatableFalse)) { + || (!shouldApplyPostProcessingRemoveUntranslatedExcluded && !hasRemoveUntranslated())) { return xmlContent; } @@ -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) { diff --git a/common/src/test/java/com/box/l10n/mojito/okapi/filters/AndroidFilterTest.java b/common/src/test/java/com/box/l10n/mojito/okapi/filters/AndroidFilterTest.java index af14a80365..2f247934a2 100644 --- a/common/src/test/java/com/box/l10n/mojito/okapi/filters/AndroidFilterTest.java +++ b/common/src/test/java/com/box/l10n/mojito/okapi/filters/AndroidFilterTest.java @@ -138,7 +138,7 @@ public void testPostProcessingKeepDescription() { String output = androidFilePostProcessor.execute(input); String expected = """ - + somestring to keep @@ -182,7 +182,7 @@ public void testPostProcessingRemoveDescription() { String output = androidFilePostProcessor.execute(input); String expected = """ - + somestring to keep @@ -257,7 +257,7 @@ public void testPostProcessingRemoveTranslatableFalse() { String output = androidFilePostProcessor.execute(input); String expected = """ - + @@ -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 = + """ + + + somestring to keep + @#$untranslated$#@ + + + @#$untranslated$#@ + @#$untranslated$#@ + + + translated + @#$untranslated$#@ + + + pin fr + pins fr + + + """; + String output = androidFilePostProcessor.execute(input); + String expected = + """ + + + + + translated + + + """; + assertEquals(expected, output); + } + + @Test + public void testPostProcessingStandaloneYes() { + AndroidFilter.AndroidFilePostProcessor androidFilePostProcessor = + new AndroidFilter.AndroidFilePostProcessor(true, true, 2, true, false); + String input = + """ + + + somestring to keep + @#$untranslated$#@ + + + @#$untranslated$#@ + @#$untranslated$#@ + + + translated + @#$untranslated$#@ + + + pin fr + pins fr + + + """; + String output = androidFilePostProcessor.execute(input); + String expected = + """ + + + + + translated + + + """; + assertEquals(expected, output); + } } diff --git a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocument.java b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocument.java index 5919a27bf5..4ae2ebb2a8 100644 --- a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocument.java +++ b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocument.java @@ -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 { @@ -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); - } - } } diff --git a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentMapper.java b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentMapper.java index bdf49ec225..0cc53bbc0e 100644 --- a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentMapper.java +++ b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentMapper.java @@ -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; @@ -202,7 +201,7 @@ Stream 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); @@ -226,7 +225,7 @@ Stream 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; @@ -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; - } } diff --git a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentReader.java b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentReader.java index fa68788d1c..ebfd371e2d 100644 --- a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentReader.java +++ b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentReader.java @@ -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))); } @@ -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 getAttributeAs( + Element element, String attributeName, Function 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; + } } diff --git a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriter.java b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriter.java index 722b585b7e..ec23b2ebb7 100644 --- a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriter.java +++ b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriter.java @@ -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)); } } @@ -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 = diff --git a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringElement.java b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringElement.java index 4833b113f6..96fd248fdf 100644 --- a/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringElement.java +++ b/webapp/src/main/java/com/box/l10n/mojito/android/strings/AndroidStringElement.java @@ -1,13 +1,5 @@ package com.box.l10n.mojito.android.strings; -import com.google.common.base.Strings; -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - public class AndroidStringElement { static final String ROOT_ELEMENT_NAME = "resources"; @@ -17,88 +9,4 @@ public class AndroidStringElement { static final String NAME_ATTRIBUTE_NAME = "name"; static final String QUANTITY_ATTRIBUTE_NAME = "quantity"; static final String ID_ATTRIBUTE_NAME = "tmTextUnitId"; - - private final Element element; - - public AndroidStringElement(Element element) { - this.element = element; - } - - public AndroidStringElement(Node node) { - this((Element) node); - } - - public boolean isSingular() { - return element.getTagName().equals(SINGULAR_ELEMENT_NAME); - } - - public boolean isPlural() { - return element.getTagName().equals(PLURAL_ELEMENT_NAME); - } - - public boolean isPluralItem() { - return element.getTagName().equals(PLURAL_ITEM_ELEMENT_NAME); - } - - public String getTextContent() { - return Optional.ofNullable(element).map(Element::getTextContent).orElse(""); - } - - public Long getIdAttribute() { - return getLongAttribute(ID_ATTRIBUTE_NAME); - } - - public String getNameAttribute() { - return getAttribute(NAME_ATTRIBUTE_NAME); - } - - public String getAttribute(String name) { - return Optional.ofNullable(element.getAttribute(name)).orElse(""); - } - - public String getUnescapedContent() { - return removeEscape(element.getTextContent()); - } - - public Long getLongAttribute(String attributeName) { - return getAttributeAs(attributeName, Long::valueOf); - } - - public T getAttributeAs(String attributeName, Function converter) { - - T result = null; - - if (element.hasAttribute(attributeName)) { - result = converter.apply(element.getAttribute(attributeName)); - } - - return result; - } - - public void forEachPluralItem(Consumer consumer) { - - AndroidStringElement node; - NodeList nodeList = element.getElementsByTagName(PLURAL_ITEM_ELEMENT_NAME); - - for (int i = 0; i < nodeList.getLength(); i++) { - - node = new AndroidStringElement((Element) nodeList.item(i)); - - if (node.isPluralItem()) { - consumer.accept( - new AndroidPluralItem( - node.getAttribute(QUANTITY_ATTRIBUTE_NAME), - node.getLongAttribute(ID_ATTRIBUTE_NAME), - node.getTextContent())); - } - } - } - - private static String removeEscape(String str) { - return Strings.nullToEmpty(str) - .replaceAll("\\\\'", "'") - .replaceAll("\\\\\"", "\"") - .replace("\\\\\n", "\n") - .replaceAll("\\\\@", "@"); - } } diff --git a/webapp/src/test/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriterTest.java b/webapp/src/test/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriterTest.java index c9af4562bb..3ab441bf30 100644 --- a/webapp/src/test/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriterTest.java +++ b/webapp/src/test/java/com/box/l10n/mojito/android/strings/AndroidStringDocumentWriterTest.java @@ -1,5 +1,6 @@ package com.box.l10n.mojito.android.strings; +import static com.box.l10n.mojito.android.strings.AndroidStringDocumentWriter.escapeQuotes; import static org.assertj.core.api.Assertions.assertThat; import com.google.common.collect.ImmutableList; @@ -291,12 +292,14 @@ public void testGenerateWithHTML() { @Test public void testEscapeQuotes() { - assertThat(writer.escapeQuotes(null)).isEqualTo(""); - assertThat(writer.escapeQuotes("")).isEqualTo(""); - assertThat(writer.escapeQuotes("String")).isEqualTo("String"); - assertThat(writer.escapeQuotes("second\\\"String")).isEqualTo("second\\\\\"String"); - assertThat(writer.escapeQuotes("third\nString")).isEqualTo("third\\nString"); - assertThat(writer.escapeQuotes("fourth\ntest\\\"String\\\"")) + AndroidStringDocumentWriter.EscapeType escapeType = + AndroidStringDocumentWriter.EscapeType.QUOTE_AND_NEW_LINE; + assertThat(escapeQuotes(null, escapeType)).isEqualTo(null); + assertThat(escapeQuotes("", escapeType)).isEqualTo(""); + assertThat(escapeQuotes("String", escapeType)).isEqualTo("String"); + assertThat(escapeQuotes("second\\\"String", escapeType)).isEqualTo("second\\\\\"String"); + assertThat(escapeQuotes("third\nString", escapeType)).isEqualTo("third\\nString"); + assertThat(escapeQuotes("fourth\ntest\\\"String\\\"", escapeType)) .isEqualTo("fourth\\ntest\\\\\"String\\\\\""); } diff --git a/webapp/src/test/resources/com/box/l10n/mojito/android/strings/test_resources_file.xml b/webapp/src/test/resources/com/box/l10n/mojito/android/strings/test_resources_file.xml index 6f877f2698..1556c0f2c2 100644 --- a/webapp/src/test/resources/com/box/l10n/mojito/android/strings/test_resources_file.xml +++ b/webapp/src/test/resources/com/box/l10n/mojito/android/strings/test_resources_file.xml @@ -3,8 +3,10 @@ Dela... - Mer \\" dela - ei \\' kommentteja + Mer \\" dela + ei \\' kommentteja + Mer \" dela + ei \' kommentteja salto de \nlinea