Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pendulum/locales/locale.py: 32%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

66 statements  

1from __future__ import annotations 

2 

3import re 

4 

5from pathlib import Path 

6from typing import Any 

7from typing import ClassVar 

8from typing import Dict 

9from typing import cast 

10 

11 

12class Locale: 

13 """ 

14 Represent a specific locale. 

15 """ 

16 

17 _cache: ClassVar[dict[str, Locale]] = {} 

18 

19 def __init__(self, locale: str, data: Any) -> None: 

20 self._locale: str = locale 

21 self._data: Any = data 

22 self._key_cache: dict[str, str] = {} 

23 

24 @classmethod 

25 def load(cls, locale: str | Locale) -> Locale: 

26 from importlib import import_module, resources 

27 

28 if isinstance(locale, Locale): 

29 return locale 

30 

31 locale = cls.normalize_locale(locale) 

32 if locale in cls._cache: 

33 return cls._cache[locale] 

34 

35 # Checking locale existence 

36 actual_locale = locale 

37 locale_path = cast(Path, resources.files(__package__).joinpath(actual_locale)) 

38 while not locale_path.exists(): 

39 if actual_locale == locale: 

40 raise ValueError(f"Locale [{locale}] does not exist.") 

41 

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

43 

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

45 

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

47 

48 return cls._cache[locale] 

49 

50 @classmethod 

51 def normalize_locale(cls, locale: str) -> str: 

52 m = re.fullmatch("([a-z]{2})[-_]([a-z]{2})", locale, re.I) 

53 if m: 

54 return f"{m.group(1).lower()}_{m.group(2).lower()}" 

55 else: 

56 return locale.lower() 

57 

58 def get(self, key: str, default: Any | None = None) -> Any: 

59 if key in self._key_cache: 

60 return self._key_cache[key] 

61 

62 parts = key.split(".") 

63 try: 

64 result = self._data[parts[0]] 

65 for part in parts[1:]: 

66 result = result[part] 

67 except KeyError: 

68 result = default 

69 

70 self._key_cache[key] = result 

71 

72 return self._key_cache[key] 

73 

74 def translation(self, key: str) -> Any: 

75 return self.get(f"translations.{key}") 

76 

77 def plural(self, number: int) -> str: 

78 return cast(str, self._data["plural"](number)) 

79 

80 def ordinal(self, number: int) -> str: 

81 return cast(str, self._data["ordinal"](number)) 

82 

83 def ordinalize(self, number: int) -> str: 

84 ordinal = self.get(f"custom.ordinal.{self.ordinal(number)}") 

85 

86 if not ordinal: 

87 return f"{number}" 

88 

89 return f"{number}{ordinal}" 

90 

91 def match_translation(self, key: str, value: Any) -> dict[str, str] | None: 

92 translations = self.translation(key) 

93 if value not in translations.values(): 

94 return None 

95 

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

97 

98 def __repr__(self) -> str: 

99 return f"{self.__class__.__name__}('{self._locale}')"