We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow comments in dialog and voc files
Having a way to comment dialog and voc files would ease the translation process as the original developer can provide context useful for the translator, and the translator can explain things that motivate his/her choice of words.

I am thinking for instance of voc files where similar words to the target word are used to trigger the skill in order to workaround speech to text errors. Documenting that the meaning of those words should not be translated in a comment would be practical.

Example: the "high" word triggers the hello world skill because "high" is similar to "hi". In the Spanish translation we have "hola" (for "hello") and we should have "ola" (literally "wave") because it sounds like "hola"

Other file formats usually used for translation purposes allow developer/translator comments (see the .po file format for instance)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mycroft/skills/skill_data.py`
Content:
```
1 # Copyright 2018 Mycroft AI Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 
16 """Module containing methods needed to load skill
17 data such as dialogs, intents and regular expressions.
18 """
19 
20 from os import listdir
21 from os.path import splitext, join
22 import re
23 
24 from mycroft.messagebus.message import Message
25 
26 
27 def load_vocab_from_file(path, vocab_type, emitter):
28     """Load Mycroft vocabulary from file
29     The vocab is sent to the intent handler using the message bus
30 
31     Args:
32         path:           path to vocabulary file (*.voc)
33         vocab_type:     keyword name
34         emitter:        emitter to access the message bus
35         skill_id(str):  skill id
36     """
37     if path.endswith('.voc'):
38         with open(path, 'r') as voc_file:
39             for line in voc_file.readlines():
40                 parts = line.strip().split("|")
41                 entity = parts[0]
42                 emitter.emit(Message("register_vocab", {
43                     'start': entity, 'end': vocab_type
44                 }))
45                 for alias in parts[1:]:
46                     emitter.emit(Message("register_vocab", {
47                         'start': alias, 'end': vocab_type, 'alias_of': entity
48                     }))
49 
50 
51 def load_regex_from_file(path, emitter, skill_id):
52     """Load regex from file
53     The regex is sent to the intent handler using the message bus
54 
55     Args:
56         path:       path to vocabulary file (*.voc)
57         emitter:    emitter to access the message bus
58     """
59     if path.endswith('.rx'):
60         with open(path, 'r') as reg_file:
61             for line in reg_file.readlines():
62                 re.compile(munge_regex(line.strip(), skill_id))
63                 emitter.emit(
64                     Message("register_vocab",
65                             {'regex': munge_regex(line.strip(), skill_id)}))
66 
67 
68 def load_vocabulary(basedir, emitter, skill_id):
69     """Load vocabulary from all files in the specified directory.
70 
71     Args:
72         basedir (str): path of directory to load from
73         emitter (messagebus emitter): websocket used to send the vocab to
74                                       the intent service
75         skill_id: skill the data belongs to
76     """
77     for vocab_file in listdir(basedir):
78         if vocab_file.endswith(".voc"):
79             vocab_type = to_letters(skill_id) + splitext(vocab_file)[0]
80             load_vocab_from_file(
81                 join(basedir, vocab_file), vocab_type, emitter)
82 
83 
84 def load_regex(basedir, emitter, skill_id):
85     """Load regex from all files in the specified directory.
86 
87     Args:
88         basedir (str): path of directory to load from
89         emitter (messagebus emitter): websocket used to send the vocab to
90                                       the intent service
91         skill_id (int): skill identifier
92     """
93     for regex_type in listdir(basedir):
94         if regex_type.endswith(".rx"):
95             load_regex_from_file(
96                 join(basedir, regex_type), emitter, skill_id)
97 
98 
99 def to_letters(number):
100     """Convert number to string of letters.
101 
102     0 -> A, 1 -> B, etc.
103 
104     Args:
105         number (int): number to be converted
106     Returns:
107         (str) String of letters
108     """
109     ret = ''
110     for n in str(number).strip('-'):
111         ret += chr(65 + int(n))
112     return ret
113 
114 
115 def munge_regex(regex, skill_id):
116     """Insert skill id as letters into match groups.
117 
118     Args:
119         regex (str): regex string
120         skill_id (int): skill identifier
121     Returns:
122         (str) munged regex
123     """
124     base = '(?P<' + to_letters(skill_id)
125     return base.join(regex.split('(?P<'))
126 
127 
128 def munge_intent_parser(intent_parser, name, skill_id):
129     """Rename intent keywords to make them skill exclusive
130     This gives the intent parser an exclusive name in the
131     format <skill_id>:<name>.  The keywords are given unique
132     names in the format <Skill id as letters><Intent name>.
133 
134     The function will not munge instances that's already been
135     munged
136 
137     Args:
138         intent_parser: (IntentParser) object to update
139         name: (str) Skill name
140         skill_id: (int) skill identifier
141     """
142     # Munge parser name
143     if str(skill_id) + ':' not in name:
144         intent_parser.name = str(skill_id) + ':' + name
145     else:
146         intent_parser.name = name
147 
148     # Munge keywords
149     skill_id = to_letters(skill_id)
150     # Munge required keyword
151     reqs = []
152     for i in intent_parser.requires:
153         if skill_id not in i[0]:
154             kw = (skill_id + i[0], skill_id + i[0])
155             reqs.append(kw)
156         else:
157             reqs.append(i)
158     intent_parser.requires = reqs
159 
160     # Munge optional keywords
161     opts = []
162     for i in intent_parser.optional:
163         if skill_id not in i[0]:
164             kw = (skill_id + i[0], skill_id + i[0])
165             opts.append(kw)
166         else:
167             opts.append(i)
168     intent_parser.optional = opts
169 
170     # Munge at_least_one keywords
171     at_least_one = []
172     for i in intent_parser.at_least_one:
173         element = [skill_id + e.replace(skill_id, '') for e in i]
174         at_least_one.append(tuple(element))
175     intent_parser.at_least_one = at_least_one
176
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mycroft/skills/skill_data.py b/mycroft/skills/skill_data.py
--- a/mycroft/skills/skill_data.py
+++ b/mycroft/skills/skill_data.py
@@ -37,6 +37,8 @@
     if path.endswith('.voc'):
         with open(path, 'r') as voc_file:
             for line in voc_file.readlines():
