mirror of
https://github.com/jazzband/django-avatar.git
synced 2026-03-16 22:20:30 +00:00
Merge with upstream master v4.0.0
This commit is contained in:
commit
144e0576d7
60 changed files with 2112 additions and 439 deletions
25
.coveragerc
Normal file
25
.coveragerc
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
[report]
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
if self\.debug
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
except ImportError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
omit =
|
||||
avatar/migrations/*
|
||||
|
||||
show_missing = True
|
||||
precision = 2
|
||||
|
||||
[html]
|
||||
directory = htmlcov/
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -8,4 +8,7 @@ dist/
|
|||
*.egg-info/
|
||||
avatars
|
||||
.coverage
|
||||
docs/_build
|
||||
docs/_build
|
||||
htmlcov/
|
||||
*.sqlite3
|
||||
test_proj/media
|
||||
|
|
|
|||
26
.travis.yml
26
.travis.yml
|
|
@ -1,21 +1,25 @@
|
|||
language: python
|
||||
python:
|
||||
- 2.6
|
||||
- 2.7
|
||||
- 3.2
|
||||
- 3.3
|
||||
- 3.4
|
||||
- 3.5
|
||||
- 3.6
|
||||
before_install:
|
||||
- pip install coveralls
|
||||
install:
|
||||
- pip install -e .
|
||||
- pip install -r tests/requirements.txt
|
||||
- pip install https://github.com/django/django/archive/${DJANGO}.zip#egg=django
|
||||
- pip install Django==${DJANGO}
|
||||
script: make test
|
||||
env:
|
||||
- DJANGO=1.4.7
|
||||
- DJANGO=1.5.3
|
||||
- DJANGO=stable/1.6.x
|
||||
- DJANGO=1.9.13
|
||||
- DJANGO=1.10.7
|
||||
- DJANGO=1.11.1
|
||||
matrix:
|
||||
exclude:
|
||||
- python: 3.2
|
||||
env: DJANGO=1.4.7
|
||||
- python: 3.3
|
||||
env: DJANGO=1.4.7
|
||||
- python: 3.6
|
||||
env: DJANGO=1.9.13
|
||||
- python: 3.6
|
||||
env: DJANGO=1.10.7
|
||||
after_success:
|
||||
- coveralls
|
||||
|
|
|
|||
54
CHANGELOG.rst
Normal file
54
CHANGELOG.rst
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
* 4.0.0 (May 27, 2017)
|
||||
* **Backwards incompatible:** Added ``AVATAR_PROVIDERS`` setting. Avatar providers are classes that return an avatar URL for a given user.
|
||||
* Added ``verbose_name`` to ``Avatar`` model fields.
|
||||
* Added the ability to override the ``alt`` attribute using the ``avatar`` template tag.
|
||||
* Added Italian translations.
|
||||
* Improved German translations.
|
||||
* Fixed bug where ``rebuild_avatars`` would fail on Django 1.10+.
|
||||
* Added Django 1.11 support.
|
||||
* Added Python 3.6 support.
|
||||
* Removed Django 1.7 and 1.8 support.
|
||||
* Removed Python 3.3 support.
|
||||
|
||||
* 3.1.0 (September 10, 2016)
|
||||
* Added the ability to override templates using ``AVATAR_ADD_TEMPLATE``, ``AVATAR_CHANGE_TEMPLATE``, and ``AVATAR_DELETE_TEMPLATE``.
|
||||
* Added the ability to pass additional HTML attributes using the ``{% avatar %}`` template tag.
|
||||
* Fixed unused verbosity setting in ``rebuild_avatars.py``.
|
||||
* Added Django 1.10 support
|
||||
* Removed Python 3.2 support
|
||||
|
||||
* 3.0.0 (February 26, 2016):
|
||||
* Added the ability to hide usernames/emails from avatar URLs.
|
||||
* Added the ability to use a Facebook Graph avatar as a backup.
|
||||
* Added a way to customize where avatars are stored.
|
||||
* Added a setting to disable the avatar cache.
|
||||
* Updated thumbnail creation to preserve RGBA.
|
||||
* Fixed issue where ``render_primary`` would not work if username/email was greater than 30 characters.
|
||||
* Fixed issue where cache was not invalidated after updating avatar
|
||||
* **Backwards Incompatible:** Renamed the ``avatar.util`` module to ``avatar.utils``.
|
||||
|
||||
* 2.2.1 (January 11, 2016)
|
||||
* Added AVATAR_GRAVATAR_FIELD setting to define the user field to get the gravatar email.
|
||||
* Improved Django 1.9/1.10 compatibility
|
||||
* Improved Brazilian translations
|
||||
|
||||
* 2.2.0 (December 2, 2015)
|
||||
* Added Python 3.5 support
|
||||
* Added Django 1.9 support
|
||||
* Removed Python 2.6 support
|
||||
* Removed Django 1.4, 1.5, and 1.6 support
|
||||
|
||||
* 2.1.1 (August 10, 2015)
|
||||
* Added Polish locale
|
||||
* Fixed RemovedInDjango19Warning warnings
|
||||
|
||||
* 2.1 (May 2, 2015)
|
||||
* Django 1.7 and 1.8 support
|
||||
* Add South and Django migrations
|
||||
* Changed Gravatar link to use HTTPS by default
|
||||
* Fixed a bug where the admin avatar list page would only show a user's primary avatar
|
||||
* Updated render_primary view to accept usernames with @ signs in them
|
||||
* Updated translations (added Dutch, Japanese, and Simple Chinese)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
This application was originally written by Eric Florenzano.
|
||||
It is now maintained by Jannis Leidel and a league of awesome contributors.
|
||||
It is now maintained by Grant McConnaughey and a league of awesome contributors.
|
||||
|
||||
See the full list here: https://github.com/jezdez/django-avatar/graphs/contributors
|
||||
See the full list here: https://github.com/grantmcconnaughey/django-avatar/graphs/contributors
|
||||
|
|
|
|||
11
Makefile
11
Makefile
|
|
@ -5,5 +5,14 @@ export PYTHONPATH=.
|
|||
|
||||
test:
|
||||
flake8 avatar --ignore=E124,E501,E127,E128
|
||||
coverage run --branch --source=avatar `which django-admin.py` test tests
|
||||
coverage run --source=avatar `which django-admin.py` test tests
|
||||
coverage report
|
||||
|
||||
publish: clean
|
||||
python setup.py sdist
|
||||
twine upload dist/*
|
||||
|
||||
clean:
|
||||
rm -vrf ./build ./dist ./*.egg-info
|
||||
find . -name '*.pyc' -delete
|
||||
find . -name '*.tgz' -delete
|
||||
|
|
|
|||
21
README.rst
21
README.rst
|
|
@ -2,8 +2,25 @@
|
|||
django-avatar
|
||||
=============
|
||||
|
||||
.. image:: https://secure.travis-ci.org/jezdez/django-avatar.png
|
||||
:target: http://travis-ci.org/jezdez/django-avatar
|
||||
.. image:: https://badge.fury.io/py/django-avatar.svg
|
||||
:target: https://badge.fury.io/py/django-avatar
|
||||
:alt: PyPI badge
|
||||
|
||||
.. image:: https://readthedocs.org/projects/django-avatar/badge/?version=latest
|
||||
:target: http://django-avatar.readthedocs.org/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://travis-ci.org/grantmcconnaughey/django-avatar.svg?branch=master
|
||||
:target: https://travis-ci.org/grantmcconnaughey/django-avatar
|
||||
:alt: Travis CI Build Status
|
||||
|
||||
.. image:: https://coveralls.io/repos/grantmcconnaughey/django-avatar/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/grantmcconnaughey/django-avatar?branch=master
|
||||
:alt: Coverage
|
||||
|
||||
.. image:: https://lintly.com/gh/grantmcconnaughey/django-avatar/badge.svg
|
||||
:target: https://lintly.com/gh/grantmcconnaughey/django-avatar/
|
||||
:alt: Lintly
|
||||
|
||||
Django-avatar is a reusable application for handling user avatars. It has the
|
||||
ability to default to Gravatar if no avatar is found for a certain user.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = '2.0'
|
||||
__version__ = '4.0.0'
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import six
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from avatar.models import Avatar
|
||||
from avatar.signals import avatar_updated
|
||||
from avatar.templatetags.avatar_tags import avatar
|
||||
from avatar.util import get_user_model
|
||||
from avatar.utils import get_user_model
|
||||
|
||||
|
||||
class AvatarAdmin(admin.ModelAdmin):
|
||||
|
|
@ -14,7 +15,13 @@ class AvatarAdmin(admin.ModelAdmin):
|
|||
list_per_page = 50
|
||||
|
||||
def get_avatar(self, avatar_in):
|
||||
return avatar(avatar_in.user, 80)
|
||||
context = dict({
|
||||
'user': avatar_in.user,
|
||||
'url': avatar_in.avatar.url,
|
||||
'alt': six.text_type(avatar_in.user),
|
||||
'size': 80,
|
||||
})
|
||||
return render_to_string('avatar/avatar_tag.html', context)
|
||||
|
||||
get_avatar.short_description = _('Avatar')
|
||||
get_avatar.allow_tags = True
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ class AvatarConf(AppConf):
|
|||
DEFAULT_SIZE = 80
|
||||
RESIZE_METHOD = Image.ANTIALIAS
|
||||
STORAGE_DIR = 'avatars'
|
||||
GRAVATAR_BASE_URL = 'http://www.gravatar.com/avatar/'
|
||||
GRAVATAR_BACKUP = True
|
||||
PATH_HANDLER = 'avatar.models.avatar_path_handler'
|
||||
GRAVATAR_BASE_URL = 'https://www.gravatar.com/avatar/'
|
||||
GRAVATAR_FIELD = 'email'
|
||||
GRAVATAR_DEFAULT = None
|
||||
AVATAR_GRAVATAR_FORCEDEFAULT = False
|
||||
DEFAULT_URL = 'avatar/img/default.jpg'
|
||||
MAX_AVATARS_PER_USER = 42
|
||||
MAX_SIZE = 1024 * 1024
|
||||
|
|
@ -18,12 +20,24 @@ class AvatarConf(AppConf):
|
|||
THUMB_QUALITY = 85
|
||||
HASH_FILENAMES = False
|
||||
HASH_USERDIRNAMES = False
|
||||
EXPOSE_USERNAMES = True
|
||||
ALLOWED_FILE_EXTS = None
|
||||
CACHE_TIMEOUT = 60 * 60
|
||||
STORAGE = settings.DEFAULT_FILE_STORAGE
|
||||
CLEANUP_DELETED = False
|
||||
AUTO_GENERATE_SIZES = (DEFAULT_SIZE,)
|
||||
FACEBOOK_GET_ID = None
|
||||
CACHE_ENABLED = True
|
||||
RANDOMIZE_HASHES = False
|
||||
ADD_TEMPLATE = ''
|
||||
CHANGE_TEMPLATE = ''
|
||||
DELETE_TEMPLATE = ''
|
||||
PROVIDERS = (
|
||||
'avatar.providers.PrimaryAvatarProvider',
|
||||
'avatar.providers.GravatarAvatarProvider',
|
||||
'avatar.providers.DefaultAvatarProvider',
|
||||
)
|
||||
|
||||
def configure_auto_generate_avatar_sizes(self, value):
|
||||
return value or getattr(settings, 'AUTO_GENERATE_AVATAR_SIZES',
|
||||
return value or getattr(settings, 'AVATAR_AUTO_GENERATE_SIZES',
|
||||
(self.DEFAULT_SIZE,))
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -3,66 +3,74 @@
|
|||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-28 10:59+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2016-09-14 14:34+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 1.8.9\n"
|
||||
|
||||
#: forms.py:34
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "avatar"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : %"
|
||||
"(valid_exts_list)s"
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s ist ein ungültiges Dateiformat. Erlaubte Formate sind: %"
|
||||
"(valid_exts_list)s"
|
||||
|
||||
#: forms.py:38
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is %"
|
||||
"(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Die Datei ist zu groß (%(size)s), die Maximalgröße ist %(max_valid_size)s"
|
||||
"%(ext)s ist ein ungültiges Dateiformat. Erlaubte Formate sind: "
|
||||
"%(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is %"
|
||||
"(nb_max_avatars)d."
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Sie haben bereits %(nb_avatars)d Avatarbilder hochgeladen. Das maximale "
|
||||
"Die Datei ist zu groß (%(size)s), die Maximalgröße ist %(max_valid_size)s"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Sie haben bereits %(nb_avatars)d Avatarbilder hochgeladen. Die maximale "
|
||||
"Anzahl ist %(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:56 forms.py:67
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr ""
|
||||
msgstr "Auswahl"
|
||||
|
||||
#: models.py:75
|
||||
#, python-format
|
||||
msgid "Avatar for %s"
|
||||
msgstr "Avatar für %s"
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: views.py:73 views.py:95
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Erfolgreich einen neuen Avatar hochgeladen."
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr "primär"
|
||||
|
||||
#: views.py:132
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Erfolgreich Ihren Avatar aktualisiert."
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr "hochgeladen am"
|
||||
|
||||
#: views.py:166
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Erfolgreich den Avatar gelöscht."
|
||||
#: models.py:98
|
||||
msgid "avatars"
|
||||
msgstr "Avatare"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
|
|
@ -83,7 +91,7 @@ msgstr "Standard auswählen"
|
|||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "Bitte wählen Sie die Avatar aus, die Sie löschen möchten."
|
||||
msgstr "Bitte wählen Sie den Avatar aus, den Sie löschen möchten."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
|
|
@ -99,14 +107,15 @@ msgid "Delete These"
|
|||
msgstr "Auswahl löschen"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> hat den Avatar aktualisiert "
|
||||
"<a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
"%(avatar_creator)s hat seinen/ihren Avatar %(avatar)s aktualisiert.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
|
|
@ -114,8 +123,8 @@ msgid ""
|
|||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> hat den Avatar aktualisiert "
|
||||
"<a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> hat ihren/seinen Avatar "
|
||||
"aktualisiert <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
|
|
@ -124,6 +133,9 @@ msgid ""
|
|||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Ihr Avatar wurde aktualisiert. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
|
|
@ -132,10 +144,22 @@ msgstr ""
|
|||
"Sie haben Ihren Avatar aktualisiert <a href=\"%(avatar_url)s\">%(avatar)s</"
|
||||
"a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:45
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Standard-Avatar"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Ein neuer Avatar wurde erfolgreich hochgeladen."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Ihr Avatar wurde erfolgreich aktualisiert."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Ihr Avatar wurde erfolgreich gelöscht."
|
||||
|
||||
#~ msgid "Avatar Updated"
|
||||
#~ msgstr "Avatar aktualisiert"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,26 +7,26 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 2.0a10\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-08-26 23:53-0500\n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2013-08-27 00:21-0600\n"
|
||||
"Last-Translator: David Loaiza M. <david@zooluciones.com>\n"
|
||||
"Language-Team: es <david.loaiza@gmail.com>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 1.5.7\n"
|
||||
"Language: es\n"
|
||||
|
||||
#: admin.py:19
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar"
|
||||
|
||||
#: forms.py:23
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "avatar"
|
||||
|
||||
#: forms.py:35
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
|
|
@ -35,7 +35,7 @@ msgstr ""
|
|||
"%(ext)s es una extensión de archivo inválida. Las extensiones de archivo "
|
||||
"autorizadas son: %(valid_exts_list)s"
|
||||
|
||||
#: forms.py:39
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
|
|
@ -44,7 +44,7 @@ msgstr ""
|
|||
"Su archivo es muy grande (%(size)s), el tamaño máximo permitido es "
|
||||
"%(max_valid_size)s"
|
||||
|
||||
#: forms.py:49
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
|
|
@ -53,43 +53,49 @@ msgstr ""
|
|||
"Usted ya tiene %(nb_avatars)d avatares, y el máximo permitido es "
|
||||
"%(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:65 forms.py:77
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Opciones"
|
||||
|
||||
#: views.py:71
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Se ha subido correctamente un nuevo avatar"
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: views.py:106
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Se ha actualizado correctamente su avatar."
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: views.py:141
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Se han eliminado correctamente los avatares solicitados."
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: templates/avatar/add.html:6 templates/avatar/change.html:6
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "avatar"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "Su avatar actual:"
|
||||
|
||||
#: templates/avatar/add.html:9 templates/avatar/change.html:9
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "No ha subido un avatar aún. Por favor, suba uno ahora."
|
||||
|
||||
#: templates/avatar/add.html:13 templates/avatar/change.html:20
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "Subir Nueva Imagen"
|
||||
|
||||
#: templates/avatar/change.html:15
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "Elige nuevo predeterminado"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:6
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "Por favor seleccione los avatares que le gustaría eliminar."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:9
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
|
|
@ -98,7 +104,7 @@ msgstr ""
|
|||
"No tiene avatares para borrar. Por favor <a href=\"%(avatar_change_url)s"
|
||||
"\">suba uno</a> ahora."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:15
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "Eliminar Estos"
|
||||
|
||||
|
|
@ -138,6 +144,18 @@ msgstr ""
|
|||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "Ha actualizado su avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:57
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Avatar Predeterminado"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Se ha subido correctamente un nuevo avatar"
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Se ha actualizado correctamente su avatar."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Se han eliminado correctamente los avatares solicitados."
|
||||
|
|
|
|||
|
|
@ -7,62 +7,76 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-28 10:59+0200\n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2010-03-26 18:35+0100\n"
|
||||
"Last-Translator: Mathieu Pillard <m.pillard@liberation.fr>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: forms.py:34
|
||||
#: admin.py:26
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar pour %s"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
#, fuzzy
|
||||
#| msgid "Default Avatar"
|
||||
msgid "avatar"
|
||||
msgstr "Avatar par défaut"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : %"
|
||||
"(valid_exts_list)s"
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s n'est pas une extension de fichier valide. Les extensions autorisées "
|
||||
"sont: %(valid_exts_list)s"
|
||||
|
||||
#: forms.py:38
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is %"
|
||||
"(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Le fichier est trop gros (%(size)s), la taille maximum autorisée est %"
|
||||
"(max_valid_size)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is %"
|
||||
"(nb_max_avatars)d."
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Vous avez déjà %(nb_avatars)d avatars, et le maximum autorisé est %"
|
||||
"(nb_max_avatars)d."
|
||||
"Le fichier est trop gros (%(size)s), la taille maximum autorisée est "
|
||||
"%(max_valid_size)s"
|
||||
|
||||
#: forms.py:56 forms.py:67
|
||||
msgid "Choices"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:75
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid "Avatar for %s"
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Vous avez déjà %(nb_avatars)d avatars, et le maximum autorisé est "
|
||||
"%(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Choix"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "avatars"
|
||||
msgstr "Avatar pour %s"
|
||||
|
||||
#: views.py:73 views.py:95
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Votre nouveau avatar a été uploadé avec succès."
|
||||
|
||||
#: views.py:132
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Votre avatar a été mis à jour avec succès."
|
||||
|
||||
#: views.py:166
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Les avatars sélectionnés ont été effacés avec succès."
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "Votre avatar actuel:"
|
||||
|
|
@ -89,8 +103,8 @@ msgid ""
|
|||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"Vous n'avez aucun avatar à effacer. Veuillez en <a href=\"%"
|
||||
"(avatar_change_url)s\">ajouter</a> un maintenant."
|
||||
"Vous n'avez aucun avatar à effacer. Veuillez en <a href="
|
||||
"\"%(avatar_change_url)s\">ajouter</a> un maintenant."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
|
|
@ -103,8 +117,9 @@ msgid ""
|
|||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> a mis à jour son avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
"%(avatar_creator)s a mis à jour son avatar %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
|
|
@ -122,16 +137,31 @@ msgid ""
|
|||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Votre avatar a été mis à jour. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "Vous avez mis à jour votre <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:45
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Avatar par défaut"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Votre nouveau avatar a été uploadé avec succès."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Votre avatar a été mis à jour avec succès."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Les avatars sélectionnés ont été effacés avec succès."
|
||||
|
||||
#~ msgid "Avatar Updated"
|
||||
#~ msgstr "Avatar mis à jour"
|
||||
|
||||
|
|
|
|||
BIN
avatar/locale/it/LC_MESSAGES/django.mo
Normal file
BIN
avatar/locale/it/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
161
avatar/locale/it/LC_MESSAGES/django.po
Normal file
161
avatar/locale/it/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 3.1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-13 16:00+0200\n"
|
||||
"PO-Revision-Date: 2013-08-27 00:21-0600\n"
|
||||
"Last-Translator: Bruno Santeramo <bruno.santeramo@gmail.com>\n"
|
||||
"Language-Team: it <bruno.santeramo@gmail.com>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: po2mo.net\n"
|
||||
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "avatar"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s non è una estensione valida. Le estensioni accettate sono : "
|
||||
"%(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Il file è troppo grande (%(size)s), la massima dimensione consentita "
|
||||
"è %(max_valid_size)s"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Hai già %(nb_avatars)d avatar, e il massimo numero consentito è "
|
||||
"%(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Opzioni"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr "utente"
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr "principale"
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr "caricato su"
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "avatar"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "Il tuo attuale avatar è:"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "Non hai ancora caricato un avatar. Per favore, carica uno adesso."
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "Carica una Nuova Immagine"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "Scegli un nuovo predefinito"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "Per favore, seleziona gli avatar che vuoi eliminare."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"Non hai avatar da eliminare. Per favore <a href=\"%(avatar_change_url)s"
|
||||
"\">carica uno </a> adesso."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "Elimina Questi"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s ha aggiornato i suoi avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> ha aggiornato i suoi avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Il tuo avatar è stato aggiornato. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "Hai aggiornato il tuo avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Avatar Predefinito"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Nuovo avatar caricato con successo"
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Il tuo avatar è stato aggiornato con successo."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Gli avatar selezionati sono stati eliminati con successo."
|
||||
BIN
avatar/locale/ja/LC_MESSAGES/django.mo
Normal file
BIN
avatar/locale/ja/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
162
avatar/locale/ja/LC_MESSAGES/django.po
Normal file
162
avatar/locale/ja/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "プロフィール画像"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "プロフィール画像"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s は利用できない拡張子です。 使用可能な拡張子 : %(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"ファイルが大きすぎます(%(size)s)。アップロード可能な最大サイズは "
|
||||
"%(max_valid_size)s です。"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"登録可能なプロフィール画像は %(nb_max_avatars)d 個までです。すでに "
|
||||
"%(nb_avatars)d 個登録されています。"
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "選択"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "プロフィール画像"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "現在のプロフィール画像:"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "登録されているプロフィール画像はありません。アップロードしてください。"
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "新しい画像のアップロード"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "デフォルトの画像を選択"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "削除したいプロフィール画像を選択してください。"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"削除できるプロフィール画像はありません。<a href=\"%(avatar_change_url)s\">新"
|
||||
"規画像のアップロード</a>."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "削除"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s さんがプロフィール画像 %(avatar)s をアップロードしまし"
|
||||
"た。\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> さんがプロフィール画像 <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a> をアップロードしました。"
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"プロフィール画像を更新しました。 %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"プロフィール画像を更新しました。 <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "デフォルトのプロフィール画像"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "新しいプロフィール画像をアップロードしました。"
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "プロフィール画像を更新しました。"
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "指定されたプロフィール画像を削除しました。"
|
||||
BIN
avatar/locale/nl/LC_MESSAGES/django.mo
Normal file
BIN
avatar/locale/nl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
160
avatar/locale/nl/LC_MESSAGES/django.po
Normal file
160
avatar/locale/nl/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2013-11-11 12:49+0100\n"
|
||||
"Last-Translator: Ivor <ivorbosloper@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "Profielfoto"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "profielfoto"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s is een ongeldig bestandsformaat. Toegestane formaten zijn : "
|
||||
"%(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Het bestand is te groot (%(size)s), de maximale groote is %(max_valid_size)s"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Er zijn al %(nb_avatars)d profielfoto's, het maximale aantal is "
|
||||
"%(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Keuzes"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "profielfoto"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "De huidige profielfoto:"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "Er is nog geen profielfoto. Upload een nieuwe."
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "Upload nieuw plaatje"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "Kies nieuwe standaard"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "Selecteer de te verwijderen de profielfoto's."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"Er zijn geen profielfoto's om te verwijderen. <a href=\"%(avatar_change_url)s"
|
||||
"\">Upload</a> een nieuwe."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "Verwijder deze"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s heeft zijn profielfoto vernieuwd %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> heeft zijn profielfoto "
|
||||
"vernieuwd <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Je profielfoto is vernieuwd. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "De profielfoto is vernieuwd <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Standaard profielfoto"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "De profielfoto is ververst."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Profielfoto vernieuwd."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Profielfoto verwijderd."
|
||||
BIN
avatar/locale/pl/LC_MESSAGES/django.mo
Normal file
BIN
avatar/locale/pl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
164
avatar/locale/pl/LC_MESSAGES/django.po
Normal file
164
avatar/locale/pl/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-avatar 0.0.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2015-07-19 15:46+0100\n"
|
||||
"Last-Translator: Adam Dobrawy <naczelnik@jawnosc.tk>\n"
|
||||
"Language-Team: Adam Dobrawy <naczelnik@jawnosc.tk>\n"
|
||||
"Language: pl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "avatar"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s jest nieprawidłowym rozszerzeniem. Dozwolone rozszerzenia to: "
|
||||
"%(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Twój plik jest zbyt duży (%(size)s), maksymalny dopuszcalny rozmiar wynosi "
|
||||
"%(max_valid_size)s"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Aktualnie masz %(nb_avatars)d avatarów, podczas gdy maksymalna dopuszczalna "
|
||||
"liczba wynosi %(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Opcje wyboru"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "avatar"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "Twój aktualny avatar"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "Nie masz aktualnie żadnych avatarów. Prosimy wyślij teraz. "
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "Wyślij nowy obraz"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "Wybierz nowy domyślny"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "Wybierz avatar, który chcesz usunąć."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"Nie masz avatarów do usunięcia. Prosimy <a href=\"%(avatar_change_url)s"
|
||||
"\">dodaj nowy</a>."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "Usuń wybrane"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s zaktualizował / zaktualizowała avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> zaktualizował / "
|
||||
"zaktualizowała <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Twój avatar został zaktualizowany %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"Zaktualizowałeś / zaktualizowałaś swój avatar <a href=\"%(avatar_url)s\">"
|
||||
"%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Domyślny avatar"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Pomyślnie wysłano nowy avatar."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Pomyślnie zaktualizowano Twój avatar."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Pomyślnie usunięto wskazany avatar."
|
||||
|
|
@ -8,75 +8,93 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-28 10:59+0200\n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: forms.py:34
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : %"
|
||||
"(valid_exts_list)s"
|
||||
msgstr ""
|
||||
#: admin.py:26
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "Avatar"
|
||||
msgstr "Avatar para %s"
|
||||
|
||||
#: forms.py:38
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
#, fuzzy
|
||||
#| msgid "Default Avatar"
|
||||
msgid "avatar"
|
||||
msgstr "Foto de Perfil Padrão"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is %"
|
||||
"(max_valid_size)s"
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s é uma extensão informada inválida. Os Formatos permitidos são : "
|
||||
"%(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is %"
|
||||
"(nb_max_avatars)d."
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Arquivo muito grande (%(size)s), o máximo permitido é %(max_valid_size)s"
|
||||
|
||||
#: forms.py:56 forms.py:67
|
||||
msgid "Choices"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:75
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid "Avatar for %s"
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"Você já possui %(nb_avatars)d fotos. O máximo permitido é %(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "Opções"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "avatars"
|
||||
msgstr "Avatar para %s"
|
||||
|
||||
#: views.py:73 views.py:95
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Nova foto de perfil enviada com sucesso."
|
||||
|
||||
#: views.py:132
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Sua foto de perfil foi atualizada com sucesso."
|
||||
|
||||
#: views.py:166
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "As fotos de perfil selecionadas foram excluídas com sucesso."
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr ""
|
||||
msgstr "Sua foto atual:"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr ""
|
||||
msgstr "Você ainda não possui uma foto de perfil"
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr ""
|
||||
msgstr "Enviar foto"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr ""
|
||||
msgstr "Escolher padrão"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr ""
|
||||
msgstr "Por favor, selecione as fotos que você deseja excluir"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
|
|
@ -84,10 +102,12 @@ msgid ""
|
|||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"Você não possui uma foto. Deseja <a href=\"%(avatar_change_url)s\">enviar "
|
||||
"uma agora?</a>"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr ""
|
||||
msgstr "Excluir estes"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, fuzzy, python-format
|
||||
|
|
@ -96,6 +116,8 @@ msgid ""
|
|||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s atualizou a foto do perfil %(avatar)s.\n"
|
||||
"\n"
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> atualizou a foto de perfil "
|
||||
"<a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
|
|
@ -115,6 +137,9 @@ msgid ""
|
|||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"Sua foto de perfil foi atualizada. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, fuzzy, python-format
|
||||
|
|
@ -123,15 +148,27 @@ msgstr ""
|
|||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> atualizou a foto de perfil "
|
||||
"<a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:45
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Foto de Perfil Padrão"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Nova foto de perfil enviada com sucesso."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Sua foto foi atualizada com sucesso."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "As fotos de perfil selecionadas foram excluídas com sucesso."
|
||||
|
||||
#~ msgid "Avatar Updated"
|
||||
#~ msgstr "Foto de Perfil Atualizada"
|
||||
|
||||
#~ msgid "avatar have been updated"
|
||||
#~ msgstr "foto de perfil foi atualizada"
|
||||
#~ msgstr "sua foto de perfil foi atualizada"
|
||||
|
||||
#~ msgid "Friend Updated Avatar"
|
||||
#~ msgstr "Amigo Atualizou Foto de Perfil"
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-03-17 00:31+0400\n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2012-03-17 00:31+0400\n"
|
||||
"Last-Translator: frost-nzcr4 <frost.nzcr4@jagmort.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
|
@ -19,50 +20,74 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"X-Poedit-SourceCharset: utf-8\n"
|
||||
|
||||
#: forms.py:33
|
||||
#, python-format
|
||||
msgid "%(ext)s is an invalid file extension. Authorized extensions are : %(valid_exts_list)s"
|
||||
msgstr "%(ext)s запрещённое расширение. Разрешённые расширения: %(valid_exts_list)s"
|
||||
#: admin.py:26
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "Avatar"
|
||||
msgstr "Аватар для %s"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
#, fuzzy
|
||||
#| msgid "Default Avatar"
|
||||
msgid "avatar"
|
||||
msgstr "Аватар по умолчанию"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid "Your file is too big (%(size)s), the maximum allowed size is %(max_valid_size)s"
|
||||
msgstr "Файл слишком большой (%(size)s), максимальный допустимый размер %(max_valid_size)s"
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr ""
|
||||
"%(ext)s запрещённое расширение. Разрешённые расширения: %(valid_exts_list)s"
|
||||
|
||||
#: forms.py:43
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid "You already have %(nb_avatars)d avatars, and the maximum allowed is %(nb_max_avatars)d."
|
||||
msgstr "У вас уже %(nb_avatars)d аватаров, максимально допустимо %(nb_max_avatars)d."
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr ""
|
||||
"Файл слишком большой (%(size)s), максимальный допустимый размер "
|
||||
"%(max_valid_size)s"
|
||||
|
||||
#: models.py:72
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid "Avatar for %s"
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr ""
|
||||
"У вас уже %(nb_avatars)d аватаров, максимально допустимо %(nb_max_avatars)d."
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "Avatar for %s"
|
||||
msgid "avatars"
|
||||
msgstr "Аватар для %s"
|
||||
|
||||
#: views.py:90
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Новый аватар загружен."
|
||||
|
||||
#: views.py:128
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Аватар обновлён."
|
||||
|
||||
#: views.py:166
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Выбранные аватары удалены."
|
||||
|
||||
#: templates/avatar/add.html:5
|
||||
#: templates/avatar/change.html:5
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "Ваш аватар:"
|
||||
|
||||
#: templates/avatar/add.html:8
|
||||
#: templates/avatar/change.html:8
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "Вы ещё не загружали аватар. Пожалуйста, загрузите его."
|
||||
|
||||
#: templates/avatar/add.html:12
|
||||
#: templates/avatar/change.html:19
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "Загрузить новое изображение"
|
||||
|
||||
|
|
@ -76,24 +101,64 @@ msgstr "Выберите аватары, которые собираетесь
|
|||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid "You have no avatars to delete. Please <a href=\"%(avatar_change_url)s\">upload one</a> now."
|
||||
msgstr "У вас нет аватаров. <a href=\"%(avatar_change_url)s\">Загрузите</a> его."
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"У вас нет аватаров. <a href=\"%(avatar_change_url)s\">Загрузите</a> его."
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "Удалить эти"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, fuzzy, python-format
|
||||
#| msgid ""
|
||||
#| "<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar "
|
||||
#| "<a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s обновил свои аватары %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "<a href=\"%(user_url)s\">%(avatar_creator)s</a> обновил свои аватары <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> обновил свои аватары <a href="
|
||||
"\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "Вы обновили аватар <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:40
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "Аватар по умолчанию"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "Новый аватар загружен."
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "Аватар обновлён."
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "Выбранные аватары удалены."
|
||||
|
|
|
|||
BIN
avatar/locale/zh_CN/LC_MESSAGES/django.mo
Normal file
BIN
avatar/locale/zh_CN/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
154
avatar/locale/zh_CN/LC_MESSAGES/django.po
Normal file
154
avatar/locale/zh_CN/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-avatar\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-14 16:37+0200\n"
|
||||
"PO-Revision-Date: 2014-03-26 17:08+0800\n"
|
||||
"Last-Translator: Bruce Yang <ayang23@gmail.com>\n"
|
||||
"Language-Team: Bruce Yang <ayang23@gmail.com>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Poedit 1.5.7\n"
|
||||
|
||||
#: admin.py:26
|
||||
msgid "Avatar"
|
||||
msgstr "头像"
|
||||
|
||||
#: forms.py:24 models.py:84 models.py:97
|
||||
msgid "avatar"
|
||||
msgstr "头像"
|
||||
|
||||
#: forms.py:37
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(ext)s is an invalid file extension. Authorized extensions are : "
|
||||
"%(valid_exts_list)s"
|
||||
msgstr "%(ext)s 是不正确的文件扩展名。 正确的扩展名为 : %(valid_exts_list)s"
|
||||
|
||||
#: forms.py:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your file is too big (%(size)s), the maximum allowed size is "
|
||||
"%(max_valid_size)s"
|
||||
msgstr "上传文件太大 (%(size)s), 允许的最大文件为 %(max_valid_size)s"
|
||||
|
||||
#: forms.py:54
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You already have %(nb_avatars)d avatars, and the maximum allowed is "
|
||||
"%(nb_max_avatars)d."
|
||||
msgstr "您目前有 %(nb_avatars)d 个头像, 最多可以有 %(nb_max_avatars)d 个。"
|
||||
|
||||
#: forms.py:71 forms.py:84
|
||||
msgid "Choices"
|
||||
msgstr "选项"
|
||||
|
||||
#: models.py:77
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:80
|
||||
msgid "primary"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:91
|
||||
msgid "uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:98
|
||||
#, fuzzy
|
||||
#| msgid "avatar"
|
||||
msgid "avatars"
|
||||
msgstr "头像"
|
||||
|
||||
#: templates/avatar/add.html:5 templates/avatar/change.html:5
|
||||
msgid "Your current avatar: "
|
||||
msgstr "您当前的头像:"
|
||||
|
||||
#: templates/avatar/add.html:8 templates/avatar/change.html:8
|
||||
msgid "You haven't uploaded an avatar yet. Please upload one now."
|
||||
msgstr "您还没有上传任何头像,请现在上传一个吧。"
|
||||
|
||||
#: templates/avatar/add.html:12 templates/avatar/change.html:19
|
||||
msgid "Upload New Image"
|
||||
msgstr "上传新照片"
|
||||
|
||||
#: templates/avatar/change.html:14
|
||||
msgid "Choose new Default"
|
||||
msgstr "选择默认"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:5
|
||||
msgid "Please select the avatars that you would like to delete."
|
||||
msgstr "选择要删除的头像。"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:8
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
|
||||
"\">upload one</a> now."
|
||||
msgstr ""
|
||||
"没有头像可以删除. 请 <a href=\"%(avatar_change_url)s\">上传一个新头像</a>。"
|
||||
|
||||
#: templates/avatar/confirm_delete.html:14
|
||||
msgid "Delete These"
|
||||
msgstr "删除"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(avatar_creator)s has updated their avatar %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"%(avatar_creator)s 更新了头像 %(avatar)s.\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_friend_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> has updated their avatar <a "
|
||||
"href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr ""
|
||||
"<a href=\"%(user_url)s\">%(avatar_creator)s</a> 更新了头像 <a href="
|
||||
"\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templates/notification/avatar_updated/full.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your avatar has been updated. %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
msgstr ""
|
||||
"您的头像已经更新。 %(avatar)s\n"
|
||||
"\n"
|
||||
"http://%(current_site)s%(avatar_url)s\n"
|
||||
|
||||
#: templates/notification/avatar_updated/notice.html:2
|
||||
#, python-format
|
||||
msgid "You have updated your avatar <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
msgstr "您已经更新了头像 <a href=\"%(avatar_url)s\">%(avatar)s</a>."
|
||||
|
||||
#: templatetags/avatar_tags.py:69
|
||||
msgid "Default Avatar"
|
||||
msgstr "默认头像"
|
||||
|
||||
#: views.py:73
|
||||
msgid "Successfully uploaded a new avatar."
|
||||
msgstr "成功上传头像。"
|
||||
|
||||
#: views.py:111
|
||||
msgid "Successfully updated your avatar."
|
||||
msgstr "更新头像成功。"
|
||||
|
||||
#: views.py:150
|
||||
msgid "Successfully deleted the requested avatars."
|
||||
msgstr "成功删除头像。"
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
from django.core.management.base import NoArgsCommand
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from avatar.conf import settings
|
||||
from avatar.models import Avatar
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
class Command(BaseCommand):
|
||||
help = ("Regenerates avatar thumbnails for the sizes specified in "
|
||||
"settings.AVATAR_AUTO_GENERATE_SIZES.")
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
def handle(self, *args, **options):
|
||||
for avatar in Avatar.objects.all():
|
||||
for size in settings.AVATAR_AUTO_GENERATE_SIZES:
|
||||
print("Rebuilding Avatar id=%s at size %s." % (avatar.id, size))
|
||||
if options['verbosity'] != 0:
|
||||
print("Rebuilding Avatar id=%s at size %s." % (avatar.id, size))
|
||||
|
||||
avatar.create_thumbnail(size)
|
||||
|
|
|
|||
28
avatar/migrations/0001_initial.py
Normal file
28
avatar/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.utils.timezone
|
||||
import avatar.models
|
||||
import django.core.files.storage
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Avatar',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('primary', models.BooleanField(default=False)),
|
||||
('avatar', models.ImageField(storage=django.core.files.storage.FileSystemStorage(), max_length=1024, upload_to=avatar.models.avatar_file_path, blank=True)),
|
||||
('date_uploaded', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
44
avatar/migrations/0002_add_verbose_names_to_avatar_fields.py
Normal file
44
avatar/migrations/0002_add_verbose_names_to_avatar_fields.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-09-16 08:50
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import avatar.models
|
||||
from django.conf import settings
|
||||
import django.core.files.storage
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('avatar', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='avatar',
|
||||
options={'verbose_name': 'avatar', 'verbose_name_plural': 'avatars'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='avatar',
|
||||
name='avatar',
|
||||
field=models.ImageField(blank=True, max_length=1024, storage=django.core.files.storage.FileSystemStorage(), upload_to=avatar.models.avatar_path_handler, verbose_name='avatar'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='avatar',
|
||||
name='date_uploaded',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='uploaded at'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='avatar',
|
||||
name='primary',
|
||||
field=models.BooleanField(default=False, verbose_name='primary'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='avatar',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user'),
|
||||
),
|
||||
]
|
||||
21
avatar/migrations/0003_auto_20170827_1345.py
Normal file
21
avatar/migrations/0003_auto_20170827_1345.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.4 on 2017-08-27 13:45
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import avatar.models
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('avatar', '0002_add_verbose_names_to_avatar_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='avatar',
|
||||
name='avatar',
|
||||
field=avatar.models.AvatarField(),
|
||||
),
|
||||
]
|
||||
0
avatar/migrations/__init__.py
Normal file
0
avatar/migrations/__init__.py
Normal file
|
|
@ -1,3 +1,4 @@
|
|||
import binascii
|
||||
import datetime
|
||||
import os
|
||||
import hashlib
|
||||
|
|
@ -7,12 +8,14 @@ from django.db import models
|
|||
from django.core.files import File
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import get_storage_class
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils import six
|
||||
from django.db.models import signals
|
||||
|
||||
from avatar.conf import settings
|
||||
from avatar.util import get_username, force_bytes, invalidate_cache
|
||||
from avatar.utils import get_username, force_bytes, invalidate_cache
|
||||
|
||||
try:
|
||||
from django.utils.timezone import now
|
||||
|
|
@ -23,13 +26,15 @@ except ImportError:
|
|||
avatar_storage = get_storage_class(settings.AVATAR_STORAGE)()
|
||||
|
||||
|
||||
def avatar_file_path(instance=None, filename=None, size=None, ext=None):
|
||||
def avatar_path_handler(instance=None, filename=None, size=None, ext=None):
|
||||
tmppath = [settings.AVATAR_STORAGE_DIR]
|
||||
if settings.AVATAR_HASH_USERDIRNAMES:
|
||||
tmp = hashlib.md5(get_username(instance.user)).hexdigest()
|
||||
tmppath.extend([tmp[0], tmp[1], get_username(instance.user)])
|
||||
else:
|
||||
tmp = hashlib.md5(force_bytes(get_username(instance.user))).hexdigest()
|
||||
tmppath.extend(tmp[0:2])
|
||||
if settings.AVATAR_EXPOSE_USERNAMES:
|
||||
tmppath.append(get_username(instance.user))
|
||||
else:
|
||||
tmppath.append(force_text(instance.user.pk))
|
||||
if not filename:
|
||||
# Filename already stored in database
|
||||
filename = instance.avatar.name
|
||||
|
|
@ -44,7 +49,10 @@ def avatar_file_path(instance=None, filename=None, size=None, ext=None):
|
|||
# File doesn't exist yet
|
||||
if settings.AVATAR_HASH_FILENAMES:
|
||||
(root, ext) = os.path.splitext(filename)
|
||||
filename = hashlib.md5(force_bytes(filename)).hexdigest()
|
||||
if settings.AVATAR_RANDOMIZE_HASHES:
|
||||
filename = binascii.hexlify(os.urandom(16)).decode('ascii')
|
||||
else:
|
||||
filename = hashlib.md5(force_bytes(filename)).hexdigest()
|
||||
filename = filename + ext
|
||||
if size:
|
||||
tmppath.extend(['resized', str(size)])
|
||||
|
|
@ -52,6 +60,9 @@ def avatar_file_path(instance=None, filename=None, size=None, ext=None):
|
|||
return os.path.join(*tmppath)
|
||||
|
||||
|
||||
avatar_file_path = import_string(settings.AVATAR_PATH_HANDLER)
|
||||
|
||||
|
||||
def find_extension(format):
|
||||
format = format.lower()
|
||||
|
||||
|
|
@ -61,14 +72,42 @@ def find_extension(format):
|
|||
return format
|
||||
|
||||
|
||||
class AvatarField(models.ImageField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AvatarField, self).__init__(*args, **kwargs)
|
||||
|
||||
self.max_length = 1024
|
||||
self.upload_to = avatar_file_path
|
||||
self.storage = avatar_storage
|
||||
self.blank = True
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(models.ImageField, self).deconstruct()
|
||||
return name, path, (), {}
|
||||
|
||||
|
||||
class Avatar(models.Model):
|
||||
user = models.ForeignKey(getattr(settings, 'AUTH_USER_MODEL', 'auth.User'))
|
||||
primary = models.BooleanField(default=False)
|
||||
avatar = models.ImageField(max_length=1024,
|
||||
upload_to=avatar_file_path,
|
||||
storage=avatar_storage,
|
||||
blank=True)
|
||||
date_uploaded = models.DateTimeField(default=now)
|
||||
user = models.ForeignKey(
|
||||
getattr(settings, 'AUTH_USER_MODEL', 'auth.User'),
|
||||
verbose_name=_("user"),
|
||||
)
|
||||
primary = models.BooleanField(
|
||||
verbose_name=_("primary"),
|
||||
default=False,
|
||||
)
|
||||
avatar = AvatarField(
|
||||
verbose_name=_("avatar")
|
||||
)
|
||||
date_uploaded = models.DateTimeField(
|
||||
verbose_name=_("uploaded at"),
|
||||
default=now,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
app_label = 'avatar'
|
||||
verbose_name = _('avatar')
|
||||
verbose_name_plural = _('avatars')
|
||||
|
||||
def __unicode__(self):
|
||||
return _(six.u('Avatar for %s')) % self.user
|
||||
|
|
@ -103,7 +142,7 @@ class Avatar(models.Model):
|
|||
else:
|
||||
diff = int((h - w) / 2)
|
||||
image = image.crop((0, diff, w, h - diff))
|
||||
if image.mode != "RGB":
|
||||
if image.mode not in ("RGB", "RGBA"):
|
||||
image = image.convert("RGB")
|
||||
image = image.resize((size, size), settings.AVATAR_RESIZE_METHOD)
|
||||
thumb = six.BytesIO()
|
||||
|
|
|
|||
84
avatar/providers.py
Normal file
84
avatar/providers.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import hashlib
|
||||
|
||||
try:
|
||||
from urllib.parse import urljoin, urlencode
|
||||
except ImportError:
|
||||
from urlparse import urljoin
|
||||
from urllib import urlencode
|
||||
|
||||
|
||||
from avatar.conf import settings
|
||||
from avatar.utils import (
|
||||
force_bytes,
|
||||
get_default_avatar_url,
|
||||
get_primary_avatar,
|
||||
)
|
||||
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
# If the FacebookAvatarProvider is used, a mechanism needs to be defined on
|
||||
# how to obtain the user's Facebook UID. This is done via
|
||||
# ``AVATAR_FACEBOOK_GET_ID``.
|
||||
get_facebook_id = None
|
||||
|
||||
if 'avatar.providers.FacebookAvatarProvider' in settings.AVATAR_PROVIDERS:
|
||||
if callable(settings.AVATAR_FACEBOOK_GET_ID):
|
||||
get_facebook_id = settings.AVATAR_FACEBOOK_GET_ID
|
||||
else:
|
||||
get_facebook_id = import_string(settings.AVATAR_FACEBOOK_GET_ID)
|
||||
|
||||
|
||||
class DefaultAvatarProvider(object):
|
||||
"""
|
||||
Returns the default url defined by ``settings.DEFAULT_AVATAR_URL``.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_avatar_url(self, user, size):
|
||||
return get_default_avatar_url()
|
||||
|
||||
|
||||
class PrimaryAvatarProvider(object):
|
||||
"""
|
||||
Returns the primary Avatar from the users avatar set.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_avatar_url(self, user, size):
|
||||
avatar = get_primary_avatar(user, size)
|
||||
if avatar:
|
||||
return avatar.avatar_url(size)
|
||||
|
||||
|
||||
class GravatarAvatarProvider(object):
|
||||
"""
|
||||
Returns the url for an avatar by the Gravatar service.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_avatar_url(self, user, size):
|
||||
params = {'s': str(size)}
|
||||
if settings.AVATAR_GRAVATAR_DEFAULT:
|
||||
params['d'] = settings.AVATAR_GRAVATAR_DEFAULT
|
||||
if settings.AVATAR_GRAVATAR_FORCEDEFAULT:
|
||||
params['f'] = 'y'
|
||||
path = "%s/?%s" % (hashlib.md5(force_bytes(getattr(user,
|
||||
settings.AVATAR_GRAVATAR_FIELD))).hexdigest(), urlencode(params))
|
||||
|
||||
return urljoin(settings.AVATAR_GRAVATAR_BASE_URL, path)
|
||||
|
||||
|
||||
class FacebookAvatarProvider(object):
|
||||
"""
|
||||
Returns the url of a Facebook profile image.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_avatar_url(self, user, size):
|
||||
fb_id = get_facebook_id(user)
|
||||
if fb_id:
|
||||
url = 'https://graph.facebook.com/{fb_id}/picture?type=square&width={size}&height={size}'
|
||||
return url.format(
|
||||
fb_id=fb_id,
|
||||
size=size
|
||||
)
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "avatar/base.html" %}
|
||||
{% load i18n avatar_tags %}
|
||||
{% load url from future %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% trans "Your current avatar: " %}</p>
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title><!-- Insert your title here --></title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Insert your content here -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1 +1 @@
|
|||
<img src="{{ url }}" alt="{{ alt }}" width="{{ size }}" height="{{ size }}" />
|
||||
<img src="{{ url }}" width="{{ size }}" height="{{ size }}" {% for key, value in kwargs.items %}{{key}}="{{value}}" {% endfor %}/>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "avatar/base.html" %}
|
||||
{% load i18n avatar_tags %}
|
||||
{% load url from future %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% trans "Your current avatar: " %}</p>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "avatar/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% trans "Please select the avatars that you would like to delete." %}</p>
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title><!-- Insert your title here --></title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Insert your content here -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
{% load i18n %}{% load url from future %}{% url 'profile_detail' username=user.username as user_url %}{# TODO: support custom user models via get_username; actually, is this template even used anymore? #}
|
||||
{% load i18n %}{% url 'profile_detail' username=user.username as user_url %}{# TODO: support custom user models via get_username; actually, is this template even used anymore? #}
|
||||
{% blocktrans with user as avatar_creator and avatar.get_absolute_url as avatar_url %}<a href="{{ user_url }}">{{ avatar_creator }}</a> has updated their avatar <a href="{{ avatar_url }}">{{ avatar }}</a>.{% endblocktrans %}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
import hashlib
|
||||
|
||||
try:
|
||||
from urllib.parse import urljoin, urlencode
|
||||
except ImportError:
|
||||
from urlparse import urljoin
|
||||
from urllib import urlencode
|
||||
|
||||
from django import template
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import six
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from avatar.conf import settings
|
||||
from avatar.util import (get_primary_avatar, get_default_avatar_url,
|
||||
cache_result, get_user_model, get_user, force_bytes)
|
||||
from avatar.models import Avatar
|
||||
from avatar.utils import (
|
||||
cache_result,
|
||||
get_default_avatar_url,
|
||||
get_user_model,
|
||||
get_user,
|
||||
)
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
|
@ -23,19 +21,11 @@ register = template.Library()
|
|||
@cache_result()
|
||||
@register.simple_tag
|
||||
def avatar_url(user, size=settings.AVATAR_DEFAULT_SIZE):
|
||||
avatar = get_primary_avatar(user, size=size)
|
||||
if avatar:
|
||||
return avatar.avatar_url(size)
|
||||
|
||||
if settings.AVATAR_GRAVATAR_BACKUP:
|
||||
params = {'s': str(size)}
|
||||
if settings.AVATAR_GRAVATAR_DEFAULT:
|
||||
params['d'] = settings.AVATAR_GRAVATAR_DEFAULT
|
||||
path = "%s/?%s" % (hashlib.md5(force_bytes(user.email)).hexdigest(),
|
||||
urlencode(params))
|
||||
return urljoin(settings.AVATAR_GRAVATAR_BASE_URL, path)
|
||||
|
||||
return get_default_avatar_url()
|
||||
for provider_path in settings.AVATAR_PROVIDERS:
|
||||
provider = import_string(provider_path)
|
||||
avatar_url = provider.get_avatar_url(user, size)
|
||||
if avatar_url:
|
||||
return avatar_url
|
||||
|
||||
|
||||
@cache_result()
|
||||
|
|
@ -52,12 +42,14 @@ def avatar(user, size=settings.AVATAR_DEFAULT_SIZE, **kwargs):
|
|||
else:
|
||||
alt = six.text_type(user)
|
||||
url = avatar_url(user, size)
|
||||
context = dict(kwargs, **{
|
||||
kwargs.update({'alt': alt})
|
||||
|
||||
context = {
|
||||
'user': user,
|
||||
'url': url,
|
||||
'alt': alt,
|
||||
'size': size,
|
||||
})
|
||||
'kwargs': kwargs,
|
||||
}
|
||||
return render_to_string('avatar/avatar_tag.html', context)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
try:
|
||||
from django.conf.urls import patterns, url
|
||||
except ImportError:
|
||||
# Django < 1.4
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
urlpatterns = patterns('avatar.views',
|
||||
url(r'^add/$', 'add', name='avatar_add'),
|
||||
url(r'^change/$', 'change', name='avatar_change'),
|
||||
url(r'^delete/$', 'delete', name='avatar_delete'),
|
||||
url(r'^render_primary/(?P<user>[\w\d\.\-_]{3,30})/(?P<size>[\d]+)/$', 'render_primary', name='avatar_render_primary'),
|
||||
url(r'^list/(?P<username>[\+\w\@\.]+)/$', 'avatar_gallery', name='avatar_gallery'),
|
||||
url(r'^list/(?P<username>[\+\w\@\.]+)/(?P<id>[\d]+)/$', 'avatar', name='avatar'),
|
||||
)
|
||||
from avatar import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^add/$', views.add, name='avatar_add'),
|
||||
url(r'^change/$', views.change, name='avatar_change'),
|
||||
url(r'^delete/$', views.delete, name='avatar_delete'),
|
||||
url(r'^render_primary/(?P<user>[\w\d\@\.\-_]+)/(?P<size>[\d]+)/$',
|
||||
views.render_primary,
|
||||
name='avatar_render_primary'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,17 +9,7 @@ try:
|
|||
except ImportError:
|
||||
force_bytes = str
|
||||
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
def get_user_model():
|
||||
return User
|
||||
|
||||
custom_user_model = False
|
||||
else:
|
||||
custom_user_model = True
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from avatar.conf import settings
|
||||
|
||||
|
|
@ -37,10 +27,7 @@ def get_username(user):
|
|||
|
||||
def get_user(username):
|
||||
""" Return user from a username/ish identifier """
|
||||
if custom_user_model:
|
||||
return get_user_model().objects.get_by_natural_key(username)
|
||||
else:
|
||||
return get_user_model().objects.get(username=username)
|
||||
return get_user_model().objects.get_by_natural_key(username)
|
||||
|
||||
|
||||
def get_cache_key(user_or_username, size, prefix):
|
||||
|
|
@ -64,14 +51,19 @@ def cache_result(default_size=settings.AVATAR_DEFAULT_SIZE):
|
|||
Decorator to cache the result of functions that take a ``user`` and a
|
||||
``size`` value.
|
||||
"""
|
||||
if not settings.AVATAR_CACHE_ENABLED:
|
||||
def decorator(func):
|
||||
return func
|
||||
return decorator
|
||||
|
||||
def decorator(func):
|
||||
def cached_func(user, size=None):
|
||||
def cached_func(user, size=None, **kwargs):
|
||||
prefix = func.__name__
|
||||
cached_funcs.add(prefix)
|
||||
key = get_cache_key(user, size or default_size, prefix=prefix)
|
||||
result = cache.get(key)
|
||||
if result is None:
|
||||
result = func(user, size or default_size)
|
||||
result = func(user, size or default_size, **kwargs)
|
||||
cache_set(key, result)
|
||||
return result
|
||||
return cached_func
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
from django.http import Http404
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils import six
|
||||
from django.utils.translation import ugettext as _
|
||||
|
|
@ -10,8 +9,8 @@ from avatar.conf import settings
|
|||
from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm
|
||||
from avatar.models import Avatar
|
||||
from avatar.signals import avatar_updated
|
||||
from avatar.util import (get_primary_avatar, get_default_avatar_url,
|
||||
get_user_model, get_user)
|
||||
from avatar.utils import (get_primary_avatar, get_default_avatar_url,
|
||||
invalidate_cache)
|
||||
|
||||
|
||||
def _get_next(request):
|
||||
|
|
@ -81,7 +80,8 @@ def add(request, extra_context=None, next_override=None,
|
|||
'next': next_override or _get_next(request),
|
||||
}
|
||||
context.update(extra_context)
|
||||
return render(request, 'avatar/add.html', context)
|
||||
template_name = settings.AVATAR_ADD_TEMPLATE or 'avatar/add.html'
|
||||
return render(request, template_name, context)
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
@ -107,6 +107,7 @@ def change(request, extra_context=None, next_override=None,
|
|||
avatar.primary = True
|
||||
avatar.save()
|
||||
updated = True
|
||||
invalidate_cache(request.user)
|
||||
messages.success(request, _("Successfully updated your avatar."))
|
||||
if updated:
|
||||
avatar_updated.send(sender=Avatar, user=request.user, avatar=avatar)
|
||||
|
|
@ -120,7 +121,8 @@ def change(request, extra_context=None, next_override=None,
|
|||
'next': next_override or _get_next(request)
|
||||
}
|
||||
context.update(extra_context)
|
||||
return render(request, 'avatar/change.html', context)
|
||||
template_name = settings.AVATAR_CHANGE_TEMPLATE or 'avatar/change.html'
|
||||
return render(request, template_name, context)
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
@ -155,69 +157,10 @@ def delete(request, extra_context=None, next_override=None, *args, **kwargs):
|
|||
'next': next_override or _get_next(request),
|
||||
}
|
||||
context.update(extra_context)
|
||||
|
||||
return render(request, 'avatar/confirm_delete.html', context)
|
||||
|
||||
|
||||
def avatar_gallery(request, username, template_name="avatar/gallery.html"):
|
||||
try:
|
||||
user = get_user(username)
|
||||
except get_user_model().DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
context = {
|
||||
"other_user": user,
|
||||
"avatars": user.avatar_set.all(),
|
||||
}
|
||||
|
||||
template_name = settings.AVATAR_DELETE_TEMPLATE or 'avatar/confirm_delete.html'
|
||||
return render(request, template_name, context)
|
||||
|
||||
|
||||
def avatar(request, username, id, template_name="avatar/avatar.html"):
|
||||
try:
|
||||
user = get_user(username)
|
||||
except get_user_model().DoesNotExist:
|
||||
raise Http404
|
||||
avatars = user.avatar_set.order_by("-date_uploaded")
|
||||
index = None
|
||||
avatar = None
|
||||
if avatars:
|
||||
avatar = avatars.get(pk=id)
|
||||
if not avatar:
|
||||
return Http404
|
||||
|
||||
index = avatars.filter(date_uploaded__gt=avatar.date_uploaded).count()
|
||||
count = avatars.count()
|
||||
|
||||
if index == 0:
|
||||
prev = avatars.reverse()[0]
|
||||
if count <= 1:
|
||||
next = avatars[0]
|
||||
else:
|
||||
next = avatars[1]
|
||||
else:
|
||||
prev = avatars[index - 1]
|
||||
|
||||
if (index + 1) >= count:
|
||||
next = avatars[0]
|
||||
prev_index = index - 1
|
||||
if prev_index < 0:
|
||||
prev_index = 0
|
||||
prev = avatars[prev_index]
|
||||
else:
|
||||
next = avatars[index + 1]
|
||||
|
||||
return render(request, template_name, {
|
||||
"other_user": user,
|
||||
"avatar": avatar,
|
||||
"index": index + 1,
|
||||
"avatars": avatars,
|
||||
"next": next,
|
||||
"prev": prev,
|
||||
"count": count,
|
||||
})
|
||||
|
||||
|
||||
def render_primary(request, user=None, size=settings.AVATAR_DEFAULT_SIZE):
|
||||
size = int(size)
|
||||
avatar = get_primary_avatar(user, size=size)
|
||||
|
|
|
|||
186
docs/index.txt
186
docs/index.txt
|
|
@ -2,9 +2,10 @@ django-avatar
|
|||
=============
|
||||
|
||||
Django-avatar is a reusable application for handling user avatars. It has the
|
||||
ability to default to Gravatar_ if no avatar is found for a certain user.
|
||||
Django-avatar automatically generates thumbnails and stores them to your default
|
||||
file storage backend for retrieval later.
|
||||
ability to default to avatars provided by third party services (like Gravatar_
|
||||
or Facebook) if no avatar is found for a certain user. Django-avatar
|
||||
automatically generates thumbnails and stores them to your default file
|
||||
storage backend for retrieval later.
|
||||
|
||||
.. _Gravatar: http://gravatar.com
|
||||
|
||||
|
|
@ -32,43 +33,51 @@ that are required. A minimal integration can work like this:
|
|||
|
||||
1. List this application in the ``INSTALLED_APPS`` portion of your settings
|
||||
file. Your settings file will look something like::
|
||||
|
||||
|
||||
INSTALLED_APPS = (
|
||||
# ...
|
||||
'avatar',
|
||||
)
|
||||
|
||||
2. Add the avatar urls to the end of your root urlconf. Your urlconf
|
||||
will look something like::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
# ...
|
||||
(r'^avatar/', include('avatar.urls')),
|
||||
)
|
||||
2. Migrate your database::
|
||||
|
||||
3. Somewhere in your template navigation scheme, link to the change avatar
|
||||
python manage.py migrate
|
||||
|
||||
3. Add the avatar urls to the end of your root urlconf. Your urlconf
|
||||
will look something like::
|
||||
|
||||
urlpatterns = [
|
||||
# ...
|
||||
url(r'^avatar/', include('avatar.urls')),
|
||||
]
|
||||
|
||||
4. Somewhere in your template navigation scheme, link to the change avatar
|
||||
page::
|
||||
|
||||
|
||||
<a href="{% url 'avatar_change' %}">Change your avatar</a>
|
||||
|
||||
4. Wherever you want to display an avatar for a user, first load the avatar
|
||||
5. Wherever you want to display an avatar for a user, first load the avatar
|
||||
template tags::
|
||||
|
||||
|
||||
{% load avatar_tags %}
|
||||
|
||||
|
||||
Then, use the ``avatar`` tag to display an avatar of a default size::
|
||||
|
||||
|
||||
{% avatar user %}
|
||||
|
||||
|
||||
Or specify a size (in pixels) explicitly::
|
||||
|
||||
|
||||
{% avatar user 65 %}
|
||||
|
||||
Example for customize the attribute of the HTML ``img`` tag::
|
||||
|
||||
{% avatar user 65 class="img-circle img-responsive" id="user_avatar" %}
|
||||
|
||||
Template tags and filter
|
||||
------------------------
|
||||
|
||||
To begin using these template tags, you must first load the tags into the
|
||||
template rendering system:
|
||||
template rendering system::
|
||||
|
||||
{% load avatar_tags %}
|
||||
|
||||
|
|
@ -76,10 +85,11 @@ template rendering system:
|
|||
Renders the URL of the avatar for the given user. User can be either a
|
||||
``django.contrib.auth.models.User`` object instance or a username.
|
||||
|
||||
``{% avatar user [size in pixels] %}``
|
||||
``{% avatar user [size in pixels] **kwargs %}``
|
||||
Renders an HTML ``img`` tag for the given user for the specified size. User
|
||||
can be either a ``django.contrib.auth.models.User`` object instance or a
|
||||
username.
|
||||
username. The (key, value) pairs in kwargs will be added to ``img`` tag
|
||||
as its attributes.
|
||||
|
||||
``{% render_avatar avatar [size in pixels] %}``
|
||||
Given an actual ``avatar.models.Avatar`` object instance, renders an HTML
|
||||
|
|
@ -94,36 +104,142 @@ Global Settings
|
|||
There are a number of settings available to easily customize the avatars that
|
||||
appear on the site. Listed below are those settings:
|
||||
|
||||
AVATAR_AUTO_GENERATE_SIZES
|
||||
.. py:data:: AVATAR_AUTO_GENERATE_SIZES
|
||||
|
||||
An iterable of integers representing the sizes of avatars to generate on
|
||||
upload. This can save rendering time later on if you pre-generate the
|
||||
resized versions. Defaults to ``(80,)``
|
||||
|
||||
AVATAR_RESIZE_METHOD
|
||||
.. py:data:: AVATAR_CACHE_ENABLED
|
||||
|
||||
Set to ``False`` if you completely disable avatar caching. Defaults to ``True``.
|
||||
|
||||
.. py:data:: AVATAR_DEFAULT_URL
|
||||
|
||||
The default URL to default to if the
|
||||
:py:class:`~avatar.providers.GravatarAvatarProvider` is not used and there
|
||||
is no ``Avatar`` instance found in the system for the given user.
|
||||
|
||||
.. py:data:: AVATAR_EXPOSE_USERNAMES
|
||||
|
||||
Puts the User's username field in the URL path when ``True``. Set to
|
||||
``False`` to use the User's primary key instead, preventing their email
|
||||
from being searchable on the web. Defaults to ``True``.
|
||||
|
||||
.. py:data:: AVATAR_FACEBOOK_GET_ID
|
||||
|
||||
A callable or string path to a callable that will return the user's
|
||||
Facebook ID. The callable should take a ``User`` object and return a
|
||||
string. If you want to use this then make sure you included
|
||||
:py:class:`~avatar.providers.FacebookAvatarProvider` in :py:data:`AVATAR_PROVIDERS`.
|
||||
|
||||
.. py:data:: AVATAR_GRAVATAR_DEFAULT
|
||||
|
||||
A string determining the default Gravatar. Can be a URL to a custom image
|
||||
or a style of Gravatar. Ex. `retro`. All Available options listed in the
|
||||
`Gravatar documentation <https://en.gravatar.com/site/implement/images
|
||||
/#default-image>`_. Defaults to ``None``.
|
||||
|
||||
.. py:data:: AVATAR_GRAVATAR_FORCEDEFAULT
|
||||
|
||||
A bool indicating whether or not to always use the default Gravitar. More
|
||||
details can be found in the `Gravatar documentation
|
||||
<https://en.gravatar.com/site/implement/images/#force-default>`_. Defaults
|
||||
to ``False``.
|
||||
|
||||
.. py:data:: AVATAR_GRAVATAR_FIELD
|
||||
|
||||
The name of the user's field containing the gravatar email. For example,
|
||||
if you set this to ``gravatar`` then django-avatar will get the user's
|
||||
gravatar in ``user.gravatar``. Defaults to ``email``.
|
||||
|
||||
.. py:data:: AVATAR_MAX_SIZE
|
||||
|
||||
File size limit for avatar upload. Default is ``1024 * 1024`` (1 MB).
|
||||
gravatar in ``user.gravatar``. Defaults to ``email``.
|
||||
|
||||
.. py:data:: AVATAR_MAX_AVATARS_PER_USER
|
||||
|
||||
The maximum number of avatars each user can have. Default is ``42``.
|
||||
|
||||
.. py:data:: AVATAR_PATH_HANDLER
|
||||
|
||||
Path to a method for avatar file path handling. Default is
|
||||
``avatar.models.avatar_path_handler``.
|
||||
|
||||
.. py:data:: AVATAR_PROVIDERS
|
||||
|
||||
Tuple of classes that are tried in the given order for returning avatar
|
||||
URLs.
|
||||
Defaults to::
|
||||
|
||||
(
|
||||
'avatar.providers.PrimaryAvatarProvider',
|
||||
'avatar.providers.GravatarAvatarProvider',
|
||||
'avatar.providers.DefaultAvatarProvider',
|
||||
)
|
||||
|
||||
If you want to implement your own provider, it must provide a class method
|
||||
``get_avatar_url(user, size)``.
|
||||
|
||||
.. py:class:: avatar.providers.PrimaryAvatarProvider
|
||||
|
||||
Returns the primary avatar stored for the given user.
|
||||
|
||||
.. py:class:: avatar.providers.GravatarAvatarProvider
|
||||
|
||||
Adds support for the Gravatar service and will always return an avatar
|
||||
URL. If the user has no avatar registered with Gravatar a default will
|
||||
be used (see :py:data:`AVATAR_GRAVATAR_DEFAULT`).
|
||||
|
||||
.. py:class:: avatar.providers.FacebookAvatarProvider
|
||||
|
||||
Add this provider to :py:data:`AVATAR_PROVIDERS` in order to add
|
||||
support for profile images from Facebook. Note that you also need to
|
||||
set the :py:data:`AVATAR_FACEBOOK_GET_ID` setting.
|
||||
|
||||
.. py:class:: avatar.providers.DefaultAvatarProvider
|
||||
|
||||
Provides a fallback avatar defined in :py:data:`AVATAR_DEFAULT_URL`.
|
||||
|
||||
.. py:data:: AVATAR_RESIZE_METHOD
|
||||
|
||||
The method to use when resizing images, based on the options available in
|
||||
PIL. Defaults to ``Image.ANTIALIAS``.
|
||||
|
||||
AVATAR_STORAGE_DIR
|
||||
.. py:data:: AVATAR_STORAGE_DIR
|
||||
|
||||
The directory under ``MEDIA_ROOT`` to store the images. If using a
|
||||
non-filesystem storage device, this will simply be appended to the beginning
|
||||
of the file name.
|
||||
of the file name. Defaults to ``avatars``.
|
||||
PIL. Defaults to ``Image.ANTIALIAS``.
|
||||
|
||||
AVATAR_GRAVATAR_BACKUP
|
||||
A boolean determining whether to default to the Gravatar service if no
|
||||
``Avatar`` instance is found in the system for the given user. Defaults to
|
||||
True.
|
||||
.. py:data:: AVATAR_CLEANUP_DELETED
|
||||
|
||||
AVATAR_DEFAULT_URL
|
||||
The default URL to default to if ``AVATAR_GRAVATAR_BACKUP`` is set to False
|
||||
and there is no ``Avatar`` instance found in the system for the given user.
|
||||
``True`` if the avatar image files should be deleted when an avatar is
|
||||
deleted from the database. Defaults to ``False``.
|
||||
|
||||
.. py:data:: AVATAR_ADD_TEMPLATE
|
||||
|
||||
Path to the Django template to use for adding a new avatar. Defaults to
|
||||
``avatar/add.html``.
|
||||
|
||||
.. py:data:: AVATAR_CHANGE_TEMPLATE
|
||||
|
||||
Path to the Django template to use for changing a user's avatar. Defaults to ``avatar/change.html``.
|
||||
|
||||
.. py:data:: AVATAR_DELETE_TEMPLATE
|
||||
|
||||
Path to the Django template to use for confirming a delete of a user's
|
||||
avatar. Defaults to ``avatar/avatar/confirm_delete.html``.
|
||||
|
||||
Management Commands
|
||||
-------------------
|
||||
|
||||
This application does include one management command: ``rebuild_avatars``. It
|
||||
takes no arguments and, when run, re-renders all of the thumbnails for all of
|
||||
the avatars for the pixel sizes specified in the ``AUTO_GENERATE_AVATAR_SIZES``
|
||||
setting.
|
||||
the avatars for the pixel sizes specified in the
|
||||
:py:data:`AVATAR_AUTO_GENERATE_SIZES` setting.
|
||||
|
||||
|
||||
.. _pip: http://www.pip-installer.org/
|
||||
|
|
|
|||
18
setup.py
18
setup.py
|
|
@ -28,20 +28,26 @@ setup(
|
|||
'Environment :: Web Environment',
|
||||
'Framework :: Django',
|
||||
'Intended Audience :: Developers',
|
||||
'Framework :: Django',
|
||||
'Framework :: Django :: 1.9',
|
||||
'Framework :: Django :: 1.10',
|
||||
'Framework :: Django :: 1.11',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
],
|
||||
keywords='avatar, django',
|
||||
author='Eric Florenzano',
|
||||
author_email='floguy@gmail.com',
|
||||
maintainer='Jannis Leidel',
|
||||
maintainer_email='jannis@leidel.info',
|
||||
url='http://github.com/jezdez/django-avatar/',
|
||||
maintainer='Grant McConnaughey',
|
||||
maintainer_email='grantmcconnaughey@gmail.com',
|
||||
url='http://github.com/grantmcconnaughey/django-avatar/',
|
||||
license='BSD',
|
||||
packages=find_packages(exclude=['tests']),
|
||||
package_data={
|
||||
|
|
|
|||
26
test_proj/manage.py
Executable file
26
test_proj/manage.py
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_proj.settings")
|
||||
|
||||
# Add the django-avatar directory to the Python path. That way the
|
||||
# avatar module can be imported.
|
||||
sys.path.append('..')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError:
|
||||
# The above import may fail for some other reason. Ensure that the
|
||||
# issue is really that Django is missing to avoid masking other
|
||||
# exceptions on Python 2.
|
||||
try:
|
||||
import django
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
)
|
||||
raise
|
||||
execute_from_command_line(sys.argv)
|
||||
0
test_proj/test_proj/__init__.py
Normal file
0
test_proj/test_proj/__init__.py
Normal file
106
test_proj/test_proj/settings.py
Normal file
106
test_proj/test_proj/settings.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
"""
|
||||
Django settings for test_proj project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.10.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.10/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.10/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '0o$jym8^hgw%vwx9hy%@ncr!29n7gik30(ln$pd$!3*4zu+9dv'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'avatar',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'test_proj.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'test_proj.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
MEDIA_URL = '/media/'
|
||||
17
test_proj/test_proj/urls.py
Normal file
17
test_proj/test_proj/urls.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from django.conf import settings
|
||||
from django.conf.urls import url, include
|
||||
from django.contrib import admin
|
||||
from django.views.static import serve
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^avatar/', include('avatar.urls')),
|
||||
]
|
||||
|
||||
|
||||
if settings.DEBUG:
|
||||
# static files (images, css, javascript, etc.)
|
||||
urlpatterns += [
|
||||
url(r'^media/(?P<path>.*)$', serve, {
|
||||
'document_root': settings.MEDIA_ROOT})
|
||||
]
|
||||
16
test_proj/test_proj/wsgi.py
Normal file
16
test_proj/test_proj/wsgi.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for test_proj project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_proj.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
BIN
tests/data/django.png
Normal file
BIN
tests/data/django.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
tests/data/django_pony_cmyk.jpg
Normal file
BIN
tests/data/django_pony_cmyk.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -1,3 +1,3 @@
|
|||
flake8
|
||||
coverage
|
||||
coverage==4.2
|
||||
django-discover-runner
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
import os
|
||||
import django
|
||||
|
||||
VERSION = django.VERSION
|
||||
SETTINGS_DIR = os.path.dirname(__file__)
|
||||
|
||||
DATABASE_ENGINE = 'sqlite3'
|
||||
|
||||
DATABASES = {
|
||||
|
|
@ -14,10 +18,32 @@ INSTALLED_APPS = [
|
|||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.comments',
|
||||
'avatar',
|
||||
]
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
)
|
||||
|
||||
if VERSION[0] == 1 and VERSION[1] < 8:
|
||||
TEMPLATE_DIRS = (
|
||||
os.path.join(SETTINGS_DIR, 'templates'),
|
||||
)
|
||||
else:
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'APP_DIRS': True,
|
||||
'DIRS': [
|
||||
os.path.join(SETTINGS_DIR, 'templates')
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
|
||||
SITE_ID = 1
|
||||
|
|
|
|||
1
tests/templates/alt/add.html
Normal file
1
tests/templates/alt/add.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTERNATE ADD TEMPLATE
|
||||
1
tests/templates/alt/change.html
Normal file
1
tests/templates/alt/change.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTERNATE CHANGE TEMPLATE
|
||||
1
tests/templates/alt/delete.html
Normal file
1
tests/templates/alt/delete.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTERNATE DELETE TEMPLATE
|
||||
168
tests/tests.py
168
tests/tests.py
|
|
@ -1,11 +1,15 @@
|
|||
import os.path
|
||||
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from avatar.admin import AvatarAdmin
|
||||
from avatar.conf import settings
|
||||
from avatar.util import get_primary_avatar, get_user_model
|
||||
from avatar.utils import get_primary_avatar, get_user_model
|
||||
from avatar.models import Avatar
|
||||
from avatar.templatetags import avatar_tags
|
||||
from PIL import Image
|
||||
|
||||
|
||||
|
|
@ -18,50 +22,65 @@ def upload_helper(o, filename):
|
|||
return response
|
||||
|
||||
|
||||
class AvatarUploadTests(TestCase):
|
||||
class AvatarTests(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.testdatapath = os.path.join(os.path.dirname(__file__), "data")
|
||||
self.user = get_user_model().objects.create_user('test', 'lennon@thebeatles.com', 'testpassword')
|
||||
self.user.save()
|
||||
self.client.login(username='test', password='testpassword')
|
||||
self.site = AdminSite()
|
||||
Image.init()
|
||||
|
||||
def testNonImageUpload(self):
|
||||
def test_admin_get_avatar_returns_different_image_tags(self):
|
||||
self.test_normal_image_upload()
|
||||
self.test_normal_image_upload()
|
||||
primary = Avatar.objects.get(primary=True)
|
||||
old = Avatar.objects.get(primary=False)
|
||||
|
||||
aa = AvatarAdmin(Avatar, self.site)
|
||||
primary_link = aa.get_avatar(primary)
|
||||
old_link = aa.get_avatar(old)
|
||||
|
||||
self.assertNotEqual(primary_link, old_link)
|
||||
|
||||
def test_non_image_upload(self):
|
||||
response = upload_helper(self, "nonimagefile")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotEqual(response.context['upload_avatar_form'].errors, {})
|
||||
|
||||
def testNormalImageUpload(self):
|
||||
def test_normal_image_upload(self):
|
||||
response = upload_helper(self, "test.png")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.redirect_chain), 1)
|
||||
self.assertEqual(response.context['upload_avatar_form'].errors, {})
|
||||
avatar = get_primary_avatar(self.user)
|
||||
self.assertNotEqual(avatar, None)
|
||||
self.assertIsNotNone(avatar)
|
||||
self.assertEqual(avatar.user, self.user)
|
||||
self.assertTrue(avatar.primary)
|
||||
|
||||
def testImageWithoutExtension(self):
|
||||
def test_image_without_wrong_extension(self):
|
||||
# use with AVATAR_ALLOWED_FILE_EXTS = ('.jpg', '.png')
|
||||
response = upload_helper(self, "imagefilewithoutext")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
|
||||
self.assertNotEqual(response.context['upload_avatar_form'].errors, {})
|
||||
|
||||
def testImageWithWrongExtension(self):
|
||||
def test_image_with_wrong_extension(self):
|
||||
# use with AVATAR_ALLOWED_FILE_EXTS = ('.jpg', '.png')
|
||||
response = upload_helper(self, "imagefilewithwrongext.ogg")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
|
||||
self.assertNotEqual(response.context['upload_avatar_form'].errors, {})
|
||||
|
||||
def testImageTooBig(self):
|
||||
def test_image_too_big(self):
|
||||
# use with AVATAR_MAX_SIZE = 1024 * 1024
|
||||
response = upload_helper(self, "testbig.png")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
|
||||
self.assertNotEqual(response.context['upload_avatar_form'].errors, {})
|
||||
|
||||
def testDefaultUrl(self):
|
||||
def test_default_url(self):
|
||||
response = self.client.get(reverse('avatar_render_primary', kwargs={
|
||||
'user': self.user.username,
|
||||
'size': 80,
|
||||
|
|
@ -73,18 +92,18 @@ class AvatarUploadTests(TestCase):
|
|||
self.assertTrue(base_url in loc)
|
||||
self.assertTrue(loc.endswith(settings.AVATAR_DEFAULT_URL))
|
||||
|
||||
def testNonExistingUser(self):
|
||||
def test_non_existing_user(self):
|
||||
a = get_primary_avatar("nonexistinguser")
|
||||
self.assertEqual(a, None)
|
||||
|
||||
def testThereCanBeOnlyOnePrimaryAvatar(self):
|
||||
def test_there_can_be_only_one_primary_avatar(self):
|
||||
for i in range(1, 10):
|
||||
self.testNormalImageUpload()
|
||||
self.test_normal_image_upload()
|
||||
count = Avatar.objects.filter(user=self.user, primary=True).count()
|
||||
self.assertEqual(count, 1)
|
||||
|
||||
def testDeleteAvatar(self):
|
||||
self.testNormalImageUpload()
|
||||
def test_delete_avatar(self):
|
||||
self.test_normal_image_upload()
|
||||
avatar = Avatar.objects.filter(user=self.user)
|
||||
self.assertEqual(len(avatar), 1)
|
||||
response = self.client.post(reverse('avatar_delete'), {
|
||||
|
|
@ -95,8 +114,8 @@ class AvatarUploadTests(TestCase):
|
|||
count = Avatar.objects.filter(user=self.user).count()
|
||||
self.assertEqual(count, 0)
|
||||
|
||||
def testDeletePrimaryAvatarAndNewPrimary(self):
|
||||
self.testThereCanBeOnlyOnePrimaryAvatar()
|
||||
def test_delete_primary_avatar_and_new_primary(self):
|
||||
self.test_there_can_be_only_one_primary_avatar()
|
||||
primary = get_primary_avatar(self.user)
|
||||
oid = primary.id
|
||||
self.client.post(reverse('avatar_delete'), {
|
||||
|
|
@ -108,9 +127,30 @@ class AvatarUploadTests(TestCase):
|
|||
avatars = Avatar.objects.filter(user=self.user)
|
||||
self.assertEqual(avatars[0].id, primaries[0].id)
|
||||
|
||||
def testTooManyAvatars(self):
|
||||
def test_change_avatar_get(self):
|
||||
self.test_normal_image_upload()
|
||||
response = self.client.get(reverse('avatar_change'))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNotNone(response.context['avatar'])
|
||||
|
||||
def test_change_avatar_post_updates_primary_avatar(self):
|
||||
self.test_there_can_be_only_one_primary_avatar()
|
||||
old_primary = Avatar.objects.get(user=self.user, primary=True)
|
||||
choice = Avatar.objects.filter(user=self.user, primary=False)[0]
|
||||
response = self.client.post(reverse('avatar_change'), {
|
||||
'choice': choice.pk,
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
new_primary = Avatar.objects.get(user=self.user, primary=True)
|
||||
self.assertEqual(new_primary.pk, choice.pk)
|
||||
# Avatar with old primary pk exists but it is not primary anymore
|
||||
self.assertTrue(Avatar.objects.filter(user=self.user, pk=old_primary.pk, primary=False).exists())
|
||||
|
||||
def test_too_many_avatars(self):
|
||||
for i in range(0, settings.AVATAR_MAX_AVATARS_PER_USER):
|
||||
self.testNormalImageUpload()
|
||||
self.test_normal_image_upload()
|
||||
count_before = Avatar.objects.filter(user=self.user).count()
|
||||
response = upload_helper(self, "test.png")
|
||||
count_after = Avatar.objects.filter(user=self.user).count()
|
||||
|
|
@ -119,6 +159,98 @@ class AvatarUploadTests(TestCase):
|
|||
self.assertNotEqual(response.context['upload_avatar_form'].errors, {})
|
||||
self.assertEqual(count_before, count_after)
|
||||
|
||||
@override_settings(AVATAR_THUMB_FORMAT='png')
|
||||
def test_automatic_thumbnail_creation_RGBA(self):
|
||||
upload_helper(self, "django.png")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
image = Image.open(avatar.avatar.storage.open(avatar.avatar_name(settings.AVATAR_DEFAULT_SIZE), 'rb'))
|
||||
self.assertEqual(image.mode, 'RGBA')
|
||||
|
||||
def test_automatic_thumbnail_creation_CMYK(self):
|
||||
upload_helper(self, "django_pony_cmyk.jpg")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
image = Image.open(avatar.avatar.storage.open(avatar.avatar_name(settings.AVATAR_DEFAULT_SIZE), 'rb'))
|
||||
self.assertEqual(image.mode, 'RGB')
|
||||
|
||||
def test_has_avatar_False_if_no_avatar(self):
|
||||
self.assertFalse(avatar_tags.has_avatar(self.user))
|
||||
|
||||
def test_has_avatar_False_if_not_user_model(self):
|
||||
self.assertFalse(avatar_tags.has_avatar("Look, I'm a string"))
|
||||
|
||||
def test_has_avatar_True(self):
|
||||
upload_helper(self, "test.png")
|
||||
|
||||
self.assertTrue(avatar_tags.has_avatar(self.user))
|
||||
|
||||
def test_avatar_tag_works_with_username(self):
|
||||
upload_helper(self, "test.png")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
|
||||
result = avatar_tags.avatar(self.user.username)
|
||||
|
||||
self.assertIn('<img src="{}"'.format(avatar.avatar_url(80)), result)
|
||||
self.assertIn('width="80" height="80" alt="test" />', result)
|
||||
|
||||
def test_avatar_tag_works_with_user(self):
|
||||
upload_helper(self, "test.png")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
|
||||
result = avatar_tags.avatar(self.user)
|
||||
|
||||
self.assertIn('<img src="{}"'.format(avatar.avatar_url(80)), result)
|
||||
self.assertIn('width="80" height="80" alt="test" />', result)
|
||||
|
||||
def test_avatar_tag_works_with_custom_size(self):
|
||||
upload_helper(self, "test.png")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
|
||||
result = avatar_tags.avatar(self.user, 100)
|
||||
|
||||
self.assertIn('<img src="{}"'.format(avatar.avatar_url(100)), result)
|
||||
self.assertIn('width="100" height="100" alt="test" />', result)
|
||||
|
||||
def test_avatar_tag_works_with_kwargs(self):
|
||||
upload_helper(self, "test.png")
|
||||
avatar = get_primary_avatar(self.user)
|
||||
|
||||
result = avatar_tags.avatar(self.user, title="Avatar")
|
||||
html = '<img src="{}" width="80" height="80" alt="test" title="Avatar" />'.format(avatar.avatar_url(80))
|
||||
self.assertInHTML(html, result)
|
||||
|
||||
def test_default_add_template(self):
|
||||
response = self.client.get('/avatar/add/')
|
||||
self.assertContains(response, 'Upload New Image')
|
||||
self.assertNotContains(response, 'ALTERNATE ADD TEMPLATE')
|
||||
|
||||
@override_settings(AVATAR_ADD_TEMPLATE='alt/add.html')
|
||||
def test_custom_add_template(self):
|
||||
response = self.client.get('/avatar/add/')
|
||||
self.assertNotContains(response, 'Upload New Image')
|
||||
self.assertContains(response, 'ALTERNATE ADD TEMPLATE')
|
||||
|
||||
def test_default_change_template(self):
|
||||
response = self.client.get('/avatar/change/')
|
||||
self.assertContains(response, 'Upload New Image')
|
||||
self.assertNotContains(response, 'ALTERNATE CHANGE TEMPLATE')
|
||||
|
||||
@override_settings(AVATAR_CHANGE_TEMPLATE='alt/change.html')
|
||||
def test_custom_change_template(self):
|
||||
response = self.client.get('/avatar/change/')
|
||||
self.assertNotContains(response, 'Upload New Image')
|
||||
self.assertContains(response, 'ALTERNATE CHANGE TEMPLATE')
|
||||
|
||||
def test_default_delete_template(self):
|
||||
response = self.client.get('/avatar/delete/')
|
||||
self.assertContains(response, 'like to delete.')
|
||||
self.assertNotContains(response, 'ALTERNATE DELETE TEMPLATE')
|
||||
|
||||
@override_settings(AVATAR_DELETE_TEMPLATE='alt/delete.html')
|
||||
def test_custom_delete_template(self):
|
||||
response = self.client.get('/avatar/delete/')
|
||||
self.assertNotContains(response, 'like to delete.')
|
||||
self.assertContains(response, 'ALTERNATE DELETE TEMPLATE')
|
||||
|
||||
# def testAvatarOrder
|
||||
# def testReplaceAvatarWhenMaxIsOne
|
||||
# def testHashFileName
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
try:
|
||||
from django.conf.urls import patterns, include
|
||||
except ImportError:
|
||||
from django.conf.urls.defaults import patterns, include
|
||||
from django.conf.urls import include, url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^avatar/', include('avatar.urls')),
|
||||
)
|
||||
urlpatterns = [
|
||||
url(r'^avatar/', include('avatar.urls')),
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue