Repository: 12rambau/sepal_ui

Issue:
crowdin untranslated keys are marked as empty string
These string are interpreted as "something" by the translator leading to empty strings everywhere in the build-in component. 

They should be ignored

Discussion:

Patch:
diff --git a/docs/source/modules/sepal_ui.translator.Translator.rst b/docs/source/modules/sepal_ui.translator.Translator.rst
index 60fa976c..642a3ab6 100644
--- a/docs/source/modules/sepal_ui.translator.Translator.rst
+++ b/docs/source/modules/sepal_ui.translator.Translator.rst
@@ -27,6 +27,7 @@ sepal\_ui.translator.Translator
         ~Translator.find_target
         ~Translator.available_locales
         ~Translator.merge_dict
+        ~Translator.delete_empty
         
 .. automethod:: sepal_ui.translator.Translator.missing_keys
 
@@ -38,6 +39,8 @@ sepal\_ui.translator.Translator
 
 .. automethod:: sepal_ui.translator.Translator.merge_dict
 
+.. automethod:: sepal_ui.translator.Translator.delete_empty
+
 .. autofunction:: sepal_ui.translator.Translator.find_target
    
    
\ No newline at end of file
diff --git a/sepal_ui/message/en/locale.json b/sepal_ui/message/en/locale.json
index 632249f8..22b77234 100644
--- a/sepal_ui/message/en/locale.json
+++ b/sepal_ui/message/en/locale.json
@@ -2,11 +2,6 @@
 	"test_key": "Test key",
 	"status": "Status: {}",
 	"widgets": {
-        "navdrawer": {
-            "code": "Source code",
-            "wiki": "Wiki",
-            "bug": "Bug report"
-        },
 		"asset_select": {
 			"types": {
 				"0": "Raster",
diff --git a/sepal_ui/sepalwidgets/app.py b/sepal_ui/sepalwidgets/app.py
index b004b9ee..df1e81d8 100644
--- a/sepal_ui/sepalwidgets/app.py
+++ b/sepal_ui/sepalwidgets/app.py
@@ -255,19 +255,13 @@ class NavDrawer(v.NavigationDrawer, SepalWidget):
 
         code_link = []
         if code:
-            item_code = DrawerItem(
-                ms.widgets.navdrawer.code, icon="far fa-file-code", href=code
-            )
+            item_code = DrawerItem("Source code", icon="far fa-file-code", href=code)
             code_link.append(item_code)
         if wiki:
-            item_wiki = DrawerItem(
-                ms.widgets.navdrawer.wiki, icon="fas fa-book-open", href=wiki
-            )
+            item_wiki = DrawerItem("Wiki", icon="fas fa-book-open", href=wiki)
             code_link.append(item_wiki)
         if issue:
-            item_bug = DrawerItem(
-                ms.widgets.navdrawer.bug, icon="fas fa-bug", href=issue
-            )
+            item_bug = DrawerItem("Bug report", icon="fas fa-bug", href=issue)
             code_link.append(item_bug)
 
         children = [
diff --git a/sepal_ui/translator/translator.py b/sepal_ui/translator/translator.py
index f0a39f77..f4fdec47 100644
--- a/sepal_ui/translator/translator.py
+++ b/sepal_ui/translator/translator.py
@@ -166,7 +166,8 @@ class Translator(SimpleNamespace):
         Identify numbered dictionnaries embeded in the dict and transform them into lists
 
         This function is an helper to prevent deprecation after the introduction of pontoon for translation.
-        The user is now force to use keys even for numbered lists. SimpleNamespace doesn't support integer indexing so this function will transform back this "numbered" dictionnary (with integer keys) into lists.
+        The user is now force to use keys even for numbered lists. SimpleNamespace doesn't support integer indexing
+        so this function will transform back this "numbered" dictionnary (with integer keys) into lists.
 
         Args:
             d (dict): the dictionnary to sanitize
@@ -252,7 +253,8 @@ class Translator(SimpleNamespace):
         """
         gather all the .json file in the provided l10n folder as 1 single json dict
 
-        the json dict will be sanitysed and the key will be used as if they were coming from 1 single file. be careful with duplication
+        the json dict will be sanitysed and the key will be used as if they were coming from 1 single file.
+        be careful with duplication. empty string keys will be removed.
 
         Args:
             folder (pathlib.path)
@@ -264,6 +266,29 @@ class Translator(SimpleNamespace):
 
         final_json = {}
         for f in folder.glob("*.json"):
-            final_json = {**final_json, **cls.sanitize(json.loads(f.read_text()))}
+            tmp_dict = cls.delete_empty(json.loads(f.read_text()))
+            final_json = {**final_json, **cls.sanitize(tmp_dict)}
 
         return final_json
+
+    @versionadded(version="2.8.1")
+    @classmethod
+    def delete_empty(cls, d):
+        """
+        Remove empty strings ("") recursively from the dictionaries. This is to prevent untranslated strings from
+        Crowdin to be uploaded. The dictionnary must only embed dictionnaries and no lists.
+
+        Args:
+            d (dict): the dictionnary to sanitize
+
+        Return:
+            (dict): the sanitized dictionnary
+
+        """
+        for k, v in list(d.items()):
+            if isinstance(v, dict):
+                cls.delete_empty(v)
+            elif v == "":
+                del d[k]
+
+        return d


Test patch:
diff --git a/tests/test_Translator.py b/tests/test_Translator.py
index 930a533e..c6d0e85e 100644
--- a/tests/test_Translator.py
+++ b/tests/test_Translator.py
@@ -49,25 +49,29 @@ class TestTranslator:
         # a test dict with many embeded numbered list
         # but also an already existing list
         test = {
-            "foo1": {"0": "foo2", "1": "foo3"},
-            "foo4": {
-                "foo5": {"0": "foo6", "1": "foo7"},
-                "foo8": "foo9",
-            },
-            "foo10": ["foo11", "foo12"],
+            "a": {"0": "b", "1": "c"},
+            "d": {"e": {"0": "f", "1": "g"}, "h": "i"},
+            "j": ["k", "l"],
         }
 
         # the sanitize version of this
         result = {
-            "foo1": ["foo2", "foo3"],
-            "foo4": {"foo5": ["foo6", "foo7"], "foo8": "foo9"},
-            "foo10": ["foo11", "foo12"],
+            "a": ["b", "c"],
+            "d": {"e": ["f", "g"], "h": "i"},
+            "j": ["k", "l"],
         }
 
         assert Translator.sanitize(test) == result
 
         return
 
+    def test_delete_empty(self):
+
+        test = {"a": "", "b": 1, "c": {"d": ""}, "e": {"f": "", "g": 2}}
+        result = {"b": 1, "c": {}, "e": {"g": 2}}
+
+        assert Translator.delete_empty(test) == result
+
     def test_missing_keys(self, translation_folder):
 
         # check that all keys are in the fr dict