summaryrefslogtreecommitdiffstats
path: root/pendulum/locales/locale.py
blob: 154db423e69d03035b58f3adc56a6e2fa4dc511a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import re

from importlib import import_module
from typing import Any
from typing import Optional
from typing import Union

from pendulum.utils._compat import basestring
from pendulum.utils._compat import decode


class Locale:
    """
    Represent a specific locale.
    """

    _cache = {}

    def __init__(self, locale, data):  # type: (str, Any) -> None
        self._locale = locale
        self._data = data
        self._key_cache = {}

    @classmethod
    def load(cls, locale):  # type: (Union[str, Locale]) -> Locale
        if isinstance(locale, Locale):
            return locale

        locale = cls.normalize_locale(locale)
        if locale in cls._cache:
            return cls._cache[locale]

        # Checking locale existence
        actual_locale = locale
        locale_path = os.path.join(os.path.dirname(__file__), actual_locale)
        while not os.path.exists(locale_path):
            if actual_locale == locale:
                raise ValueError("Locale [{}] does not exist.".format(locale))

            actual_locale = actual_locale.split("_")[0]

        m = import_module("pendulum.locales.{}.locale".format(actual_locale))

        cls._cache[locale] = cls(locale, m.locale)

        return cls._cache[locale]

    @classmethod
    def normalize_locale(cls, locale):  # type: (str) -> str
        m = re.match("([a-z]{2})[-_]([a-z]{2})", locale, re.I)
        if m:
            return "{}_{}".format(m.group(1).lower(), m.group(2).lower())
        else:
            return locale.lower()

    def get(self, key, default=None):  # type: (str, Optional[Any]) -> Any
        if key in self._key_cache:
            return self._key_cache[key]

        parts = key.split(".")
        try:
            result = self._data[parts[0]]
            for part in parts[1:]:
                result = result[part]
        except KeyError:
            result = default

        if isinstance(result, basestring):
            result = decode(result)

        self._key_cache[key] = result

        return self._key_cache[key]

    def translation(self, key):  # type: (str) -> Any
        return self.get("translations.{}".format(key))

    def plural(self, number):  # type: (int) -> str
        return decode(self._data["plural"](number))

    def ordinal(self, number):  # type: (int) -> str
        return decode(self._data["ordinal"](number))

    def ordinalize(self, number):  # type: (int) -> str
        ordinal = self.get("custom.ordinal.{}".format(self.ordinal(number)))

        if not ordinal:
            return decode("{}".format(number))

        return decode("{}{}".format(number, ordinal))

    def match_translation(self, key, value):
        translations = self.translation(key)
        if value not in translations.values():
            return None

        return {v: k for k, v in translations.items()}[value]

    def __repr__(self):
        return "{}('{}')".format(self.__class__.__name__, self._locale)