We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Nested YAML dictionary is serialized as OrderedDict in PO file
### Problem
If there is a nested dictionary in a YAML file, the resulting po file contains a string starting with `OrderedDict`
### Expectation
The nested keys are shown correctly in the PO file
### How to reproduce
The following YAML input
```
e1:
- s1: Subtag 1
```
given to `yaml2po -i test.yml -o test.po` results in the PO file content of
```
#: t1-%3E[0]
msgid "OrderedDict([('s1', 'Subtag 1')])"
msgstr ""
```
I would expect something like
```
#: t1-%3E[0]-%3Es1
msgid "Subtag 1"
msgstr ""
```
Perhaps it may be related to #3819.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `translate/storage/yaml.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2016 Michal Čihař
4 #
5 # This file is part of the Translate Toolkit.
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, see <http://www.gnu.org/licenses/>.
19 
20 r"""Class that manages YAML data files for translation
21 """
22 
23 from __future__ import absolute_import
24 from __future__ import unicode_literals
25 
26 import uuid
27 
28 import six
29 from ruamel.yaml import YAML, YAMLError
30 from ruamel.yaml.comments import CommentedMap
31 
32 from translate.lang.data import cldr_plural_categories, plural_tags
33 from translate.misc.deprecation import deprecated
34 from translate.misc.multistring import multistring
35 from translate.storage import base
36 
37 
38 class YAMLUnit(base.TranslationUnit):
39     """A YAML entry"""
40 
41     def __init__(self, source=None, **kwargs):
42         self._id = None
43         if source:
44             self.source = source
45         super(YAMLUnit, self).__init__(source)
46 
47     @property
48     def source(self):
49         return self.target
50 
51     @source.setter
52     def source(self, source):
53         self.target = source
54 
55     # Deprecated on 2.3.1
56     @deprecated("Use `source` property instead")
57     def getsource(self):
58         return self.source
59 
60     def setid(self, value):
61         self._id = value
62 
63     def getid(self):
64         # Ensure we have ID (for serialization)
65         if self._id is None:
66             self._id = str(uuid.uuid4())
67         return self._id
68 
69     def getlocations(self):
70         return [self.getid()]
71 
72 
73 class YAMLFile(base.TranslationStore):
74     """A YAML file"""
75 
76     UnitClass = YAMLUnit
77 
78     def __init__(self, inputfile=None, **kwargs):
79         """construct a YAML file, optionally reading in from inputfile."""
80         super(YAMLFile, self).__init__(**kwargs)
81         self.filename = ''
82         self._file = u''
83         if inputfile is not None:
84             self.parse(inputfile)
85 
86     def get_root_node(self, node):
87         """Returns root node for serialize"""
88         return node
89 
90     def serialize_value(self, value):
91         return value
92 
93     def serialize(self, out):
94         def nested_set(target, path, value):
95             value = self.serialize_value(value)
96             if len(path) > 1:
97                 if len(path) == 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():
98                     if path[0] not in target:
99                         target[path[0]] = []
100                     target[path[0]].append(value)
101                 else:
102                     # Add empty dict in case there is value and we
103                     # expect dict
104                     if path[0] not in target or not isinstance(target[path[0]], dict):
105                         target[path[0]] = CommentedMap()
106                     nested_set(target[path[0]], path[1:], value)
107             else:
108                 target[path[0]] = value
109 
110         units = CommentedMap()
111         for unit in self.unit_iter():
112             nested_set(units, unit.getid().split('->'), unit.target)
113         yaml = YAML()
114         yaml.default_flow_style = False
115         yaml.dump(self.get_root_node(units), out)
116 
117     def _parse_dict(self, data, prev):
118         for k, v in six.iteritems(data):
119             if not isinstance(k, six.string_types):
120                 raise base.ParseError(
121                     'Key not string: {0}/{1} ({2})'.format(prev, k, type(k))
122                 )
123 
124             for x in self._flatten(v, '->'.join((prev, k)) if prev else k):
125                 yield x
126 
127     def _flatten(self, data, prev=""):
128         """Flatten YAML dictionary.
129         """
130         if isinstance(data, dict):
131             for x in self._parse_dict(data, prev):
132                 yield x
133         else:
134             if isinstance(data, six.string_types):
135                 yield (prev, data)
136             elif isinstance(data, (bool, int)):
137                 yield (prev, str(data))
138             elif isinstance(data, list):
139                 for k, v in enumerate(data):
140                     key = '[{0}]'.format(k)
141                     yield ('->'.join((prev, key)), six.text_type(v))
142             elif data is None:
143                 pass
144             else:
145                 raise ValueError("We don't handle these values:\n"
146                                  "Type: %s\n"
147                                  "Data: %s\n"
148                                  "Previous: %s" % (type(data), data, prev))
149 
150     def preprocess(self, data):
151         """Preprocess hook for child formats"""
152         return data
153 
154     def parse(self, input):
155         """parse the given file or file source string"""
156         if hasattr(input, 'name'):
157             self.filename = input.name
158         elif not getattr(self, 'filename', ''):
159             self.filename = ''
160         if hasattr(input, "read"):
161             src = input.read()
162             input.close()
163             input = src
164         if isinstance(input, bytes):
165             input = input.decode('utf-8')
166         yaml = YAML()
167         try:
168             self._file = yaml.load(input)
169         except YAMLError as e:
170             message = e.problem if hasattr(e, 'problem') else e.message
171             if hasattr(e, 'problem_mark'):
172                 message += ' {0}'.format(e.problem_mark)
173             raise base.ParseError(message)
174 
175         self._file = self.preprocess(self._file)
176 
177         for k, data in self._flatten(self._file):
178             unit = self.UnitClass(data)
179             unit.setid(k)
180             self.addunit(unit)
181 
182 
183 class RubyYAMLFile(YAMLFile):
184     """Ruby YAML file, it has language code as first node."""
185 
186     def preprocess(self, data):
187         if isinstance(data, CommentedMap) and len(data) == 1:
188             lang = list(data.keys())[0]
189             self.settargetlanguage(lang)
190             return data[lang]
191         return data
192 
193     def get_root_node(self, node):
194         """Returns root node for serialize"""
195         if self.targetlanguage is not None:
196             result = CommentedMap()
197             result[self.targetlanguage] = node
198             return result
199         return node
200 
201     def _parse_dict(self, data, prev):
202         # Does this look like a plural?
203         if data and all((x in cldr_plural_categories for x in data.keys())):
204             # Ensure we have correct plurals ordering.
205             values = [data[item] for item in cldr_plural_categories if item in data]
206             yield (prev, multistring(values))
207             return
208 
209         # Handle normal dict
210         for x in super(RubyYAMLFile, self)._parse_dict(data, prev):
211             yield x
212 
213     def serialize_value(self, value):
214         if not isinstance(value, multistring):
215             return value
216 
217         tags = plural_tags.get(self.targetlanguage, plural_tags['en'])
218 
219         strings = [six.text_type(s) for s in value.strings]
220 
221         # Sync plural_strings elements to plural_tags count.
222         if len(strings) < len(tags):
223             strings += [''] * (len(tags) - len(strings))
224         strings = strings[:len(tags)]
225 
226         return CommentedMap(zip(tags, strings))
227
```
--- 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/translate/storage/yaml.py b/translate/storage/yaml.py
--- a/translate/storage/yaml.py
+++ b/translate/storage/yaml.py
@@ -94,10 +94,15 @@
         def nested_set(target, path, value):
             value = self.serialize_value(value)
             if len(path) > 1:
-                if len(path) == 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():
+                if len(path) >= 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():
                     if path[0] not in target:
                         target[path[0]] = []
-                    target[path[0]].append(value)
+                    if len(path) > 2:
+                        new_value = CommentedMap()
+                        nested_set(new_value, path[2:], value)
+                        target[path[0]].append(new_value)
+                    else:
+                        target[path[0]].append(value)
                 else:
                     # Add empty dict in case there is value and we
                     # expect dict
@@ -138,7 +143,8 @@
             elif isinstance(data, list):
                 for k, v in enumerate(data):
                     key = '[{0}]'.format(k)
-                    yield ('->'.join((prev, key)), six.text_type(v))
+                    for value in self._flatten(v, '->'.join((prev, key))):
+                        yield value
             elif data is None:
                 pass
             else:

{"golden_diff": "diff --git a/translate/storage/yaml.py b/translate/storage/yaml.py\n--- a/translate/storage/yaml.py\n+++ b/translate/storage/yaml.py\n@@ -94,10 +94,15 @@\n         def nested_set(target, path, value):\n             value = self.serialize_value(value)\n             if len(path) > 1:\n-                if len(path) == 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():\n+                if len(path) >= 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():\n                     if path[0] not in target:\n                         target[path[0]] = []\n-                    target[path[0]].append(value)\n+                    if len(path) > 2:\n+                        new_value = CommentedMap()\n+                        nested_set(new_value, path[2:], value)\n+                        target[path[0]].append(new_value)\n+                    else:\n+                        target[path[0]].append(value)\n                 else:\n                     # Add empty dict in case there is value and we\n                     # expect dict\n@@ -138,7 +143,8 @@\n             elif isinstance(data, list):\n                 for k, v in enumerate(data):\n                     key = '[{0}]'.format(k)\n-                    yield ('->'.join((prev, key)), six.text_type(v))\n+                    for value in self._flatten(v, '->'.join((prev, key))):\n+                        yield value\n             elif data is None:\n                 pass\n             else:\n", "issue": "Nested YAML dictionary is serialized as OrderedDict in PO file\n### Problem\r\nIf there is a nested dictionary in a YAML file, the resulting po file contains a string starting with `OrderedDict`\r\n### Expectation\r\nThe nested keys are shown correctly in the PO file\r\n### How to reproduce\r\nThe following YAML input\r\n```\r\ne1:\r\n- s1: Subtag 1\r\n```\r\ngiven to `yaml2po -i test.yml -o test.po` results in the PO file content of\r\n```\r\n#: t1-%3E[0]\r\nmsgid \"OrderedDict([('s1', 'Subtag 1')])\"\r\nmsgstr \"\"\r\n```\r\nI would expect something like\r\n```\r\n#: t1-%3E[0]-%3Es1\r\nmsgid \"Subtag 1\"\r\nmsgstr \"\"\r\n```\r\nPerhaps it may be related to #3819.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2016 Michal \u010ciha\u0159\n#\n# This file is part of the Translate Toolkit.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\nr\"\"\"Class that manages YAML data files for translation\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nimport uuid\n\nimport six\nfrom ruamel.yaml import YAML, YAMLError\nfrom ruamel.yaml.comments import CommentedMap\n\nfrom translate.lang.data import cldr_plural_categories, plural_tags\nfrom translate.misc.deprecation import deprecated\nfrom translate.misc.multistring import multistring\nfrom translate.storage import base\n\n\nclass YAMLUnit(base.TranslationUnit):\n    \"\"\"A YAML entry\"\"\"\n\n    def __init__(self, source=None, **kwargs):\n        self._id = None\n        if source:\n            self.source = source\n        super(YAMLUnit, self).__init__(source)\n\n    @property\n    def source(self):\n        return self.target\n\n    @source.setter\n    def source(self, source):\n        self.target = source\n\n    # Deprecated on 2.3.1\n    @deprecated(\"Use `source` property instead\")\n    def getsource(self):\n        return self.source\n\n    def setid(self, value):\n        self._id = value\n\n    def getid(self):\n        # Ensure we have ID (for serialization)\n        if self._id is None:\n            self._id = str(uuid.uuid4())\n        return self._id\n\n    def getlocations(self):\n        return [self.getid()]\n\n\nclass YAMLFile(base.TranslationStore):\n    \"\"\"A YAML file\"\"\"\n\n    UnitClass = YAMLUnit\n\n    def __init__(self, inputfile=None, **kwargs):\n        \"\"\"construct a YAML file, optionally reading in from inputfile.\"\"\"\n        super(YAMLFile, self).__init__(**kwargs)\n        self.filename = ''\n        self._file = u''\n        if inputfile is not None:\n            self.parse(inputfile)\n\n    def get_root_node(self, node):\n        \"\"\"Returns root node for serialize\"\"\"\n        return node\n\n    def serialize_value(self, value):\n        return value\n\n    def serialize(self, out):\n        def nested_set(target, path, value):\n            value = self.serialize_value(value)\n            if len(path) > 1:\n                if len(path) == 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():\n                    if path[0] not in target:\n                        target[path[0]] = []\n                    target[path[0]].append(value)\n                else:\n                    # Add empty dict in case there is value and we\n                    # expect dict\n                    if path[0] not in target or not isinstance(target[path[0]], dict):\n                        target[path[0]] = CommentedMap()\n                    nested_set(target[path[0]], path[1:], value)\n            else:\n                target[path[0]] = value\n\n        units = CommentedMap()\n        for unit in self.unit_iter():\n            nested_set(units, unit.getid().split('->'), unit.target)\n        yaml = YAML()\n        yaml.default_flow_style = False\n        yaml.dump(self.get_root_node(units), out)\n\n    def _parse_dict(self, data, prev):\n        for k, v in six.iteritems(data):\n            if not isinstance(k, six.string_types):\n                raise base.ParseError(\n                    'Key not string: {0}/{1} ({2})'.format(prev, k, type(k))\n                )\n\n            for x in self._flatten(v, '->'.join((prev, k)) if prev else k):\n                yield x\n\n    def _flatten(self, data, prev=\"\"):\n        \"\"\"Flatten YAML dictionary.\n        \"\"\"\n        if isinstance(data, dict):\n            for x in self._parse_dict(data, prev):\n                yield x\n        else:\n            if isinstance(data, six.string_types):\n                yield (prev, data)\n            elif isinstance(data, (bool, int)):\n                yield (prev, str(data))\n            elif isinstance(data, list):\n                for k, v in enumerate(data):\n                    key = '[{0}]'.format(k)\n                    yield ('->'.join((prev, key)), six.text_type(v))\n            elif data is None:\n                pass\n            else:\n                raise ValueError(\"We don't handle these values:\\n\"\n                                 \"Type: %s\\n\"\n                                 \"Data: %s\\n\"\n                                 \"Previous: %s\" % (type(data), data, prev))\n\n    def preprocess(self, data):\n        \"\"\"Preprocess hook for child formats\"\"\"\n        return data\n\n    def parse(self, input):\n        \"\"\"parse the given file or file source string\"\"\"\n        if hasattr(input, 'name'):\n            self.filename = input.name\n        elif not getattr(self, 'filename', ''):\n            self.filename = ''\n        if hasattr(input, \"read\"):\n            src = input.read()\n            input.close()\n            input = src\n        if isinstance(input, bytes):\n            input = input.decode('utf-8')\n        yaml = YAML()\n        try:\n            self._file = yaml.load(input)\n        except YAMLError as e:\n            message = e.problem if hasattr(e, 'problem') else e.message\n            if hasattr(e, 'problem_mark'):\n                message += ' {0}'.format(e.problem_mark)\n            raise base.ParseError(message)\n\n        self._file = self.preprocess(self._file)\n\n        for k, data in self._flatten(self._file):\n            unit = self.UnitClass(data)\n            unit.setid(k)\n            self.addunit(unit)\n\n\nclass RubyYAMLFile(YAMLFile):\n    \"\"\"Ruby YAML file, it has language code as first node.\"\"\"\n\n    def preprocess(self, data):\n        if isinstance(data, CommentedMap) and len(data) == 1:\n            lang = list(data.keys())[0]\n            self.settargetlanguage(lang)\n            return data[lang]\n        return data\n\n    def get_root_node(self, node):\n        \"\"\"Returns root node for serialize\"\"\"\n        if self.targetlanguage is not None:\n            result = CommentedMap()\n            result[self.targetlanguage] = node\n            return result\n        return node\n\n    def _parse_dict(self, data, prev):\n        # Does this look like a plural?\n        if data and all((x in cldr_plural_categories for x in data.keys())):\n            # Ensure we have correct plurals ordering.\n            values = [data[item] for item in cldr_plural_categories if item in data]\n            yield (prev, multistring(values))\n            return\n\n        # Handle normal dict\n        for x in super(RubyYAMLFile, self)._parse_dict(data, prev):\n            yield x\n\n    def serialize_value(self, value):\n        if not isinstance(value, multistring):\n            return value\n\n        tags = plural_tags.get(self.targetlanguage, plural_tags['en'])\n\n        strings = [six.text_type(s) for s in value.strings]\n\n        # Sync plural_strings elements to plural_tags count.\n        if len(strings) < len(tags):\n            strings += [''] * (len(tags) - len(strings))\n        strings = strings[:len(tags)]\n\n        return CommentedMap(zip(tags, strings))\n", "path": "translate/storage/yaml.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2016 Michal \u010ciha\u0159\n#\n# This file is part of the Translate Toolkit.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\nr\"\"\"Class that manages YAML data files for translation\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nimport uuid\n\nimport six\nfrom ruamel.yaml import YAML, YAMLError\nfrom ruamel.yaml.comments import CommentedMap\n\nfrom translate.lang.data import cldr_plural_categories, plural_tags\nfrom translate.misc.deprecation import deprecated\nfrom translate.misc.multistring import multistring\nfrom translate.storage import base\n\n\nclass YAMLUnit(base.TranslationUnit):\n    \"\"\"A YAML entry\"\"\"\n\n    def __init__(self, source=None, **kwargs):\n        self._id = None\n        if source:\n            self.source = source\n        super(YAMLUnit, self).__init__(source)\n\n    @property\n    def source(self):\n        return self.target\n\n    @source.setter\n    def source(self, source):\n        self.target = source\n\n    # Deprecated on 2.3.1\n    @deprecated(\"Use `source` property instead\")\n    def getsource(self):\n        return self.source\n\n    def setid(self, value):\n        self._id = value\n\n    def getid(self):\n        # Ensure we have ID (for serialization)\n        if self._id is None:\n            self._id = str(uuid.uuid4())\n        return self._id\n\n    def getlocations(self):\n        return [self.getid()]\n\n\nclass YAMLFile(base.TranslationStore):\n    \"\"\"A YAML file\"\"\"\n\n    UnitClass = YAMLUnit\n\n    def __init__(self, inputfile=None, **kwargs):\n        \"\"\"construct a YAML file, optionally reading in from inputfile.\"\"\"\n        super(YAMLFile, self).__init__(**kwargs)\n        self.filename = ''\n        self._file = u''\n        if inputfile is not None:\n            self.parse(inputfile)\n\n    def get_root_node(self, node):\n        \"\"\"Returns root node for serialize\"\"\"\n        return node\n\n    def serialize_value(self, value):\n        return value\n\n    def serialize(self, out):\n        def nested_set(target, path, value):\n            value = self.serialize_value(value)\n            if len(path) > 1:\n                if len(path) >= 2 and path[1] and path[1][0] == '[' and path[1][-1] == ']' and path[1][1:-1].isdigit():\n                    if path[0] not in target:\n                        target[path[0]] = []\n                    if len(path) > 2:\n                        new_value = CommentedMap()\n                        nested_set(new_value, path[2:], value)\n                        target[path[0]].append(new_value)\n                    else:\n                        target[path[0]].append(value)\n                else:\n                    # Add empty dict in case there is value and we\n                    # expect dict\n                    if path[0] not in target or not isinstance(target[path[0]], dict):\n                        target[path[0]] = CommentedMap()\n                    nested_set(target[path[0]], path[1:], value)\n            else:\n                target[path[0]] = value\n\n        units = CommentedMap()\n        for unit in self.unit_iter():\n            nested_set(units, unit.getid().split('->'), unit.target)\n        yaml = YAML()\n        yaml.default_flow_style = False\n        yaml.dump(self.get_root_node(units), out)\n\n    def _parse_dict(self, data, prev):\n        for k, v in six.iteritems(data):\n            if not isinstance(k, six.string_types):\n                raise base.ParseError(\n                    'Key not string: {0}/{1} ({2})'.format(prev, k, type(k))\n                )\n\n            for x in self._flatten(v, '->'.join((prev, k)) if prev else k):\n                yield x\n\n    def _flatten(self, data, prev=\"\"):\n        \"\"\"Flatten YAML dictionary.\n        \"\"\"\n        if isinstance(data, dict):\n            for x in self._parse_dict(data, prev):\n                yield x\n        else:\n            if isinstance(data, six.string_types):\n                yield (prev, data)\n            elif isinstance(data, (bool, int)):\n                yield (prev, str(data))\n            elif isinstance(data, list):\n                for k, v in enumerate(data):\n                    key = '[{0}]'.format(k)\n                    for value in self._flatten(v, '->'.join((prev, key))):\n                        yield value\n            elif data is None:\n                pass\n            else:\n                raise ValueError(\"We don't handle these values:\\n\"\n                                 \"Type: %s\\n\"\n                                 \"Data: %s\\n\"\n                                 \"Previous: %s\" % (type(data), data, prev))\n\n    def preprocess(self, data):\n        \"\"\"Preprocess hook for child formats\"\"\"\n        return data\n\n    def parse(self, input):\n        \"\"\"parse the given file or file source string\"\"\"\n        if hasattr(input, 'name'):\n            self.filename = input.name\n        elif not getattr(self, 'filename', ''):\n            self.filename = ''\n        if hasattr(input, \"read\"):\n            src = input.read()\n            input.close()\n            input = src\n        if isinstance(input, bytes):\n            input = input.decode('utf-8')\n        yaml = YAML()\n        try:\n            self._file = yaml.load(input)\n        except YAMLError as e:\n            message = e.problem if hasattr(e, 'problem') else e.message\n            if hasattr(e, 'problem_mark'):\n                message += ' {0}'.format(e.problem_mark)\n            raise base.ParseError(message)\n\n        self._file = self.preprocess(self._file)\n\n        for k, data in self._flatten(self._file):\n            unit = self.UnitClass(data)\n            unit.setid(k)\n            self.addunit(unit)\n\n\nclass RubyYAMLFile(YAMLFile):\n    \"\"\"Ruby YAML file, it has language code as first node.\"\"\"\n\n    def preprocess(self, data):\n        if isinstance(data, CommentedMap) and len(data) == 1:\n            lang = list(data.keys())[0]\n            self.settargetlanguage(lang)\n            return data[lang]\n        return data\n\n    def get_root_node(self, node):\n        \"\"\"Returns root node for serialize\"\"\"\n        if self.targetlanguage is not None:\n            result = CommentedMap()\n            result[self.targetlanguage] = node\n            return result\n        return node\n\n    def _parse_dict(self, data, prev):\n        # Does this look like a plural?\n        if data and all((x in cldr_plural_categories for x in data.keys())):\n            # Ensure we have correct plurals ordering.\n            values = [data[item] for item in cldr_plural_categories if item in data]\n            yield (prev, multistring(values))\n            return\n\n        # Handle normal dict\n        for x in super(RubyYAMLFile, self)._parse_dict(data, prev):\n            yield x\n\n    def serialize_value(self, value):\n        if not isinstance(value, multistring):\n            return value\n\n        tags = plural_tags.get(self.targetlanguage, plural_tags['en'])\n\n        strings = [six.text_type(s) for s in value.strings]\n\n        # Sync plural_strings elements to plural_tags count.\n        if len(strings) < len(tags):\n            strings += [''] * (len(tags) - len(strings))\n        strings = strings[:len(tags)]\n\n        return CommentedMap(zip(tags, strings))\n", "path": "translate/storage/yaml.py"}]}