1# -*- coding: utf-8 -*- 2# 3# Copyright (C) 2007-2011 Edgewall Software, 2013-2021 the Babel team 4# All rights reserved. 5# 6# This software is licensed as described in the file LICENSE, which 7# you should have received as part of this distribution. The terms 8# are also available at http://babel.edgewall.org/wiki/License. 9# 10# This software consists of voluntary contributions made by many 11# individuals. For the exact contribution history, see the revision 12# history and logs, available at http://babel.edgewall.org/log/. 13 14import pytest 15 16from babel import core 17from babel.core import default_locale, Locale 18 19 20def test_locale_provides_access_to_cldr_locale_data(): 21 locale = Locale('en', 'US') 22 assert u'English (United States)' == locale.display_name 23 assert u'.' == locale.number_symbols['decimal'] 24 25 26def test_locale_repr(): 27 assert repr(Locale('en', 'US')) == "Locale('en', territory='US')" 28 assert ("Locale('de', territory='DE')" == repr(Locale('de', 'DE'))) 29 assert ("Locale('zh', territory='CN', script='Hans')" == 30 repr(Locale('zh', 'CN', script='Hans'))) 31 32 33def test_locale_comparison(): 34 en_US = Locale('en', 'US') 35 en_US_2 = Locale('en', 'US') 36 fi_FI = Locale('fi', 'FI') 37 bad_en_US = Locale('en_US') 38 assert en_US == en_US 39 assert en_US == en_US_2 40 assert en_US != fi_FI 41 assert not (en_US != en_US_2) 42 assert en_US is not None 43 assert en_US != bad_en_US 44 assert fi_FI != bad_en_US 45 46 47def test_can_return_default_locale(os_environ): 48 os_environ['LC_MESSAGES'] = 'fr_FR.UTF-8' 49 assert Locale('fr', 'FR') == Locale.default('LC_MESSAGES') 50 51 52def test_ignore_invalid_locales_in_lc_ctype(os_environ): 53 # This is a regression test specifically for a bad LC_CTYPE setting on 54 # MacOS X 10.6 (#200) 55 os_environ['LC_CTYPE'] = 'UTF-8' 56 # must not throw an exception 57 default_locale('LC_CTYPE') 58 59 60def test_get_global(): 61 assert core.get_global('zone_aliases')['GMT'] == 'Etc/GMT' 62 assert core.get_global('zone_aliases')['UTC'] == 'Etc/UTC' 63 assert core.get_global('zone_territories')['Europe/Berlin'] == 'DE' 64 65 66def test_hash(): 67 locale_a = Locale('en', 'US') 68 locale_b = Locale('en', 'US') 69 locale_c = Locale('fi', 'FI') 70 assert hash(locale_a) == hash(locale_b) 71 assert hash(locale_a) != hash(locale_c) 72 73 74class TestLocaleClass: 75 76 def test_attributes(self): 77 locale = Locale('en', 'US') 78 assert locale.language == 'en' 79 assert locale.territory == 'US' 80 81 def test_default(self, os_environ): 82 for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: 83 os_environ[name] = '' 84 os_environ['LANG'] = 'fr_FR.UTF-8' 85 default = Locale.default('LC_MESSAGES') 86 assert (default.language, default.territory) == ('fr', 'FR') 87 88 def test_negotiate(self): 89 de_DE = Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) 90 assert (de_DE.language, de_DE.territory) == ('de', 'DE') 91 de = Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) 92 assert (de.language, de.territory) == ('de', None) 93 nothing = Locale.negotiate(['de_DE', 'de'], ['en_US']) 94 assert nothing is None 95 96 def test_negotiate_custom_separator(self): 97 de_DE = Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-') 98 assert (de_DE.language, de_DE.territory) == ('de', 'DE') 99 100 def test_parse(self): 101 l = Locale.parse('de-DE', sep='-') 102 assert l.display_name == 'Deutsch (Deutschland)' 103 104 de_DE = Locale.parse(l) 105 assert (de_DE.language, de_DE.territory) == ('de', 'DE') 106 107 def test_parse_likely_subtags(self): 108 l = Locale.parse('zh-TW', sep='-') 109 assert l.language == 'zh' 110 assert l.territory == 'TW' 111 assert l.script == 'Hant' 112 113 l = Locale.parse('zh_CN') 114 assert l.language == 'zh' 115 assert l.territory == 'CN' 116 assert l.script == 'Hans' 117 118 l = Locale.parse('zh_SG') 119 assert l.language == 'zh' 120 assert l.territory == 'SG' 121 assert l.script == 'Hans' 122 123 l = Locale.parse('und_AT') 124 assert l.language == 'de' 125 assert l.territory == 'AT' 126 127 l = Locale.parse('und_UK') 128 assert l.language == 'en' 129 assert l.territory == 'GB' 130 assert l.script is None 131 132 def test_get_display_name(self): 133 zh_CN = Locale('zh', 'CN', script='Hans') 134 assert zh_CN.get_display_name('en') == 'Chinese (Simplified, China)' 135 136 def test_display_name_property(self): 137 assert Locale('en').display_name == 'English' 138 assert Locale('en', 'US').display_name == 'English (United States)' 139 assert Locale('sv').display_name == 'svenska' 140 141 def test_english_name_property(self): 142 assert Locale('de').english_name == 'German' 143 assert Locale('de', 'DE').english_name == 'German (Germany)' 144 145 def test_languages_property(self): 146 assert Locale('de', 'DE').languages['ja'] == 'Japanisch' 147 148 def test_scripts_property(self): 149 assert Locale('en', 'US').scripts['Hira'] == 'Hiragana' 150 151 def test_territories_property(self): 152 assert Locale('es', 'CO').territories['DE'] == 'Alemania' 153 154 def test_variants_property(self): 155 assert (Locale('de', 'DE').variants['1901'] == 156 'Alte deutsche Rechtschreibung') 157 158 def test_currencies_property(self): 159 assert Locale('en').currencies['COP'] == 'Colombian Peso' 160 assert Locale('de', 'DE').currencies['COP'] == 'Kolumbianischer Peso' 161 162 def test_currency_symbols_property(self): 163 assert Locale('en', 'US').currency_symbols['USD'] == '$' 164 assert Locale('es', 'CO').currency_symbols['USD'] == 'US$' 165 166 def test_number_symbols_property(self): 167 assert Locale('fr', 'FR').number_symbols['decimal'] == ',' 168 169 def test_decimal_formats(self): 170 assert Locale('en', 'US').decimal_formats[None].pattern == '#,##0.###' 171 172 def test_currency_formats_property(self): 173 assert (Locale('en', 'US').currency_formats['standard'].pattern == 174 u'\xa4#,##0.00') 175 assert (Locale('en', 'US').currency_formats['accounting'].pattern == 176 u'\xa4#,##0.00;(\xa4#,##0.00)') 177 178 def test_percent_formats_property(self): 179 assert Locale('en', 'US').percent_formats[None].pattern == '#,##0%' 180 181 def test_scientific_formats_property(self): 182 assert Locale('en', 'US').scientific_formats[None].pattern == '#E0' 183 184 def test_periods_property(self): 185 assert Locale('en', 'US').periods['am'] == 'AM' 186 187 def test_days_property(self): 188 assert Locale('de', 'DE').days['format']['wide'][3] == 'Donnerstag' 189 190 def test_months_property(self): 191 assert Locale('de', 'DE').months['format']['wide'][10] == 'Oktober' 192 193 def test_quarters_property(self): 194 assert Locale('de', 'DE').quarters['format']['wide'][1] == '1. Quartal' 195 196 def test_eras_property(self): 197 assert Locale('en', 'US').eras['wide'][1] == 'Anno Domini' 198 assert Locale('en', 'US').eras['abbreviated'][0] == 'BC' 199 200 def test_time_zones_property(self): 201 time_zones = Locale('en', 'US').time_zones 202 assert (time_zones['Europe/London']['long']['daylight'] == 203 'British Summer Time') 204 assert time_zones['America/St_Johns']['city'] == u'St. John\u2019s' 205 206 def test_meta_zones_property(self): 207 meta_zones = Locale('en', 'US').meta_zones 208 assert (meta_zones['Europe_Central']['long']['daylight'] == 209 'Central European Summer Time') 210 211 def test_zone_formats_property(self): 212 assert Locale('en', 'US').zone_formats['fallback'] == '%(1)s (%(0)s)' 213 assert Locale('pt', 'BR').zone_formats['region'] == u'Hor\xe1rio %s' 214 215 def test_first_week_day_property(self): 216 assert Locale('de', 'DE').first_week_day == 0 217 assert Locale('en', 'US').first_week_day == 6 218 219 def test_weekend_start_property(self): 220 assert Locale('de', 'DE').weekend_start == 5 221 222 def test_weekend_end_property(self): 223 assert Locale('de', 'DE').weekend_end == 6 224 225 def test_min_week_days_property(self): 226 assert Locale('de', 'DE').min_week_days == 4 227 228 def test_date_formats_property(self): 229 assert Locale('en', 'US').date_formats['short'].pattern == 'M/d/yy' 230 assert Locale('fr', 'FR').date_formats['long'].pattern == 'd MMMM y' 231 232 def test_time_formats_property(self): 233 assert Locale('en', 'US').time_formats['short'].pattern == 'h:mm a' 234 assert Locale('fr', 'FR').time_formats['long'].pattern == 'HH:mm:ss z' 235 236 def test_datetime_formats_property(self): 237 assert Locale('en').datetime_formats['full'] == u"{1} 'at' {0}" 238 assert Locale('th').datetime_formats['medium'] == u'{1} {0}' 239 240 def test_datetime_skeleton_property(self): 241 assert Locale('en').datetime_skeletons['Md'].pattern == u"M/d" 242 assert Locale('th').datetime_skeletons['Md'].pattern == u'd/M' 243 244 def test_plural_form_property(self): 245 assert Locale('en').plural_form(1) == 'one' 246 assert Locale('en').plural_form(0) == 'other' 247 assert Locale('fr').plural_form(0) == 'one' 248 assert Locale('ru').plural_form(100) == 'many' 249 250 251def test_default_locale(os_environ): 252 for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: 253 os_environ[name] = '' 254 os_environ['LANG'] = 'fr_FR.UTF-8' 255 assert default_locale('LC_MESSAGES') == 'fr_FR' 256 257 os_environ['LC_MESSAGES'] = 'POSIX' 258 assert default_locale('LC_MESSAGES') == 'en_US_POSIX' 259 260 for value in ['C', 'C.UTF-8', 'POSIX']: 261 os_environ['LANGUAGE'] = value 262 assert default_locale() == 'en_US_POSIX' 263 264 265def test_negotiate_locale(): 266 assert (core.negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) == 267 'de_DE') 268 assert core.negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) == 'de' 269 assert (core.negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) == 270 'de_DE') 271 assert (core.negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) == 272 'de_DE') 273 assert (core.negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) == 274 'ja_JP') 275 assert core.negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) == 'nb_NO' 276 277 278def test_parse_locale(): 279 assert core.parse_locale('zh_CN') == ('zh', 'CN', None, None) 280 assert core.parse_locale('zh_Hans_CN') == ('zh', 'CN', 'Hans', None) 281 assert core.parse_locale('zh-CN', sep='-') == ('zh', 'CN', None, None) 282 283 with pytest.raises(ValueError) as excinfo: 284 core.parse_locale('not_a_LOCALE_String') 285 assert (excinfo.value.args[0] == 286 "'not_a_LOCALE_String' is not a valid locale identifier") 287 288 assert core.parse_locale('it_IT@euro') == ('it', 'IT', None, None) 289 assert core.parse_locale('en_US.UTF-8') == ('en', 'US', None, None) 290 assert (core.parse_locale('de_DE.iso885915@euro') == 291 ('de', 'DE', None, None)) 292 293 294@pytest.mark.parametrize('filename', [ 295 'babel/global.dat', 296 'babel/locale-data/root.dat', 297 'babel/locale-data/en.dat', 298 'babel/locale-data/en_US.dat', 299 'babel/locale-data/en_US_POSIX.dat', 300 'babel/locale-data/zh_Hans_CN.dat', 301 'babel/locale-data/zh_Hant_TW.dat', 302 'babel/locale-data/es_419.dat', 303]) 304def test_compatible_classes_in_global_and_localedata(filename): 305 # Use pickle module rather than cPickle since cPickle.Unpickler is a method 306 # on Python 2 307 import pickle 308 309 class Unpickler(pickle.Unpickler): 310 311 def find_class(self, module, name): 312 # *.dat files must have compatible classes between Python 2 and 3 313 if module.split('.')[0] == 'babel': 314 return pickle.Unpickler.find_class(self, module, name) 315 raise pickle.UnpicklingError("global '%s.%s' is forbidden" % 316 (module, name)) 317 318 with open(filename, 'rb') as f: 319 return Unpickler(f).load() 320 321 322def test_issue_601_no_language_name_but_has_variant(): 323 # kw_GB has a variant for Finnish but no actual language name for Finnish, 324 # so `get_display_name()` previously crashed with a TypeError as it attempted 325 # to concatenate " (Finnish)" to None. 326 # Instead, it's better to return None altogether, as we can't reliably format 327 # part of a language name. 328 329 assert Locale.parse('fi_FI').get_display_name('kw_GB') == None 330