Repository: uccser/cs-unplugged

Issue:
Allow translations of job badges resource
Created from #484.
Increase font size on job badges
@saranglove: While converting job badges resource to support translations, the font size seems to have been decreased. This should be changed back to the original font size to improve readability.


Discussion:

Resolving patch:
diff --git a/csunplugged/resources/generators/JobBadgesResourceGenerator.py b/csunplugged/resources/generators/JobBadgesResourceGenerator.py
--- a/csunplugged/resources/generators/JobBadgesResourceGenerator.py
+++ b/csunplugged/resources/generators/JobBadgesResourceGenerator.py
@@ -1,7 +1,9 @@
 """Class for Job Badges resource generator."""
 
-from PIL import Image
+from PIL import Image, ImageDraw
 from resources.utils.BaseResourceGenerator import BaseResourceGenerator
+from django.utils.translation import ugettext as _
+from utils.TextBoxDrawer import TextBoxDrawer
 
 
 class JobBadgesResourceGenerator(BaseResourceGenerator):
@@ -13,5 +15,45 @@ def data(self):
         Returns:
             A dictionary of the one page for the resource.
         """
-        image = Image.open("static/img/resources/job-badges/job-badges.png")
+        path = "static/img/resources/job-badges/job-badges"
+        image_path = "{}.png".format(path)
+        svg_path = "{}.svg".format(path)
+        image = Image.open(image_path)
+
+        draw = ImageDraw.Draw(image)
+        textbox_drawer = TextBoxDrawer(image, draw, svg_path)
+
+        hello_ids = [
+            "programmer_hello1",
+            "programmer_hello2",
+            "tester_hello1",
+            "tester_hello2",
+            "bot_hello1",
+            "bot_hello2",
+        ]
+
+        for hello_id in hello_ids:
+            textbox_drawer.write_text_box(
+                hello_id,
+                _("Hello, I'm a"),
+                horiz_just="center"
+            )
+
+        for i in range(1, 3):
+            textbox_drawer.write_text_box(
+                "programmer{}".format(i),
+                _("Programmer"),
+                horiz_just="center"
+            )
+            textbox_drawer.write_text_box(
+                "tester{}".format(i),
+                _("Tester"),
+                horiz_just="center"
+            )
+            textbox_drawer.write_text_box(
+                "bot{}".format(i),
+                _("Bot"),
+                horiz_just="center"
+            )
+
         return {"type": "image", "data": image}
diff --git a/csunplugged/utils/TextBoxDrawer.py b/csunplugged/utils/TextBoxDrawer.py
--- a/csunplugged/utils/TextBoxDrawer.py
+++ b/csunplugged/utils/TextBoxDrawer.py
@@ -88,7 +88,10 @@ def load_svg(svg_path):
             MissingSVGFile: SVG file could not be found at given path
         """
         try:
-            return ET.parse(svg_path).getroot()
+            svg = ET.parse(svg_path).getroot()
+            # Remove comments within SVG to avoid errors
+            ET.strip_tags(svg, ET.Comment)
+            return svg
         except OSError:
             raise MissingSVGFile(svg_path)
 
