Commit d42f6858 authored by Michael Fladischer's avatar Michael Fladischer

New upstream version 5.2

parent 76c43cdd
[main]
host = https://www.transifex.com
[django-countries.djangopo]
file_filter = django_countries/locale/<lang>/LC_MESSAGES/django.po
source_file = django_countries/locale/en/LC_MESSAGES/django.po
source_lang = en
......@@ -4,11 +4,152 @@ Change Log
This log shows interesting changes that happen for each version, latest
versions first. It can be assumed that translations have been updated each
release (and any new translations added).
release, and any new translations added.
5.2 (9 March 2018)
==================
Version 3.4 (22 October 2015)
=============================
- Ensure Django 2.1 compatibility for ``CountrySelectWidget``.
- Fix regression introduced into 5.1 when using Django 1.8 and certain queryset
lookup types (like ``__in``).
5.1.1 (31 January 2018)
=======================
- Fix some translations that were included in 5.1 but not compiled.
5.1 (30 January 2018)
=====================
* Tests now also cover Django Rest Framework 3.7 and Django 2.0.
* Allow for creating country fields using (valid) alpha-3 or numeric codes.
* Fix migration error with blank default (thanks Jens Diemer).
* Add a ``{% get_countries %}`` template tag (thanks Matija Čvrk).
5.0 (10 October 2017)
=====================
* No longer allow ``multiple=True`` and ``null=True`` together. This causes
problems saving the field, and ``null`` shouldn't really be used anyway
because the country field is a subclass of ``CharField``.
4.6 (16 June 2017)
==================
* Add a ``CountryFieldMixin`` Django Rest Framework serializer mixin that
automatically picks the right field type for a ``CountryField`` (both single
and multi-choice).
* Validation for Django Rest Framework field (thanks Simon Meers).
* Allow case-insensitive ``.by_name()`` matching (thanks again, Simon).
* Ensure a multiple-choice ``CountryField.max_length`` is enough to hold all
countries.
* Fix inefficient pickling of countries (thanks Craig de Stigter for the report
and tests).
* Stop adding a blank choice when dealing with a multi-choice ``CountryField``.
* Tests now cover multiple Django Rest Framework versions (back to 3.3).
4.6.1
-----
* Fix invalid reStructuredText in CHANGES.
4.6.2
-----
* Use transparency layer for flag sprites.
4.5 (18 April 2017)
===================
* Change rest framework field to be based on ``ChoiceField``.
* Allow for the rest framework field to deserialize by full country name
(specifically the English name for now).
4.4 (6 April 2017)
==================
* Fix for broken CountryField on certain models in Django 1.11.
Thanks aktiur for the test case.
* Update tests to cover Django 1.11
4.3 (29 March 2017)
===================
* Handle "Czechia" translations in a nicer way (fall back to "Czech Republic"
until new translations are available).
* Fix for an import error in Django 1.9+ due to use of non-lazy ``ugettext`` in
the django-countries custom admin filter.
* Back to 100% test coverage.
4.2 (10 March 2017)
===================
* Add sprite flag files (and ``Country.flag_css`` property) to help minimize
HTTP requests.
4.1 (22 February 2017)
======================
* Better default Django admin filter when filtering a country field in a
``ModelAdmin``.
* Fix settings to support Django 1.11
* Fix when using a model instance with a deferred country field.
* Allow ``CountryField`` to handle multiple countries at once!
* Allow CountryField to still work if Deferred.
* Fix a field with customized country list. Thanks pilmie!
4.0 (16 August 2016)
====================
Django supported versions are now 1.8+
* Drop legacy code
* Fix tests, 100% coverage
* IOS / OSX unicode flags function
* Fix widget choices on Django 1.9+
* Add ``COUNTRIES_FIRST_SORT``. Thanks Edraak!
4.0.1
-----
* Fix tests for ``COUNTRIES_FIRST_SORT`` (feature still worked, tests didn't).
3.4 (22 October 2015)
=====================
* Extend test suite to cover Django 1.8
......@@ -20,14 +161,14 @@ Version 3.4 (22 October 2015)
* New ``CountryField`` Django Rest Framework serializer field.
Version 3.4.1
-------------
3.4.1
-----
* Fix minor packaging error.
Version 3.3 (30 Mar 2015)
=========================
3.3 (30 Mar 2015)
=================
* Add the attributes to ``Countries`` class that can override the default
settings.
......@@ -46,8 +187,8 @@ Version 3.3 (30 Mar 2015)
Iran, Micronesia, and Venezuela.
Version 3.2 (24 Feb 2015)
=========================
3.2 (24 Feb 2015)
=================
* Fixes initial iteration failing for a fresh ``Countries`` object.
......@@ -57,8 +198,8 @@ Version 3.2 (24 Feb 2015)
a country code by its full country name. Thanks Josh Schneier.
Version 3.1 (15 Jan 2015)
=========================
3.1 (15 Jan 2015)
=================
* Start change log :)
......@@ -68,14 +209,14 @@ Version 3.1 (15 Jan 2015)
* Add a ``blank_label`` argument to ``CountryField`` to allow customization of
the label shown in the initial blank choice shown in the select widget.
Version 3.1.1 (15 Jan 2015)
---------------------------
3.1.1 (15 Jan 2015)
-------------------
* Packaging fix (``CHANGES.rst`` wasn't in the manifest)
Version 3.0 (22 Oct 2014)
=========================
3.0 (22 Oct 2014)
=================
Django supported versions are now 1.4 (LTS) and 1.6+
......@@ -96,44 +237,44 @@ Django supported versions are now 1.4 (LTS) and 1.6+
* Field descriptor now returns ``None`` if no country matches (*reverted in v3.0.1*)
Version 3.0.1 (27 Oct 2014)
---------------------------
3.0.1 (27 Oct 2014)
-------------------
* Revert descriptor to always return a Country object.
* Fix the ``CountryField`` widget choices appearing empty due to a translation
change in v3.0.
Version 3.0.2 (29 Dec 2014)
---------------------------
3.0.2 (29 Dec 2014)
-------------------
* Fix ``CountrySelectWidget`` failing when used with a model form that is
passed a model instance.
Version 2.1 (24 Mar 2014)
=========================
2.1 (24 Mar 2014)
=================
* Add IOC (3 letter) country codes.
* Fix bug when loading fixtures.
Version 2.1.1 (28 Mar 2014)
---------------------------
2.1.1 (28 Mar 2014)
-------------------
* Fix issue with translations getting evaluated early.
Version 2.1.2 (28 Mar 2014)
---------------------------
2.1.2 (28 Mar 2014)
-------------------
* Fix Python 3 compatibility.
Version 2.0 (18 Feb 2014)
=========================
2.0 (18 Feb 2014)
=================
This is the first entry to the change log. The previous version was 1.5,
This is the first entry to the change log. The previous was 1.5,
released 19 Nov 2012.
* Optimized flag images, adding flags missing from original source.
......
......@@ -3,3 +3,4 @@ include LICENSE
include tox.ini
graft django_countries/static/flags
graft django_countries/locale
graft .tx
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -5,21 +5,32 @@ README.rst
setup.cfg
setup.py
tox.ini
.tx/config
django_countries/__init__.py
django_countries/base.py
django_countries/conf.py
django_countries/data.py
django_countries/fields.py
django_countries/filters.py
django_countries/ioc_data.py
django_countries/makesprite.py
django_countries/models.py
django_countries/release.py
django_countries/serializer_fields.py
django_countries/serializers.py
django_countries/widgets.py
django_countries.egg-info/PKG-INFO
django_countries.egg-info/SOURCES.txt
django_countries.egg-info/dependency_links.txt
django_countries.egg-info/not-zip-safe
django_countries.egg-info/requires.txt
django_countries.egg-info/top_level.txt
django_countries/locale/ar/LC_MESSAGES/django.mo
django_countries/locale/ar/LC_MESSAGES/django.po
django_countries/locale/bg/LC_MESSAGES/django.mo
django_countries/locale/bg/LC_MESSAGES/django.po
django_countries/locale/ca/LC_MESSAGES/django.mo
django_countries/locale/ca/LC_MESSAGES/django.po
django_countries/locale/cs/LC_MESSAGES/django.mo
django_countries/locale/cs/LC_MESSAGES/django.po
django_countries/locale/de/LC_MESSAGES/django.mo
......@@ -34,6 +45,10 @@ django_countries/locale/es/LC_MESSAGES/django.mo
django_countries/locale/es/LC_MESSAGES/django.po
django_countries/locale/et/LC_MESSAGES/django.mo
django_countries/locale/et/LC_MESSAGES/django.po
django_countries/locale/eu/LC_MESSAGES/django.mo
django_countries/locale/eu/LC_MESSAGES/django.po
django_countries/locale/eu_ES/LC_MESSAGES/django.mo
django_countries/locale/eu_ES/LC_MESSAGES/django.po
django_countries/locale/fa/LC_MESSAGES/django.mo
django_countries/locale/fa/LC_MESSAGES/django.po
django_countries/locale/fi/LC_MESSAGES/django.mo
......@@ -42,10 +57,18 @@ django_countries/locale/fr/LC_MESSAGES/django.mo
django_countries/locale/fr/LC_MESSAGES/django.po
django_countries/locale/hr/LC_MESSAGES/django.mo
django_countries/locale/hr/LC_MESSAGES/django.po
django_countries/locale/hu/LC_MESSAGES/django.mo
django_countries/locale/hu/LC_MESSAGES/django.po
django_countries/locale/it/LC_MESSAGES/django.mo
django_countries/locale/it/LC_MESSAGES/django.po
django_countries/locale/ja/LC_MESSAGES/django.mo
django_countries/locale/ja/LC_MESSAGES/django.po
django_countries/locale/ko_KR/LC_MESSAGES/django.mo
django_countries/locale/ko_KR/LC_MESSAGES/django.po
django_countries/locale/lt/LC_MESSAGES/django.mo
django_countries/locale/lt/LC_MESSAGES/django.po
django_countries/locale/lv/LC_MESSAGES/django.mo
django_countries/locale/lv/LC_MESSAGES/django.po
django_countries/locale/nb/LC_MESSAGES/django.mo
django_countries/locale/nb/LC_MESSAGES/django.po
django_countries/locale/nl/LC_MESSAGES/django.mo
......@@ -66,6 +89,8 @@ django_countries/locale/tr_TR/LC_MESSAGES/django.mo
django_countries/locale/tr_TR/LC_MESSAGES/django.po
django_countries/locale/uk/LC_MESSAGES/django.mo
django_countries/locale/uk/LC_MESSAGES/django.po
django_countries/locale/zh-Hans/LC_MESSAGES/django.mo
django_countries/locale/zh-Hans/LC_MESSAGES/django.po
django_countries/locale/zh_CN/LC_MESSAGES/django.mo
django_countries/locale/zh_CN/LC_MESSAGES/django.po
django_countries/static/flags/__.gif
......@@ -276,6 +301,10 @@ django_countries/static/flags/sl.gif
django_countries/static/flags/sm.gif
django_countries/static/flags/sn.gif
django_countries/static/flags/so.gif
django_countries/static/flags/sprite-hq.css
django_countries/static/flags/sprite-hq.png
django_countries/static/flags/sprite.css
django_countries/static/flags/sprite.png
django_countries/static/flags/sr.gif
django_countries/static/flags/ss.gif
django_countries/static/flags/st.gif
......@@ -326,7 +355,7 @@ django_countries/tests/custom_countries.py
django_countries/tests/forms.py
django_countries/tests/models.py
django_countries/tests/settings.py
django_countries/tests/settings_lts.py
django_countries/tests/test_admin_filters.py
django_countries/tests/test_countries.py
django_countries/tests/test_drf.py
django_countries/tests/test_fields.py
......
[dev]
tox
django
pytest
pytest-django
[maintainer]
transifex-client
zest.releaser[recommended]
django
[test]
pytest
pytest-django
pytest-cov
......@@ -7,6 +7,8 @@ from django.utils import six
from django.utils.encoding import force_text
from django.utils.translation import override
from .base import CountriesBase
try:
import pyuca
except ImportError:
......@@ -15,16 +17,20 @@ except ImportError:
# Use UCA sorting if it's available.
if pyuca:
collator = pyuca.Collator()
sort_key = lambda item: collator.sort_key(item[1])
def sort_key(item):
return collator.sort_key(item[1])
else:
import unicodedata
# Cheap and dirty method to sort against ASCII characters only.
sort_key = lambda item: (
unicodedata.normalize('NFKD', item[1])
.encode('ascii', 'ignore').decode('ascii'))
def sort_key(item):
return (
unicodedata.normalize('NFKD', item[1])
.encode('ascii', 'ignore').decode('ascii'))
class Countries(object):
class Countries(CountriesBase):
"""
An object containing a list of ISO3166-1 countries.
......@@ -64,10 +70,10 @@ class Countries(object):
else:
# Local import so that countries aren't loaded into memory
# until first used.
from django_countries.data import COUNTRIES, COMMON_NAMES
from django_countries.data import COUNTRIES
self._countries = dict(COUNTRIES)
if self.get_option('common_names'):
self._countries.update(COMMON_NAMES)
self._countries.update(self.COMMON_NAMES)
override = self.get_option('override')
if override:
self._countries.update(override)
......@@ -109,6 +115,31 @@ class Countries(object):
if hasattr(self, '_countries'):
del self._countries
def translate_pair(self, code):
"""
Force a country to the current activated translation.
:returns: 2-tuple of ``(code, translated_country_name)``
"""
name = self.countries[code]
if code in self.OLD_NAMES:
# Check if there's an older translation available if there's no
# translation for the newest name.
with override(None):
source_name = force_text(name)
name = force_text(name)
if name == source_name:
for old_name in self.OLD_NAMES[code]:
with override(None):
source_old_name = force_text(old_name)
old_name = force_text(old_name)
if old_name != source_old_name:
name = old_name
break
else:
name = force_text(name)
return (code, name)
def __iter__(self):
"""
Iterate through countries, sorted by name.
......@@ -130,8 +161,16 @@ class Countries(object):
countries = self.countries
# Yield countries that should be displayed first.
for code in self.countries_first:
yield (code, force_text(countries[code]))
countries_first = (
self.translate_pair(code)
for code in self.countries_first
)
if self.get_option('first_sort'):
countries_first = sorted(countries_first, key=sort_key)
for item in countries_first:
yield item
if self.countries_first:
first_break = self.get_option('first_break')
......@@ -140,9 +179,9 @@ class Countries(object):
# Force translation before sorting.
first_repeat = self.get_option('first_repeat')
countries = [
(code, force_text(name)) for code, name in countries.items()
if first_repeat or code not in self.countries_first]
countries = (
self.translate_pair(code) for code in countries
if first_repeat or code not in self.countries_first)
# Return sorted country list.
for item in sorted(countries, key=sort_key):
......@@ -158,10 +197,16 @@ class Countries(object):
code = force_text(code).upper()
if code.isdigit():
lookup_code = int(code)
find = lambda alt_codes: alt_codes[1] == lookup_code
def find(alt_codes):
return alt_codes[1] == lookup_code
elif len(code) == 3:
lookup_code = code
find = lambda alt_codes: alt_codes[0] == lookup_code
def find(alt_codes):
return alt_codes[0] == lookup_code
else:
find = None
if find:
......@@ -181,7 +226,9 @@ class Countries(object):
If no match is found, returns an empty string.
"""
code = self.alpha2(code)
return self.countries.get(code, '')
if code not in self.countries:
return ''
return self.translate_pair(code)[1]
def by_name(self, country, language='en'):
"""
......@@ -191,11 +238,19 @@ class Countries(object):
Warning: This depends on the quality of the available translations.
If no match is found, returns an empty string.
..warning:: Be cautious about relying on this returning a country code
(especially with any hard-coded string) since the ISO names of
countries may change over time.
"""
with override(language):
for code, name in self:
if name == country:
if name.lower() == country.lower():
return code
if code in self.OLD_NAMES:
for old_name in self.OLD_NAMES[code]:
if old_name.lower() == country.lower():
return code
return ''
def alpha3(self, code):
......@@ -264,4 +319,5 @@ class Countries(object):
return list(islice(self.__iter__(), index.start, index.stop,
index.step))
countries = Countries()
try:
from django.utils.translation import ugettext_lazy as _
except ImportError: # pragma: no cover
# Allows this module to be executed without Django installed.
def _(x):
return x
class CountriesBase(object):
COMMON_NAMES = {
"BN": _("Brunei"),
"BO": _("Bolivia"),
"GB": _("United Kingdom"),
"IR": _("Iran"),
"KP": _("North Korea"),
"KR": _("South Korea"),
"LA": _("Laos"),
"MD": _("Moldova"),
"MK": _("Macedonia"),
"RU": _("Russia"),
"SY": _("Syria"),
"TW": _("Taiwan"),
"TZ": _("Tanzania"),
"VE": _("Venezuela"),
"VN": _("Vietnam"),
}
OLD_NAMES = {
"CZ": [_("Czech Republic")],
}
def __getstate__(self):
return None
import django.conf
class AppSettings(django.conf.BaseSettings):
class AppSettings(object):
"""
A holder for app-specific default settings that allows overriding via
the project's settings.
......@@ -93,4 +93,12 @@ class Settings(AppSettings):
countries.
"""
COUNTRIES_FIRST_SORT = False
"""
Countries listed in :attr:`COUNTRIES_FIRST` will be alphanumerically
sorted based on their translated name instead of relying on their
order in :attr:`COUNTRIES_FIRST`.
"""
settings = Settings()
......@@ -19,29 +19,14 @@ from __future__ import unicode_literals
import glob
import os
from django_countries.base import CountriesBase
try:
from django.utils.translation import ugettext_lazy as _
except ImportError: # pragma: no cover
# Allows this module to be executed without Django installed.
_ = lambda x: x
COMMON_NAMES = {
"BN": _("Brunei"),
"BO": _("Bolivia"),
"GB": _("United Kingdom"),
"IR": _("Iran"),
"KP": _("North Korea"),
"KR": _("South Korea"),
"LA": _("Laos"),
"MD": _("Moldova"),
"MK": _("Macedonia"),
"RU": _("Russia"),
"SY": _("Syria"),
"TW": _("Taiwan"),
"TZ": _("Tanzania"),
"VE": _("Venezuela"),
"VN": _("Vietnam"),
}
def _(x):
return x
# Nicely titled (and translatable) country names.
COUNTRIES = {
......@@ -104,7 +89,7 @@ COUNTRIES = {
"CU": _("Cuba"),
"CW": _("Curaçao"),
"CY": _("Cyprus"),
"CZ": _("Czech Republic"),
"CZ": _("Czechia"),
"DK": _("Denmark"),
"DJ": _("Djibouti"),
"DM": _("Dominica"),
......@@ -628,7 +613,7 @@ def check_flags(verbosity=1):
def check_common_names():
common_names_missing = set(COMMON_NAMES) - set(COUNTRIES)
common_names_missing = set(CountriesBase.COMMON_NAMES) - set(COUNTRIES)
if common_names_missing: # pragma: no cover
print("")
print(
......
This diff is collapsed.
from django.contrib import admin
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
class CountryFilter(admin.FieldListFilter):
"""
A country filter for Django admin that only returns a list of countries
related to the model.
"""
title = _('Country')
def expected_parameters(self):
return [self.field.name]
def choices(self, changelist):
value = self.used_parameters.get(self.field.name)
yield {
'selected': value is None,
'query_string': changelist.get_query_string(
{}, [self.field.name]),
'display': _('All'),
}
for lookup, title in self.lookup_choices(changelist):
yield {
'selected': value == force_text(lookup),
'query_string': changelist.get_query_string(
{self.field.name: lookup}, []),
'display': title,
}
def lookup_choices(self, changelist):
qs = changelist.model._default_manager.all()
codes = set(
qs.distinct()
.order_by(self.field.name)
.values_list(self.field.name, flat=True))
for k, v in self.field.get_choices(include_blank=False):
if k in codes:
yield k, v
......@@ -109,7 +109,7 @@ IOC_TO_ISO = {
'LBR': 'LR',
'LCA': 'LC',
'LES': 'LS',
'LIB': 'LB',
'LBN': 'LB',
'LIE': 'LI',
'LTU': 'LT',