From b36eb36cf2707b8d9e9f359145b7fcb31a21e51a Mon Sep 17 00:00:00 2001 From: Jean Aurambault Date: Fri, 30 Aug 2024 20:22:49 -0700 Subject: [PATCH] Add post-processing to AndroidFilter to remove non-translatable elements Introduced a new post-processing option, postRemoveTranslatableFalse, in AndroidFilter. This option removes elements with the attribute translatable="false", ensuring only translatable elements are written to the output. Note: This does not prevent these elements from being pushed to Mojito, this is a post-processing step. Due to an existing bug in the filter, singular elements are properly excluded from translation, but plural ones are not (to fix later). But excluded elements from translation in Mojito are still outputted, while this new option ensures they are removed from the final output. Typically used with pull -fo postRemoveTranslatableFalse=true. --- .../mojito/okapi/filters/AndroidFilter.java | 41 ++++++++++++++-- .../okapi/filters/AndroidFilterTest.java | 47 +++++++++++++++++-- 2 files changed, 81 insertions(+), 7 deletions(-) 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 b48ae4d12..656b05938 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 @@ -59,6 +59,9 @@ public class AndroidFilter extends XMLFilter { private static final String POST_PROCESS_INDENT = "postProcessIndent"; + private static final String POST_PROCESS_REMOVE_TRANSLATABLE_FALSE = + "postRemoveTranslatableFalse"; + private static final Pattern PATTERN_PLURAL_START = Pattern.compile(""); private static final Pattern PATTERN_XML_COMMENT = Pattern.compile(""); @@ -110,6 +113,8 @@ public List getConfigurations() { boolean removeDescription = false; + boolean removeTranslatableFalse = false; + int postProcessIndent = 2; @Override @@ -128,7 +133,9 @@ public void open(RawDocument input) { // in the TranslateStep input.setAnnotation( new OutputDocumentPostProcessingAnnotation( - new AndroidFilePostProcessing(removeDescription, postProcessIndent)::execute, + new AndroidFilePostProcessing( + removeDescription, postProcessIndent, removeTranslatableFalse) + ::execute, removeDescription)); } @@ -152,6 +159,12 @@ void applyFilterOptions(RawDocument input) { removeDescription = b; }); + filterOptions.getBoolean( + POST_PROCESS_REMOVE_TRANSLATABLE_FALSE, + b -> { + removeTranslatableFalse = b; + }); + filterOptions.getInteger( POST_PROCESS_INDENT, i -> { @@ -424,10 +437,13 @@ void updateFormInSkeleton(ITextUnit textUnit) { static class AndroidFilePostProcessing { static final String DESCRIPTION_ATTRIBUTE = "description"; boolean removeDescription; + boolean removeTranslatableFalse; int indent; - AndroidFilePostProcessing(boolean removeDescription, int indent) { + AndroidFilePostProcessing( + boolean removeDescription, int indent, boolean removeTranslatableFalse) { this.removeDescription = removeDescription; + this.removeTranslatableFalse = removeTranslatableFalse; this.indent = indent; } @@ -491,6 +507,9 @@ String execute(String xmlContent) { } } + if (removeTranslatableFalse) { + removeTranslatableFalseElements(document); + } removeWhitespaceNodes(document); TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -521,7 +540,7 @@ String execute(String xmlContent) { } } - public void removeWhitespaceNodes(Node node) { + void removeWhitespaceNodes(Node node) { NodeList childNodes = node.getChildNodes(); for (int i = childNodes.getLength() - 1; i >= 0; i--) { Node childNode = childNodes.item(i); @@ -532,5 +551,21 @@ public void removeWhitespaceNodes(Node node) { } } } + + void removeTranslatableFalseElements(Node node) { + NodeList childNodes = node.getChildNodes(); + for (int i = childNodes.getLength() - 1; i >= 0; i--) { + Node childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) childNode; + if (element.hasAttribute("translatable") + && element.getAttribute("translatable").equals("false")) { + node.removeChild(element); + } else { + removeTranslatableFalseElements(element); + } + } + } + } } } 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 e8f7397a6..99dd4e0d0 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 @@ -113,7 +113,7 @@ void testUnescaping(String input, String expected) { @Test public void testPostProcessingKeepDescription() { AndroidFilter.AndroidFilePostProcessing androidFilePostProcessing = - new AndroidFilter.AndroidFilePostProcessing(false, 2); + new AndroidFilter.AndroidFilePostProcessing(false, 2, false); String input = """ @@ -157,7 +157,7 @@ public void testPostProcessingKeepDescription() { @Test public void testPostProcessingRemoveDescription() { AndroidFilter.AndroidFilePostProcessing androidFilePostProcessing = - new AndroidFilter.AndroidFilePostProcessing(true, 2); + new AndroidFilter.AndroidFilePostProcessing(true, 2, false); String input = """ @@ -201,7 +201,7 @@ public void testPostProcessingRemoveDescription() { @Test public void testPostProcessingEmptyFile() { AndroidFilter.AndroidFilePostProcessing androidFilePostProcessing = - new AndroidFilter.AndroidFilePostProcessing(true, 2); + new AndroidFilter.AndroidFilePostProcessing(true, 2, false); String input = ""; String output = androidFilePostProcessing.execute(input); String expected = ""; @@ -211,7 +211,7 @@ public void testPostProcessingEmptyFile() { @Test public void testPostProcessingNoProlog() { AndroidFilter.AndroidFilePostProcessing androidFilePostProcessing = - new AndroidFilter.AndroidFilePostProcessing(true, 2); + new AndroidFilter.AndroidFilePostProcessing(true, 2, false); String input = """ @@ -228,4 +228,43 @@ public void testPostProcessingNoProlog() { """; assertEquals(expected, output); } + + @Test + public void testPostProcessingRemoveTranslatableFalse() { + AndroidFilter.AndroidFilePostProcessing androidFilePostProcessing = + new AndroidFilter.AndroidFilePostProcessing(true, 2, true); + String input = + """ + + + somestring to keep + @#$untranslated$#@ + + + @#$untranslated$#@ + @#$untranslated$#@ + + + translated + @#$untranslated$#@ + + + pin fr + pins fr + + + """; + String output = androidFilePostProcessing.execute(input); + String expected = + """ + + + + + translated + + + """; + assertEquals(expected, output); + } }