# Path: openformats/strings.py
# class OpenString(object):
#     """
#     This class will abstract away the business of generating hashes out of your
#     strings and will serve as a place to get translations from when compiling.
#     Several OpenStrings in our process define a *Stringset*, which is simply a
#     python list of OpenStrings. To create an OpenString, you need 2 arguments:
# 
#     * The 'key'
# 
#       Something in your source file that uniquely identifies the section that
#       the source string originated from. It might be helpful for your
#       compiler to use something that appears in the same form in language
#       files as well.
# 
#     * The 'string' or 'plural forms of the string':
# 
#       If the file format you're working with does not support plural forms,
#       or if the string in question is not pluralized, you can just supply the
#       string itself as the second argument. If you string is pluralized
#       however, you have to supply all plural forms in a dictionary with the
#       rule numbers as keys. For example::
# 
#           OpenString("UNREAD MESSAGES",
#                      {1: "You have %s unread message",
#                       5: "You have %s unread messages"})
# 
#     * There are a number of optional keyword arguments to `OpenString`:
# 
#       context, order, character_limit, occurrences, developer_comment, flags,
#       fuzzy, obsolete
# 
#     Their main purpose is to provide context to the translators so that they
#     can achieve higher quality. Two of them however, though optional, are
#     highly recommended:
# 
#     * Context
# 
#       This is also taken into account when producing the hash, so if you
#       can't ensure that your keys aren't unique within the source file, you
#       can still get away with ensuring that the `(key, context)` pair is.
# 
#     * Order
# 
#       If you provide an order (integer), Transifex will save it in the
#       database and then, when you try to compile a template against a
#       stringset fetched from Transifex, it will already be ordered, even if
#       it contains translations. This can allow you to optimize the
#       compilation process as the order that the hashes appear in the template
#       will be the same as the order of strings in the stringset.
# 
#       Another valuable outcome is that the order will be preserved when the
#       strings are shown to translators which can provide context and thus
#       improve translation quality.
# 
#     Once you have created an OpenString, you can get it's hash using the
#     `template_replacement` property
#     """
# 
#     DEFAULTS = {
#         'context': "",
#         'order': None,
#         'character_limit': None,
#         'occurrences': None,
#         'developer_comment': "",
#         'flags': "",
#         'fuzzy': False,
#         'obsolete': False,
#         'tags': None
#     }
# 
#     def __init__(self, key, string_or_strings, **kwargs):
#         self.key = key
#         if isinstance(string_or_strings, dict):
#             self.pluralized = len(string_or_strings) > 1
#             self._strings = {
#                 key: value
#                 for key, value in six.iteritems(string_or_strings)
#             }
#         else:
#             self.pluralized = False
#             self._strings = {5: string_or_strings}
# 
#         for key, value in six.iteritems(self.DEFAULTS):
#             setattr(self, key, kwargs.get(key, value))
# 
#         if 'pluralized' in kwargs:
#             self.pluralized = kwargs['pluralized']
# 
#         self._string_hash = None
# 
#     def __hash__(self):
#         return hash((self.key, self.context, self._strings[5]))
# 
#     def __repr__(self):
#         return next(
#             (
#                 self._strings.get(i) for i in six.moves.xrange(5, -1, -1)
#                 if self._strings.get(i)
#             ), 'Invalid string'
#         ).encode('utf-8')
# 
#     @property
#     def string(self):
#         if self.pluralized:
#             return self._strings
#         else:
#             return self._strings[5]
# 
#     @property
#     def strings(self):
#         return self._strings
# 
#     def _get_string_hash(self):
#         keys = [self.key, self.context or '']
#         return md5(':'.join(keys).encode('utf-8')).hexdigest()
# 
#     @property
#     def string_hash(self):
#         if self._string_hash is None:
#             self._string_hash = self._get_string_hash()
#         return self._string_hash
# 
#     @property
#     def template_replacement(self):
#         suffix = 'pl' if self.pluralized else 'tr'
#         return "{hash}_{suffix}".format(hash=self.string_hash, suffix=suffix)
# 
# Path: openformats/tests/utils/strings.py
# def generate_random_string(length=20):
#     return ''.join((choice(ascii_letters + digits)
#                     for _ in six.moves.xrange(length)))


from hashlib import md5
from random import randint
from unittest import TestCase
from openformats.strings import OpenString
from openformats.tests.utils import generate_random_string
import six
        self.assertEqual(open_string.string, random_string)

    def test_plurals_are_returned(self):
        random_strings = {
            i: generate_random_string()
            for i in six.moves.xrange(randint(10, 20))
            }
        open_string = OpenString('test', random_strings)

        self.assertTrue(open_string.pluralized)
        self.assertEqual(open_string.string, random_strings)

    def test_multiples_are_plural(self):
        test_strings = {
            i: generate_random_string()
            for i in six.moves.xrange(randint(5, 10))
            }
        open_string = OpenString('test', test_strings)

        self.assertEqual(open_string._strings, test_strings)
        self.assertTrue(open_string.pluralized)

    def test_defaults_are_assigned_to_self(self):
        random_property_name = generate_random_string()
        random_default = generate_random_string()

        backup_defaults = OpenString.DEFAULTS
        OpenString.DEFAULTS = {
            random_property_name: random_default
        }