+                if line.startswith("#"):
+                    continue
                 parts = line.strip().split("|")
                 entity = parts[0]
                 emitter.emit(Message("register_vocab", {
@@ -59,6 +61,8 @@
     if path.endswith('.rx'):
         with open(path, 'r') as reg_file:
             for line in reg_file.readlines():
+                if line.startswith("#"):
+                    continue
                 re.compile(munge_regex(line.strip(), skill_id))
                 emitter.emit(
                     Message("register_vocab",

{"golden_diff": "diff --git a/mycroft/skills/skill_data.py b/mycroft/skills/skill_data.py\n--- a/mycroft/skills/skill_data.py\n+++ b/mycroft/skills/skill_data.py\n@@ -37,6 +37,8 @@\n     if path.endswith('.voc'):\n         with open(path, 'r') as voc_file:\n             for line in voc_file.readlines():\n+                if line.startswith(\"#\"):\n+                    continue\n                 parts = line.strip().split(\"|\")\n                 entity = parts[0]\n                 emitter.emit(Message(\"register_vocab\", {\n@@ -59,6 +61,8 @@\n     if path.endswith('.rx'):\n         with open(path, 'r') as reg_file:\n             for line in reg_file.readlines():\n+                if line.startswith(\"#\"):\n+                    continue\n                 re.compile(munge_regex(line.strip(), skill_id))\n                 emitter.emit(\n                     Message(\"register_vocab\",\n", "issue": "Allow comments in dialog and voc files\nHaving a way to comment dialog and voc files would ease the translation process as the original developer can provide context useful for the translator, and the translator can explain things that motivate his/her choice of words.\r\n\r\nI am thinking for instance of voc files where similar words to the target word are used to trigger the skill in order to workaround speech to text errors. Documenting that the meaning of those words should not be translated in a comment would be practical.\r\n\r\nExample: the \"high\" word triggers the hello world skill because \"high\" is similar to \"hi\". In the Spanish translation we have \"hola\" (for \"hello\") and we should have \"ola\" (literally \"wave\") because it sounds like \"hola\"\r\n\r\nOther file formats usually used for translation purposes allow developer/translator comments (see the .po file format for instance)\n", "before_files": [{"content": "# Copyright 2018 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\"\"\"Module containing methods needed to load skill\ndata such as dialogs, intents and regular expressions.\n\"\"\"\n\nfrom os import listdir\nfrom os.path import splitext, join\nimport re\n\nfrom mycroft.messagebus.message import Message\n\n\ndef load_vocab_from_file(path, vocab_type, emitter):\n    \"\"\"Load Mycroft vocabulary from file\n    The vocab is sent to the intent handler using the message bus\n\n    Args:\n        path:           path to vocabulary file (*.voc)\n        vocab_type:     keyword name\n        emitter:        emitter to access the message bus\n        skill_id(str):  skill id\n    \"\"\"\n    if path.endswith('.voc'):\n        with open(path, 'r') as voc_file:\n            for line in voc_file.readlines():\n                parts = line.strip().split(\"|\")\n                entity = parts[0]\n                emitter.emit(Message(\"register_vocab\", {\n                    'start': entity, 'end': vocab_type\n                }))\n                for alias in parts[1:]:\n                    emitter.emit(Message(\"register_vocab\", {\n                        'start': alias, 'end': vocab_type, 'alias_of': entity\n                    }))\n\n\ndef load_regex_from_file(path, emitter, skill_id):\n    \"\"\"Load regex from file\n    The regex is sent to the intent handler using the message bus\n\n    Args:\n        path:       path to vocabulary file (*.voc)\n        emitter:    emitter to access the message bus\n    \"\"\"\n    if path.endswith('.rx'):\n        with open(path, 'r') as reg_file:\n            for line in reg_file.readlines():\n                re.compile(munge_regex(line.strip(), skill_id))\n                emitter.emit(\n                    Message(\"register_vocab\",\n                            {'regex': munge_regex(line.strip(), skill_id)}))\n\n\ndef load_vocabulary(basedir, emitter, skill_id):\n    \"\"\"Load vocabulary from all files in the specified directory.\n\n    Args:\n        basedir (str): path of directory to load from\n        emitter (messagebus emitter): websocket used to send the vocab to\n                                      the intent service\n        skill_id: skill the data belongs to\n    \"\"\"\n    for vocab_file in listdir(basedir):\n        if vocab_file.endswith(\".voc\"):\n            vocab_type = to_letters(skill_id) + splitext(vocab_file)[0]\n            load_vocab_from_file(\n                join(basedir, vocab_file), vocab_type, emitter)\n\n\ndef load_regex(basedir, emitter, skill_id):\n    \"\"\"Load regex from all files in the specified directory.\n\n    Args:\n        basedir (str): path of directory to load from\n        emitter (messagebus emitter): websocket used to send the vocab to\n                                      the intent service\n        skill_id (int): skill identifier\n    \"\"\"\n    for regex_type in listdir(basedir):\n        if regex_type.endswith(\".rx\"):\n            load_regex_from_file(\n                join(basedir, regex_type), emitter, skill_id)\n\n\ndef to_letters(number):\n    \"\"\"Convert number to string of letters.\n\n    0 -> A, 1 -> B, etc.\n\n    Args:\n        number (int): number to be converted\n    Returns:\n        (str) String of letters\n    \"\"\"\n    ret = ''\n    for n in str(number).strip('-'):\n        ret += chr(65 + int(n))\n    return ret\n\n\ndef munge_regex(regex, skill_id):\n    \"\"\"Insert skill id as letters into match groups.\n\n    Args:\n        regex (str): regex string\n        skill_id (int): skill identifier\n    Returns:\n        (str) munged regex\n    \"\"\"\n    base = '(?P<' + to_letters(skill_id)\n    return base.join(regex.split('(?P<'))\n\n\ndef munge_intent_parser(intent_parser, name, skill_id):\n    \"\"\"Rename intent keywords to make them skill exclusive\n    This gives the intent parser an exclusive name in the\n    format <skill_id>:<name>.  The keywords are given unique\n    names in the format <Skill id as letters><Intent name>.\n\n    The function will not munge instances that's already been\n    munged\n\n    Args:\n        intent_parser: (IntentParser) object to update\n        name: (str) Skill name\n        skill_id: (int) skill identifier\n    \"\"\"\n    # Munge parser name\n    if str(skill_id) + ':' not in name:\n        intent_parser.name = str(skill_id) + ':' + name\n    else:\n        intent_parser.name = name\n\n    # Munge keywords\n    skill_id = to_letters(skill_id)\n    # Munge required keyword\n    reqs = []\n    for i in intent_parser.requires:\n        if skill_id not in i[0]:\n            kw = (skill_id + i[0], skill_id + i[0])\n            reqs.append(kw)\n        else:\n            reqs.append(i)\n    intent_parser.requires = reqs\n\n    # Munge optional keywords\n    opts = []\n    for i in intent_parser.optional:\n        if skill_id not in i[0]:\n            kw = (skill_id + i[0], skill_id + i[0])\n            opts.append(kw)\n        else:\n            opts.append(i)\n    intent_parser.optional = opts\n\n    # Munge at_least_one keywords\n    at_least_one = []\n    for i in intent_parser.at_least_one:\n        element = [skill_id + e.replace(skill_id, '') for e in i]\n        at_least_one.append(tuple(element))\n    intent_parser.at_least_one = at_least_one\n", "path": "mycroft/skills/skill_data.py"}], "after_files": [{"content": "# Copyright 2018 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\"\"\"Module containing methods needed to load skill\ndata such as dialogs, intents and regular expressions.\n\"\"\"\n\nfrom os import listdir\nfrom os.path import splitext, join\nimport re\n\nfrom mycroft.messagebus.message import Message\n\n\ndef load_vocab_from_file(path, vocab_type, emitter):\n    \"\"\"Load Mycroft vocabulary from file\n    The vocab is sent to the intent handler using the message bus\n\n    Args:\n        path:           path to vocabulary file (*.voc)\n        vocab_type:     keyword name\n        emitter:        emitter to access the message bus\n        skill_id(str):  skill id\n    \"\"\"\n    if path.endswith('.voc'):\n        with open(path, 'r') as voc_file:\n            for line in voc_file.readlines():\n                if line.startswith(\"#\"):\n                    continue\n                parts = line.strip().split(\"|\")\n                entity = parts[0]\n                emitter.emit(Message(\"register_vocab\", {\n                    'start': entity, 'end': vocab_type\n                }))\n                for alias in parts[1:]:\n                    emitter.emit(Message(\"register_vocab\", {\n                        'start': alias, 'end': vocab_type, 'alias_of': entity\n                    }))\n\n\ndef load_regex_from_file(path, emitter, skill_id):\n    \"\"\"Load regex from file\n    The regex is sent to the intent handler using the message bus\n\n    Args:\n        path:       path to vocabulary file (*.voc)\n        emitter:    emitter to access the message bus\n    \"\"\"\n    if path.endswith('.rx'):\n        with open(path, 'r') as reg_file:\n            for line in reg_file.readlines():\n                if line.startswith(\"#\"):\n                    continue\n                re.compile(munge_regex(line.strip(), skill_id))\n                emitter.emit(\n                    Message(\"register_vocab\",\n                            {'regex': munge_regex(line.strip(), skill_id)}))\n\n\ndef load_vocabulary(basedir, emitter, skill_id):\n    \"\"\"Load vocabulary from all files in the specified directory.\n\n    Args:\n        basedir (str): path of directory to load from\n        emitter (messagebus emitter): websocket used to send the vocab to\n                                      the intent service\n        skill_id: skill the data belongs to\n    \"\"\"\n    for vocab_file in listdir(basedir):\n        if vocab_file.endswith(\".voc\"):\n            vocab_type = to_letters(skill_id) + splitext(vocab_file)[0]\n            load_vocab_from_file(\n                join(basedir, vocab_file), vocab_type, emitter)\n\n\ndef load_regex(basedir, emitter, skill_id):\n    \"\"\"Load regex from all files in the specified directory.\n\n    Args:\n        basedir (str): path of directory to load from\n        emitter (messagebus emitter): websocket used to send the vocab to\n                                      the intent service\n        skill_id (int): skill identifier\n    \"\"\"\n    for regex_type in listdir(basedir):\n        if regex_type.endswith(\".rx\"):\n            load_regex_from_file(\n                join(basedir, regex_type), emitter, skill_id)\n\n\ndef to_letters(number):\n    \"\"\"Convert number to string of letters.\n\n    0 -> A, 1 -> B, etc.\n\n    Args:\n        number (int): number to be converted\n    Returns:\n        (str) String of letters\n    \"\"\"\n    ret = ''\n    for n in str(number).strip('-'):\n        ret += chr(65 + int(n))\n    return ret\n\n\ndef munge_regex(regex, skill_id):\n    \"\"\"Insert skill id as letters into match groups.\n\n    Args:\n        regex (str): regex string\n        skill_id (int): skill identifier\n    Returns:\n        (str) munged regex\n    \"\"\"\n    base = '(?P<' + to_letters(skill_id)\n    return base.join(regex.split('(?P<'))\n\n\ndef munge_intent_parser(intent_parser, name, skill_id):\n    \"\"\"Rename intent keywords to make them skill exclusive\n    This gives the intent parser an exclusive name in the\n    format <skill_id>:<name>.  The keywords are given unique\n    names in the format <Skill id as letters><Intent name>.\n\n    The function will not munge instances that's already been\n    munged\n\n    Args:\n        intent_parser: (IntentParser) object to update\n        name: (str) Skill name\n        skill_id: (int) skill identifier\n    \"\"\"\n    # Munge parser name\n    if str(skill_id) + ':' not in name:\n        intent_parser.name = str(skill_id) + ':' + name\n    else:\n        intent_parser.name = name\n\n    # Munge keywords\n    skill_id = to_letters(skill_id)\n    # Munge required keyword\n    reqs = []\n    for i in intent_parser.requires:\n        if skill_id not in i[0]:\n            kw = (skill_id + i[0], skill_id + i[0])\n            reqs.append(kw)\n        else:\n            reqs.append(i)\n    intent_parser.requires = reqs\n\n    # Munge optional keywords\n    opts = []\n    for i in intent_parser.optional:\n        if skill_id not in i[0]:\n            kw = (skill_id + i[0], skill_id + i[0])\n            opts.append(kw)\n        else:\n            opts.append(i)\n    intent_parser.optional = opts\n\n    # Munge at_least_one keywords\n    at_least_one = []\n    for i in intent_parser.at_least_one:\n        element = [skill_id + e.replace(skill_id, '') for e in i]\n        at_least_one.append(tuple(element))\n    intent_parser.at_least_one = at_least_one\n", "path": "mycroft/skills/skill_data.py"}]}