@@ -116,15 +119,29 @@ def get_box(self, box_id):
         Raises:
             TextBoxNotFoundInSVG: No textbox could be found with the given id
         """
+        # Replace underscores with hex code (mimic AI export behavior)
+        box_id = box_id.replace('_', '_x5F_')
+        # If starts with digit, replace with hex code (mimic AI export behavior)
+        if box_id[0].isdigit():
+            box_id = "_x{}_{}".format(hex(ord(box_id[0]))[2:], box_id[1:])
         text_layer = self.svg.find("{http://www.w3.org/2000/svg}g[@id=\"TEXT\"]")
-
+        namespaces = {
+            "x": "http://www.w3.org/2000/svg",
+            "re": "http://exslt.org/regular-expressions"
+        }
         try:
-            text_elem = text_layer.find("{{http://www.w3.org/2000/svg}}text[@id=\"{}\"]".format(box_id))
+            text_elem = text_layer.xpath(
+                "x:text[re:test(@id, '{}(_[0-9]_)?')]".format(box_id),
+                namespaces=namespaces
+            )[0]
             box_elem = text_elem.getprevious()
             assert box_elem is not None
         except Exception:
             try:
-                box_elem = text_layer.find("{{http://www.w3.org/2000/svg}}rect[@id=\"{}\"]".format(box_id))
+                box_elem = text_layer.xpath(
+                    "x:rect[re:test(@id, '{}(_[0-9]_)?')]".format(box_id),
+                    namespaces=namespaces
+                )[0]
                 text_elem = box_elem.getnext()
                 assert text_elem is not None
             except Exception:


Test patch:
diff --git a/csunplugged/tests/utils/text_box_drawer/basic.svg b/csunplugged/tests/utils/text_box_drawer/basic.svg
--- a/csunplugged/tests/utils/text_box_drawer/basic.svg
+++ b/csunplugged/tests/utils/text_box_drawer/basic.svg
@@ -5,6 +5,11 @@
     <rect x="100.0" y="200.0" style="fill:none;" width="50.0" height="75.0"/>
     <text id="box1" transform="matrix(1 0 0 1 112.9186 39.8638)" style="fill:#006838; font-family:'PatrickHand-Regular'; font-size:48px;">13 Digit Barcode</text>
     <rect id="onrectangle" x="100.0" y="200.0" style="fill:none;" width="82.6" height="27.5"/>
+    <rect id="element2" x="100.0" y="100.0" style="fill:none;" width="100.0" height="100.0"/>
+    <!-- Next element has id '123' in Adobe Illustrator program -->
+    <rect id="_x31_23" x="100.0" y="100.0" style="fill:none;" width="100.0" height="100.0"/>
+    <!-- Next element has id 'element_2' in Adobe Illustrator program -->
+    <rect id="element_x5F_2" x="100.0" y="100.0" style="fill:none;" width="100.0" height="100.0"/>
     <text transform="matrix(1 0 0 1 6.7101 91.6138)" style="fill:#006838; font-family:'PatrickHand-Regular'; font-size:18px;">Separate!</text>
     <rect x="100.0" y="200.0" style="fill:none;" width="86.1" height="72.5"/>
     <text id="withtspan" transform="matrix(1 0 0 1 6.7101 339.1938)">
diff --git a/csunplugged/tests/utils/text_box_drawer/test_text_box_drawer.py b/csunplugged/tests/utils/text_box_drawer/test_text_box_drawer.py
--- a/csunplugged/tests/utils/text_box_drawer/test_text_box_drawer.py
+++ b/csunplugged/tests/utils/text_box_drawer/test_text_box_drawer.py
@@ -69,6 +69,24 @@ def test_get_box_invalid_id(self):
         with self.assertRaises(TextBoxNotFoundInSVG):
             tbd.get_box("invalid")
 
+    def test_get_box_id_with_digit(self):
+        svg = os.path.join(BASE_PATH, "basic.svg")
+        image = Image.new("RGB", (2000, 4000))
+        tbd = TextBoxDrawer(image, None, svg)
+        tbd.get_box("element2")
+
+    def test_get_box_id_start_with_digit(self):
+        svg = os.path.join(BASE_PATH, "basic.svg")
+        image = Image.new("RGB", (2000, 4000))
+        tbd = TextBoxDrawer(image, None, svg)
+        tbd.get_box("123")
+
+    def test_get_box_id_with_underscore(self):
+        svg = os.path.join(BASE_PATH, "basic.svg")
+        image = Image.new("RGB", (2000, 4000))
+        tbd = TextBoxDrawer(image, None, svg)
+        tbd.get_box("element_2")
+
     def text_get_box_with_tspan(self):
         svg = os.path.join(BASE_PATH, "basic.svg")
         image = Image.new("RGB", (1000, 1000))