# Path: openformats/strings.py
# class OpenString(object):
#     """
#     This class will abstract away the business of generating hashes out of your
#     strings and will serve as a place to get translations from when compiling.
#     Several OpenStrings in our process define a *Stringset*, which is simply a
#     python list of OpenStrings. To create an OpenString, you need 2 arguments:
# 
#     * The 'key'
# 
#       Something in your source file that uniquely identifies the section that
#       the source string originated from. It might be helpful for your
#       compiler to use something that appears in the same form in language
#       files as well.
# 
#     * The 'string' or 'plural forms of the string':
# 
#       If the file format you're working with does not support plural forms,
#       or if the string in question is not pluralized, you can just supply the
#       string itself as the second argument. If you string is pluralized
#       however, you have to supply all plural forms in a dictionary with the
#       rule numbers as keys. For example::
# 
#           OpenString("UNREAD MESSAGES",
#                      {1: "You have %s unread message",
#                       5: "You have %s unread messages"})
# 
#     * There are a number of optional keyword arguments to `OpenString`:
# 
#       context, order, character_limit, occurrences, developer_comment, flags,
#       fuzzy, obsolete
# 
#     Their main purpose is to provide context to the translators so that they
#     can achieve higher quality. Two of them however, though optional, are
#     highly recommended:
# 
#     * Context
# 
#       This is also taken into account when producing the hash, so if you
#       can't ensure that your keys aren't unique within the source file, you
#       can still get away with ensuring that the `(key, context)` pair is.
# 
#     * Order
# 
#       If you provide an order (integer), Transifex will save it in the
#       database and then, when you try to compile a template against a
#       stringset fetched from Transifex, it will already be ordered, even if
#       it contains translations. This can allow you to optimize the
#       compilation process as the order that the hashes appear in the template
#       will be the same as the order of strings in the stringset.
# 
#       Another valuable outcome is that the order will be preserved when the
#       strings are shown to translators which can provide context and thus
#       improve translation quality.
# 
#     Once you have created an OpenString, you can get it's hash using the
#     `template_replacement` property
#     """
# 
#     DEFAULTS = {
#         'context': "",
#         'order': None,
#         'character_limit': None,
#         'occurrences': None,
#         'developer_comment': "",
#         'flags': "",
#         'fuzzy': False,
#         'obsolete': False,
#         'tags': None
#     }
# 
#     def __init__(self, key, string_or_strings, **kwargs):
#         self.key = key
#         if isinstance(string_or_strings, dict):
#             self.pluralized = len(string_or_strings) > 1
#             self._strings = {
#                 key: value
#                 for key, value in six.iteritems(string_or_strings)
#             }
#         else:
#             self.pluralized = False
#             self._strings = {5: string_or_strings}
# 
#         for key, value in six.iteritems(self.DEFAULTS):
#             setattr(self, key, kwargs.get(key, value))
# 
#         if 'pluralized' in kwargs:
#             self.pluralized = kwargs['pluralized']
# 
#         self._string_hash = None
# 
#     def __hash__(self):
#         return hash((self.key, self.context, self._strings[5]))
# 
#     def __repr__(self):
#         return next(
#             (
#                 self._strings.get(i) for i in six.moves.xrange(5, -1, -1)
#                 if self._strings.get(i)
#             ), 'Invalid string'
#         ).encode('utf-8')
# 
#     @property
#     def string(self):
#         if self.pluralized:
#             return self._strings
#         else:
#             return self._strings[5]
# 
#     @property
#     def strings(self):
#         return self._strings
# 
#     def _get_string_hash(self):
#         keys = [self.key, self.context or '']
#         return md5(':'.join(keys).encode('utf-8')).hexdigest()
# 
#     @property
#     def string_hash(self):
#         if self._string_hash is None:
#             self._string_hash = self._get_string_hash()
#         return self._string_hash
# 
#     @property
#     def template_replacement(self):
#         suffix = 'pl' if self.pluralized else 'tr'
#         return "{hash}_{suffix}".format(hash=self.string_hash, suffix=suffix)
# 
# Path: openformats/tests/utils/strings.py
# def generate_random_string(length=20):
#     return ''.join((choice(ascii_letters + digits)
#                     for _ in six.moves.xrange(length)))


# Path: openformats/tests/test_strings.py
from hashlib import md5
from random import randint
from unittest import TestCase
from openformats.strings import OpenString
from openformats.tests.utils import generate_random_string
import six

        self.assertEqual(open_string.string, random_string)

    def test_plurals_are_returned(self):
        random_strings = {
            i: generate_random_string()
            for i in six.moves.xrange(randint(10, 20))
            }
        open_string = OpenString('test', random_strings)

        self.assertTrue(open_string.pluralized)
        self.assertEqual(open_string.string, random_strings)

    def test_multiples_are_plural(self):
        test_strings = {
            i: generate_random_string()
            for i in six.moves.xrange(randint(5, 10))
            }
        open_string = OpenString('test', test_strings)

        self.assertEqual(open_string._strings, test_strings)
        self.assertTrue(open_string.pluralized)

    def test_defaults_are_assigned_to_self(self):
        random_property_name = generate_random_string()
        random_default = generate_random_string()

        backup_defaults = OpenString.DEFAULTS
        OpenString.DEFAULTS = {
            random_property_name: random_default
        }

        open_string = OpenString('test', 'test')